Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Unity に於ける iOS ビルド自動化のおはなし【実践編】
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Tetsuya Mori
PRO
October 30, 2014
Programming
270
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Unity に於ける iOS ビルド自動化のおはなし【実践編】
Tetsuya Mori
PRO
October 30, 2014
More Decks by Tetsuya Mori
See All by Tetsuya Mori
ビルドシステムを C# 大統一したお話
monry
PRO
2
1.5k
C# 大統一理論推進委員会 会員のための Unity Package Manager プロジェクト構成案
monry
PRO
0
1.7k
はじめての C# 大統一理論
monry
PRO
0
830
unity1week でチーム開発を成功させる秘訣
monry
PRO
0
310
Unity で ARゲームを作った話
monry
PRO
1
1k
Visual Programming Framework UniFlow のご紹介/Introducing UniFlow
monry
PRO
2
3.2k
UniFlow 完全に理解した / I can develop UniFlow a little.
monry
PRO
0
550
Democratized Unity Package Manager
monry
PRO
1
3k
使ってみよう! Unity RemoteSettings/Let's use Unity RemoteSettings
monry
PRO
1
1.3k
Other Decks in Programming
See All in Programming
Agentic UI
manfredsteyer
PRO
0
120
生成AI時代にこそ効くGo | Why Go Works in the Age of Generative AI
mom0tomo
8
3.2k
A2UI という光を覗いてみる
satohjohn
1
120
RTSPクライアントを自作してみた話
simotin13
0
520
These Five Tricks Can Make Your Apps Greener, Cheaper, & Nicer
hollycummins
0
280
並列実装の現場、2ヶ月間実務でAIを使い倒したAIもPCも私も限界が近い
ming_ayami
0
110
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
120
Hunting Vulnerabilities in Symfony with LLMs
vinceamstoutz
0
530
肥大化するレガシーコードに立ち向かうためのインターフェース分離と依存の逆転 / JJUG CCC 2026 Spring
hirokunimaeta
0
520
気づいたらRubyで100作品 ー クリエイティブコーディングが生活の一部になるまで / 100 Ruby Sketches Later: How Creative Coding Became Part of My Life
chobishiba
3
560
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.6k
Technical Debt: Understanding it Rightly, Engaging it Rightly #LaravelLiveJP
shogogg
0
210
Featured
See All Featured
RailsConf 2023
tenderlove
30
1.5k
Optimizing for Happiness
mojombo
378
71k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
450
Measuring & Analyzing Core Web Vitals
bluesmoon
9
860
Crafting Experiences
bethany
1
170
Statistics for Hackers
jakevdp
799
230k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
560
Odyssey Design
rkendrick25
PRO
2
690
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.5k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
250
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.9k
The AI Search Optimization Roadmap by Aleyda Solis
aleyda
1
5.9k
Transcript
6OJUZʹԙ͚Δ J04ϏϧυࣗಈԽͷ ͓ͳ͠ʲ࣮ફฤʳ 5IV 6OJUZษڧձWPM גࣜձࣾΩοζελʔ γεςϜσϕϩϓϝϯτνʔϜϦʔμʔ ɹ࠸
͜ΜΜʂ
ʮ·͓ͨલ͔ʯ ͱ͔ݴΘͳ͍ɻ ΜΓ͌Ͱͬ͢ʂ
ࠓͷςʔϚ
None
ͱɺ͍͏Θ͚Ͱ Ϗϧυ ͷ͓ͳ͠Ͱ͢
͓͠ͳ͕͖
͓͠ͳ͕͖ w ࣗݾհ w લஔ͖ w Δ͜ͱ w Γ͔ͨ
ࣗݾհ
XIPBNJ w lɹ࠸zͱਃ͠·͢ɻ w BLBΜΓ͌5!NPOSZ'NPOSZ w ࡀˁ0ܕఱṝ࠲طࠗ w झຯʮ͓ञʯͱʮ߹এʯͰ͢ɻ
XIPBNJ w େֶΛ ࣗओతʹ ଔۀޙɺϕϯνϟʔΛసʑɻ w 8FCͷϑϩϯτΤϯυɺαʔόαΠυ͕ಘҙɻ w 6OJUZྺ͘Β͍ɻ w
"84ͱΩϟοΩϟϑϑ͢Δͷ͖Ͱ͢ɻ w ઈࢍ4IBEFSͷ͓ษڧதɻ
KPCT w lגࣜձࣾΩοζελʔzͬͯձࣾͰಇ͍ͯ·͢ɻ w ະबֶࣇʙখֶੜͷ͓ࢠ͞·Λ͓࣋ͪͷ ϑΝϛϦʔΛλʔήοτʹͨ͠ɺҭڭҭʹ ؔΘΔΞϓϦɾαʔϏεΛల։͓ͯ͠Γ·͢ɻ w ͓ӄ༷Ͱ&E5FDIͳҭʹԙ͍ͯ /PنͰల։͓ͯ͠Γ·͢ʂ
ࣾௐ͆
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
ࠓΔίτ w l#VJMEzϘλϯΛԡͨ͠Ҏ߱ͷ w ۃྗ9DPEFΛૢ࡞͠ͳ͍ͬͯ w 1PTU1SPDFTT#VJMEͳ
ࠓΒͳ͍͜ͱ w /BUJWF1MVHJOͷ w J5VOFT$POOFDUͰͷਃͷ
Δ͜ͱ
6OJUZ㱺9DPEF
6OJUZ㱺9DPEF ͜ͷϘλϯΛԡ͢ͱʜ
6OJUZ㱺9DPEF ίϨΛܗʹͯ͠ʜ
6OJUZ㱺9DPEF ͜Μͳͷ͕ग़ྗ͞Εʜ
6OJUZ㱺9DPEF ͍ͭ͜ʹϓϩδΣΫτใͱ͔͕ఆٛ͞ΕΔ
"SDIJWF
1SF"SDIJWF w ΞΠίϯઃఆ w "3$ͳ/BUJWF1MVHJOGPCKDBSDͷઃఆ w 0UIFS-JOLFS'MBHTͷઃఆ w Ճ'SBNFXPSLͷઃఆ w
ΞΠίϯԼͷΞϓϦ໊ઃఆ w 63-4DIFNFTઃఆ
1BDLBHJOH ίϨΛग़ྗ͢Δ
1BDLBHJOH 9DPEF1SPKFDUͱ1SPWJTJPOJOH1SPpMF͕ॏཁ º
1BDLBHJOH 9DPEFͷϝχϡʔ͔Β<1SPEVDU><"SDIJWF>
1BDLBHJOH 0SHBOJ[FSͰ<&YQPSU>Ϙλϯԡͯ͠ʜ
1BDLBHJOH ςελʔ͞ΜʹΔ༻ͷJQB࡞ͬͨΓͱ͔Ͷɻ
͜͜·Ͱͷ࡞ۀΛ ৬ਓ͕୮ਫ਼ࠐΊͯ ख࡞ۀͰɻ
@ dᵲᵲʏźŕũŽƀŕŜ
͡Ό͋ʜ
͍ͭࣗಈԽ͢Δͷʂʁ
ࠓͰ͠ΐʂ
Γ͔ͨ
&YQPSU9DPEF1SPKFDU
&YQPSU9DPEF1SPKFDU UnityEditor.BuildPipeline.BuildPlayer( string[] levels, string locationPathName, UnityEditor.BuildTarget target, UnityEditor.BuildOptions options
); ઌͣجຊ͔Β
&YQPSU9DPEF1SPKFDU BuildPipeline.BuildPlayer( new string[] { "Main.scene" }, "/Users/monry/SampleProject", BuildTarget.iPhone, BuildOptions.Development
| BuildOptions.AllowDebugging ); &YBNQMF ͜ΕͰ9DPEF1SPKFDU͕ग़ྗ͞ΕΔ
ίί͔Βઌ 1PTU1SPDFTT#VJME Ͱॲཧ͢Δ
"SDIJWF
"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ઃఆ
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ઃఆ
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ͷઃఆ
Ճ'SBNFXPSLͷઃఆ XCProject project = new UnityEditor.XCodeEditor.XCProject("/path/to/export"); project.ApplyMod(Path.Combine(Application.dataPath, "path/to/projmods")); ͬͺΓ9DPEF&EJUPSGPS6OJUZ͏ QSPKNPETͳΔϑΝΠϧΛ৯ΘͤΔ
Ճ'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ઃఆ
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.- ΛΰϦΰϦॻ͖͑Δ จࣈͷτίɺॻ͖͑ͯͶɻ
͓·͚
͓·͚ w Ϗϧυͨ͠JQBΛ%FQMPZ(BUFʹࣗಈ164) ͢ΔͱɺΦγϟϨʂ w ߋʹͦͷ݁ՌΛ$IBU8PSLͳΓ4MBDLͳΓʹ ࣗಈ1045͢ΔͱɺͬͱΦγϟϨʂʂ w ߋʹߋʹɺίί·ͰΛ+FOLJOTΦδαϯͱ͔ʹ ͓ئ͍͢Δͱɺ࠷ߴʹΦγϟϨʂʂʂ
·ͱΊ
·ͱΊ w 1PTU1SPDFTT#VJMEͰɺجຊతͳઃఆΛஔ w #VJMEˠ"SDIJWFˠ%FQMPZࣗಈԽ͠Α͏ʂ
5IBOLZPVGPS ZPVSBUUFOUJPO