iOSウィジェットから認証済みAPIリクエストを送信する方法
iOSのウィジェット・エクステンションからアプリケーション本体でKeychainに保存したAPIトークンを読み出し、認証ありのAPIリクエストを送信する方法についてまとめてみました。
異なるアプリケーションの間でKeychainを共有するKeychain Sharing
iOSウィジェットで認証ありのAPIリクエストをしたいのですが、ウィジェットではログイン処理などのUIを実装できません。ログイン処理はアプリケーション本体で行い、何らかの方法でセッション・トークンなどの認証情報をウィジェットにシェアすることになります。今回はKeychainを使ってみました。
iOSではアプリケーション本体とウィジェット・エクステンションは別アプリのような扱いになっていて、そのままではウィジェットからアプリケーションが管理するKeychainにアクセスすることができません。Keychain Sharingを使ってアプリからKeychainを「共有」する必要があります。
Keychain Sharingについてはこちらの記事を参考にしています。
アプリケーション本体のKeychain Sharingを有効化
Capabilitiesの設定
Xcodeでプロジェクトを選択したあとでアプリケーション本体のターゲットを選択、「Capabilities」のタブで「Keychain Sharing」を追加します。
Keychain Groupの欄には今回シェアするKeychainのグループ名を追加します。「WidgetSharingGroup」とします。
Entitlementsの設定
Entitlementsを開きKeychain Access Groupのキーを追加、値は「$(AppIdentifierPrefix)WidgetSharingGroup」にします。先程Capabilitiesで設定したグループ名の先頭にアプリケーションIDを差し込んだ文字列になります。
Keychain Access Groupは必ずApplication ID(Team ID)を含むようになっていて、これによってKeychainの公開範囲を同一の配布元のアプリケーションに限定します。
ウィジェット・エクステンションでKeychain Sharingを有効化
Widget側でもKeychain Sharingを有効にする必要があります。XcodeのターゲットでWidget Extensionを選択して、アプリケーション本体と同様にKeychain Sharingの設定をしていきます。Keychainのグループ名はアプリケーション本体と同じになります。
ウィジェットのコードから共有されたKeychainにアクセス
KeychainAccessを導入
ウィジェットからKeychainにアクセスするために、CocoaPodsの KeychainAccessを導入しました。
ウィジェットにCocoaPodsのパッケージを導入するためにPodfileに記述を追加します。
target 'WidgetExtension' do
use_frameworks!
pod 'KeychainAccess', '~> 4.2'
end
getTimeline()でKeychainにアクセス
ウィジェットのコンテンツはgetTimeline()で生成します。ここでKeychainAccessを使います。引数「accessGroup」でアプリケーション本体から共有されたKeychainグループを指定します。
struct SessionToken: Codable {
var sessionToken: String
var expiredAt: Int
var refreshToken: String
}
func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
(...途中省略...)
let keychain = Keychain(service: "app", accessGroup: "(Entitilementsに追加した、AppIDを含むグループ名)")
let result = try! keychain.getData("(取得したいデータのキー)")
guard let sessionTokenJSON = result else { return }
let decoder = JSONDecoder()
let sessionToken = try? decoder.decode(SessionToken.self, from: sessionTokenJSON)
}
まとめ
ウィジェットのタイムライン生成時にKeychainからセッション・トークンを取り出すことができるようになりました。このトークンを使ってAPIサーバにアクセスして表示データを所得できます。
ログイン画面を実装できないiOSウィジェットで認証付きのAPIリクエストができるようになりました。この記事ではセッション・トークンのリフレッシュなどの処理は省いて記述していますが、ウィジェット内でセッション・トークンを更新した場合は、新しいトークン本体アプリケーションのKeyChainに書き戻す処理などが必要になると思います。
はじめてこのブログを読んだ方へ: U-motionとは?
U-motionは牛の首につけたセンサーを使って活動内容を記録、AIの力で健康状態を解析して畜産農家さんをサポートするモニタリング・システムです。
U-motion開発部は、
- センサーから集めたデータを処理するバックエンド・システム
- データをグラフ化するReactベースのウェブ・アプリケーション
- 牛の健康状態の変化をプッシュ通知のアラートでお知らせするReact Nativeベースのスマホ・アプリケーション
などを開発中。こちらのアカウントでは、開発時に得た知見を公開しています。
Discussion