Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RubyでiOSアプリをビルドしよう

henteko
August 25, 2016

 RubyでiOSアプリをビルドしよう

iOSDC 2016 前夜祭

henteko

August 25, 2016
Tweet

More Decks by henteko

Other Decks in Technology

Transcript

  1. 3VCZͰJ04ΞϓϦΛ
    Ϗϧυ͠Α͏
    J04%$લ໷ࡇ
    ΁Μͯ͜

    View full-size slide

  2. %FQMPZ(BUF
    5XJUUFS!IFOUFLP
    ࣗݾ঺հ
    ΁Μͯ͜

    View full-size slide

  3. 3VCZͰJ04ΞϓϦΛ
    Ϗϧυ͢Δख๏

    View full-size slide

  4. EHBEEEFWJDFT

    View full-size slide

  5. BEEEFWJDFTҎલ

    View full-size slide

  6. Ϣʔβʔ͕ΞϓϦͷςετʹࢀՃ
    ͜ͷ࣌఺Ͱ͸·ͩΞϓϦͷΠϯετʔϧ͕ग़དྷͳ͍

    6%*%͕։ൃऀʹ఻ΘΔ
    खಈͰ%FW$FOUFSʹొ࿥্ͯ͛͠௚͠
    ΞϓϦΠϯετʔϧͰ͖ΔΑ͏ʹ

    View full-size slide

  7. BEEEFWJDFT࢖͏ͱ

    View full-size slide

  8. Ϣʔβʔ͕ΞϓϦͷςετʹࢀՃ
    ͜ͷ࣌఺Ͱ͸·ͩΞϓϦͷΠϯετʔϧ͕ग़དྷͳ͍

    BEEEFWJDFTΛୟ͚ͩ͘
    ΞϓϦΠϯετʔϧͰ͖ΔΑ͏ʹ

    View full-size slide

  9. BEEEFWJDFTTFSWFS

    View full-size slide

  10. Ϣʔβʔ͕ΞϓϦͷςετʹࢀՃ
    ͜ͷ࣌఺Ͱ͸·ͩΞϓϦͷΠϯετʔϧ͕ग़དྷͳ͍

    ࣗಈͰΞϓϦ͕Ϗϧυ͞ΕΔ
    ͙͢ʹΞϓϦΠϯετʔϧͰ͖ΔΑ͏ʹ

    View full-size slide

  11. ओʹ͍ͯ͠Δ͜ͱ
    9DPEFϓϩδΣΫτͷղੳ
    ϩʔΧϧͷ1SPWJTJPOJOH1SPpMFͷղੳ
    J04ΞϓϦͷϏϧυ

    View full-size slide

  12. 9DPEFϓϩδΣΫτղੳ
    #VOEMF*EFOUJpFSͷऔಘ
    ྫDPNIFOUFLPMPPQFS
    ઃఆ͍ͯ͠Δ1SPWJTJPOJOH1SPpMFͷಛఆ

    View full-size slide

  13. 9DPEFϓϩδΣΫτղੳ
    Ϗϧυ͢Δ4DIFNFΛಛఆ͢Δ
    ͦͷ4DIFNFͷYDTDIFNFϑΝΠϧΛऔಘ͢Δ
    YDTDIFNFϑΝΠϧ͔Β5BSHFU/BNFΛऔಘ͢Δ
    9DPEFϓϩδΣΫτΛऔಘ͢Δ

    View full-size slide

  14. 4DIFNFऔಘ
    Ϗϧυର৅ͷ4DIFNFΛऔಘ͢Δ

    View full-size slide

  15. 4DIFNFऔಘ
    HZN GBTUMBOF
    Λ࢖͍ͬͯΔ
    1 def target_scheme
    2 config = FastlaneCore::Configuration.create(
    3 Gym::Options.available_options,
    4 {
    5 workspace: XCODE_WORKSPACE_PATH
    6 }
    7 )
    8 project = FastlaneCore::Project.new(config)
    9 project.select_scheme
    10 project.options[:scheme]
    11 end

    View full-size slide

  16. YDTDIFNFϑΝΠϧऔಘ
    औಘͨ͠4DIFNF͔ΒYDTDIFNFϑΝΠϧΛऔಘ
    ͢Δ
    ී௨ʹσΟϨΫτϦ಺Λ୳ࡧ
    BQQYDPEFQSPKYDVTFSEBUBVTFSYDVTFSEBUBE
    YDTDIFNFTUBSHFU@TDIFNFYDTDIFNF

    View full-size slide

  17. 1 def find_xcschemes(target_scheme)
    2 Dir[
    3 File.join(
    4 XCODE_PROJECT_PATH,
    5 'xcuserdata',
    6 '*.xcuserdatad',
    7 'xcschemes',
    8 '*.xcscheme'
    9 )
    10 ].reject do |scheme|
    11 target_scheme !=
    12 File.basename(scheme, '.xcscheme')
    13 end
    14 end

    View full-size slide

  18. 5BSHFU/BNFͷऔಘ
    औಘͨ͠YDTDIFNFϑΝΠϧ͔ΒUBSHFUOBNFΛ
    औಘ͢Δ
    YDPEFQSPKΛ࢖͍ͬͯΔ

    View full-size slide

  19. 1 xs = Xcodeproj::XCScheme.new(scheme_file)
    2 target_name = xs.
    3 profile_action.
    4 buildable_product_runnable.
    5 buildable_reference.
    6 target_name

    View full-size slide

  20. 9DPEFϓϩδΣΫτऔಘ
    ϓϩδΣΫτΛऔಘ͢Δ
    1 project = Xcodeproj::Project.open(
    2 XCODE_PROJECT_PATH)
    3 project = project.
    4 native_targets.
    5 reject{|target| target.name != target_name}.
    6 first

    View full-size slide

  21. #VJME$POpHVSBUJPO
    ֤#VJMEDPOpHVSBUJPO͝ͱͷઃఆΛऔಘͰ͖Δ
    1 def target_build_configuration(target_project)
    2 target_project.
    3 build_configuration_list.
    4 build_configurations.
    5 reject{|conf| conf.name != 'Release'}.
    6 first
    7 end

    View full-size slide

  22. ֤ઃఆΛऔಘ
    #VOEMF*EFOUJpFSͳͲΛऔಘͰ͖Δ
    1 target_project.
    2 product_name
    3 target_build_configuration.
    4 build_settings['PRODUCT_BUNDLE_IDENTIFIER']
    5 target_build_configuration.
    6 build_settings['PROVISIONING_PROFILE']

    View full-size slide

  23. 1SPWJTJPOJOH1SPpMFղੳ
    ϩʔΧϧʹ͋Δ1SPWJTJPOJOH1SPpMFΛղੳ͢Δ
    1SPWJTJPOJOH1SPpMFͷূ໌ॻ͕.BDʹΠϯετʔ
    ϧ͞Ε͍ͯΔ͔ݟΔ

    View full-size slide

  24. QSPpMFͷऔಘ
    NPCJMFQSPWJTJPOϑΝΠϧΛऔಘ͢Δ
    d-JCSBSZ.PCJMF%FWJDF1SPWJTJPOJOH1SPpMFT
    ʹଘࡏ͍ͯ͠Δ

    View full-size slide

  25. 1 def load_profile_paths
    2 profiles_path =
    3 File.expand_path("~") +
    4 "/Library/MobileDevice/Provisioning
    5 Profiles/*.mobileprovision"
    6 Dir[profiles_path]
    7 end

    View full-size slide

  26. QSPpMFΛղੳ
    PQFOTTMͱQMJTUͰղੳ͢Δ
    1 def profile_to_plist(profile_path)
    2 File.open(profile_path) do |profile|
    3 asn1 = OpenSSL::ASN1.decode(profile.read)
    4 plist_str = asn1.value[1].value[0].value[2].
    5 value[1].value[0].value
    6 plist = Plist.parse_xml plist_str.
    7 force_encoding('UTF-8')
    8 plist['Path'] = profile_path
    9 return plist
    10 end
    11 end

    View full-size slide

  27. 66*%
    ༗ޮظݶ
    "QQMJDBUJPO*EFOUJpFS
    5FBNOBNF
    1 profile['UUID']
    2 profile['ExpirationDate']
    3 if profile['Entitlements']
    4 profile['Entitlements']['application-
    5 identifier']
    6 end
    7 profile['TeamName']

    View full-size slide

  28. "EIPD͔Ͳ͏͔
    1SPWJTJPOJOH1SPpMF͕"EIPD༻͔Ͳ͏͔֬ೝͰ͖
    Δ
    1SPWJTJPOT"MM%FWJDFT͕͋Δͱ*O)PVTF༻
    1 def adhoc?(profile)
    2 !profile['Entitlements']['get-task-allow'] &&
    3 profile['ProvisionsAllDevices'].nil?
    4 end

    View full-size slide

  29. ূ໌ॻͷ֬ೝ
    .BDʹ1SPWJTJPOJOH1SPpMFͷূ໌ॻ͕Πϯετʔ
    ϧ͞Ε͍ͯΔ͔Ͳ͏͔ͷ֬ೝ
    Πϯετʔϧ͞Ε͍ͯͳ͍ͱJ04ΞϓϦͷϏϧυʹ
    ࣦഊ͢Δ

    View full-size slide

  30. ূ໌ॻҰཡऔಘ
    TFDVSJUZίϚϯυΛ࢖͏
    1 def installed_certificates
    2 available = `security find-identity -v -p
    3 codesigning`
    4 certificates = []
    5 available.split("\n").each do |current|
    6 next if current.include? "REVOKED"
    7 certificates << current
    8 end
    9
    10 certificates
    11 end

    View full-size slide

  31. J1IPOF%JTUSJCVUJPO༻Λऔಘ
    J1IPOF%JTUSJCVUJPO)0(&ͳ΋ͷ͚ͩΛऔಘ
    1 def installed_distribution_certificate_ids
    2 certificates = installed_certificates()
    3 ids = []
    4 certificates.each do |current|
    5 next unless current.match(/iPhone
    6 Distribution:/)
    7 (ids << current.match(/.*\) (.*) \".*/)[1])
    8 end
    9
    10 ids
    11 end

    View full-size slide

  32. Πϯετʔϧ֬ೝ
    PQFOTTMͰ1SPpMFͷJEΛ֬ೝ
    ΠϯετʔϧࡁΈͷJEʹͦΕؚ͕·Ε͍ͯͨΒΠϯ
    ετʔϧࡁΈ

    View full-size slide

  33. 1 def installed_certificate?(profile_path)
    2 profile = profile_to_plist profile_path
    3 certs = profile['DeveloperCertificates'].map
    4 do |cert|
    5 certificate_str = cert.read
    6 certificate = OpenSSL::X509::Certificate.
    7 new certificate_str
    8 id = OpenSSL::Digest::SHA1.new(certificate.
    9 to_der).to_s.upcase
    10 installed_distribution_certificate_ids.
    11 include?(id)
    12 end
    13 certs.include?(true)
    14 end

    View full-size slide

  34. J04ΞϓϦϏϧυ
    HZN GBTUMBOF
    Λ࢖͏
    ಛʹԿ΋ߟ͑ͳͯ͘΋ɺࠓ·Ͱಘͨ৘ใͰϏϧυ͕
    Ͱ͖Δ

    View full-size slide

  35. 1 EXPORT_METHOD = 'ad-hoc'
    2 WORKSPACE = '/path/to/ios-app/app.xcodeproj'
    3 CONFIGURATION = 'Release'
    4 SCHEME = 'target_scheme'
    5 CODESIGNING_IDENTITY = 'iPhone Distribution:
    6 HOGE (xxxxxxxxx)'
    7
    8 def build
    9 values = {
    10 export_method: EXPORT_METHOD,
    11 workspace: WORKSPACE,
    12 configuration: CONFIGURATION,
    13 scheme: SCHEME,
    14 codesigning_identity:
    15 CODESIGNING_IDENTITY
    16 }
    17 v = FastlaneCore::Configuration.create(Gym::
    18 Options.available_options, values)
    19
    20 File.expand_path(Gym::Manager.new.work(v))
    21 end

    View full-size slide

  36. ·ͱΊ
    3VCZͰ9DPEFϓϩδΣΫτͷղੳ͕Ͱ͖·͢
    1SPWJTJPOJOH1SPpMFͷղੳ΋
    Ϗϧυ͸GBTUMBOFܦ༝ͰYDPEFCVJMEΛୟ͘ͷ͕
    ͓͢͢Ί
    IUUQTHJUIVCDPNIFOUFLP
    JPTED@@TBNQMF

    View full-size slide

  37. EHΑΖ͘͠Ͷʂ
    ιʔείʔυ͸(JUIVCͰެ։த

    View full-size slide