Questa guida descrive come richiedere credenziali digitali utilizzando Gestore delle credenziali in un'app per Android che utilizza WebView. Utilizza un bridge JavaScript per facilitare la comunicazione tra la pagina web e l'app.
Panoramica
I seguenti passaggi descrivono il ciclo di vita di una richiesta di credenziali digitali da una WebView:
- Generazione della richiesta: la pagina web nella WebView invia una richiesta al server dell'app, che genera un JSON di richiesta OpenID4VP e lo restituisce.
- Avvio della richiesta: la pagina web utilizza
navigator.credentials.get({ digital: ...}) per richiedere le credenziali digitali utilizzando il file JSON della richiesta. - Intercettazione: l'
bridge.jsinserito intercetta questa chiamata, estrae il file JSON della richiesta OpenID4VP specifico e lo passa all'app per Android. - Gestione di Android: l'app per Android riceve il messaggio e chiama l'API
CredentialManager.getCredential. - Selezione dell'utente: Gestore delle credenziali mostra una UI che chiede all'utente di condividere la propria credenziale. La credenziale viene restituita all'app per Android.
- Risposta del bridge: l'app per Android invia la risposta alla pagina web utilizzando il bridge.
- Completamento: la pagina web riceve e gestisce la risposta.
Prerequisiti
Prima di implementare il bridge JavaScript per le credenziali digitali in WebView, assicurati che il tuo progetto soddisfi i seguenti requisiti:
- Compatibilità con le versioni di Android: la tua app deve avere come target Android 6.0 (livello API 23) o versioni successive.
- Controllo dell'app host: devi controllare l'app per Android che ospita
WebViewin modo da poter allegare unWebMessageListenerprima di caricare la pagina web. - HTTPS e frame di primo livello: la pagina web che richiede la credenziale deve essere pubblicata tramite
https://ed eseguita nel frame principale (isMainFramedeve esseretrue). I frame secondari e gli elementi<iframe>incorporati non sono supportati. - Attivazione dell'API sperimentale: poiché l'API Digital Credentials è sperimentale, devi annotare le classi o i metodi che utilizzano
GetDigitalCredentialOptioncon@OptIn(ExperimentalDigitalCredentialApi::class).
Aggiungi dipendenze
Aggiungi le dipendenze di Gestore delle credenziali e AndroidX WebKit al file build.gradle.kts del modulo dell'app:
dependencies {
// Credential Manager dependencies
implementation("androidx.credentials:credentials:1.7.0-alpha03")
implementation("androidx.credentials:credentials-play-services-auth:1.7.0-alpha03")
// AndroidX WebKit (required for WebMessageListener bridge)
implementation("androidx.webkit:webkit:1.14.0")
}
Implementa le credenziali digitali in WebView
Dovrai aggiungere JavaScript alla tua WebView per effettuare la richiesta di credenziali
e intercettarla con bridge.js.
Crea la richiesta JavaScript
Per comunicare tra JavaScript in esecuzione in una WebView e il codice Android, inserisci il codice JavaScript nella WebView:
// Example digital credential request to request verified email
const request = {
"providers": [
{
"protocol": "openid4vp",
"request": JSON.stringify({
"requests": [
{
"protocol": "openid4vp-v1-unsigned",
"data": {
"response_type": "vp_token",
"response_mode": "dc_api",
"nonce": "n-0S6_W_2F", // Generate dynamically
"dcql_query": {
"credentials": [
{
"id": "user_info_query",
"format": "dc+sd-jwt",
"meta": {
"vct_values": ["UserInfoCredential"]
},
"claims": [
{"path": ["email"]},
{"path": ["email_verified"]},
{"path": ["name"]}
]
}
]
}
}
}
]
})
}
]
};
try {
const credential = await navigator.credentials.get({
digital: request
});
// Process response
} catch (err) {
// Handle error
}
Crea il bridge JavaScript
Crea un file denominato bridge.js o inserisci questo codice utilizzando evaluateJavascript.
Questo script esegue l'override di navigator.credentials.get per intercettare la richiesta e inviare la stringa JSON OpenID4VP interna all'app per Android.
(function() {
if (!navigator.credentials) {
navigator.credentials = {};
}
const originalGet = navigator.credentials.get;
// Overrides navigator.credentials.get() to intercept W3C Digital Credential requests.
navigator.credentials.get = async function(options) {
if (options && options.digital) {
if (window.DigitalCredentialBridge) {
return new Promise((resolve, reject) => {
const digital = options.digital;
if (digital.providers && digital.providers.length > 0) {
const provider = digital.providers[0];
if (provider.protocol === "openid4vp") {
const requestJson = provider.request;
const message = {
type: "get",
request: requestJson
};
console.log("Sending message to native bridge:", JSON.stringify(message));
// Send the request string to native Android code
window.DigitalCredentialBridge.postMessage(JSON.stringify(message));
// Receive the response sent from native code using replyProxy.postMessage()
window.DigitalCredentialBridge.onmessage = function(event) {
console.log("Received response from native bridge:", event.data);
try {
const response = JSON.parse(event.data);
if (response.error) {
reject(new Error(response.error));
} else {
resolve(response);
}
} catch (e) {
// If it's not JSON, just resolve with the raw data
resolve(event.data);
}
};
} else {
reject(new Error("Unsupported protocol: " + provider.protocol));
}
} else {
reject(new Error("No providers specified in digital credential request"));
}
});
} else {
console.warn("DigitalCredentialBridge not found, falling back to original");
}
}
if (originalGet) {
return originalGet.call(navigator.credentials, options);
} else {
throw new Error("navigator.credentials.get is not supported and no bridge available");
}
};
})();
Implementa le credenziali digitali in Android
Configura la tua app per Android in modo che gestisca le richieste di credenziali inviate da bridge.js.
Crea il listener Android
Configura una classe DigitalCredentialWebListener che implementa
WebViewCompat.WebMessageListener. Questa classe gestisce i messaggi bidirezionali tra JavaScript e il codice Android nativo, applicando controlli di sicurezza su isMainFrame e sourceOrigin e impedendo richieste sovrapposte.
Implementa il gestore di Gestore delle credenziali
Chiama getCredential per richiedere le credenziali digitali dal dispositivo.
@OptIn(ExperimentalDigitalCredentialApi::class)
class CredentialManagerHandler(private val context: Context) {
private val credentialManager = CredentialManager.create(context)
suspend fun getDigitalCredential(requestJson: String): String {
val digitalCredentialOption = GetDigitalCredentialOption(requestJson)
val getCredRequest = GetCredentialRequest(listOf(digitalCredentialOption))
return try {
val result = credentialManager.getCredential(context, getCredRequest)
val credential = result.credential
if (credential is DigitalCredential) {
credential.credentialJson
} else {
"{\"error\": \"Unexpected credential type\"}"
}
} catch (e: GetCredentialException) {
"{\"error\": \"${e.message}\"}"
} catch (e: Exception) {
"{\"error\": \"Unknown exception\"}"
}
}
companion object {
private const val TAG = "CredManHandler"
}
}
Applica il framework alla tua attività
Nel tuo Activity o View, registra WebMessageListener e le funzioni associate.
// Inside your Activity or View setup
AndroidView(
factory = { context ->
val handler = CredentialManagerHandler(context)
WebView(context).apply {
settings.javaScriptEnabled = true
// Register the bridge before loading URL
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
val listener = DigitalCredentialWebListener(coroutineScope, credentialManagerHandler)
WebViewCompat.addWebMessageListener(
webView,
INTERFACE_NAME,
setOf("*"),
listener
)
loadUrl("https://your-secure-domain.com/login")
}
},
)
Test del flusso…
Testa il flusso per confermare la comunicazione tra WebView e l'app per Android. Il selettore delle credenziali viene visualizzato in WebView durante la procedura e la credenziale selezionata torna a WebView al termine.