M1 (Apple Silicon) Macで既存のReact Nativeプロジェクトの開発環境が整うまで
M1 Macで既存のReact Nativeプロジェクトを開発する環境が整うまでにしたことをまとめました。
Xcodeをインストール
Mac App StoreからXcode 12.2をインストールします。
Homebrewをインストール
公式サイトにあるインストールスクリプトを実行すると、以下のようにRosetta 2を使用するか、他のインストールオプションを勧められます。
Homebrew is not (yet) supported on ARM processors!
Rerun the Homebrew installer under Rosetta 2.
If you really know what you are doing and are prepared for a very broken
experience you can use another installation option for installing on ARM:
https://docs.brew.sh/Installation
なるべくネイティブで動作させたいので、Installationのドキュメントを参照します。
However do yourself a favour and install to /usr/local on macOS Intel, /opt/homebrew on macOS ARM, and /home/linuxbrew/.linuxbrew on Linux. Some things may not build when installed elsewhere. One of the reasons Homebrew just works relative to the competition is because we recommend installing here. Pick another prefix at your peril!
macOS ARMでは/opt/homebrew
にインストールするよう推奨されているので、/opt
に移動してhomebrew
ディレクトリを作成(ついでに所有権も変更)しておきます。
cd /opt
sudo mkdir homebrew
sudo chown <自分のユーザー名>:admin homebrew
HomebrewのGitHubからmasterを取得して展開します。
curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew
このままではパスが通っていないので、~/.zshrc
にパスの設定を追加します。
export PATH=$PATH:/opt/homebrew/bin
Terminalを再起動するか、source
コマンドで.zshrcの変更を反映します。
source ~/.zshrc
React Native開発環境をセットアップ
公式ドキュメントのReact Native CLI Quickstartの通り、nodeとwatchmanをHomebrewでインストールします。
brew install node
brew install watchman
プロジェクトの依存パッケージもインストールします。
npm install
iOSビルドを準備
cocoapodsをインストール
単純にcocoapodsをインストールしようとすると、cocoapodsが依存しているffiがエラーになります。
sudo gem install cocoapods
LoadError - dlopen(/Library/Ruby/Gems/2.6.0/gems/ffi-1.13.1/lib/ffi_c.bundle, 0x0009): missing compatible arch in /Library/Ruby/Gems/2.6.0/gems/ffi-1.13.1/lib/ffi_c.bundle - /Library/Ruby/Gems/2.6.0/gems/ffi-1.13.1/lib/ffi_c.bundle
現時点でffiをarm64でインストールするのは一筋縄ではいかなそうなので、ここは以下のissueで議論されている通り、Rosetta 2(64-bit intel)で動かすことで回避します。
このためにTerminalの設定を変えるのも何なので、arch -x86_64
コマンドを使って64-bit intelアーキテクチャでcocoapodsをインストールします(ffiだけをx86_64でインストールした後、cocoapodsをarm64でインストールするとうまくいきませんでした)。
arch -x86_64 sudo gem install cocoapods
podsのインストールはarm64で実行できます。
12/1 追記
pod repo update
した後pod install
するとまたffiのところでエラーになったので、x86_64で実行した方が無難かもしれません。
cd ios && arch -x86_64 pod install
PodsプロジェクトのBuild Settingsを設定
この段階でxcworkspaceを開いてSimulator向けのビルドをすると、エラーになります。
Undefined symbols for architecture x86_64:
...
これはPodsプロジェクトのBuilde SettingsでDebugビルド時のBuild Active Architecture Only
(ONLY_ACTIVE_ARCH
)をYes
→No
に変更することで回避できます。
このままだと再びpod install
したときにまたYes
に戻ってしまうので、Podfile
のpost_install
で上書きするように設定します。
post_install do |installer|
installer.pods_project.build_configurations.each do |build_configuration|
build_configuration.build_settings['ONLY_ACTIVE_ARCH'] = 'No'
end
end
12/1 追記
Podsプロジェクトだけでなく、プロダクトのプロジェクトの方もBuilde SettingsでDebugビルド時のBuild Active Architecture Only
をNo
にしないとエラーになるケースがありました。🤔
11/27 追記
ほぼ同じ構成の別プロジェクトでSimulator向けのビルドを試したところ、以下のようなエラーになりました。
ld: in ..., building for iOS Simulator, but linking in object file built for iOS, file '...' for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
調べてみるとPods-ProductName
ターゲットとPods-ProductNameTests
ターゲットのBuild SettingsでExcluded Architectures
(EXCLUDED_ARCHS
)のAny iOS Simulator SDK
にarm64
を指定していないことが原因でした。
(これはうまくビルドできた方のプロジェクト)
Podsプロジェクトのxcconfigで設定しているようですが、依存パッケージの違いか、エラーになった方のPodsプロジェクトではxcconfigにこの設定がなかったので、Podfile
のpost_install
で設定するようにします。
post_install do |installer|
installer.aggregate_targets.each do |aggregate_target|
aggregate_target.xcconfigs.each do |config_name, config_file|
config_file.attributes['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] ='arm64'
config_file.save_as(aggregate_target.xcconfig_path(config_name))
end
end
end
Bundle React Native code and images
今度はビルドフェーズのBundle React Native code and images
でnodeが見つからないというエラーになります。
env: node: No such file or directory
Command PhaseScriptExecution failed with a nonzero exit code
ここで実行されるシェルスクリプトにnodeへのパスが通っていないだけなので、スクリプト内でパスを設定してもいいですが、CI環境でのビルドに影響が出ないように/usr/local/bin
にsymlinkを作ることにします。
sudo ln -s `which node` /usr/local/bin
Androidビルドを準備
Android Studioをインストール
公式サイトからダウンロードしてインストールします。UniversalでないのでRosetta 2での動作になります。
コマンドラインから使うことも考慮して、バンドルされているJDKにパスを通しておきます。
export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jre/jdk/Contents/Home
Emulatorを設定
M1はVT-xをサポートしていないので、Virtual Deviceを作成するときに警告が出ています。
無理矢理作成して起動してもエラーになります。
emulator: ERROR: x86 emulation currently requires hardware acceleration!
CPU acceleration status: Android Emulator requires an Intel processor with VT-x and NX support. (VT-x is not supported)
トラブルシュートを見ると、物理デバイスを使うか、Intel Macで開発するか、ARMシステムイメージのVirtual Deviceを使う(ただし10倍遅い)か、と書かれています。
Troubleshoot
Unfortunately, your computer does not support hardware accelerated virtualization.
Here are some of your options:
- Use a physical device for testing
- Develop on a Windows/OSX computer with an Intel processor that supports VT-x and NX
- Develop on a Linux computer that supports VT-x or SVM
- Use an Android Virtual Device based on an ARM system image
(This is 10x slower than hardware accelerated virtualization)
Other Imagesのところを見てみると、一応ARMシステムイメージのものがありますが、一番新しいのでもAndroid 7.1.1と少々古いです。
これで作成したVirtual Deviceを起動してみましたが、10倍どころではない遅さでホーム画面に辿り着くのに10分以上かかった上、最終的にはクラッシュしました。
これでは使い物にならないので、デバッグは物理デバイスを使うことにします。普段iOSで大体デバッグしてからAndroidで最終調整しているので、あまり問題にならないでしょう。
fastlane
fastlaneの実行でもやはりffiのインストールでエラーになります。
Undefined symbols for architecture arm64:
"_ffi_call", referenced from:
_ffi_raw_call in raw_api.o
_ffi_java_raw_call in java_raw_api.o
...
An error occurred while installing ffi (1.13.1), and Bundler cannot continue.
こちらもx86_64で実行して回避します。
arch -x86_64 bundle install
arch -x86_64 bundle exec fastlane
まとめ
ここまでやって、ようやくiOSはSimulator、Androidは実機で動かしてデバッグができ、fastlaneによるビルドも回すことができるようになりました。
すでに対応も進んでいるようですが、ffiとAndroid Studioがarm64に対応したらすんなり開発環境を構築できそうです。
Discussion
Cocopods めんどくさそうっすね〜〜。
arm64で何とかやろうとすると面倒ですね。