Wear OS アプリはコンパニオン アプリがなくてもスタンドアロンで動作できます。つまり、Wear OS アプリは、インターネットからデータにアクセスする際、独自に認証を管理する必要があります。しかし、スマートウォッチは画面サイズが小さく、入力機能が限定されているため、Wear OS アプリで使用できる認証オプションは限られています。
このガイドでは、Wear OS アプリで推奨される認証方法である Credential Manager の手順について説明します。
優れたログイン エクスペリエンスを設計する方法について詳しくは、ログイン UX ガイドをご覧ください。
予備的な考慮事項
実装を開始する前に、次の点を考慮してください。
ゲストモード
すべての機能で認証を求めるのではなく、ログインを必要としない機能をできるだけ多くユーザーに提供してください。
モバイルアプリを使用したことがないユーザーが Wear アプリを見つけてインストールする場合があります。そうしたユーザーはアカウントを持っていないことや、アカウントで提供される機能を知らないことがあります。ゲストモード機能によってアプリの機能が正確に紹介されることを確認してください。
一部のデバイスではロックが解除された状態が長く続くことがあります
Wear OS 5 以降を搭載するサポート対象デバイスでは、ユーザーがデバイスを手首に装着しているかどうかが検出されます。ユーザーが手首検出をオフにしてデバイスを手首から外すと、システムはデバイスのロックを通常よりも長い時間解除したままにします。
アプリでより高いレベルのセキュリティが必要な場合(機密情報や個人情報が表示される可能性がある場合など)は、まず手首検出が有効になっているかどうかを確認します。
val wristDetectionEnabled =
isWristDetectionAutoLockingEnabled(applicationContext)
このメソッドの戻り値が false
の場合は、ユーザー固有のコンテンツを表示する前に、アプリのアカウントにログインするようユーザーに促します。
認証情報マネージャー
Wear OS での認証には、認証情報マネージャー API を使用することをおすすめします。これにより、ペア設定されたスマートフォンを接続したり、パスワードを記憶したりすることなく、スタンドアロン設定で Wear OS アプリケーションにログインするための、より安全な環境が提供されます。
このドキュメントでは、デベロッパーが Credential Manager ソリューションを実装するために必要な情報について説明します。このソリューションは、次の標準認証メカニズムをホストします。
- パスキー
- パスワード
- フェデレーション ID(Google でログインなど)
このガイドでは、認証情報マネージャーのバックアップとして、他の許容される Wear OS 認証方法(データレイヤ トークン共有と OAuth)を移行する方法についても説明します。また、現在非推奨となっているスタンドアロンの「Google でログイン」ボタンから、埋め込み型の認証情報マネージャー バージョンへの移行を処理するための特別な手順についても説明します。
Wear OS のパスキー
デベロッパーは、Wear OS Credential Manager の実装でパスキーを実装することが強く推奨されます。パスキーはエンドユーザー認証の新しい業界標準であり、ユーザーにとっていくつかの大きなメリットがあります。
パスキーは簡単
- ユーザーはログインに使用するアカウントを選択できます。ユーザー名を入力する必要はありません。
- ユーザーはデバイスの画面ロックを使用して認証できます。
- パスキーを作成して登録すると、ユーザーは新しいデバイスにシームレスに切り替えて、再登録することなくすぐに使用できます。
パスキーは安全性が高い
- デベロッパーはパスワードを保存する代わりに公開鍵のみをサーバーに保存するため、悪意のあるユーザーがサーバーに侵入する価値が大幅に減り、侵害が発生した場合のクリーンアップも大幅に減ります。
- パスキーは、フィッシング対策に有効な保護機能です。パスキーは登録したウェブサイトやアプリでのみ機能します。ブラウザや OS が検証を行うため、ユーザーが偽のサイトで認証を行うように騙されることはありません。
- パスキーを使用すると SMS を送信する必要がなくなるため、認証の費用対効果が高まります。
パスキーを実装する
すべての実装タイプのセットアップとガイダンスが含まれています。
設定
アプリケーション モジュールの build.gradle ファイルで、ターゲット API レベルを 35 に設定します。
android { defaultConfig { targetSdkVersion(35) } }
androidx.credentials
リリースの最新の安定版を使用して、アプリまたはモジュールの build.gradle ファイルに次の行を追加します。androidx.credentials:credentials:1.5.0 androidx.credentials:credentials-play-services-auth:1.5.0
組み込み認証方法
Credential Manager は統合 API であるため、Wear OS の実装手順は他のデバイスタイプと同じです。
モバイル向けの手順に沿って、パスキーとパスワードのサポートを実装します。
認証情報マネージャーに「Google でログイン」のサポートを追加する手順はモバイル開発を対象としていますが、Wear OS でも同じ手順です。このケースに関する特別な考慮事項については、以前の Google でログインからの移行のセクションをご覧ください。
Wear OS では認証情報を作成できないため、モバイルの手順で説明されている認証情報作成メソッドを実装する必要はありません。
バックアップ認証方法
Wear OS アプリで許容される認証方法は、OAuth 2.0(いずれかのバリエーション)とモバイル認証トークン データレイヤ共有の 2 つです。これらのメソッドは Credential Manager API に統合ポイントはありませんが、ユーザーが Credential Manager 画面を閉じるときにフォールバックとして Credential Manager の UX フローに含めることができます。
認証情報マネージャー画面を閉じるユーザー アクションを処理するには、GetCredential
ロジックの一部として NoCredentialException
をキャッチし、独自のカスタム認証 UI に移動します。
yourCoroutineScope.launch {
try {
val response = credentialManager.getCredential(activity, request)
signInWithCredential(response.credential)
} catch (e: GetCredentialCancellationException) {
navigateToFallbackAuthMethods()
}
}
カスタム認証 UI は、ログイン UX ガイドで説明されている他の許容可能な認証方法を提供できます。
データレイヤートークンの共有
スマートフォンのコンパニオン アプリは、ウェアラブル データレイヤ API を使用して認証データを Wear OS アプリに安全に転送できます。認証情報をメッセージまたはデータ項目として転送します。
この種の認証では通常、ユーザーによる操作は必要ありません。ただし、ログイン中であることをユーザーに通知せずに認証を行うことは避けてください。閉じることができる画面を使用して、アカウントがモバイルから移行されることをユーザーに通知できます。
重要: このオプションは、対応するモバイルアプリがインストールされている場合に、Android とペア設定されたスマートウォッチでしか機能しないため、Wear OS アプリは他の認証方法を少なくとも 1 つ提供する必要があります。対応するモバイルアプリを持っていないユーザーや、Wear OS デバイスが iOS デバイスとペア設定されているユーザー向けに、代替の認証方法を提供してください。
次の例に示すように、モバイルアプリからデータレイヤを使用してトークンを渡します。
val token = "..." // Auth token to transmit to the Wear OS device.
val dataClient: DataClient = Wearable.getDataClient(context)
val putDataReq: PutDataRequest = PutDataMapRequest.create("/auth").run {
dataMap.putString("token", token)
asPutDataRequest()
}
val putDataTask: Task<DataItem> = dataClient.putDataItem(putDataReq)
次の例に示すように、Wear OS アプリのデータ変更イベントをリッスンします。
val dataClient: DataClient = Wearable.getDataClient(context)
dataClient.addListener{ dataEvents ->
dataEvents.forEach { event ->
if (event.type == DataEvent.TYPE_CHANGED) {
val dataItemPath = event.dataItem.uri.path ?: ""
if (dataItemPath.startsWith("/auth")) {
val token = DataMapItem.fromDataItem(event.dataItem).dataMap.getString("token")
// Display an interstitial screen to notify the user that
// they're being signed in.
// Then, store the token and use it in network requests.
}
}
}
}
ウェアラブル データレイヤの使用方法について詳しくは、Wear OS でのデータの送信と同期をご覧ください。
OAuth 2.0 を使用する
Wear OS は 2 つの OAuth 2.0 ベースのフローをサポートしています。これらについては、この後のセクションで説明します。
- RFC 7636 で定義されている、Proof Key for Code Exchange(PKCE)による Authorization Code Grant
- RFC 8628 で定義されている Device Authorization Grant(DAG)
Proof Key for Code Exchange(PKCE)
PKCE を効果的に使用するには、RemoteAuthClient
を使用します。次に、Wear OS アプリから OAuth プロバイダに認証リクエストを行うには、OAuthRequest
オブジェクトを作成します。このオブジェクトは、トークンを取得するための OAuth エンドポイントへの URL と CodeChallenge
オブジェクトで構成されます。
次のコードは、認証リクエストの作成例を示しています。
val request = OAuthRequest.Builder(this.applicationContext)
.setAuthProviderUrl(Uri.parse("https://...."))
.setClientId(clientId)
.setCodeChallenge(codeChallenge)
.build()
認証リクエストを作成したら、sendAuthorizationRequest()
メソッドを使用してコンパニオン アプリに送信します。
val client = RemoteAuthClient.create(this)
client.sendAuthorizationRequest(request,
{ command -> command?.run() },
object : RemoteAuthClient.Callback() {
override fun onAuthorizationResponse(
request: OAuthRequest,
response: OAuthResponse
) {
// Extract the token from the response, store it, and use it in
// network requests.
}
override fun onAuthorizationError(errorCode: Int) {
// Handle any errors.
}
}
)
このリクエストによってコンパニオン アプリの呼び出しがトリガーされ、ユーザーのスマートフォンのウェブブラウザに認証 UI が表示されます。OAuth 2.0 プロバイダがユーザーを認証し、リクエストされた権限についてユーザーの同意を得ます。レスポンスは、自動生成されたリダイレクト URL に送信されます。
認証が成功または失敗した後、OAuth 2.0 サーバーは、リクエストで指定された URL にリダイレクトします。ユーザーがアクセス リクエストを承認すると、レスポンスに認証コードが格納されます。ユーザーがリクエストを承認しないと、レスポンスにエラー メッセージが格納されます。
レスポンスはクエリ文字列の形式を取り、次の例のようになります。
https://wear.googleapis.com/3p_auth/com.your.package.name?code=xyz
https://wear.googleapis-cn.com/3p_auth/com.your.package.name?code=xyz
これにより、ユーザーをコンパニオン アプリに誘導するページが読み込まれます。コンパニオン アプリはレスポンス URL を検証し、onAuthorizationResponse
API を使用して Wear OS アプリにレスポンスを中継します。
スマートウォッチ アプリは、認証コードをアクセス トークンと交換できます。
Device Authorization Grant
Device Authorization Grant を使用する場合、ユーザーは別のデバイスで検証 URI を開きます。次に、認証サーバーはリクエストを承認または拒否するよう求めます。
このプロセスを簡素化するには、次の例に示すように、RemoteActivityHelper
を使用して、ユーザーのペア設定されたモバイル デバイスでウェブページを開きます。
// Request access from the authorization server and receive Device Authorization
// Response.
val verificationUri = "..." // Extracted from the Device Authorization Response.
RemoteActivityHelper.startRemoteActivity(
this,
Intent(Intent.ACTION_VIEW)
.addCategory(Intent.CATEGORY_BROWSABLE)
.setData(Uri.parse(verificationUri)),
null
)
// Poll the authorization server to find out if the user completed the user
// authorization step on their mobile device.
iOS アプリの場合は、トークンの認証にブラウザを使用するのではなく、ユニバーサル リンクを使用して、アプリでこのインテントをインターセプトします。
以前の「Google でログイン」からの移行
認証情報マネージャーには、「Google でログイン」ボタン専用の統合ポイントがあります。以前は、このボタンはアプリの認証 UX の任意の場所に追加できましたが、Credential Manager に含まれるようになったため、以前のオプションは非推奨になりました。
// Define a basic SDK check.
fun isCredentialManagerAvailable(): Boolean {
return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM
}
// Elsewhere in the code, use it to selectively disable the legacy option.
Button(
onClick = {
if (isCredentialManagerAvailable()) {
Log.w(TAG, "Devices on API level 35 or higher should use
Credential Manager for Sign in with Google")
} else {
navigateToSignInWithGoogle()
}},
enabled = !isCredentialManagerAvailable(),
label = { Text(text = stringResource(R.string.sign_in_with_google)) },
secondaryLabel = { Text(text = "Disabled on API level 35+")
}
)