iOSアーキテクチャとApp Thinningについてまとめてみた

## はじめに
[ユアマイスターアドベントカレンダー2018](https://qiita.com/advent-calendar/2018/yourmystar) の19日目の記事です。

現在、個人的にiOSアプリを作っており、XcodeからApp Store Connectにアプリをアップロードしようとしたとき、そのバイナリにBitcodeを含めると、App Store Connectで `ビルドの読み込み中にエラーが発生しました`となる問題が発生しました。
そのときは、Bitcodeが何か、すでにビルドされたアプリをアップロードしているのにApp Store Connectでビルドエラーとなるのか、さっぱりわかりませんでしたので、この機会に色々調べてみました。
今回はそのまとめを書きたいと思います。

## アーキテクチャとは
ここでのアーキテクチャとは、CPUの命令セットアーキテクチャのことを指します。
命令セットとは、CPUに対して命令を伝えるための言葉です。

## デバイスで使われているアーキテクチャ
使われているアーキテクチャ一覧です。

### iPhone

|アーキテクチャ|32/64bit|iPhone端末           |
|:---------|:------:|:--------------------|
|armv6     |32bit   |iPhone 3G            |
|armv7     |32bit   |iPhone 3GS, 4, 4S    |
|armv7s    |32bit   |iPhone 5, 5c         |
|arm64     |64bit   |iPhone 5s 〜 iPhone X|
|arm64e    |64bit   |iPhone XS, XS Max, XR|

### Apple Watch

|アーキテクチャ|32/64bit|端末       |
|:---------|:------:|:----------|
|armv7k    |32bit   |Apple Watch|

### Apple TV

|アーキテクチャ|32/64bit|端末    |
|:---------|:------:|:-------|
|arm64     |64bit   |Apple TV|


### Simulator

|アーキテクチャ|32/64bit|端末     |
|:---------|:------:|:--------|
|i386      |32bit   |Simulator|
|x86_64    |64bit   |Simulator|


## Xcodeでの設定
Xcodeの `Build Settings` で、どのアーキテクチャ向けにアプリをビルドするのかが書いてありました。
Build Settings の　`Architectures(ARCHS)` と `Valid Architectures(VALID_ARCHS)` の項目です。
Architectures(ARCHS)が、バイナリの対象となるアーキテクチャ、Valid Architectures(VALID_ARCHS)もバイナリの対象となるアーキテクチャですが、これら両方に当てはまったアーキテクチャに向けてビルドします。

Xcode10のデフォルトでは、Architectures(ARCHS)には `Standard Architectures($ARCHS_STANDARD)` の変数で定義いました。
$ARCHS_STANDARD を見たところ、iPhone OSのとき `armv7 arm64`、Simulator OSのとき `i386 x86_64`、Mac OSXのとき `x86_64` となるようです。
Valid Architectures(VALID_ARCHS)には、`armv7 armv7s arm64　arm64e` が入っていました。

## App Thinning
App Thinning は、WWDC15で発表された、アプリを自動で最適化して配信してくれる仕組みです。
そうすることで、アプリのサイズを小さくすることができ、アプリのダウンロード時間を短縮したり、端末の容量を抑えることができます。
また、端末によって最適化されたアプリを提供できるので、性能の向上もできます。

App Thinningは、大きく3つあります。

- App Slicing
- Bitcode
- On-Demand Resources

## App Slicing
App Slicingは、App Storeからアプリをダウンロードするときに、使用するデバイスにあったバイナリやリソースのみを含むバイナリをダウンロードする仕組みです。iOS9以降とtvOSで対応しています。

これまでは、すべてのデバイス・解像度に対応したアプリを提供していましたが、それではデバイス・解像度が増える度にアプリのサイズが増大します。また、使用する端末で使わないバイナリやリソースが含まれてしまいます。
App Slicingを使うことで、使用する端末に必要なバイナリ・リソースを選別してApp Storeからダウンロードするとことができ、必要最低限のものだけを端末に入れることができます。

例えば、iPhone Xを所有しているユーザがダウンロードする場合、アーキテクチャが `arm64` 、`64bit`、解像度が`@3x`のリソースのバイナリをApp Storeは配信します。

## Bitcode
Bitcodeは、 LLVM の中間言語で、それぞれのプラットフォームに依存しない言語で書かれています。

これまでは、Xcode上で機械語にコンパイルしたものをApp Storeで配信していましたが、Bitcodeを用いた場合は BitcodeをApp Store Connectにアップロードし、AppleがBitcodeを機械語に変換して配信するようになります。

これによって、Appleがarmv7・arm64・arm64eといったアーキテクチャごとにバイナリを作成することができ、これがApp Slicingでの最適化して配信にすることができるようになります。
また、新しいアーキテクチャが出た場合でも、開発者は何もせずAppleだけで対応することができます。

## On-Demand Resources
On-Demand Resourcesは、そのリソースが必要なタイミングでAppStoreからダウンロードすることができる仕組みです。iOS9から使えます。
この仕組によって、最初からすべてのリソースをアプリと一緒にダウンロードしないようにでき、必要最小限のアプリサイズを提供することができます。

## App Thinningの効果
Bitcodeを含めた場合と含めなかった場合でどれくらいアプリのサイズが違うのか見てみました。
App Store Connectのアプリの `アクティビティ` タブで、提出されたすべてのiOSビルドが見れるので、そこから見ました。デバイスの種類によって多少サイズが異なりますのでだいたいの平均です。

- Bitcodeを含めたとき
  - ダウンロードサイズ 14.3MB
  - インストールサイズ 23.5MB
- Bitcodeを含めなかったとき
  - ダウンロードサイズ 15.5MB
  - インストールサイズ 31.1MB

ダウンロードサイズは約8%、インストールサイズは約25%くらい削減できていました。

## まとめ
今回調べてみて、アプリのサイズを最小限に抑えるための工夫がたくさんあることがわかりました。

このようなアプリを最適化する仕組みは、Androidでも[Android App Bundle](https://support.google.com/googleplay/android-developer/answer/9006925?hl=ja)があったなと思い出しました。
ただ、[Android App Bundle](https://support.google.com/googleplay/android-developer/answer/9006925?hl=ja)が出たのは、Android Studio 3.2.0-alpha18が2018年6月。App ThinningはXcode7が出た2015年9月。
約3年前に実現していたAppleがすごい。(Android端末の種類すべてに対応することを考えると、致し方ないかも)

今回はエラーがきっかけで色々調べてみましたが、一旦立ち止まってしっかり調べてみる良い機会だったと思います。

## 参考
- [iOSデバイス一覧表](https://qiita.com/takkyun/items/814aa45beee422a5f0c6)
- [Xcode Build Settings Reference](https://pewpewthespells.com/blog/buildsettings.html)
- [App Thinning メモ](https://qiita.com/usagimaru/items/cb19f283db4ac0cd8bd6)
- [Xcode 7ではデフォルトでビルド時にビットコードが含まれる](https://project-flora.net/2015/09/13/xcode-7%E3%81%A7%E3%81%AF%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%81%A7%E3%83%93%E3%83%AB%E3%83%89%E6%99%82%E3%81%AB%E3%83%93%E3%83%83%E3%83%88%E3%82%B3%E3%83%BC%E3%83%89%E3%81%8C%E5%90%AB/)
- [LLVM bitcode基礎知識](https://qiita.com/gamako/items/f37dbb05de9d3832ce6b)
- [新規インストール時のアプリサイズを計測し、最適化を行なう方法について](https://dev.classmethod.jp/smartphone/reducing-the-size-of-ios-app/)