iOSプロジェクトとCI/CDをM1 Macに移行

![Codemagic-blog-header-Migrating-iOS-app.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2028491/24541261-bffb-2c1f-1ed8-491822839ac4.png)
Appleシリコンプロセッサーは、デスクトップCPUの世界に革命を起こしました。**Intelのx86_64アーキテクチャからAppleのarm64への移行**は、パフォーマンスを大きく落とすことなくx86_64コマンドをarm64に変換する、**ロゼッタ2エミュレータ**のおかげで、消費者にとってとてもスムーズでした。しかし、2020年末に新アーキテクチャがリリースされた当初は、開発者たちもエミュレーションに頼る必要がありました。というのも、開発者ツールやライブラリの大半は、arm64アーキテクチャをサポートしておらず、さらにそのために、パフォーマンスが不安定になったり、場合によってはクラッシュしたりすることもあったからです。

新しいAppleシリコンチップが登場して約2年が経過した今、状況は一変しています。**arm64**アーキテクチャへの移行がまだの方は、この機会にご検討ください。昨年や2020年末と比較すると、ほとんどの依存関係やツールが新しいアーキテクチャに対応しているので、移行作業中に大きなハードルに直面することはないでしょう。

さらに、皆様にご愛用いただいているCI/CDプロバイダーである[Codemagic](https://codemagic.io/https://codemagic.io/?utm_source=qiita&utm_medium=referral&utm_campaign=flutter_distribution&utm_content=japanese_lang)が、初のMac mini M1ビルドマシンを一般公開したことにも触れないわけにはいきません!　すでに一部のお客様には、新しい効率的なチップを搭載した強力なビルドマシンをお試しいただき、ビルドタイムの大幅な短縮に成功されております。そこで、**IntelからM1への移行**、つまり、プロジェクトのCI/CDパイプラインを、古き良きx86_64からピカピカの新しいarm64へ移行することについてご説明させていただきます。 

本記事では、以下のトピックについてご紹介いたします：

- 必要条件
- 新アーキテクチャでの作業
- サードパーティの依存関係を更新
- Mac mini M1とMac Proのビルド時間

それでは、さっそく始めましょう！


## M1への移行に必要な条件

本稿執筆時点では、ワークフローをCodemagic上の新しいApple M1仮想マシンに移行するには、**Xcode 13.3+**を使用する必要があります。これは、macOS M1ビルドマシンのベースイメージにそれがプリインストールされているからです。Xcode 13.3.1 (13E500a) は最新版で、`codemagic.yaml` ファイルに `13.3`、`13.3.1`、`edge`、または`latest` を設定するか、Flutterアプリのワークフローエディタのビルド設定で選択すると、デフォルトで使用されます。

2020年にAppleがカスタムシリコンを発表すると、新アーキテクチャへの2年間の移行が始まりました。開発者は開発者移行キット（DTK＝Developer Transition Kit）を利用して、アプリのテスト、アップデート、Appleシリコンへの移行ができました。 

当初、開発者たちは、ロゼッタエミュレーションを使って、Intelプロセッサを搭載したMac向けに作られたアプリを利用していました。また、CocoaPods依存関係とSwiftパッケージは、最初の数か月は**arm64**アーキテクチャに未対応でした。開発者たちが移行を開始し、最新のM1やM1 Pro/Max/Ultraシリーズデバイスを入手するにつれて、オープンソースプロジェクトや、**arm64**アーキテクチャに対応した様々なSDKを要求するようになりました。 

移行がほぼ終了した現在、Alamofire、Kingfisher、あるいはFirebase SDKなど、数多くの人気オープンソースプロジェクトがAppleシリコンマシンに対応するようになりました。これで、ほとんどの場合、ロゼッタエミュレーションを使う必要がなくなり、Appleの効率的なチップの生の処理能力を活用できるようになりました。


## 新アーキテクチャとの連携

iPhoneのアーキテクチャはすでに「arm64」ですが、Intelは「x86_64」のシミュレーターを使用しました。新しいM1シリーズのデバイスでは、シミュレーターも「arm64」アーキテクチャで動作します。 

> Appleは、Appleシリコンのアーキテクチャビルドエラーを解決するための[詳細記事](https://developer.apple.com/documentation/technotes/tn3117-resolving-build-errors-for-apple-silicon)を提供しています。

Xcodeはすでに、すべてのプラットフォームでビルドして出荷するのに役立つデフォルトのアーキテクチャビルド設定を備えています。設定の1つに **アクティブなアーキテクチャのみを構築（Build Active Architectures Only）**というブーリアン値があり、デフォルト値はDebug構成の場合は**Yes**、Release構成の場合は**No**となっています。値が **Yes**に設定されている場合、Xcodeは選択されたアーキテクチャ用に自動的にビルドします。つまり、Appleシリコンマシンを使っている場合は**arm64**シミュレーター用にビルドし、Intelマシンを使っている場合は**x86_64**シミュレーター用にビルドします。 

デバイスとシミュレーターは異なるアーキテクチャを持つかもしれませんが、特にIntelマシンを使用している場合、Xcodeにどちらか一方のみを対象にビルドさせたいと考えるかもしれません。

プロジェクトに移動し、ターゲットを選択し、**ビルド設定**を選択します。アーキテクチャ**セクションで、デバッグビルド用に**アクティブなアーキテクチャのみを構築（Build Active Architectures Only）**を**YES**に設定します。これにより、コンパイラは1つのアーキテクチャ用のバイナリのみを生成するようになります。

![](https://blog.codemagic.io/uploads/2022/04/build_active_arch_project.png)

Podsも同様にします：

![](https://blog.codemagic.io/uploads/2022/04/build_active_arch_pods.png)

それを**NO**に設定すると、Xcodeはすべての有効なアーキテクチャ用にプロジェクトを構築します。しかし、次のようなエラーが表示されることがあります： 

```
Could not find module 'ColorKit' for target 'x86_64-apple-ios-simulator'; found: 
arm64-apple-ios-simulator, at: /Users/rudrankriyam/Library/Developer/Xcode/DerivedData/Musadora-ccjzyuildzfnokedenrcjqixspxo/Build/Products/Debug-iphonesimulator/ColorKit.swiftmodule
```

Xcodeの**アクティブなアーキテクチャを構築（Build Active Architecture）**を**YES**に設定すると、ビルド時間が劇的に短縮されます。なぜなら、2つのアーキテクチャではなく1つのアーキテクチャ用にコンパイルされるからです。これでさらに作業が加速します！

## サードパーティの依存関係を更新

あなたのプロジェクトでは、サードパーティの依存関係を管理するために、CocoaPods、Carthage、および/またはSwiftパッケージマネージャを使用できます。 

M1 MacでHomebrewを使うと、CocoaPodsの管理も簡単です。

```
brew install cocoapods
```

Carthageを使用する場合は、**XCFrameworks**を使用するのが最適な解決策です。これにより、アプリを構築するのに必要な有効なアーキテクチャのみを構築できます：

```
carthage update --use-xcframeworks
```

Podやパッケージを最新版に更新する必要があるかもしれません。これにより、ユニバーサルバイナリ（x86_64とarm64の両アーキテクチャの実行コードを含む）のサポートを受けられる可能性が高まり、インテルマシンからAppleシリコンマシンへの移行がスムーズに行えるようになります。 

この投稿では、サードパーティの依存関係を組み合わせた[サンプルプロジェクト](https://github.com/rudrankriyam/Silicon)を使用します。CocoaPodsとSwiftパッケージマネージャの両方を使用しています。

Swiftパッケージとしてのプロジェクトの依存関係は以下の通りです： 

- Kingfisher 
- Swinject
- Alamofire 

Podsとしてのプロジェクトの依存関係は以下の通りです： 

- SwiftLint
- AppsFlyerFramework

最初のプロジェクトでは、XCFrameworkが **arm64**アーキテクチャをサポートしていない場合に発生するエラーをご紹介するために、古いバージョンのフレームワークが用意されています。 

```
pod 'AppsFlyerFramework', '6.2.0'
```

ソースコードがないため、自分たちでユニバーサルバイナリを作ることはできません。プロジェクトを実行すると、次のようなエラーが表示されます： 

```
ld: in /Users/rudrankriyam/Downloads/Silicon/Pods/AppsFlyerFramework/iOS/AppsFlyerLib.framework/AppsFlyerLib(AFSDKKeychainFactory.o), 
building for iOS Simulator, but linking in object file built for iOS, 
file '/Users/rudrankriyam/Downloads/Silicon/Pods/AppsFlyerFramework/iOS/AppsFlyerLib.framework/AppsFlyerLib' 
for architecture arm64
```

シミュレーターでプロジェクトを実行するには、**arm64**アーキテクチャが必要です。しかし、今回のフレームワークのバージョンでは、それをサポートしていません。

この問題を解決するには、フレームワークのリポジトリを検索し、**arm64**のサポートを追加するバージョンがリリースされているかどうかを確認します。前述したように、多くの優先フレームワークやオープンソースプロジェクトは、最新のシリコンチップ上での動作に対応しています。幸いなことに、このフレームワークはバージョン `6.3.0` で **arm64**をサポートするようになったため、`Podfile`を更新して最新バージョンを取得できます。

```
pod 'AppsFlyerFramework'
```

`pod update`コマンドを入力すると、M1デバイスとIntelマシンでプロジェクトを正常に実行できるようになります。

ある依存関係がまだarm64をサポートしていない場合、フレームワークの作者に両方のアーキテクチャをサポートする新しいアップデート版を提供するように依頼できます。ユニバーサルXCFrameworkを提供することで**arm64**対応に移行したiOS SDKの例として、AppsFlyer iOS SDKは複数の開発者からの要望を受けて、昨年4月に**arm64**サポートをリリースしました。

多くの依存関係は迅速なサポートを備えている一方で、ご使用のフレームワークは古くなっている可能性があります。また、ソースコードにアクセスできないプロプライエタリなフレームワークである場合もあります。また、これらのフレームワーク/パッケージのアップデートが当面ないと仮定します。その場合、こちらの記事[「ネイティブARM64バイナリをiOSシミュレータ上で動作させるためのハッキング」（Hacking native ARM64 binaries to run on iOS Simulator）](https://bogo.wtf/arm64-to-sim.html) をご覧ください。その名の通り、ハッキングして動作させるものなので、この極端な回避策は最終手段としてのみ使うことをお勧めいたします。 


## M1 Mac miniとIntel Mac Proのビルドタイム

移行に成功したオープンソースプロジェクトからヒントを得て、新しいチップに取り組むことができます。そのようなプロジェクトの例をいくつか見てみましょう。[こちら](https://blog.codemagic.io/open-source-ios-projects-to-learn-better-practices/)をご覧ください。 

M1マシンとIntelマシンのビルド時間の違いを理解し、M1 Mac miniの優れた効率性と速度を知るために、公式の[Wikipedia iOS](https://github.com/nevercode-rudrank/wikipedia-ios)アプリを構築しテストを実行しました。これは、何百ものテストを行う実戦的なシナリオを実証しています。オープンソースのアプリなので、ご自分で調べることも可能です。

**テスト名** | **Mac mini M1** | **Mac Pro**
--- | --- | ---
スクリプトのインストール | **17s** | 163s
プロジェクトのビルド | **254s**  | 280s
テストの実行 | **270s** | 395s
全体 | **573s** | 883s

特にテストの実行中に、M1ビルドマシンの方が大幅に高速に動作していることが、数字で確認できます。このアプリに対して同じテストを複数回実行した結果、全体のビルド時間が**35～40%**減少していることが確認できました。多くのビルドを実行する場合、数値の差は加算され、より速い反復処理によりかなりの時間を節約できます。  
 
## 結論

AppleシリコンチップはMacハードウェアの未来であり、これからますます良くなっていきます。一般的なオープンソースのフレームワークやSDKはすでに新しいチップに対応しているため、1年前と比べると移行はずっと簡単です。 

> 再度のお知らせ：[M1 Mac miniビルドマシンは、Codemagicですでにご利用いただけます](https://codemagic.io/m1-mac-mini/https://codemagic.io/?utm_source=qiita&utm_medium=referral&utm_campaign=flutter_distribution&utm_content=japanese_lang)。従量課金（pay as you go）の場合は、単に`instance_type: mac_mini_m1`を使用してお試しください。プロフェッショナルプランをご利用のお客様で、Mac mini M1の試用版をご希望の方は、カスタマーエンジニアリングチームにご連絡いただけますと、新しいマシンで迅速にグリーンビルド（成功ビルド）を実現できます!