Help us understand the problem. What is going on with this article?

App Clips を試してみる

この記事はフラー Advent Calendar 2020 の 20日目の記事です。
19日目は@nobux42さんで「Next.jsとShopifyで最速でECサイトをつくる」でした。

App Clips とは

App Clips は WWDC 2020 で発表はされた iOS 14 の新機能です。
まだ中々町中では見かけることは無いので、実際の挙動を確認すべく試した内容を記事としてまとめます。

作成方法

Xcode で適当なプロジェクトを作成し、file -> new -> Target... から App Clips を選んで Target に追加します。
スクリーンショット 2020-12-17 5.08.26.png

いくつかのファイルがつくられますが、ContentView.swift の中身を書き換えて実行してみます。

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Welcome to App Clip")
            .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

実行結果

App Clip の起動自体できましたが、肝心のカードが表示されません。

App Clip Card の設定は App Store Connect 上で行うものなので、App Clip 開発時に設定するようなものではありません。
しかし、カードを確認する方法はちゃんと用意されており、今回は App Clips のテスト機能である Local Experiences を使ってカードを表示させてみます。

Local Experiences の設定

iPhone の設定を開いて Developer -> Local Experiences -> Register Local Experiences... と進むと、URL, Bundle ID と App Clip Card の内容を設定する画面へ遷移するので、適当な URL と設定した Bundle ID を入力し、カード情報を好きに設定します。

これで保存し、端末に先程の App Clips をインストール (Run すればよい) して準備完了です。
Local Experience で設定した URL を QRコードか NFCタグで読み取ればカードを表示できるようになります。

$ brew install qrencode
$ qrencode -o - https://example.com | open -f -a preview

動作確認

output.gif

コントロールセンターの QRコードリーダ (標準のカメラアプリでは開けない) で、Local Experience で設定した URL を読み取って、先程作成した App Clip が起動できているのが分かります。
この方法は Associated Domain の設定や apple-app-site-association file の配置なども不要なので、カードを見てみたいだけならオススメです。

起動URLを取得

App Clip Card の確認はできましたが、開発には起動時の環境変数を指定することで、特定のURLから起動したときの動作を検証することができます。
App Clip では Invocation URL のパラメータを見て処理を分岐させることが可能なので、開発時には使うことが多そうな機能です。
App Clip Target の Edit Schema -> Run -> Arguments を選択し、Environment Variables にテストしたい URL を入力します。

スクリーンショット 2020-12-18 11.43.15.png

上記のように設定した上で、AppClipSampleClip.swift で起動URLを取得する処理を実装します。

AppClipSampleClipApp.swift
@main
struct AppClipSampleClipApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { userActivity in
                    guard let incomingURL = userActivity.webpageURL,
                          let components = NSURLComponents(url: incomingURL,
                              resolvingAgainstBaseURL: true) else {
                        return
                    }

                    print(components.debugDescription)
                }
        }
    }
}

出力結果

<NSURLComponents 0x6000016ec3b0> {
  scheme = https,
  user = (null),
  password = (null),
  host = example.com,
  port = (null),
  path = /menu,
  query = parameter1=foo&parameter2=bar,
  fragment = (null)
}

起動URLが取得できていることが確認できました。

データ共有

App Clip と本体アプリ間でのデータの共有の受け渡しを実装してみます。
折角なので先程取得した起動時のパラメータを本体アプリに渡してみましょう。

まず、App Groups を設定します。

(Automatically managed signing を利用しています)
Targets で AppClipSample を選び、Signing & Capabilities を選択し、+ Capability から App Groups を選択します。
Signing & Capabilities の箇所に App Groups というセクションができているので、+ を押して Group を作成します。
同じ手順で、AppClipSampleClip にも同じ Group を指定します。

同じ Group に設定すると、Shared User Defaults でデータの共有ができるようになるので、それを使います。

AppClipSampleClipApp.swift
@main
struct AppClipSampleClipApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { userActivity in
                    guard let incomingURL = userActivity.webpageURL,
                          let components = NSURLComponents(url: incomingURL,
                              resolvingAgainstBaseURL: true) else {
                        return
                    }
                    guard let sharedUserDefaults = UserDefaults(suiteName: "group.example.appClipMigration") else {
                        return
                    }
                    sharedUserDefaults.set(components.path, forKey: "path")
                    sharedUserDefaults.set(components.query, forKey: "query")
                }
        }
    }
}
AppClipSample/ContentView.swift
struct ContentView: View {
    var body: some View {
        let sharedUserDefaults = UserDefaults(suiteName: "group.example.appClipMigration")
        let path = sharedUserDefaults?.string(forKey: "path") ?? "faild"
        let query = sharedUserDefaults?.string(forKey: "query") ?? "faild"

        return VStack {
            Text("Full Application")
            Text("path: \(path)")
            Text("query: \(query)")
        }
    }
}

UserDefaultsinit(suiteName:) に先程設定した Group名を指定して、保存します。
それを、本体アプリの ContentView で取り出して表示させます。

これで、AppClip を起動したあとに、本体アプリを起動すると、無事にデータを送れたことが確認できます。

App Clip の操作した内容を保存しておいて、ユーザが本体アプリをインストールした場合に利用できるのは、様々な用途で使いそうですね。

ただし、下記のように App Clip からは Keychain にはアクセスできないため、App Clip 側でログインした際の認証情報などを本体アプリに引き継ぐことはできないようです。

To preserve user privacy across apps and App Clips, an App Clip can only share its data with its corresponding app. In addition, you can’t make information the App Clip stores in the keychain accessible to its corresponding full app.

終わりに

簡単にですが、App Clip を試した内容をまとめました。
App Clip はアプリをインストールすること無く、体験を提供することができるので、現実のサービスと連携するようなアプリとかでは特に相性が良いと感じました。
他にも色々な機能があるので、今後も試して紹介していければいいなと思っています。

参考

https://developer.apple.com/documentation/app_clips/testing_your_app_clip_s_launch_experience
https://developer.apple.com/documentation/app_clips/making_data_available_to_the_app_clip_s_corresponding_app

jfurudo
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away