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

13a7077b3e75fa9578056b8f31b1746b?s=47 henteko
August 25, 2016

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

iOSDC 2016 前夜祭

13a7077b3e75fa9578056b8f31b1746b?s=128

henteko

August 25, 2016
Tweet

Transcript

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

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

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

  4. EHEFQMPZ

  5. None
  6. EHBEEEFWJDFT

  7. BEEEFWJDFTҎલ

  8. Ϣʔβʔ͕ΞϓϦͷςετʹࢀՃ ͜ͷ࣌఺Ͱ͸·ͩΞϓϦͷΠϯετʔϧ͕ग़དྷͳ͍ 6%*%͕։ൃऀʹ఻ΘΔ खಈͰ%FW$FOUFSʹొ࿥্ͯ͛͠௚͠ ΞϓϦΠϯετʔϧͰ͖ΔΑ͏ʹ

  9. BEEEFWJDFT࢖͏ͱ

  10. Ϣʔβʔ͕ΞϓϦͷςετʹࢀՃ ͜ͷ࣌఺Ͱ͸·ͩΞϓϦͷΠϯετʔϧ͕ग़དྷͳ͍ BEEEFWJDFTΛୟ͚ͩ͘ ΞϓϦΠϯετʔϧͰ͖ΔΑ͏ʹ

  11. BEEEFWJDFTTFSWFS

  12. Ϣʔβʔ͕ΞϓϦͷςετʹࢀՃ ͜ͷ࣌఺Ͱ͸·ͩΞϓϦͷΠϯετʔϧ͕ग़དྷͳ͍ ࣗಈͰΞϓϦ͕Ϗϧυ͞ΕΔ ͙͢ʹΞϓϦΠϯετʔϧͰ͖ΔΑ͏ʹ ਆ

  13. None
  14. 3VCZ

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

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

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

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

  19. None
  20. 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
  21. YDTDIFNFϑΝΠϧऔಘ औಘͨ͠4DIFNF͔ΒYDTDIFNFϑΝΠϧΛऔಘ ͢Δ ී௨ʹσΟϨΫτϦ಺Λ୳ࡧ BQQYDPEFQSPKYDVTFSEBUBVTFSYDVTFSEBUBE YDTDIFNFTUBSHFU@TDIFNFYDTDIFNF

  22. 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
  23. 5BSHFU/BNFͷऔಘ औಘͨ͠YDTDIFNFϑΝΠϧ͔ΒUBSHFUOBNFΛ औಘ͢Δ YDPEFQSPKΛ࢖͍ͬͯΔ

  24. 1 xs = Xcodeproj::XCScheme.new(scheme_file) 2 target_name = xs. 3 profile_action.

    4 buildable_product_runnable. 5 buildable_reference. 6 target_name
  25. 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
  26. #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
  27. ֤ઃఆΛऔಘ #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']
  28. 1SPWJTJPOJOH1SPpMFղੳ ϩʔΧϧʹ͋Δ1SPWJTJPOJOH1SPpMFΛղੳ͢Δ 1SPWJTJPOJOH1SPpMFͷূ໌ॻ͕.BDʹΠϯετʔ ϧ͞Ε͍ͯΔ͔ݟΔ

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

  30. 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
  31. 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
  32. 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']
  33. "EIPD͔Ͳ͏͔ 1SPWJTJPOJOH1SPpMF͕"EIPD༻͔Ͳ͏͔֬ೝͰ͖ Δ 1SPWJTJPOT"MM%FWJDFT͕͋Δͱ*O)PVTF༻ 1 def adhoc?(profile) 2 !profile['Entitlements']['get-task-allow'] &&

    3 profile['ProvisionsAllDevices'].nil? 4 end
  34. ূ໌ॻͷ֬ೝ .BDʹ1SPWJTJPOJOH1SPpMFͷূ໌ॻ͕Πϯετʔ ϧ͞Ε͍ͯΔ͔Ͳ͏͔ͷ֬ೝ Πϯετʔϧ͞Ε͍ͯͳ͍ͱJ04ΞϓϦͷϏϧυʹ ࣦഊ͢Δ

  35. ূ໌ॻҰཡऔಘ 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
  36. 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
  37. Πϯετʔϧ֬ೝ PQFOTTMͰ1SPpMFͷJEΛ֬ೝ ΠϯετʔϧࡁΈͷJEʹͦΕؚ͕·Ε͍ͯͨΒΠϯ ετʔϧࡁΈ

  38. 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
  39. J04ΞϓϦϏϧυ HZN GBTUMBOF Λ࢖͏ ಛʹԿ΋ߟ͑ͳͯ͘΋ɺࠓ·Ͱಘͨ৘ใͰϏϧυ͕ Ͱ͖Δ

  40. 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
  41. ·ͱΊ 3VCZͰ9DPEFϓϩδΣΫτͷղੳ͕Ͱ͖·͢ 1SPWJTJPOJOH1SPpMFͷղੳ΋ Ϗϧυ͸GBTUMBOFܦ༝ͰYDPEFCVJMEΛୟ͘ͷ͕ ͓͢͢Ί IUUQTHJUIVCDPNIFOUFLP JPTED@@TBNQMF

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