Share
Embed
Unity に於ける iOS ビルド自動化のおはなし【実践編】
Tetsuya Mori PRO
October 30, 2014
Transcript
62 slides
-
XIPBNJ w େֶΛ ࣗओతʹ ଔۀޙɺϕϯνϟʔΛసʑɻ w 8FCͷϑϩϯτΤϯυɺαʔόαΠυ͕ಘҙɻ w 6OJUZྺ͘Β͍ɻ w
"84ͱΩϟοΩϟϑϑ͢Δͷ͖Ͱ͢ɻ w ઈࢍ4IBEFSͷ͓ษڧதɻ -
MTMBBQQT ͳΓ͖Γ ͬ͜͝ϥϯυ ύζϧςΠϧζ ͓͔͠ͷ͘ʹΛ ͭ͘Δͷ͡Ό ͳΓ͖Γ ΞΠεΫϦʔϜ ͞Μͬ͜͝ ͳΓ͖Γ
ϚϚͬ͜͝ ͓หΛͭ͘Ζ͏ʂ ͓͔͠ͷՈΛ ͭ͘Ζ͏ʂ ϋϯόʔΨʔ ͞Μͬ͜͝ ඈߦػΛ ΈཱͯΑ͏ʂ i18n i18n i18n i18n Ώ͔͍ͳ ͓Ֆ͞Μ App Store / Google Play カテゴリランキング1位 多数獲得!!! -
ڥ w 0QFSBUJPO4ZTUFN049:PTFNJUF w 6OJUZG 1SP0OMZ w 9DPEF XJUI$PNNJOE-JOF5PPMT
w 1MBUGPSNJ04 w -BOHVBHF$ w 0UIFS9DPEF&EJUPSGPS6OJUZ GPSLFECZNPOSZ -
1SF"SDIJWF w ΞΠίϯઃఆ w "3$ͳ/BUJWF1MVHJOGPCKDBSDͷઃఆ w 0UIFS-JOLFS'MBHTͷઃఆ w Ճ'SBNFXPSLͷઃఆ w
ΞΠίϯԼͷΞϓϦ໊ઃఆ w 63-4DIFNFTઃఆ -
&YQPSU9DPEF1SPKFDU BuildPipeline.BuildPlayer( new string[] { "Main.scene" }, "/Users/monry/SampleProject", BuildTarget.iPhone, BuildOptions.Development
| BuildOptions.AllowDebugging ); &YBNQMF ͜ΕͰ9DPEF1SPKFDU͕ग़ྗ͞ΕΔ -
"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ߏϢʔςΟϦςΟ ͱ͔ͰௐΔײ͡Ͱɻ -
"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Λࢦఆ͢Δ -
ΞΠίϯઃఆ 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༻ͷΞΠίϯ͕ൈ͚ΔͷͰɻ ࠷৽ ͰରԠࡁ͔ʁ ௐͯͳ͍ɻ -
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ʹϑϥάΛ͚ͯ͋͛Δඞཁ͕͋Δɻ -
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%,ͱ͔͏ͱ͖ʹඞཁͩͬͨΓ͢Δɻ -
Ճ'SBNFXPSLͷઃఆ { "group": "", "patches": [], "libs": [], "librarysearchpaths": [],
"frameworksearchpaths": [], "frameworks": [ "Security.framework", "CoreData.framework", ], "headerpaths": [], "files": [], "folders": [], "excludes": ["^.*\\.meta$", "^.*\\.mdown^", "^.*\\.pdf$"] } IPHFQSPKNPETͷαϯϓϧ +40/ܗࣜͰهड़ɻ ঢ়گʹԠͯ͡ଞͷΩʔઃఆͨ͠Γͱ͔ɻ -
ΞΠίϯԼͷΞϓϦ໊ // Unity-iPhone/en.lproj/InfoPlist.strings CFBundleDisplayName = "HogeFuga"; // Unity-iPhone/ja.lproj/InfoPlist.strings CFBundleDisplayName =
"ほげふが"; ઌͣ*OGP1MJTUTUSJOHTΛ࡞Δ ϑΝΠϧ໊ͱ͔ίϨ͡Όແͯ͘0, -
ΞΠίϯԼͷΞϓϦ໊ 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ΛՃ͠ͳ͍ͱμϝɻ -
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.- ΛΰϦΰϦॻ͖͑Δ จࣈͷτίɺॻ͖͑ͯͶɻ