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

Unity に於ける iOS ビルド自動化のおはなし【実践編】

Unity に於ける iOS ビルド自動化のおはなし【実践編】

Tetsuya Mori

October 30, 2014
Tweet

More Decks by Tetsuya Mori

Other Decks in Programming

Transcript

  1. MTMBBQQT ͳΓ͖Γ ͬ͜͝ϥϯυ ύζϧςΠϧζ
 ͓͔͠ͷ͘ʹΛ ͭ͘Δͷ͡Ό ͳΓ͖Γ ΞΠεΫϦʔϜ ԰͞Μͬ͜͝ ͳΓ͖Γ

    ϚϚͬ͜͝ ͓ห౰Λͭ͘Ζ͏ʂ ͓͔͠ͷՈΛ ͭ͘Ζ͏ʂ ϋϯόʔΨʔ ΍͞Μͬ͜͝ ඈߦػΛ ૊ΈཱͯΑ͏ʂ i18n i18n i18n i18n Ώ͔͍ͳ ͓Ֆ԰͞Μ App Store / Google Play カテゴリランキング1位 多数獲得!!!
  2. ؀ڥ w 0QFSBUJPO4ZTUFN049:PTFNJUF w 6OJUZG 1SP0OMZ  w 9DPEF XJUI$PNNJOE-JOF5PPMT

     w 1MBUGPSNJ04 w -BOHVBHF$ w 0UIFS9DPEF&EJUPSGPS6OJUZ GPSLFECZNPOSZ
  3. "SDIJWF System.Diagnostics.Process process = new System.Diagnostics.Process(); process.StartInfo.FileName = "/usr/bin/xcodebuild"; process.StartInfo.Arguments

    = string.Format( "-project \"{0}/Unity-iPhone.xcodeproj\" -sdk iphoneos -target \"Unity-iPhone\" -configuration Release clean build CODE_SIGN_IDENTITY=\"iPhone Distribution\" PROVISIONING_PROFILE= \"{1}\"", "/path/to/export", "Provisioning Profile ID" ); process.StartInfo.CreateNoWindow = true; process.Start(); process.WaitForExit(); process.Close(); ઌͣ͸YDPEFCVJMEίϚϯυ࣮ߦ 1SPWJTJPOJOHͷ*%͸J1IPOFߏ੒ϢʔςΟϦςΟ ͱ͔Ͱௐ΂Δײ͡Ͱɻ
  4. "SDIJWF System.Diagnostics.Process process = new System.Diagnostics.Process(); process.StartInfo.FileName = "/usr/bin/xcrun"; process.StartInfo.Arguments

    = string.Format( "-sdk iphoneos PackageApplication \"{0}/build/{1}.app\" -o \"{0}/build/Unity-iPhone.ipa\" --embed \"{2}.mobileprovision\"", "/path/to/export", "SampleProject", // プロジェクト名 "Provisioning Profile ID" ); process.StartInfo.CreateNoWindow = true; process.Start(); process.WaitForExit(); process.Close(); ଓ͍ͯYDSVOίϚϯυ࣮ߦ ϓϩδΣΫτ໊͸ɺ1MBZFS4FUUJOHTͷ 1SPEVDU/BNFΛࢦఆ͢Δ
  5. ΞΠίϯઃఆ string path = "/path/to/export"; File.Copy( Path.Combine(Application.dataPath, "/Path/to/Icon-180.png"), Path.Combine(path, "Unity-iPhone/Images.xcassets/AppIcon.appiconset/Icon-180.png"),

    true ); string jsonText = File.ReadAllText( Path.Combine(path, "Unity-iPhone/Images.xcassets/AppIcon.appiconset/Contents.json") ); jsonText = Regex.Replace( jsonText, "\t\\}\n\t\\],", "\t},\n\t\t\t{\n\t\t\"size\" : \"60x60\",\n\t\t\"idiom\" : \"iphone\",\n\t\t\"filename\" : \"Icon-180.png\",\n\t\t\"scale\" : \"3x\"\n\t}\n\t]," ); File.WriteAllText( Path.Combine( path, "Unity-iPhone/Images.xcassets/AppIcon.appiconset/Contents.json" ), jsonText ); J1IPOF1MVT༻ͷΞΠίϯ͕ൈ͚ΔͷͰɻ ࠷৽  Ͱ͸ରԠࡁ͔΋ʁ ௐ΂ͯͳ͍ɻ
  6. GPCKDBSDઃఆ XCProject project = new UnityEditor.XCodeEditor.XCProject("/path/to/export"); string[] filePathList = new

    string[] { "/path/to/ file1", "/path/to/file2", ... }; foreach (string filePath in filePathList) { PBXBuildFile buildFile = project.GetBuildFile(project.GetFile(filePath)); if (null != buildFile) { buildFile.AddCompilerFlag("-fobjc-arc"); } } 9DPEF&EJUPSGPS6OJUZΛ࢖͏ 6OJUZ͸/PO"3$ͳͷͰɺ"3$ͳ/BUJWF 1MVHJOʹ͸ϑϥάΛ෇͚ͯ͋͛Δඞཁ͕͋Δɻ
  7. 0UIFS-JOLFS'MBHTઃఆ XCProject project = new UnityEditor.XCodeEditor.XCProject("/path/to/export"); string[] flagNameList = new

    string[] { "-ObjC", "- all_load", ... }; foreach (string flagName in flagNameList) { project.AddOtherLDFlags(flagName); } ಉ͘͡9DPEF&EJUPSGPS6OJUZ࢖͏ ֎෦4%,ͱ͔࢖͏ͱ͖ʹඞཁͩͬͨΓ͢Δɻ
  8. ௥Ճ'SBNFXPSLͷઃఆ { "group": "", "patches": [], "libs": [], "librarysearchpaths": [],

    "frameworksearchpaths": [], "frameworks": [ "Security.framework", "CoreData.framework", ], "headerpaths": [], "files": [], "folders": [], "excludes": ["^.*\\.meta$", "^.*\\.mdown^", "^.*\\.pdf$"] } IPHFQSPKNPETͷαϯϓϧ +40/ܗࣜͰهड़ɻ ঢ়گʹԠͯ͡ଞͷΩʔ΋ઃఆͨ͠Γͱ͔ɻ
  9. ΞΠίϯԼͷΞϓϦ໊ XCProject project = new UnityEditor.XCodeEditor.XCProject("/path/to/export"); PBXVariantGroup infoPlist = project.GetVariantGroup("InfoPlist.strings",

    null, project.GetGroup("Supporting Files")); string[] languageCodeList = new string[] { "ja", "en" }; foreach (string languageCode in languageCodeList) { project.project.AddKnownRegion(languageCode); project.AddFile( Path.Combine(this.path, string.Format("Unity-iPhone/{0}.lproj/ InfoPlist.strings", languageCode)), infoPlist, "SOURCE_ROOT", true, false, string.Format("{0}.lproj/InfoPlist.strings", languageCode) ); } *OGP1MJTUTUSJOHTΛ7BSJBOU(SPVQʹ௥Ճ 7BSJBOU(SPVQରԠ൛͕ίνϥʹ͍͟͝·͢ɻ ,OPXO3FHJPOΛ௥Ճ͠ͳ͍ͱμϝɻ
  10. 63-4DIFNFTઃఆ XmlDocument infoPlist = new XmlDocument(); infoPlist.Load(Path.Combine("/path/to/export", "Info.plist")); XmlNode infoPlistBaseNode

    = this.infoPlist.SelectSingleNode("/plist/dict"); // 一つ分の URL Type を表現するノードを構築 XmlElement _dict = infoPlist.CreateElement("dict"); _dict.AppendChild(infoPlist.CreateSimpleTextNode("key", "CFBundleTypeRole")); _dict.AppendChild(infoPlist.CreateSimpleTextNode("string", "Editor")); _dict.AppendChild(infoPlist.CreateSimpleTextNode("key", "CFBundleURLName")); _dict.AppendChild(infoPlist.CreateSimpleTextNode("string", "tv.kidsstar.app.${PRODUCT_NAME:rfc1034identifier}")); _dict.AppendChild(infoPlist.CreateSimpleTextNode("key", "CFBundleURLSchemes")); XmlElement _array = infoPlist.CreateElement("array"); _array.AppendChild(infoPlist.CreateSimpleTextNode("string", "tv.kidsstar.app.${PRODUCT_NAME:rfc1034identifier}")); _dict.AppendChild(_array); // 作ったノードを key: CFBundleURLTypes の要素として追加 XmlNode _CFBundleURLTypesNode = infoPlist.SelectSingleNode("/plist/dict/array[preceding-sibling::key[.= \"CFBundleURLTypes\"]][1]"); if (null == _CFBundleURLTypesNode) { infoPlistBaseNode.AppendChild(infoPlist.CreateSimpleTextNode("key", "CFBundleURLTypes")); _CFBundleURLTypesNode = infoPlist.CreateElement("array"); infoPlistBaseNode.AppendChild(_CFBundleURLTypesNode); } _CFBundleURLTypesNode.AppendChild(_dict); JOGPQMJTU 9.- ΛΰϦΰϦॻ͖׵͑Δ ੺จࣈͷτί͸ɺॻ͖׵͑ͯͶɻ