WWDC Quick Look 💓 By SwiftGGTeam
Build light and fast App Clips

Build light and fast App Clips

元の動画を見る

ハイライト

iOS 15 では App Clip のより厳しいサイズ制限と、より豊富な発見シーンが提供されます。開発者は体系的なサイズ最適化、正しいメタデータ設定、位置検証 API により、App Clip Code のスキャンや Web ページ訪問時にユーザーが即座に軽量体験を得られるようにする必要があります。

主要内容

サイズ制限はハードな門番

App Clip の中核価値は「即座に使える」ことです。ユーザーが QR コードをスキャンするか NFC タグにタップし、数秒で機能画面に入る必要があります。その約束の裏には、モバイル回線でも素早くダウンロードできるほど小さくなければならないという硬性制約があります。

Apple は App Clip のサイズに明確な制限を設けています。開発中に繰り返し検証し、提出審査時に初めて超過に気づかないようにしてください。Xcode はサイズレポートを生成でき、デバイス変体ごとの IPA をエクスポートして非圧縮サイズを確認できます。

Fruta サンプルから見る最適化の道筋

講演者は意図的に肥大化させた Fruta サンプルで、よくある「罠」を示す完全な最適化フローをデモしました。

サイズレポート生成後、すべてのデバイス変体のサイズがほぼ同じでした。これは app thinning が効いていないことを意味し、リソースが非最適な形でパッケージされている可能性があります。

IPA を展開すると次の問題が見つかりました。

  • 画像が Asset Catalog ではなく独立 bundle リソースとして存在
  • ドキュメント zip と README ファイルが含まれる
  • 不要なフレームワークがリンクされている
  • ローカライズフォルダに冗長なコンテンツがある可能性

基本的な最適化ステップ

ビルド最適化設定の確認

Archive ビルドが Release 構成で、最適化レベルがデフォルトの「最小サイズ、最速」になっていることを確認してください。

Asset Catalog の使用

Asset Catalog には 2 つの利点があります。

  1. Xcode がビルド時にメディアを自動最適化
  2. App Thinning をサポートし、ユーザーは自分のデバイス向けリソースだけをダウンロード

App と App Clip で共有する画像は共有 Asset Catalog に、App 専用画像は別 Catalog に入れ、App Clip ターゲットから除外します。

不要ファイルの整理

Target Membership エディタで README、ドキュメント zip など配布物に含まれるべきでないファイルを除外します。

コードの削減

Build Phases のソースファイル一覧を確認し、App Clip に不要な機能モジュールを削除します。Fruta サンプルでは recipe と rewards はフル App 向けで、Clip ターゲットから外せます。

ローカライズ文字列の管理

フル App のすべてのローカライズを含めず、App Clip 専用の文字列ファイルを作成します。

高度な最適化戦略

外部依存の評価

App Clip は必要なフレームワークだけをリンクすべきです。システム組み込みフレームワークを優先してください。

  • カスタムログインの代わりに Sign in with Apple
  • 自作決済の代わりに Apple Pay
  • ネットワークは NSURLSession
  • 3D グラフィックスは RealityKit / Metal

画像フォーマットの選択

  • 透明度や高周波ディテール(シャープなエッジ)が必要: PNG
  • 非写真素材: PNG8 を試し、大幅なサイズ削減
  • 写真素材: JPEG、適切な圧縮比
  • アイコンと UI コントロール: SVG または SF Symbols

SF Symbols は 2000 以上の設定可能なシンボル、複数のウェイトとサイズ、テキストラベルとの自動整列、Dynamic Type のネイティブサポートを提供します。

// [14:18](https://developer.apple.com/videos/play/wwdc2021/10013/?time=858)
label.text = "Hello"

let textStyle = UIFont.TextStyle.largeTitle

label.font = .preferredFont(forTextStyle: textStyle)
let config = UIImage.SymbolConfiguration(textStyle: textStyle)

imageView.image = UIImage(systemName: "pencil.and.outline", withConfiguration: config)

// Align baseline of text and symbol image
imageView.firstBaselineAnchor.constraint(equalTo: label.firstBaselineAnchor).isActive = true

キーポイント:

  • UIFont.TextStyle.largeTitle をラベルフォントとシンボル設定の両方に使用
  • UIImage.SymbolConfiguration(textStyle:) でシンボルとテキストを同じサイズ体系に
  • firstBaselineAnchor 制約でシンボルとテキストのベースラインを揃える

実行時にバリアントを構築

同じ素材の複数の表示形式ごとに複数画像を用意しない。基本画像 1 枚を実行時にコードでバリアントを構築します。

遅延読み込み

最適化後も超過する場合、CDN から一部リソースを遅延読み込みします。App Clip には低解像度プレースホルダーを同梱し、起動後 AsyncImage で高解像度に置き換えます。

App Clip が正しく表示されるようにする

メタデータ設定

App Store Connect では各 App Clip に Default Experience(Safari と Messages 用)が必要です。QR、NFC、App Clip Code など物理的な呼び出しには Advanced Experience も追加します。

設定変更はデバイスへの反映に時間がかかり、即座には効きません。

Web Meta Tag

Web ページの <head> に正しい meta タグを追加しないと App Clip カードは表示されません。

<!-- [18:08](https://developer.apple.com/videos/play/wwdc2021/10013/?time=1088) -->
<meta name="apple-itunes-app" content="app-id=myAppStoreID, app-clip-bundle-id=appClipBundleID, app-clip-display=card">

キーポイント:

  • app-id: App Store ID
  • app-clip-bundle-id: App Clip の bundle ID
  • app-clip-display=card: カード形式で表示

ユニバーサルリンク関連の検証

呼び出しドメインは Associated Domains entitlements と AASA ファイルで App / App Clip と安全に関連付ける必要があります。設定ミスは App Clip 表示不可の原因になります。

よくある問題のトラブルシュート

Safari で App Clip カードが見えない場合:

  1. meta タグの構文を確認
  2. app-clip-bundle-id が正しいか確認
  3. Web URL と App Clip 体験の関連設定を検証
  4. entitlements の Associated Domains を確認
  5. AASA ファイルがアクセス可能で形式が正しいか確認

App Clip 専用機能

位置検証

App Clip は APActivationPayload でユーザーが特定の地理的領域にいるか検証でき、来店シーン向けの App に適しています。

// [27:41](https://developer.apple.com/videos/play/wwdc2021/10013/?time=1661)
if let activationPayload = userActivity?.appClipActivationPayload {
  activationPayload.confirmAcquired(in: region) { inRegion, error in
    if let error = error as? APActivationPayloadError {
      if error.code == APActivationPayloadError.disallowed {
        // User denied permission
        // Or invocation was not from visual code or NFC
      } else if error.code == APActivationPayloadError.doesNotMatch {
        // Activation payload is not the most recent
        // Catch in testing. Handle as above.
      }
    } else if error == nil {
      // Platform was able to determine location
      // OK to check inRegion
    }
  }
}

キーポイント:

  • confirmAcquired(in:) はビジュアルコードまたは NFC で指定領域内から起動したか検証
  • disallowed はユーザーが許可を拒否したか、呼び出し方法が要件を満たさない
  • doesNotMatch はアクティベーションペイロードが期限切れ。テストで捕捉
  • 成功時は inRegion でユーザーが領域内か確認

テストの推奨

  • Network Link Conditioner で異なる帯域をテスト
  • 低速回線でも合理的な時間でタスク完了できるか検証
  • 位置検証の境界ケースをテスト

詳細

サイズレポート生成の完全フロー

  1. フル App スキームを選択
  2. Product > Archive
  3. Organizer で Distribute App をクリック
  4. Development を選択
  5. App Clip ターゲットを選択
  6. App Thinning ドロップダウンで All compatible device variants
  7. Rebuild from bitcode にチェック
  8. エクスポート後 App Thinning Size Report.txt を開く
  9. デバイス変体ごとの非圧縮サイズを確認

IPA 内容の確認

# .ipa を .zip にリネームして展開
mv AppClip.ipa AppClip.zip
unzip AppClip.zip

# Payload の内容を表示
cd Payload/AppClip.app
ls -la

注目すべき内容:

  • .bundle 内の独立画像リソース
  • 不要なドキュメントファイル
  • 未使用フレームワーク
  • 過大なローカライズフォルダ
  • 実行ファイルサイズ

Asset Catalog 分離戦略

SharedAssets.xcassets    # App と Clip で共有
AppOnlyAssets.xcassets   # App のみ

Target Membership で AppOnlyAssets.xcassets を App Clip から除外します。

画像最適化チェックリスト

シーン推奨フォーマット備考
透明度が必要PNG可逆圧縮
非写真、色数が少ないPNG8大幅なサイズ削減
写真、可逆圧縮不要JPEG圧縮比を調整
アイコン、コントロールSVG / SF Symbolsベクター、任意サイズ

重要ポイント

1. オフラインシーン向けの即時体験を設計する

  • 何をするか: レストラン、小売、駐車場などで App Clip を作り、スキャンで注文・支払い・車の受け取り
  • なぜ価値があるか: App Clip はフル App ダウンロードの摩擦を除去し、従来方式よりコンバージョンが高い
  • どう始めるか: Xcode で App Clip ターゲットを追加し、Associated Domains を設定し、コアタスクフローを実装

2. カスタムアイコンを SF Symbols に置き換える

  • 何をするか: 界面のカスタムアイコンをすべて SF Symbols に
  • なぜ価値があるか: システム組み込みで App Clip サイズを増やさず、Dynamic Type とダークモードを自動サポート
  • どう始めるか: SF Symbols app でシンボルを選び、UIImage(systemName:) で読み込む

3. 位置ベースの検証を実装する

  • 何をするか: 来店サービスに地理的位置検証を追加し、ユーザーが店舗近くにいることを確認
  • なぜ価値があるか: リモート悪用を防ぎ、店舗に信頼できる来店データを提供
  • どう始めるか: APActivationPayload.confirmAcquired(in:)CLRegion を渡す

4. 段階的リソース読み込みを構築する

  • 何をするか: App Clip には低品質プレースホルダーを同梱し、起動後 CDN から高解像度版を読み込む
  • なぜ価値があるか: サイズ制限を突破しつつ最終体験の品質を維持
  • どう始めるか: SwiftUI の AsyncImage または UIKit の非同期画像読み込み

5. サイズ監視フローを CI に組み込む

  • 何をするか: CI に App Clip サイズチェックを追加し、コミットごとに自動検証
  • なぜ価値があるか: リリース直前のサイズ超過を防ぎ、緊急最適化のリスクを減らす
  • どう始めるか: xcodebuild archive を呼ぶスクリプトで Size Report を解析し、閾値アラートを設定

関連セッション

コメント

GitHub Issues · utterances