プログラマのための IT 教科書

モバイルアプリの実務

この部の 9 / 9 章 ・ 全体で 42 / 76 章 ・ 読了目安 45 分

この章を読むとできるようになること
  • 後方互換性と冪等性が必須になる理由を説明できる
  • 端末を信頼しない設計ができる
  • API を作る側としてモバイルの前提を考慮できる

Web とモバイルアプリは、同じ「クライアント」でも運用の前提が根本的に違います。

Web:      直せばすぐ全員に反映される
モバイル: 審査を通し、利用者が更新して、初めて反映される

この違いが、設計のあらゆる部分に影響します。 モバイルを担当しなくても、API を作る側は必ず知っておく必要があります。

最大の違い: 配ったものを取り消せない

1. コードを直す
2. ストアに提出する
3. 審査を待つ(数時間〜数日。リジェクトされることもある)
4. 公開される
5. 利用者が更新する          ← ここが最大の問題

5 が保証されません。 自動更新を切っている人、容量が足りない人、 古い OS のままの人がいます。

つまり、

複数のバージョンが同時に動き続ける
今この瞬間、あなたのサーバーには
  v1.0 / v1.4 / v2.0 / v2.3 のアプリからリクエストが来ている

これが、モバイルを持つサービスの API 設計を決定づけます。

□ API の後方互換性は「望ましい」ではなく「必須」(スキーマと RPC)
□ フィールドを消せない。型を変えられない
□ 「フロントと同時にデプロイすればいい」が通用しない
□ 半年前のバージョンをいつまでサポートするかを、方針として決める

Web だけの経験しかないと、ここで必ず事故ります。

強制アップデートの仕組みを最初から入れる

アプリ起動時にサーバーへ問い合わせ
  → 「このバージョンは最低要件を満たしていますか」
  → 満たしていなければ、更新を促す画面を出して先に進ませない

これを後から入れることはできません(入れる前のバージョンには届かないため)。 初回リリースに必ず含めてください。モバイル開発で最も重要な初期設計の1つです。

ネイティブか、クロスプラットフォームか

方式特徴
ネイティブ(Swift / Kotlin)OS の機能をすべて使える。2つ作る必要がある
クロスプラットフォーム(Flutter / React Native)1つのコードで両方。OS 固有機能は追加実装が要る
Web View 中心Web の資産を活かせる。体験は劣ることが多い

どれが正しいということはありません(新しい言語をどう学ぶか)。 チームの人数、求める体験、OS 固有機能の必要性で決まります。

新人として重要なのは、なぜその選択をしているかを聞くことです。

ライフサイクル — アプリは止まったり殺されたりする

Web のタブとは違い、モバイルアプリはOS に管理されています。

起動 → 前面(動作中) → 背面(バックグラウンド) → OS に破棄される
                              ↑ ここで処理が止まる
□ バックグラウンドでは、通信も処理も制限される(OS が止める)
□ メモリが足りなければ、アプリは予告なく破棄される
□ 復帰時、画面の状態を自分で復元する必要がある
「アプリを開き直したら入力が消えた」

入力途中でホーム画面に戻り、しばらくして戻ってきたらアプリが破棄されていた。

これはバグではなく、OS の正常な動作です。

□ 入力中の内容は、こまめにローカルへ保存する
□ 復帰時に「前回の続きから」を復元する
□ 長いフォームは、途中保存を前提に設計する

Web でも同じ配慮は要りますが、モバイルでは頻度が桁違いです。

ネットワークは、繋がらないもの

Web:      基本的に繋がっている前提で書ける
モバイル: 電車・地下・エレベーター・機内モード・回線切り替え
□ オフラインでも、できることは動かす(閲覧・下書き)
□ 失敗したら、後で自動的に再送する(非同期処理とメッセージングの冪等性が必須)
□ 通信中であることを必ず表示する
□ タイムアウトを短めにし、再試行の導線を出す
□ 大きな通信は Wi-Fi 時に限定することも検討する
再送するなら冪等性が絶対に必要
送信 → タイムアウト → 利用者が再送 → 実は1回目も届いていた
→ 二重に注文が作られる

モバイルは電波状況で「送ったか分からない」状態が頻繁に起きます。

だから、冪等キー(API を設計する・非同期処理とメッセージング)が Web 以上に重要です。 「モバイルアプリがあるサービスの API は、冪等でなければならない」 と考えてください。

端末に何を保存してよいか

端末は、利用者の手元にあります。 解析される前提で考えます。

□ 認証トークン → Keychain(iOS)/ Keystore(Android)などの安全な領域へ
□ 個人情報   → 必要最小限。可能なら保存しない(エンジニアと法律)
□ APIキー等  → アプリに埋め込んだ時点で公開情報。解析すれば取り出せる
□ 業務ロジック → 金額計算や権限判定を端末側で完結させない(認証と認可の実装)

「アプリの中だから見えない」は成立しません。 これはフロントエンドの環境変数(フロントエンドの実務)と同じ話です。

権限

カメラ・位置情報・通知・連絡先などは、利用者が拒否できます。

□ 拒否された場合の画面を必ず作る
□ 「なぜ必要か」を、要求する直前に説明する(許可率が大きく変わる)
□ 起動直後にすべての権限を求めない(拒否されやすい)
□ 一度拒否されたら、アプリからは再要求できない(設定アプリへ誘導する)

プッシュ通知

□ 許可を取る必要がある(拒否される前提)
□ 端末トークンは変わる。サーバー側で更新を受け付ける
□ **届く保証はない**。重要な情報を通知だけに頼らない
□ 送りすぎると通知を切られる。切られたら二度と届かない

通知は「届いたらラッキー」な経路です。 重要な連絡は、アプリ内にも必ず残してください。

ストア課金

自社の決済ではなく、ストアの仕組みを使う必要がある場合があります (デジタルコンテンツの販売など。規約は変化するので必ず最新を確認してください)。

□ ストアの手数料がかかる
□ レシートの検証は必ずサーバー側で行う(端末の言い分を信じない)
□ サブスクリプションは状態管理が複雑(更新・解約・返金・猶予期間)
□ 課金の状態は、サーバー側を正本にする
端末から「購入しました」を信じない

端末の言い分だけで課金状態を有効にすると、改造したアプリから無料で使えます。

必ず、ストアのサーバーに問い合わせて検証してください。 認証と認可の実装の「クライアントを信頼しない」と同じ原則です。

リリースの運用

Web と比べて、やり直しが効かないぶん慎重になります。

□ 段階的リリース(数%から始めて、問題が無ければ拡大する)
□ **フィーチャーフラグ**(CI/CD)— アプリを更新せずに機能を止められる
□ クラッシュ収集を必ず入れる(Crashlytics 等)
□ リリース後の数値を見る(クラッシュ率、起動時間、離脱)
フィーチャーフラグは Web 以上に重要

Web なら、問題があればすぐ切り戻せます(CI/CD)。

モバイルでは切り戻せません。審査からやり直しです。

だから、サーバー側から機能をオフにできる仕組みを持っておきます。

問題発覚 → サーバーの設定を変更 → 全ユーザーで機能が無効になる(数分)

これが無いと、「審査を通すまでの数日間、障害が続く」ことになります。

端末と OS の多様性

□ 画面サイズ・解像度・ノッチ・折りたたみ
□ OS のバージョン(サポート範囲をチームで決める)
□ 端末の性能差(低スペック端末で動くか)
□ 地域・言語・文字サイズ設定(アクセシビリティ)

実機で確認するしかありません。シミュレータだけでは分からない差があります。

API を作る側が知っておくべきこと

モバイル担当でなくても、サーバー側の設計が変わります。

□ 後方互換性は必須(古いバージョンが動き続ける)
□ 冪等性は必須(電波状況で再送が起きる)
□ 通信回数を減らす設計(1画面に必要なデータをまとめて返す)
□ ペイロードを小さく(モバイル回線と電池を消費する)
□ バージョン情報を受け取り、最低要件を返せるようにする
□ 「どのバージョンが、どれだけ使われているか」を計測する
モバイルでは「N+1 の往復」が特に痛い

サーバー間の RPC が 1ms でも、モバイル回線では1往復に数百ミリ秒かかります。

1画面を表示するのに API を10回呼ぶ
→ Wi-Fi では気にならない
→ 4G の電波が弱い場所では、数秒〜十数秒

画面単位で必要なデータをまとめて返す設計(BFF など)が 検討されるのは、この理由が大きいです(API を設計する・性能と負荷対策)。

モバイルアプリを持つサービスの API から、使われていないフィールドを削除したいと考えています。

実務の落とし穴まとめ

  1. 強制アップデートの仕組みを入れずにリリース — 後から追加できない
  2. API のフィールドを削除・型変更 — 古いアプリが壊れる
  3. 冪等性が無い — 電波状況による再送で二重登録
  4. アプリ破棄を考慮しない — 入力が消える
  5. オフラインを考えない — 圏外で何もできなくなる
  6. 端末に秘密情報を埋め込む — 解析すれば取り出せる
  7. 権限を拒否された場合の画面が無い — 詰む
  8. 通知に依存する — 届かない前提で設計する
  9. 端末の「購入しました」を信じる — サーバーで検証する
  10. フィーチャーフラグが無い — 問題が起きても審査待ちになる
  11. API の往復が多い — モバイル回線では体感が桁違いに悪い

まとめ

  • モバイルの本質は配ったものを取り消せないこと。 だから複数バージョンが同時に動き続ける
  • API の後方互換性と冪等性は必須。Web の常識が通用しない
  • 強制アップデートの仕組みは初回リリースに含める
  • アプリはOS に破棄される。状態の保存と復元を前提にする
  • ネットワークは繋がらないもの。オフラインと再送を設計する
  • 端末に置いたものは解析される。判定はサーバー側で
  • 権限も通知も拒否・不達が前提
  • フィーチャーフラグが Web 以上に重要。切り戻せないから
  • API を作る側も、この前提を知っている必要がある

公式ドキュメント

迷ったら一次情報に戻ってください。

対象リンク
Apple Developer Documentationhttps://developer.apple.com/documentation/
Android Developers(日本語)https://developer.android.com/?hl=ja
App Store Review ガイドライン(日本語)https://developer.apple.com/jp/app-store/review/guidelines/
Google Play デベロッパー ポリシーhttps://play.google.com/about/developer-content-policy/
Flutterhttps://docs.flutter.dev/

章末問題

モバイルアプリから注文を送信する API を設計します。Web 版と比べて、特に重要になるのはどれですか。

第4部はここまでです。次の第5部では、 これらのクライアントが呼ぶサーバー側を作っていきます。

読み終わったら記録しておくと、目次で進み具合が分かります。