【社内勉強会資料】iOSアプリ開発のナレッジ〜管理・設計・テスト・リリース・運用のポイント〜

# この記事は何？

- 先日行った社内勉強会のスライドを元に書き起こしたものです。
- iOSアプリ開発のマネジメント、設計、テスト、リリース後の運用（維持保守）において考慮すべきポイントについて解説しました。
- 開発者だけでなく、マネージャやソリューションアーキテクトも意識した内容になっていますので、実装に関する細かい話は出てきません。

認識違いなどがありましたら、コメント欄で教えていただけるとありがたいです。

# XcodeとiOSのバージョン追従について

## Xcodeの概要

- Xcodeは、Apple純正で、Appleプラットフォーム※のアプリを開発するための統合開発環境。（※今回はiOSのみに話を絞る）
- XcodeはMacにしか入れられないので**Macは必須。**
- iOS SDKが内包されており、XcodeのバージョンとiOS SDKのバージョンは対応している（後述）。
- iOSシミュレータが内包されており、実機がなくてもある程度のデバッグは可能。ただし加速度センサー、カメラ、マイクなど、一部のセンサー/デバイスを使うテストはできない。
- SwiftとObjective-Cコンパイラが内包されており選択可能だが、今やSwiftの方がネット上にサンプルコード等の情報が圧倒的に多く、Null安全性などのメリットも有ることから、新規アプリであればSwift一択。

## Xcodeのバージョンアップ追従

- iOSがバージョンアップされると、そのSDKを含むXcodeがリリースされる。→Xcodeを上げないと新機能のAPIが使えない
- **Xcodeのメジャーアップデートが毎年9月にあり、翌年4月以降、最新メジャーVerのXcodeでビルドしないとビルドをAppleのサーバーにアップロードできないことが慣例化。**
- Xcodeのバージョンアップに伴い、Swiftコンパイラのバージョンが上がって、アプリのコードを修正しなければならないことがある。また、**ライブラリの対応状況の事前調査が必要。**

https://qiita.com/y-some/items/f7b2cbec8bff507cf894

## iOSの新バージョンへの追従

似たような話題として、**リリース済みアプリが、新OSバージョン下ではユーザーが期待しない挙動となってしまう**場合がある。

### iOS 14において発生した事例：

#### ペーストボード読み取りバナー問題

プライバシー保護のため、[アプリがコピペ内容を読み取るとバナーで通知される機能](https://japanese.engadget.com/ios14-clipboard-095008858.html)が追加された。
仮にアプリ側には該当コードがなくても、利用ライブラリに該当コードを含む場合にバナーが表示されてしまい、ライブラリのアップデートが必要となった。

https://qiita.com/y-some/items/485d5d09f37ccb8fffd8

#### デフォルトブラウザ変更問題

デフォルトのブラウザをユーザーが設定できる機能が追加された。 Safari以外に設定された場合に、アプリからブラウザが開けなくなってしまい、改修が必要となった。

https://qiita.com/y-some/items/ced67320f48318f83877

#### App Tracking Transparency(ATS)導入問題

iOS 14 SDKに含まれるAPIを利用してユーザーにオプトインしてもらわない限り、広告ID（IDFA）が取得できなくなった。
また、Appleの新しいトラッキングのポリシーに違反している（利用ライブラリを含む）場合に、審査リジェクトされる事例が発生した。

https://qiita.com/y-some/items/6bf895f53c7466a485d2

## アプリ運用保守の年間スケジュール例

![スクリーンショット 2021-06-20 11.08.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122917/b43ed3e7-8248-67ad-bda1-4b1834b2a512.png)

# 開発ライセンスについて

## Apple Developer Program (ADP)

- アプリをApp Storeで配布するための開発ライセンス。
- アプリ審査あり。
- 個人、法人ともにライセンス取得可能。
- 法人の場合、実在を証明する「D-U-N-S Number」の取得が必要。（東京商工リサーチに申請）
- 法人の場合、**アプリを「所有する」法人自身がライセンスを取得する必要あり。**受託業者は開発者としてチームに招待される形。
- 99 US$/年

https://developer.apple.com/jp/programs/

内部テストのためのアプリ配布については後述

## Apple Developer Enterprise Program (ADEP)

- 社内用アプリを配布するための開発ライセンス。
- 逆にApp Storeでの配布はできない。（配布用サーバーが必要）
- アプリ審査なし。
- 従業員100名以上であることが条件。
- 「D-U-N-S Number」の取得が必要。
- 社外にアプリを配布することは規約違反となる。
    - **現状、ADEPを取得するのは非常に難しい**模様。この規約を守らない事例が多いため？
- 399 US$/年

https://developer.apple.com/jp/programs/enterprise/

# Human Interface Guideline (HIG)

- Apple公式のUI/UXデザインガイド。
- デザイナー向けのガイドではあるが、HIG違反は審査リジェクトの可能性があるため、**実質「開発ルール」でもある。**
- このため、iOS Developerは（できればManagerやArchitectも）HIGを十分理解する必要があり、また頻繁にアップデートされるため最新情報のキャッチアップが必要。

https://developer.apple.com/design/human-interface-guidelines/

# ライブラリについて

- よほど機能がシンプルなアプリでない限り、**OSSライブラリの利用は避けられない。**一から全て自作するには工数も技術力も必要なので…
    - FirebaseなどmBaaSのSDK（※Firebaseの紹介は後述）
    - 実装を簡易にするためのライブラリ
    - アニメーション、ネットワーキング、DB、Keychainアクセスなど
- ただし、Xcodeの項で触れた通り、**ライブラリ起因で「Xcodeのバージョンアップができない」等の運用トラブルが起こりがち**なので、利用ライブラリの種類とバージョンの管理が重要。

## ライブラリ管理ツール

- CocoaPods
    - 最も歴史が長く、対応しているライブラリが多いため**無難な選択肢。**
    - Xcodeのプロジェクト定義ファイル(XML)を直接自動編集してしまう仕様のためトラブルが発生すると解決が大変。
- Carthage（カルタゴ／カーセッジ）
    - ビルドが高速なことが売り。
    - 対応していないライブラリもちらほらある。
- Swift Package Manager
    - Xcode 9で同梱された比較的新しめの公式ツール。
    - 徐々に対応しているライブラリが増えてきたので**新規アプリの選択肢としては大いにアリ。**

## Firebaseについて

- モバイルアプリの開発や運用のための便利なクラウドサービス。
- 無料（2021年6月現在）で使える鉄板サービス
    - **Analytics：** アプリでのユーザー行動をデータ化し分析できる機能。
    - **Cloud Messaging (FCM)：** Apple Push Notificationサービス(APNs)との中継を行なってくれるサービス（詳細は後述）。ユーザー属性と行動に合わせて作成したセグメントに対して、メッセージを送信するような使い方が可能。
    - **Crashlytics：** クラッシュレポーティング。Xcodeの標準機能よりも反映が早くて見やすい。
- 認証サービスやリアルタイムDBなどの便利なサービスもあるが、有料である

# プッシュ通知

## 全体的な仕組みおよびFCMを使うメリット

https://qiita.com/softbase/items/14eb61c13e0c72d3951d

FCMを使わない場合のバックエンドの煩雑さ
・iOSはAPNs、AndroidはFCMにそれぞれ異なるAPIでリクエストを送らなければならない。
・バックエンドサーバーにAPNs用の証明書または認証キーを登録しなければならない。
↓
FCMを使うことで解消される点
・iOS、Androidとも同じAPIでリクエストを送れる。
・APNs用の証明書または認証キーはFCMの管理コンソールで登録すれば良い。

## 最も基本的なペイロード

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122917/f797e36d-7b86-5bd0-aaae-9b7ae8924e8f.png" width="60%" alt="プッシュ通知のペイロード">

- 規定項目はiOSが勝手に処理するためアプリが取得する必要はない。
- それ以外にアプリとして自由にカスタム項目を追加できる。
    - それを利用して、「この値のプッシュ通知を受け取ったら画面Xに遷移する」などの機能を実現できる。

## リッチな通知

iOS 10以降では、画像・動画・音声、カスタムアクションが使える。

https://dev.classmethod.jp/articles/ios-push-notification-attach-file/

https://dev.classmethod.jp/articles/user-notifications-ui-framework-3/

iOS 12以降の機能

- 通知センター上でのグルーピングが可能となった。
- ユーザー許諾を初回の通知受信時に行うことが可能になった。

https://tofucodes.hatenablog.jp/entry/2018/09/06/010901

## サイレントプッシュ通知

- 特徴
    - 画面上には何も表示されない通知。
    - iOSは通知を受け取ると該当アプリをバックグラウンドで起動する。
    - アプリはこれを受けたタイミングで何かしらのバックグラウンド処理を起動することができる（サーバーから最新データを取得する等）。
- 通知を受けた際のフック処理
    - 「何かしらの処理」は最大30秒間しか実行できない。
    - 実行タイミングはiOSが判断するため（充電状態や通信状態等？） 、全く実行されない場合や、遅延される可能性がある。

https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app

https://qiita.com/chocoyama/items/56cd3ac2daaf69dffa0f

# バックグラウンド処理

## 全体感

iOSではアプリのバックグラウンド処理について制約が大きい。

- 実行タイミングがシステムに依存している。
- 処理時間が制限されている。
- 実行時点での環境（バッテリー状況、通信状況など）によって実行されない場合もある。
- ユーザーが「設定」アプリにてオプトアウトできる。

## 定型的なバックグラウンド処理

- オーディオ再生、AirPlay、Picture in Picture
- 通話、通話用のプッシュ通知
- サイレントプッシュ通知（※）
- 位置情報の取得（※）
- 外部アクセサリやBluetooth機器との通信（※）

（※）ユーザーの許諾が必要なもの

## 任意のバックグラウンド処理

### iOS 12以前

- Background Task Completion
    - フォアグラウンドでやり残した作業をバックグラウンド状態でも引き継いで実行させることが可能。
    - 実行可能時間は不明（最大30秒？）。

https://qiita.com/chocoyama/items/8162bf67e452e41b574b

- Background Fetch
    - SNSアプリのタイムライン事前取得等を想定した機能。
    - ユーザによるオプトアウトが可能。「設定」app＞対象アプリ＞「Appのバックグラウンド更新」
    - OSによってスケジューリングされ、遅延されたり実行されない場合も。
    - 端末や該当アプリの利用傾向をOSが自動判定してタイミングを決めているらしい。
    - 実行可能時間は30秒。

https://qiita.com/griffin_stewie/items/8371c09059b3ba7bb202

### iOS 13以降

iOS 13で“BackgroundTasks Framework”が登場。

- Background App Refresh Tasks
    - Background Fetchの後継であり、基本は変わらず。
- Background Processing Tasks
    - iOS 13から利用可能な新機能
    - 比較的重たい処理を想定し、数分間の実行時間が許されている。
    - 例えば、Core MLを利用した機械学習のトレーニング処理などを想定。
    - アプリ側で条件設定が可能（Wi-Fi接続時とか、充電中とか）
        - ただし、条件を満たしても確実に実行される保証はない。

https://shiba1014.medium.com/advances-in-app-background-execution-6739bfe82c04

https://qiita.com/chocoyama/items/d69322932f400a5d012b

# ローカルデータストア

## Key-Value Store

- UserDefaults
    - アプリ内部に保存される
    - アプリを削除すると値が消失する
    - 平文で保存される　**→センシティブ情報の保存には向かない**
- Keychain
    - デバイスのiCloud Keychainに保存される
    - アプリを削除しても値は無くならない（再インストールしたら復活する）
    - 暗号化され保存される＋プロビジョニング・プロファイル（※）によって読み出し保護されている。

（※）開発者証明書とアプリIDによって正規のアプリであることを担保するためのプロファイル

## Database

- CoreData
    - iOS SDK同梱
    - SQLiteのwrapper
    - 暗号化したければOSSライブラリが必要。
- Realm（レルム） →個人的におすすめ
    - 鉄板のOSS
    - オブジェクトデータベースで、エンティティをSwiftの型で定義できる。
    - 永続化するかオンメモリーだけで保持するかを簡単に切り替えられる。
    - 暗号化機能がある。

# Webブラウジング

## SFSafariViewController

- ブラウザアプリに飛ばすよりも**アプリと一体感がある。**
- 見た目を変える、ボタンを追加する等の**カスタマイズはほとんどできない。**
- イベントのフックなどもほとんどできない。
- アプリからSFSafariViewControllerに認証情報は渡せない（IFがない）。つまり、アプリ側でサービスにログインしても、Web側のコンテンツを開くときに再ログインが必要になるので設計上の工夫が必要。
- ドメイン名が表示されるのでオープンリダイレクト対策効果がある。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122917/0a747745-19cf-c875-9348-4ae993260bc8.png" width="50%">

https://dev.classmethod.jp/articles/ios-safari-view-controller-limitation/

## WKWebView

- **見た目を変える、ボタンを追加する等のカスタマイズが可能。**逆にデフォルトはノッペラボーなので、閉じるボタン、ローディングインジケーター等、全て実装が必要。
- URLやドメイン名は見えない。必要なら実装が必要。
- Viewの一部に埋め込むこともできる。
- イベントのフックが可能（リクエスト時、ロード開始時、ロード終了時などなど）。
- Swiftコードで要素を拾うことやJSを注入することも可能。
- 認証Cookieを渡すことも可能。
    - ただし、iOSに内包されているWebKitの影響を受けて、iOSのバージョンアップ後に以前とは違った挙動をしたりする等のトラブルがある。
    - ご利用は計画的に。

# テスト 

## TestFlight

- ADPライセンスを取得すると、“App Store Connect”に、アプリの公開のための情報を登録することができるようになる。
- App Store Connectにはテストのための“TestFlight”機能がある。
- テスターのApple IDを登録できる。
- 開発者がアプリのビルドをアップロードすると、テスターのiOSデバイスのTestFlightアプリからテストアプリをダウンロード可能になる。
- Jenkins, Bitrise, CircleCIなどを利用してCI/CDも可能。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122917/c22ecdc0-e027-4443-2378-dd9238baa31d.png" width=70%">

## テスターの種類

- 内部テスター
    - App Store ConnectのロールはAccount Holder（アカウントホルダー）、Admin（管理者）、App Manager（App管理者）、Developer（デベロッパ）、Marketing（マーケティング）で、最大100人まで。
    - 内部テスターは、上記のメンバーを設定できる。
    - 各自最大30台のデバイスをテスト用デバイスとして登録できる。
- 外部テスター
    - 最大10,000人まで、Eメールやリンクによって招待できる。
    - 未リリースのアプリは、簡易的な審査を受けなければ、外部テストはできない。
- テスト用ビルドは90日で無効になり、起動できなくなる。

https://developer.apple.com/jp/testflight/

## テストのTips

- 本番用のアプリとはBundle ID（アプリID）を変えて、テスト用のアプリを別に作り、開発中はそちらを使ってテストした方が良い。
    - プッシュ通知など、間違えて本番向きに飛ばしてしまうと事故になってしまう。
    - クラッシュレポートに開発中／本番のログが混在してしまう。
    - テスト用アプリのみ、サーバーの接続先変更機能を持たせる。
- リリース直前の最終検証フェーズから本番アプリに切り替える、などの運用が良い。
- ただし、本番／テストビルドの切り替えを自動化するために、設定ファイルによるDI、ビルドスクリプト、あるいはブランチ運用などの手法の検討が必要。

# 自動テスト

## XCTest

- ロジックのユニットテスト。
- Swiftでテストコードを記述する。要はxUnit。

## XCUITest

- 自動シナリオテスト。Swiftで「実行ボタンをtapする」「アラートに◯◯という文字列が表示されること」というようなテストコードを書くと、シミュレータ上で実際に動作してテストが行われる。
- テストコードからテストシナリオを読み取ることが難しく、メンテナンスがおざなりになってテストが陳腐化しがち。
- 実行時間が長い。テストシナリオが１００を超えると１〜２時間以上は掛かる。

アプリ機能の拡大とともに自動テスト、特にUIテストの維持保守は指数関数的に困難になって行く。
なるべくXCUITestに頼らずにXCTestを増やしたほうが良いが、そのためにはVIPERなどのテスタブルなアーキテクチャーの採用を検討しなければならない。

**自動テストの導入には、戦略、計画、合意が重要。**

# App審査提出

## 大まかな流れ

1. App Store Connectにアプリの基本情報（アプリID、説明文、検索キーワード、個人情報収集の説明etc）を登録する。
2. App Store上に表示させるアイコン画像を作成し登録する。
3. 同、スクリーンショット画像（または動画）を作成し登録する。
4. プライバシーポリシー用Webページを作成し、リンクを登録する。
5. サポート用Webページを作成し、リンクを登録する。
6. アプリのビルドをアップロードしビルド番号を指定してsubmit。

主にプロダクトオーナーとデザイナーに負荷が掛かるフェーズ。

## アプリ審査の注意点

- App Store Reviewガイドラインは一度目を通したほうが良い。
- 審査は結局レビューアの主観なので、今まで指摘されなかった問題を急に指摘されリジェクトを受けることもある。
- 審査にかかる日数は以前と比較すると短縮される傾向があるが、依然として数日待たされるケースもある。混み具合による？
- 2020年から、バグ修正の場合は法的問題以外はガイドライン違反があってもリジェクトされず公開できることになった。

https://developer.apple.com/jp/app-store/review/guidelines/

リリース計画には、**審査日数とリジェクトのリスクを考慮する必要あり。**

## 実際に遭遇したリジェクト事例

- 非公開APIを使用している。
- 使用禁止となった旧APIを使用している。
- “Android”のような、他のモバイルプラットフォームに関連する単語を表示している。
- 「ボタンtapでSafariに飛ばす」は“Minimum Functionality”なのでSFSafariViewControllerを使え。
- App Store Connect上で入力したバージョンアップ説明文にて未発表のApple製品名に言及している。
- 機能を見られずレビューできないので動画を添付せよ。

# おわりに

iOSアプリ開発に携わる方にとって大事なこと

- Appleのポリシーを知ること。
- Appleの最新動向をキャッチアップすること。
- 問題に突き当たったときは、まず公式ドキュメントを調べること。
    - 公式ではないWeb記事等を参考にするときは、記事の執筆日時をチェックするクセをつけること（3年以上前の記事は当てにならないことが多い）。