XcodeのReact NativeにおけるBuild Phases
XcodeのArchiveビルドが私だけできないという現象に遭遇し、原因がBuild Phasesにあったのだがその際にBuild Phasesの処理を概要だけでも知っておこうとまとめた。
React NativeアプリのBuild Phasesは下図のようになっていて全部で10 項目ある。
各項目でどんな処理が行われているか順を追って見て行く。
Target Dependencies
アプリで使用されるフレームワークはそれを使用するアプリよりも先にビルドされるよ必要があり、これを指してdependency(依存関係)と呼ぶ。
下図のように自作したライブラリのプロジェクトを使用するような場合に、どちらを先にビルドするかXcodeに教えてあげる際に使用される。
xcode target dependencies between two projects - Stack Overflow
[CP]Check Pods Manifest.lock
Pods Manifest.lockはPodfile.lockのコピーであり、pod installをする度に生成される。
Pods Manifest.lockとPodfile.lockに差分があるとエラーが出力される。
diff "${PODS_PODFILE_DIR_PATH}/Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null if [ $? != 0 ] ; then # print error to STDERR echo "error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation." >&2 exit 1 fi # This output is used by Xcode 'outputs' to avoid re-running this script phase. echo "SUCCESS" > "${SCRIPT_OUTPUT_FILE_0}"
Podsディレクトリは常にバージョン管理下にあるわけではないので、開発者が実行前にポッドを更新するように教えるための仕組み。
Bundle React Native Code And Images(1つめ)
React NativeのバグなのかBundle React Native Code And Imagesは2つ存在し、しかも1つ目では手前のCheck Pods Manifest.lockで行っているのと同様にPods Manifest.lockとPodfile.lockの差分を確認している。
Build Phases見てたんだけど[Bundle React Native Code And Images]の項目が2つあって、しかも手前の方はPodfile.lockとPodsManifest.lockの差分
— Yuri@TeamHubエンジニア (@yuri_htt) September 22, 2018
チェックしてるのおかしい
Podfile.lockとPodsManifest.lockに差分はその手前の[Check Pods Manifest.lock]で確認既にしてるし。 pic.twitter.com/UfqB8S0HZn
Compile Sources
ライブラリはリンクの仕方によって,Static LibraryとDynamic Libraryに分類できる。
Static Libraryはアプリケーションのコンパイル時に組み込まれる形で(静的に)リンクし、Dynamic Libraryはアプリケーションの実行時にローダがライブラリを検索し,(動的に)リンクするという違いがある。
ここではコンパイルする静的ライブラリの中でも実行ファイルであるAppDelegate.mとmain.mが指定されている。
Link Binary With Libraries
ここも静的ライブラリのコンパイルするものが並んでいるがライブラリの静的ファイルを扱っている。
Copy Bundle Resources
フォントや画像など、bundleしたアプリで使用する素材たちが列挙されている。
Bundle React Native Code And Images(2つめ)
ここではnode_modules/react-native/scripts/react-native-xcode.shを実行し、その中でjsのコードと手前でコピーした画像をbundleする処理を行っている。
react-native-xcode.sh
コード
react-native/react-native-xcode.sh at master · facebook/react-native · GitHub
今回私の環境でArchiveビルドができなかった原因としてnvm lsコマンドでインストールされているバージョンを見ることができるがここのdefaultが設定されていなかった。
(default設定後)
react-native-xcode.shの中でnodeを設定しているがここら辺で問題が起きた様子。
ちなみにシミュレーターだとビルドできていたのは下記のコードによるもの。
if [[ "$PLATFORM_NAME" == *simulator ]]; then if [[ "$FORCE_BUNDLING" ]]; then echo "FORCE_BUNDLING enabled; continuing to bundle." else echo "Skipping bundling in Debug for the Simulator (since the packager bundles for you). Use the FORCE_BUNDLING flag to change this behavior." exit 0; fi else
run script
ここでもreact-native-xcode.shを実行している。
同じ処理をしてしまっている項目については削除しても問題ないかもしれないしビルド時間が短縮されそうなので今後上司に聞いてみたい。
[CP]Copy Pods Resources
Pods-AppName-resources.shを実行
bundleしたライブラリたちをインストールした後にシンボリックリンクをコピー
if [[ "$CONFIGURATION" == "Debug" ]]; then install_resource "${PODS_ROOT}/FBSDKCoreKit/FacebookSDKStrings.bundle" ・・・ fi mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" fi rm -f "$RESOURCES_TO_COPY"
まとめ
1.ライブラリを使用する前にその管理ファイルであるPods Manifest.lockを確認
2.アプリの大本となるAppDelegate.mやmain.mをコンパイルしてバイナリファイルを生成
3.使用するライブラリのバイナリファイルを紐づける
4.アプリで使用する素材系のbundleされたデータをコピー
5.JavaScriptのコードをbundle
JSはスクリプト言語なのでコンパイル不要bundleのみ
6.bundleされたライブラリをコピー
7.フレームワークを埋め込む
コンパイルする必要があるものをコンパイル、
その後で既に提供されているであろうライブラリのバイナリファイルを紐づけ、
その後に素材やJSなどのコードをbundle
ライブラリのコンパイルやbundleをしているところが見当たらないのでライブラリの方で既に作成して提供してくれているのかもしれない。