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
React Nativeで作るiOSアプリケーションの環境構築設計 / react nativ...
Search
Kou
March 29, 2019
Programming
2.5k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
React Nativeで作るiOSアプリケーションの環境構築設計 / react native env for ios
Kou
March 29, 2019
More Decks by Kou
See All by Kou
デザインを見ながらフロントエンドコーディングをするときの考え方 / design-coding
kkoudev
2
1.7k
フロントエンドコーディングにおけるPageSpeed Insights対策 / frontend pagespeed insights-
kkoudev
7
7.2k
Docker Compose利用者から見た Kubernetes 開発環境構築入門 / introduction to kubernetes for docker compose user
kkoudev
19
11k
フロントエンドデザイン・開発におけるマークアップ設計の基礎 / frontend markup design basics
kkoudev
4
2.9k
Dockerを利用したローカル環境から本番環境までの構築設計 / Project structure design for docker application
kkoudev
0
360
Other Decks in Programming
See All in Programming
New "Type" system on PicoRuby
pocke
1
980
Developing with AI Agents — Codex, Claude Code & Cowork Practical Guide
x5gtrn
PRO
0
1.3k
セキュリティの専門家じゃなくてもできる。「セキュリティ意識」をアップデートして サプライチェーン攻撃への耐性を高めよう。
tk3fftk
5
890
Make SRE Operations Easier with Azure SRE Agent
kkamegawa
0
7.1k
TSKaigi Night Talks 2026_TypeScriptでサプライチェーンの整合性を型に閉じ込める
geekplus_tech
0
400
ローカルLLMを使ってB2Bサービスを作っていての学び
yaotti
0
200
そのテスト、説明できますか?~LWテスト戦略FW~のご紹介
nakahara
0
150
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
720
Lessons from Spec-Driven Development
simas
PRO
0
210
エージェンティックRAGにAWSで入門しよう!
har1101
8
1.7k
C# and C++ Interoperability - cho-dotnetnew
harukasao
0
310
Mujeres en SEO Summit 2026 - Greatest Disaster Hits en Web Performance
guaca
0
190
Featured
See All Featured
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
11k
First, design no harm
axbom
PRO
2
1.2k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
3.5k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.5k
BBQ
matthewcrist
89
10k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
400
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.5k
A Soul's Torment
seathinner
6
3k
Evolving SEO for Evolving Search Engines
ryanjones
0
220
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Prompt Engineering for Job Search
mfonobong
0
350
Transcript
R e a c t N a t i v
e Ͱ ࡞ Δ i O S Ξ ϓ Ϧ έ ʔ γ ϣ ϯ ͷ ڥ ߏ ங ઃ ܭ WEBΤϯδχΞษڧձ #12 Koichi Nagaoka
Ԭ ߒҰ (@kkoudev) ࣗݾհ גࣜձࣾϛΫγΟͰΤϯδχΞͬͯ·͢ɻ
mocriʢ͘Γʣͱ͍͏Ի௨ΞϓϦͷiOSϕʔλ൛ΛTestFlightܦ༝ͰϦϦʔε͠·ͨ͠ʂ ͜ͷΞϓϦέʔγϣϯReact NativeͰ࡞ΒΕ͍ͯ·͢ʂ ʢৄࡉ https://mocri.jp ͔ Twitterͷ @mocri_jp ʂ) ϕʔλ൛ΛϦϦʔε͠·ͨ͠ʂʂ
• JavaScript / TypeScriptΛͬͯɺReactΛͬͨiOS /AndroidΞ ϓϦέʔγϣϯ͕࡞ΕΔɻiOSʹಛʹڧ͍ɻ (Ұ࣌ظະରԠͰ ʹͳͬͨAndroid 64bitରԠ v0.59
͔ΒߦΘΕ͍ͯ·͢ʂ) • ReduxMobXͱ͍ͬͨWebͰར༻ՄೳͳΞʔΩςΫνϟʔ ͦͷ··͑Δ • JSͷมߋө͕΄΅ҰॠɻϗοτϦϩʔυʹରԠ͍ͯ͠Δɻ Ϗϧυ͠ͳ͍ͱөͰ͖ͳ͍ωΠςΟϒʹൺΔͱૉૣ͘ मਖ਼֬ೝ͕͍͢͠ React Nativeʹ͍ͭͯ
React Native্ख͍͘͜ͳͤωΠςΟϒͷΈͰ։ൃ͢Δ ΑΓ։ൃ͘͢͠ͳΓ·͕͢ɺͦΕʹΞʔΩςΫνϟʔͷ ઃܭڥߏஙɺϥΠϒϥϦͷબఆ͕ඇৗʹॏཁʹͳ͖ͬͯ· ͢ɻ Ͱ͕͢ɺ͜ͷʹಥͬࠐΜͩղઆެؚࣜΊͯগͳ͍ͨΊɺࠓ ճiOSΞϓϦέʔγϣϯΛReact NativeͰ࡞͢Δ্Ͱͷ ڥߏஙઃܭʹ͍ͭͯղઆக͠·͢ɻ
1. ϓϩδΣΫτઃఆͷ CocoaPodsԽ
React NativeͷiOSΞϓϦέʔγϣϯͰωΠςΟϒϞδϡʔϧ (react-native linkΛ͢Δඞཁͷ͋Δͷ)ΛՃ͢ΔࡍɺiOSଆ PodfileʹґଘؔΛՃ͢Δͷ͕ۙͩͱຆͲͰ͢ɻ ୠ͠ɺreact-native init Ͱ࡞ͨ͠ϓϩδΣΫτCocoaPodsͰ ґଘؔΛཧ͢ΔΑ͏ʹͳ͍ͬͯͳ͍ͨΊɺቕͬͨܦݧͷ͋ Δํଟ͍ͱࢥ͍·͢ɻରࡦ৭ʑ͋ΔͷͰ͕͢ɺࠓճݸਓ
తʹҰ൪݁ͱࢥΘΕΔಛʹผ్ύεमਖ਼͢ΔgemͳͲΛՃ ͤͣͱରԠՄೳͳํ๏Λհ͠·͢ɻ React NativeͷґଘؔͷCocoaPodsԽʹ͍ͭͯ
react-native initͰ࡞ͨ͠ϓϩδΣΫτʹCocoaPodsΛಋೖ͠ ·͢ɻiosσΟϨΫτϦʹXcodeͷϓϩδΣΫτ(*.xcodeproj)͕ ͋ΔͷͰɺxcworkspaceΛ৽نʹ࡞্ͨ͠Ͱ͜ΕΛPodsϓϩ δΣΫτͱҰॹʹ͠ɺCocoaPodsͷґଘؔΛಡΈࠐΊΔϓϩ δΣΫτͱ͠·͢ɻ (CocoaPodsࣗମͷಋೖํ๏ެࣜαΠτʹৄ͘͠ॻ͍ͯ͋Δ ͨΊׂѪ͠·͢) 1-1. CocoaPodsΛಋೖ͢Δ
react-native initͰ࡞ͨ͠ϓϩδΣΫτҎԼͷΩϟϓνϟʹ ͋ΔΑ͏ʹෳͷXcodeϓϩδΣΫτΛґଘؔʹઃఆ͍ͯ͠ ·͢ɻ 1-2. Build Phasesʹ͋ΔεΫϦϓτΛ֎ग़͠ ͜ͷதʹ͋ΔʮReact.xcodeprojʯͷBuild Phasesʹ͋ΔεΫϦϓτΛγΣϧεΫϦϓ τͱͯ͠֎ग़͠͠·͢ɻ
React.xcodeprojͷରBuild Phases
React.xcodeprojͷBuild Phase֎ग़͠ޙ ॴϓϩδΣΫτԼͳΒͲ͜Ͱ Α͍Ͱ͕͢ɺ͜ͷྫͰϓϩδΣΫτ ϧʔτʹ scripts ͱ͍͏σΟϨΫτϦΛ ࡞͠ɺͦͷதʹϑΝΠϧΛஔͯ͠ ͍·͢ɻ
Build PhasesΛ֎ग़ͨ͠͠ΒɺLibrariesԼ ͷϓϩδΣΫτΛશͯΞϓϦέʔγϣϯͷґ ଘ͔ؔΒআ͠·͢ɻ(ࢀরͷΈআ͠ɺ ݩϑΝΠϧࣗମআ͠ͳ͍Ͱ͓͍ͯͯ͠ ͍ͩ͘͞) 1-3. React NativeґଘؔProjectΛআ͢Δ
࣮React Nativeͷxcodeproj܈શͯ podspec ϑΝΠϧ͕༻ ҙ͞Ε͍ͯΔͨΊɺCocoaPodsͰґଘؔͱͯ͠ࢦఆ͢Δ͜ͱ ͕ՄೳͰ͢ɻ۩ମతʹ node_modules/react-native Լʹ͍ ͋ΔҎԼͷ podspec
ϑΝΠϧΛPodfileʹهड़͠·͢ɻ 1-4. React NativeґଘؔProjectΛCocoaPodsԽ
React NativeґଘؔΛࢦఆͨ͠CocoaPodsͷPodfile ※ReactͷґଘؔԼͷ subspecsReact Native ͷόʔδϣϯʹΑͬͯมԽ ͠·͢ɻࢦఆՄೳͳ subspec React.podspec ʹهࡌ͞Ε͍ͯΔͷͰ֬
ೝͯ͠Έ͍ͯͩ͘͞ɻ ※use_frameworksʹඇ ରԠͳͷͰҙʂʂ
React Nativeຊମ͕͍ͬͯΔthird-partyϥΠϒϥϦͰ͋Δɺ yogaɺFollyɺDoubleConversionɺglogຊདྷͰ͋Εreact- native run-iosΛ࣮ߦͨ͠ࡍʹࣗಈతʹϑΝΠϧ͕ల։͞ΕΔΑ ͏ʹͳ͍ͬͯΔ͕ɺCocoaPodsԽ͢Δʹ͋ͨͬͯ༧ΊϑΝΠ ϧΛల։͓ͯ͘͠ඞཁ͕͋ΔͨΊɺखಈ࣮ߦ͢ΔεΫϦϓτΛ ࡞͓͖ͯ͠·͢ɻ 1-5. third-partyϥΠϒϥϦͷల։εΫϦϓτ࡞
#!/bin/bash readonly PROJECT_DIR="$(cd ${0%/*}/.. && pwd)" readonly GLOG_VERSION="0.3.5" cd ${PROJECT_DIR}/node_modules/react-native
&& ./scripts/ios-install-third-party.sh cd ${PROJECT_DIR}/node_modules/react-native/third-party/glog-${GLOG_VERSION} && ${PROJECT_DIR}/node_modules/react- native/scripts/ios-configure-glog.sh ࡞ͨ͠third-partyϥΠϒϥϦల։εΫϦϓτྫ ※React NativeͷnpmϞδϡʔϧʹల։༻ͷεΫϦϓτ͕͋Δ͕ɺ ͦͷεΫϦϓτ͕ΠϚΠνͳ࡞ΓͷͨΊɺ্هͷΑ͏ʹσΟϨΫτ ϦҠಈ͔ͯ͠Β࣮ߦ͠ͳ͍ͱਖ਼ৗʹల։ͯ͘͠Εͳ͍ɻ ͜ΕΛϓϩδΣΫτϧʔτʹ setup.sh Λஔͯ͠ॳճʹ։ൃऀʹ ࣮ߦͯ͠Β͏Α͏ʹ͠·͢ɻ
͜͜·Ͱग़དྷͨΒɺҰ ios σΟϨΫτϦԼͰ pod ίϚϯυ Λ࣮ߦ͠ɺਖ਼ৗʹίϚϯυ͕ྃ͢Δ͜ͱΛ֬ೝͯͩ͘͠͞ ͍ɻࣦഊ͢Δ߹Podfileͷࢦఆ͕ؒҧ͍ͬͯΔͷͰ֬ೝ͠ ͯΈ͍ͯͩ͘͞ɻ(ಛʹ use_frameworks ʹ͍ͭͯඇରԠͳͷ
Ͱࢦఆ͠ͳ͍Ͱ͍ͩ͘͞) 1-6. CocoaPodsΛ࣮ߦͯ͠ਖ਼ৗྃ͢Δ͜ͱΛ֬ೝ͢Δ
1-2ͷखॱͰ֎ग़ͨ͠͠React.xcodeprojʹ͋ͬͨBuild PhaseΛ ΞϓϦέʔγϣϯຊମͷXcodeϓϩδΣΫτͷBuild Phase Ճ͠ɺ࡞ͨ͠εΫϦϓτ(*.sh)ΛͦΕͧΕݺͼग़͢Α͏ʹͯ͠ ͓͖·͢ɻ 1-7. XcodeϓϩδΣΫτBuild PhasesΛՃ͢Δ
Build PhasesΛՃޙͷঢ়ଶ
Ҏ্ͰCocoaPodsԽྃͰ͢ɻ react-native linkͨ͠ࡍʹՃՄೳͳωΠςΟϒϞδϡʔϧ͜ ͷํ๏ΛऔΒͳ͍ͱReact Nativeؔ࿈ͷϔομϑΝΠϧ͕Π ϯΫϧʔυͰ͖ͳͯ͘ϏϧυΤϥʔʹͳΔͷ͋Γ·͢ɻ React NativeؚΊͯCocoaPodsͷґଘؔͱͯ͠ࢦఆ͢Δ͜ ͱͰωΠςΟϒϏϧυؔ࿈ͷ΄΅ͳ͘ͳΔͷͰɺੋඇͱ ͜ͷํ๏ΛऔΔ͜ͱΛਪ͍ͨ͠·͢ɻ
2. TypeScriptͷಋೖ
react-native initͰ࡞ͨ͠React NativeϓϩδΣΫτv0.57͔ ΒTypeScriptΛਖ਼ࣜʹαϙʔτ͢ΔΑ͏ʹͳΓ·ͨ͠ɻ TypeScriptΛΘͳͯ͘։ൃՄೳͰ͕͢ɺܕ͕ͳ͍ͱΤσ ΟλͷิػೳͷԸܙΛड͚ΒΕͳ͔ͬͨΓɺϦϑΝΫλϦϯ ά͕ͮ͠Β͘ͳΔͱ͍ͬͨσϝϦοτ͕ଟ͘ൃੜ͢ΔͨΊɺن ͕େ͖͘ͳΕͳΔ΄Ͳਏ͘ͳΓ·͢ɻ ͦͷͨΊɺTypeScriptΛಋೖ͠·͢ɻ TypeScriptͷඞཁੑ
લड़ͷͱ͓ΓReact Native v0.57 ͔ΒBabel7ͷTypeScriptα ϙʔτΛར༻ͯ͠TypeScriptʹରԠ͍ͯ͠·͢ɻͨͩ͜͠ͷ Babel7ͷTypeScriptαϙʔτܕνΣοΫʹ͍ͭͯ tsc ʹ ͤΔલఏͱͳ͍ͬͯΔͨΊɺ݁ہ tsc
͕ඞཁʹͳΓ·͢ɻͦͷ ͨΊɺҎԼͷϞδϡʔϧ͕ඞཁʹͳΓ·͢ɻ 2-1. TypeScriptؔ࿈ͷґଘؔΛՃ͢Δ • typescript • @types/react • @types/react-native
tsconfigʹ͍ͭͯҎԼͷΛ࠷ݶઃఆ͍ͯͩ͘͠͞ɻ 2-2. tsconfigͷઃఆΛߦ͏ • jsxΛ react-native ʹ͢Δ • noEmit Λ
true ʹ͢Δ (ܕνΣοΫ͚͕ͩతͷͨΊ) • allowSyntheticDefaultImports Λ true ʹ͢Δ • experimentalDecorators Λ true ʹ͢Δ (MobXΛ͏ͳΒඞਢ) ͋ͱ package.json ͷ scripts ʹ tsc Λ࣮ߦ͢ΔλεΫΛՃ͠·͢ɻྫͱ͠ ͯreact-native run-ios ͱ tsc -w Λฒྻ࣮ߦ͢Δ scripts Λఆ͓ٛͯ͘͠ͷ͕͓ ͢͢ΊͰ͢ɻ
JavaScript / TypeScriptʹΑΔ import ௨ৗ૬ରύεͰಡΈ ࠐΉઃఆͱͳ͍ͬͯ·͢ɻͨͩ͠ɺ૬ରύεͩͱϑΝΠϧͷҐ ஔʹΑͬͯ import ύε͕͘ͳͬͯ͠·͏͔Γ͔ɺϑΝΠϧ ΛҠಈ͢Δͱ؆୯ʹΤϥʔʹͳͬͯ͠·͏ͨΊɺอकੑͷѱ͍
ίʔυʹͳͬͯ͠·͍·͢ɻͦ͜ͰɺಛఆͷจࣈྻΛࢦఆͨ͠ ઈରύεࢦఆͰ import ͕ग़དྷΔΑ͏ʹରԠ͠·͢ɻ 2-3. ઈରύεʹΑΔimportͷઃఆ
·ͣτϥϯεύΠϧ࣌ʹઈରύεΛղऍͰ͖ΔΑ͏ʹઃఆ͠· ͢ɻ۩ମతʹ babel-plugin-module-resolver ΛՃ ͠ɺ.babelrcϑΝΠϧ·ͨbabel.config.jsهड़ΛՃ͠· ͢ɻ babel-plugin-module-resolver ʹ͍ͭͯ 3.1.1 Λࢦఆͯ͠Ճ
͢ΔΑ͏ʹ͍ͯͩ͘͠͞ɻͦΕҎ߱ͷόʔδϣϯͩͱBabel7ର Ԡʹෆඋ͕͋Δͷ͔ɺ͏·͘ಈ࡞͠ͳ͍߹͕͋Γ·͢ɻ Babelͷઃఆͷฤू
module.exports = { presets: [ 'module:metro-react-native-babel-preset', ], plugins: [ [
'@babel/plugin-proposal-decorators', { legacy: true } ], [ 'module-resolver', { root: ['./src'], extensions: ['.js', '.ios.js', '.android.js'], alias: { '@/*': './src/', } } ] ] }; babel.config.jsͷઃఆྫ ͜ͷઃఆΛߦ͏͜ͱͰɺsrcσΟϨΫτ ϦԼͷϑΝΠϧΛʮ@/ʯͰࢦఆͰ͖ ΔΑ͏ʹͳΓ·͢ɻ ͪͳΈʹ͜ͷྫʹ͞Γ͛ͳ͋͘Δ @babel/plugin-proposal-decorators ʹ ͍ͭͯBabelଆͰσίϨʔλΛղऍ ͢ΔͨΊʹඞཁͳઃఆʹͳΓ·͢ɻ
BabelଆͰઈରύεͷղऍՄೳʹͳΓ·͕ͨ͠ɺtscʹΑΔܕ νΣοΫͱผઃఆͳͷͰɺtsconfigʹઈରύεಡΈࠐΈͷ ઃఆ͕ඞཁʹͳΓ·͢ɻ͜ͷล͕ઃఆײ͕͋ͬͯগʑΠέ ͯͳ͍Ͱ͕͢ɺBabel7͕͜ͷΑ͏ͳରԠελΠϧΛऔ͍ͬͯΔ ͨΊํͳ͘ઃఆ͠·͢ɻtsconfigʹҎԼͷઃఆΛՃ͠· ͢ɻ tsconfigͷઃఆͷฤू
ίʔυνΣοΫͷͨΊʹESLintΛಋೖ͠·͢ɻҰੲલ·Ͱ TSLintͱ͍͏Linter͕TypeScriptͰओྲྀͰ͕ͨ͠ɺ2019ʹ ͳͬͯTypeScriptνʔϜ͕ ESLintҠߦ͢Δ͜ͱΛൃද͍ͯ͠ ·͢ɻ۩ମతʹɺҎԼͷϞδϡʔϧΛಋೖͯ͠ઃఆ͠·͢ɻ (ઃఆํ๏ʹ͍ͭͯެࣜΛࢀরͷ͜ͱ) ESLintͷઃఆ • @typescript-eslint/eslint-plugin •
eslint • eslint-plugin-node • eslint-plugin-react
Ҏ্ͰTypeScriptԽྃͰ͢ɻ TypeScriptՃ͢ΔϞδϡʔϧ͕ύοέʔδʹఆٛϑΝΠ ϧΛಉ͍ࠝͯ͠Δͷ͋Εɺreact-nativeຊମͷΑ͏ʹ @types/react-native ͱ͍ͬͨΑ͏ʹDefinitelyTypedʹΞοϓϩ ʔυ͞Ε͍ͯΔϑΝΠϧΛΠϯετʔϧ͢Δ߹͋Γ·͢ɻ ͨͩதʹͲͪΒʹఆٛϑΝΠϧ͕ଘࡏ͠ͳ͍έʔε͋Δ ͨΊɺͦͷ߹ࣗͰఆٛϑΝΠϧΛࣗͰॻ͔͘ɺimport Ͱͳ͘requireͰಡΈࠐΜͰ͏Α͏ʹ͍ͯͩ͘͠͞ɻ
3. Clean Architectureͷಋೖ
Clean Architecture Robert Cecil Martin ࢯʹΑͬͯఏএ͞Εͨ ΞʔΩςΫνϟʔͷҰछͰ͢ɻ؆୯ʹݴ͏ͱΫϥε͚Λࡉ͔ ͘ߦ͏͜ͱͰɺMVCMVPͰʹͳΓ͕ͪͩͬͨFat ControllerFat Presenterͱ͍ͬͨΫϥε͕ൃੜͮ͠Β͘ͳΔ
ΑΓΫϦʔϯͳઃܭͱͳΓɺςετίʔυ͕ॻ͖͘͢ͳΓ· ͢ɻৄࡉͳઃܭʹ͍ͭͯωοτʹΑ͘հ͞Ε͍ͯΔͷ Ͱɺ͜͜ͰׂѪ͍͖ͤͯͨͩ͞·͢ɻ Clean Architectureͱ
Clean Architectureઃܭ͕៉ྷʹͳΓɺ1ͭͷϑΝΠϧʹॲཧ ͕ूத͠ͳ͍རΛ࣋ͪ߹Θ͍ͤͯ·͕͢ɺϑΝΠϧΫϥ ε͕ඇৗʹଟ͘ͳͬͯ͠·͏ܽΛ๊͍͑ͯ·͢ɻ ࣮ࡍʹClean ArchitectureΛ࠷ॳʹ࠾༻ͯ͠͠·͏ͱɺ͋·Γͷ ϑΝΠϧͷଟ͞ʹ׳Εͣʹ࠳ંͯ͠͠·͍͕ͪͰ͢ɻ ͱ͍͑ɺ៉ྷͳઃܭΛ࠷ॳʹߦ͓ͬͯ͘ͱޙͷػೳվम࣌ʹ ༗རͰ͢ɻͦͷͨΊɺ͋ΔఔॲཧΛ·ͱΊΔ͜ͱΛڐ༰͠ ͨઃܭΛ࠾༻͢Δ͜ͱʹ͠·ͨ͠ɻ
Clean Architectureͷརͱܽ
mocriͰLayered ArchitectureɺOnion ArchitectureΛϕʔεʹ Clean ArchitectureΛҰ෦ΞϨϯδ͠ɺ͔ͭMobXͱͷ૬ੑΛߟ ͑ͨઃܭΛ࠾༻͠·ͨ͠ɻ Clean ArchitectureΛҰ෦ΞϨϯδ͢Δ
Clean ArchitectureΛ࠾༻ͨ͠σΟϨΫτϦߏ
ೖྗσʔλͷྲྀΕʹ͍ͭͯҎԼͷ௨Γͱ͍ͯ͠·͢ɻ 1. ΠϯλʔϑΣʔε (interface) 2. ΞϓϦέʔγϣϯ (application) 3. υϝΠϯ (domain)
4. ΠϯϑϥετϥΫνϟ (infrastructure) ·ͨɺ্هͷʹՃ͑ͯҎԼͷ۠ͷΫϥε(Ͳͷ͔ΒݺΜͰྑ͍)͕ఆٛ͞Ε͍ͯ ·͢ɻ ઃఆ (config) ϢʔςΟϦςΟʔ (util) ֤ͷσʔλͷྲྀΕʹ͍ͭͯ
͜ͷUIʹؔ࿈͢ΔʹͳΓ·͢ɻControllerͱPresenterɺ ·֤ͨը໘ίϯϙʔωϯτͷϏϡʔ (tsx) Λఆ͍ٛͯ͠· ͢ɻControllerͱPresenterinterfaceͱ࣮ΫϥεΛఆٛ͠· ͢ɻ֤ίϯϙʔωϯτͷΠϕϯτʹ͍ͭͯController͕ॲཧΛ ͠ɺͦͷController͕গ͠ෳࡶͳॲཧΛ͢ΔࡍUseCaseΛݺ ͼग़͢ͱ͍͏ϧʔϧʹ͍ͯ͠·͢ɻ ·ͨɺMobXΛ͏্Ͱ observable
ͱͳΔঢ়ଶʹ͍ͭͯɺ ͜ͷʹ͋Δ Presenter ʹ࣋ͨͤΔΑ͏ʹ͍ͯ͠·͢ɻ interfaceʹ͍ͭͯ
͜ͷUseCaseΛఆ͍ٛͯ͠·͢ɻUseCaseϏδωεϩδ οΫΛ࢘ΔΫϥεʹͳΓ·͢ɻ͜͜Ͱinterfaceͱ࣮Ϋϥε Λఆٛ͠·͢ɻຊདྷͷClean Architectureͩͱ̍ΞΫγϣϯʹͭ ͖̍ͭͷॲཧΛUseCaseͰఆٛ͢ΔΑ͏ʹݴΘΕ͍ͯ·͕͢ɺ ͦΕͩͱ͋·ΓʹϑΝΠϧ͕૿͑͗ͯ͢͠·͏ͷͰɺ1ίϯϙ ʔωϯτ(ը໘ؚΉ)ʹରͯ͠1ͭͷUseCaseΫϥεΛఆٛ͠ɺ֤ ίϯϙʔωϯτͷϏδωεϩδοΫΛ͜ͷUseCaseΫϥεʹه ࡌ͢Δͱ͍͏ϧʔϧͱ͠·ͨ͠ɻ applicationʹ͍ͭͯ
͜ͷmodel, repository, service, value, factoryΛఆٛ͠· ͢ɻapplicationͷUseCaseͱͷେ͖ͳҧ͍ɺશը໘ίϯ ϙʔωϯτͰڞ௨ར༻͞ΕΔϏδωεϩδοΫछผΛఆٛ͢ Δͱ͍͏ϧʔϧͱ͍ͯ͠·͢ɻrepositoryͱservice͜͜Ͱ interfaceͱͯ͠ఆٛ͠·͢ɻ domainʹ͍ͭͯ
͜ͷdomainͷrepositoryͱserviceͷ࣮Ϋϥε(ඌImpl ͷΫϥε)ͷ͏ͪɺ֎෦σʔλʹґଘ͢ΔॲཧΛఆٛ͠·͢ɻ API௨৴ͷ࣮ɺAsyncStorageͷอଘʹ͍ͭͯ͜ͷʹ ࣮ࡍͷॲཧΛهड़͠·͢ɻ infrastructureʹ͍ͭͯ
֤ͷinterfaceΫϥεͱ࣮Ϋϥεʹ͍ͭͯɺDIΛ͔ͭͬͯ ΠϯελϯεΛઃఆ͠·͢ɻ͜ΕΛReact NativeͰߦ͏ʹ inversify ͱ͍͏ϥΠϒϥϦΛಋೖ͠·͢ɻ ґଘੑೖ(DI)ʹ͍ͭͯ
import 'reflect-metadata'; import { Container } from 'inversify'; // ίϯςφΛ࡞͢Δ
export const container = new Container(); /** * ґଘؔछผ */ export const IOCType = { // Launch LaunchController: Symbol('LaunchController'), LaunchPresenter: Symbol('LaunchPresenter'), LaunchUseCase: Symbol('LaunchUseCase'), }; Inversifyͷ༻ྫ (1) ֤࣮ΫϥεʹରԠ͢ΔछผΛ SymbolͰఆٛ͠·͢ɻ͜ͷͱ ͖ɺಉ͡ϑΝΠϧʹ Container Ϋ ϥεͷΠϯελϯεΛSingletonΠ ϯελϯεͱͯ͠ఆ͓͖ٛͯ͠· ͢ɻ(ྫͱͯ͠ɺioc.ts ͱ͍͏ϑΝ Πϧ໊ͱ͠·͢)
Inversifyͷ༻ྫ (2) interfaceͱରԠ͢Δ࣮Ϋϥεͷඥ ͚Λߦ͍·͢ɻ͜ͷͱ͖ɺΠ ϯελϯεੜ͢Δ͔Singleton͔Λ બͿ͜ͱ͕Ͱ͖·͢ɻجຊతʹ domainͷͷSingleton (ঢ়ଶΛ ࣋ͨͤͳ͍ͨΊ)ɺͦΕҎ֎֤ʑͰ ঢ়ଶΛ͍࣋ͪͨͷͰɺΠϯελ
ϯεੜΛߦ͍·͢ɻ·ͨɺ࣮Ϋ ϥεʹ @injectable ͷσίϨʔλ ʔΛ༩͍ͯͩ͘͠͞ɻ import { container, IOCType } from './ioc'; // Πϯελϯεੜ͢Δ߹ to ·ͰΛݺͼग़ͤOK container.bind<ILaunchController>(IOCType.LaunchController) .to(LaunchControllerImpl); container.bind<ILaunchPresenter>(IOCType.LaunchPresenter) .to(LaunchPresenterImpl); container.bind<ILaunchUseCase>(IOCType.LaunchUseCase) .to(LaunchUseCaseImpl); // Singletonʹ͢Δ߹ inSingletonScope Λݺͼग़͓ͯ͘͠ container.bind<IAuthRepository>(IOCType.AuthRepository) .to(AuthRepositoryImpl).inSingletonScope();
Inversifyͷ༻ྫ (3) import { IOCType, container } from './ioc'; /**
* ىಈը໘ίϯτϩʔϥʔ࣮ */ @injectable() export class LaunchControllerImpl implements ILaunchController { /** * ىಈը໘Ϣʔεέʔε */ private readonly usecase: ILaunchUseCase = container.get(IOCType.LaunchUseCase); // .... লུ .... } ͋ͱར༻͍ͨ͠ControllerUseCase ͰϑΟʔϧυఆٛͱҰॹʹݺͼग़͠ ·͢ɻPresenterͷΠϯελϯεঢ়ଶ Λ͍࣋ͬͯΔ্ؔɺController UseCaseͰผΠϯελϯεΛੜ͠ͳ ͍Α͏ʹɺඞཁʹԠͯ͡Πϯελϯε Λڞ༗ͭͭ͠ѻ͍·͢ɻ(Controllerͱ UseCaseͰಉPresenterΛࢀর͚ͨ͠Ε ControllerͰ࡞ͨ͠ΠϯελϯεΛ UseCaseڞ༗͢Δ͜ͱ)
Ҏ্ͰClean Architectureͷ؆୯ͳઆ໌ྃͰ͢ɻ ͜ͷઃܭΛ࠾༻ͨ͜͠ͱͰɺ୭͕࣮ͯ͠΄΅ϒϨͷͳ͍Ϋ ϥεઃܭΛ୲อ͘͢͠ͳΓ·ͨ͠ɻ ·ͨɺClean ArchitectureҰݟૣ͘࡞Δ͜ͱʹॏ͖Λஔ͍ͨε λʔτΞοϓͷαʔϏεʹෆ͖Ͱ͕͢ɺ͍ΘΏΔෛͷҨ࢈ Λ૿֬֨͢ஈʹݮΔͷͱɺΛ༏ઌͯ͠૿ͨ͠ෛͷ Ҩ࢈ͷճऩʹ࣌ؒΛऔΒΕͯ݁ہτʔλϧͰಉ͘͡Β͍࣌ؒ ͕͔͔Δͱ͍͏έʔε͋ΔͷͰɺέʔεʹΑΓ·͕͋͢Δ
ఔ͔ͬ͠Γઃܭͯ͠࡞͓ͬͯ͘͜ͱΛ͓͢͢Ί͠·͢ɻ
4. ωΠςΟϒϒϦοδͷઃఆ
React NativeͷΞϓϦέʔγϣϯશͯJavaScript / TypeScript Ͱॻ͚Δ͜ͱʹӽͨ͜͠ͱͳ͍ͷͰ͕͢ɺఏڙ͞Ε͍ͯͳ͍ ػೳʹ͍ͭͯͲ͏ͯ͠ωΠςΟϒͷॲཧΛॻ͘ඞཁ͕ग़ͯ ͖·͢ɻReact Nativeඪ४ͰωΠςΟϒϒϦοδͷͨΊͷ ΈΛఏڙͯ͘͠ΕΔͷͰɺϧʔϧʹԊͬͯॻ͚ͩ͘ͰOKͰ ͢ɻ
※iOS 12.2ʹ͓͍ͯSwiftར༻࣌ͷωΠςΟϒϒϦοδʹࣦഊ͢Δෆ۩߹͕͋ΔͨΊɺҎԼͷ Issue͕ղܾ͍ͯ͠ͳ͍߹ iOS 12.1 (Xcode 10.1)ͰϏϧυ͢ΔΑ͏ʹ͍ͯͩ͘͠͞ https://github.com/facebook/react-native/issues/24139 ωΠςΟϒϒϦοδͱ
React NativeͷΞϓϦέʔγϣϯ react-native init Ͱ࡞ͨ͠ ঢ়ଶͷ··ͩͱObjective-C͔͑͠·ͤΜɻͦ͜ͰɺԿ͔̍ͭ swiftϑΝΠϧΛՃ͢ΔͱɺBridge-HeaderϑΝΠϧ(*.h)Λ Ճ͢ΔΑ͏ʹଅ͞ΕΔͷͰૉʹՃ͠·͢ɻ͜ΕʹΑͬͯɺ Swiftؔ࿈ͷϏϧυઃఆϓϩδΣΫτʹՃ͞Ε·͢ɻ࣍ʹɺ ࡞͞ΕͨBridge-HeaderϑΝΠϧʹ֤छϔομΛ
#import ͠ ·͢ɻ 4-1. ϒϦοδϔομΛՃ͢Δ
// // Use this file to import your target's public
headers that you would like to expose to Swift. // #import <React/RCTBridgeModule.h> #import <React/RCTEventDispatcher.h> #import <React/RCTEventEmitter.h> ϒϦοδϔομʹ#importΛՃ͢Δ
ࠨͷΑ͏ʹ Swift ͰΫϥεΛ࡞͠· ͢ɻݟͯͷ௨Γɺ@objcΞϊςʔγϣ ϯ͕هࡌ͞Ε͍ͯ·͢ɻSwift͕هड़ Ͱ͖Δͱ͍ͬͯ࠷ऴతʹObjCͱ ͯ͠ղऍͤ͞Δඞཁ͕͋ΔͨΊɺ͜ ͷΑ͏ʹهࡌ͢Δඞཁ͕͋Γ·͢ɻ 4-2. SwiftͰΫϥεϑΝΠϧΛՃ͢Δ(1)
@objc(VoiceSession) class VoiceSession: NSObject { @objc static func requiresMainQueueSetup() -> Bool { return true } @objc func start(_ callback: RCTResponseSenderBlock) { // ... ॲཧ } }
·ͱΊΔͱɺՃͨ͠SwiftΫϥεҎԼͷϧʔϧʹ४ڌ͢ Δඞཁ͕͋Γ·͢ɻ 1. NSObjectΛܧঝ͍ͯ͠Δ͜ͱ 2. Ϋϥεϔομʹ @objc(Ϋϥε໊) Λهड़͢Δ͜ͱ 3. staticͰBoolΛฦ͢requiresMainQueueSetupϝιουΛ࣮͢Δ͜ͱ
4. ֤ϝιουʹ @objc ΞϊςʔγϣϯΛهड़͢Δ͜ͱ ͋ͱ͜ΕʹՃ͑ͯɺ༻ՄೳͳܕҰ෦ͷܕʹ੍ݶ͞Ε ͍ͯ·͢ɻ(ಠࣗͷΫϥεܕෆՄɻৄࡉެࣜΛࢀর) 4-2. SwiftͰΫϥεϑΝΠϧΛՃ͢Δ(2)
࣍ʹɺObjective-CͷϞδϡʔϧϑΝΠϧ(*.m)ΛՃ͠·͢ɻઌ ͷεϥΠυͰհͨ͠SwiftͰ࡞ͨ͠ΫϥεʹରԠ͢ΔܗͰɺ ࣍ͷΑ͏ʹهड़͠·͢ɻ 4-3. Objective-CͷϞδϡʔϧϑΝΠϧΛՃ͢Δ
#import <React/RCTBridgeModule.h> @interface RCT_EXTERN_MODULE(VoiceSession, NSObject) RCT_EXTERN_METHOD(start:(RCTResponseSenderBlock)callback) @end Ճ͢ΔObjective-CͷϞδϡʔϧϑΝΠϧྫ
4-4. JSଆͷରԠίʔυͷ࡞ ͋ͱରԠ͢ΔΫϥεΛJSଆͰ࡞͢Εݺͼग़͕͠Մೳʹͳ Γ·͢ɻωΠςΟϒϒϦοδͷΓʹ͍ͭͯɺ Callback(RCTResponseSenderBlock)·ͨ Promise(RCTPromiseResolveBlockͱRCTPromiseRejectBlock) ʹͯඇಉظͰड͚औΔ༷ʹͳ͍ͬͯ·͢ɻ͜ΕJS͕ಈ࡞͢ ΔεϨουͱωΠςΟϒ͕ಈ࡞͢ΔεϨου͕ҟͳΔͨΊɺ͜ ͷΑ͏ͳ༷ͱͳ͍ͬͯ·͢ɻ
import { NativeModules } from 'react-native'; export class VoiceSession {
private readonly session = NativeModules.VoiceSession; public start(callback: () => void): void { this.session.start(callback); } } JSଆͷରԠΫϥε࡞ྫ
Ҏ্ͰωΠςΟϒϒϦοδͷઆ໌ྃͰ͢ɻ ωΠςΟϒϒϦοδଟ༻͢ΔͱiOSͱAndroidͷΫϩεϓϥο τϑΥʔϜͰΞϓϦΛ࡞͢ΔࡍʹͦͷωΠςΟϒίʔυ Λॻ͘ඞཁग़͖ͯͯ͠·͍·͕͢ɺReact Native͚ͩͰ࣮ ݱͰ͖ͳ͍ػೳΛ࣮ݱ͢Δ্ͰඞਢʹͳΓ·͢ɻmocriͰ gRPCͰϧʔϜؔ࿈ͷػೳΛ࣮ݱ͍ͯ͠ΔؔͰɺreact-native Ͱ͑ͳ͍gRPCωΠςΟϒͷॲཧΛSwiftͰهड़͍ͯ͠· ͢ɻ͜ͷΑ͏ͳέʔεʹඞਢͱͳΔͨΊɺωΠςΟϒϒϦο δͷํ͚ͩͰ͓֮͑ͯ͘͜ͱΛ͓קΊ͠·͢ɻ
5. ಋೖਪϥΠϒϥϦ
ͦΕͰ࠷ޙʹɺiOSΞϓϦέʔγϣϯΛ࡞Δ্ͰΑ͘͏ͱ ࢥΘΕΔReact NativeͰ༻ՄೳͳϥΠϒϥϦΛհ͍ͨ͠· ͢ɻ ಋೖਪϥΠϒϥϦʹ͍ͭͯ
React NativeΞϓϦέʔγϣϯىಈ࣌(εϓϥογϡը໘දࣔ ޙ)ʹɺJSϑΝΠϧΛϩʔυ͢ΔͨΊʹҰॠը໘͕ਅͬനʹͳ ΔλΠϛϯά͕͋Γ·͢ɻ͜ΕΛࢭ͢Δͷ͕ react-native- splash-screen Ͱ͢ɻͳΔ͘ωΠςΟϒΞϓϦʹ͍ۙܗΛ ࢦ͢ͷͰ͋Εɺੋඇͱಋೖ͢Δ͜ͱΛ͓͢͢Ί͠·͢ɻ 4-1. react-native-splash-screen
React Nativeʹ͓͚Δը໘ભҠΛߦ͏ϥΠϒϥϦͰ͢ɻ ͜Ε͕ͳ͍ͱΞϓϦΛ࡞Δͷ͍͠ͱ͍͏͘Β͍ը໘ભҠʹ ͍ͭͯ͜ΕʹউΔͷ͕ͳ͍Ͱ͢ɻϓογϡʹΑΔը໘ભ ҠɺϞʔμϧʹΑΔը໘ભҠΛ࢝Ίɺλϒόʔͷαϙʔτ͠ ͍ͯ·͢ɻiOSωΠςΟϒΞϓϦͷ࡞ʹ׳Ε͍ͯΔͱͦͷҧ ͍͔Βएׯށ͏͜ͱ͋Γ·͕͢ɺ׳ΕΕඇৗʹ͍͢ ͍ϥΠϒϥϦͰ͢ɻ 4-2. react-navigation
React Native͕ඪ४Ͱαϙʔτ͍ͯ͠ͳ͍ media query Λ style ʹͯαϙʔτ͢ΔͨΊͷϥΠϒϥϦͰ͢ɻϋοΩϦݴͬ ͯɺ͜ͷϥΠϒϥϦ͕ͳ͍ͱReact NativeͰσΟεϓϨΠαΠ ζ͕ҟͳΔෳରԠΛߦ͏ͷ͕ਏ͘ͳͬͯ͠·͍·͢ɻ͜
ͷϥΠϒϥϦΛ͏͜ͱͰը໘෯ʹԠͯ͡ελΠϧΛม͑ͨ Γɺ·ͨඪ४ͰͰ͖ͳ͍ʮ100% - 24ʯͷΑ͏ͳϒϥβͰ ͍͏calcಉͷࢦఆՄೳʹͳΔͷͰɺϨΠΞτͷ͢͠͞ ͕֨ஈʹ্͠·͢ɻੋඇಋೖ͠·͠ΐ͏ɻ 4-3. react-native-extended-stylesheet
ڥมͷઃఆΛߦ͏ͨΊͷϥΠϒϥϦͰ͢ɻ React NativeͰىಈ࣌ʹڥมΛઃఆͨ͠ͱͯ͠ɺ NODE_ENVҎ֎ͷΛ͢͜ͱͰ͖ͳ͍ͷͱɺ͔ͭͦͷ NODE_ENV development ·ͨ production Ҏ֎ઃఆͰ͖ ͳ͍Α͏ʹͳͬͯ·͢ɻ͜ͷϥΠϒϥϦΛ͏ͱଞͷڥม
͢͜ͱ͕ՄೳʹͳΓ·͢ɻ 4-4. react-native-config
ϒϥβͰ௨৴Λߦ͏ࡍ͓ೃછΈͷ axios Ͱ͕͢ɺReact NativeͰ͑·͢ɻͪΖΜΘͳͯ͘௨৴ॲཧΛॻ͘͜ ͱՄೳͰ͕͢ɺaxiosͷrequestresponseͷinterceptorͳͲ ͷΈඇৗʹศརͰ͍͍ͨ͢Ίɺ௨৴ॲཧΛ࡞͢Δ ࡍ axios Λϥοϓͨ͠ΫϥΠΞϯτΫϥεΛ࡞Δ͜ͱΛ͓͢ ͢Ί͠·͢ɻ
4-5. axios
ϞʔμϧදࣔΛߦ͏ϙοϓΞοϓͷ࣮ʹ͑ΔϥΠϒϥϦͰ ͢ɻReact Nativeඪ४ͰModalίϯϙʔωϯτΛ͍ͬͯ ·͕͢ɺͪ͜Βඪ४ΑΓߴػೳͰ͢ɻ͜ΕΛ͡Ίͱ͠ ͨɺGithubͷreact-native-communityͷorganizationʹͯ։ൃ͞ Ε͍ͯΔϥΠϒϥϦɺReact Nativeඪ४ػೳΛผϥΠϒϥϦ ͯ͠։ൃ͓ͯ͠Γɺجຊతʹ react-native-community ͷํ͕ػೳ͕๛ͱͳ͍ͬͯ·͢ɻ
4-6. react-native-modal
iOSͷSafe AreaΛ࣮ݱ͢ΔͨΊͷϥΠϒϥϦͱͳΓ·͢ɻ react-navigationΛ͍ͬͯΔը໘Ͱࣗಈతʹ͜ͷϥΠϒϥϦ ΛͬͯSafe AreaΛ࣮ݱ͍ͯ͠·͕͢ɺϙοϓΞοϓ(Modal) ͷΑ͏ʹreact-navigationΛܦ༝͠ͳ͍έʔεͰඞཁʹͳ͖ͬͯ ·͢ɻiOSʹ͓͍ͯඞਢͱͳΔϥΠϒϥϦͳͷͰੋඇಋೖ͠ ·͠ΐ͏ɻ 4-7. react-native-safe-area-view
άϥσʔγϣϯΛ࣮ݱ͢ΔϥΠϒϥϦͰ͢ɻ React Nativeඪ४ͰάϥσʔγϣϯΛαϙʔτ͍ͯ͠ͳ͍ ͨΊɺ͜ͷϥΠϒϥϦΛͬͯάϥσʔγϣϯΛ࣮ݱ͢Δඞཁ ͕͋Γ·͢ɻ 4-8. react-native-linear-gradient
SVGλάΛReact NativeͰ͑ΔΑ͏ʹ͢ΔϥΠϒϥϦͰ͢ɻ mocriͰԁܗͷΦϒδΣΫτΞχϝʔγϣϯ͕ొ͢Δͨ Ίɺ͜ͷreact-native-svgΛ͏͜ͱͰ࣮ݱ͍ͯ͠·͢ɻ 4-9. react-native-svg
·ͱΊ
React NativeiOSωΠςΟϒͰΞϓϦέʔγϣϯΛ࡞͢Δ ͷʹ׳ΕͨํͷதͰɺAutoLayout͍Ϗϧυ࣌ؒʹۤ͠Ί ΒΕͨํʹಛʹΦεεϝͷπʔϧͰ͢ɻ ωΠςΟϒΞϓϦΛ࡞ͬͨܦݧͷͳ͍WebͰReact͔ͬͨ͠ ͜ͱͳ͍ํͰ࡞ΕΔͷ͔ɺͱݴΘΕΔͱͦ͏͍͏Θ͚Ͱͳ ͍Ͱ͕͢ɺͦ͏͍͏ํʹ͋Δఔͱ͖͍ͬͭ͢ϙΠ ϯτͱͯ͠ߴ͍͔ͱࢥ͍·͢ɻಛʹΫϩεϓϥοτϑΥʔϜ ͰͱΓ͋͑ͣΞϓϦΛग़͍ͨ͠ͱ͍͏ελʔτΞοϓʹ͓͍ͯ ༗ӹͳπʔϧͳͷͰɺͦͷΑ͏ͳέʔεͰੋඇಋೖΛݕ౼
͢Δ͜ͱΛ͓͢͢Ίக͠·͢ɻ
T H A N K Y O U ͝ ੩
ௌ ͋ Γ ͕ ͱ ͏ ͝ ͟ ͍ · ͠ ͨ