Un servizio di compilazione automatica è un'app che semplifica la compilazione dei moduli da parte degli utenti inserendo dati nelle visualizzazioni di altre app. I servizi di compilazione automatica possono anche Recuperare i dati utente dalle viste di un'app e memorizzarli per utilizzarli in un secondo momento nel tempo. I servizi di compilazione automatica vengono solitamente forniti da app che gestiscono i dati utente, come i gestori delle password.
Android semplifica la compilazione dei moduli grazie al framework di compilazione automatica disponibile Android 8.0 (livello API 26) e versioni successive. Gli utenti possono sfruttare la compilazione automatica solo se esiste un'app che fornisce servizi di compilazione automatica sui dispositivo.
Questa pagina mostra come implementare un servizio di compilazione automatica nella tua app. Se stai cercando un esempio di codice che mostri come implementare un servizio, consulta l'esempio AutofillFramework in Java o Kotlin.
Per ulteriori dettagli sul funzionamento dei servizi di compilazione automatica, consulta le pagine di riferimento per le classi AutofillService
e AutofillManager
.
Dichiarazioni e autorizzazioni del manifest
Le app che forniscono servizi di compilazione automatica devono includere una dichiarazione che descriva
l'implementazione del servizio. Per specificare la dichiarazione, includi un
<service>
nel
manifest dell'app. La
L'elemento <service>
deve
includono i seguenti attributi ed elementi:
- Attributo
android:name
che punta alla sottoclasseAutofillService
nell'app che implementa il servizio. android:permission
attributo che dichiara l'autorizzazioneBIND_AUTOFILL_SERVICE
.- Elemento
<intent-filter>
il cui elemento secondario obbligatorio<action>
specifica l'azioneandroid.service.autofill.AutofillService
. - Facoltativo
<meta-data>
che puoi utilizzare per fornire parametri di configurazione aggiuntivi per il servizio.
L'esempio seguente mostra una dichiarazione del servizio di compilazione automatica:
<service
android:name=".MyAutofillService"
android:label="My Autofill Service"
android:permission="android.permission.BIND_AUTOFILL_SERVICE">
<intent-filter>
<action android:name="android.service.autofill.AutofillService" />
</intent-filter>
<meta-data
android:name="android.autofill"
android:resource="@xml/service_configuration" />
</service>
L'elemento <meta-data>
include un parametro
android:resource
che punta a una risorsa XML con ulteriori dettagli sul servizio.
La risorsa service_configuration
nell'esempio precedente specifica un
che consenta agli utenti di configurare il servizio. L'esempio riportato di seguito mostra la risorsa XML service_configuration
:
<autofill-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="com.example.android.SettingsActivity" />
Per ulteriori informazioni sulle risorse XML, vedi Panoramica delle risorse per app.
Richiesta di attivazione del servizio
Un'app viene utilizzata come servizio di compilazione automatica dopo aver dichiarato
Autorizzazione BIND_AUTOFILL_SERVICE
e l'utente la abilita nel dispositivo
impostazioni. Un'app può verificare se è il servizio attualmente attivo chiamando il metodo hasEnabledAutofillServices()
della classe AutofillManager
.
Se l'app non è il servizio di compilazione automatica corrente, può chiedere all'utente di modificare le impostazioni di compilazione automatica utilizzando l'intent ACTION_REQUEST_SET_AUTOFILL_SERVICE
. L'intent restituisce un valore RESULT_OK
se l'utente seleziona un servizio di compilazione automatica corrispondente al pacchetto del chiamante.
Compila le visualizzazioni dei clienti
Il servizio di compilazione automatica riceve richieste di compilazione delle visualizzazioni del client quando l'utente interagisce con altre app. Se il servizio di compilazione automatica dispone di dati utente che soddisfano la richiesta, li invia nella risposta. Il sistema Android mostra UI di compilazione automatica con i dati disponibili, come mostrato nella figura 1:
Il framework di compilazione automatica definisce un flusso di lavoro per compilare le viste, progettato per
ridurre al minimo il tempo in cui il sistema Android è associato al servizio di compilazione automatica. Nella
a ogni richiesta, il sistema Android invia al servizio un oggetto AssistStructure
chiamata al onFillRequest()
.
Il servizio di compilazione automatica controlla se può soddisfare la richiesta con i dati utente memorizzati in precedenza. Se può soddisfare la richiesta, il servizio impacchetta i dati negli oggetti Dataset
. Il servizio chiama il metodo onSuccess()
, passando un oggetto FillResponse
contenente gli oggetti Dataset
. Se il servizio non
dispone di dati per soddisfare la richiesta, trasmette null
al metodo onSuccess()
.
Se si verifica un errore durante l'elaborazione della richiesta, il servizio chiama il metodo onFailure()
. Per una spiegazione dettagliata del flusso di lavoro, consulta la descrizione nella pagina di riferimento AutofillService
.
Il seguente codice mostra un esempio del metodo onFillRequest()
:
Kotlin
override fun onFillRequest( request: FillRequest, cancellationSignal: CancellationSignal, callback: FillCallback ) { // Get the structure from the request val context: List<FillContext> = request.fillContexts val structure: AssistStructure = context[context.size - 1].structure // Traverse the structure looking for nodes to fill out val parsedStructure: ParsedStructure = parseStructure(structure) // Fetch user data that matches the fields val (username: String, password: String) = fetchUserData(parsedStructure) // Build the presentation of the datasets val usernamePresentation = RemoteViews(packageName, android.R.layout.simple_list_item_1) usernamePresentation.setTextViewText(android.R.id.text1, "my_username") val passwordPresentation = RemoteViews(packageName, android.R.layout.simple_list_item_1) passwordPresentation.setTextViewText(android.R.id.text1, "Password for my_username") // Add a dataset to the response val fillResponse: FillResponse = FillResponse.Builder() .addDataset(Dataset.Builder() .setValue( parsedStructure.usernameId, AutofillValue.forText(username), usernamePresentation ) .setValue( parsedStructure.passwordId, AutofillValue.forText(password), passwordPresentation ) .build()) .build() // If there are no errors, call onSuccess() and pass the response callback.onSuccess(fillResponse) } data class ParsedStructure(var usernameId: AutofillId, var passwordId: AutofillId) data class UserData(var username: String, var password: String)
Java
@Override public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal, FillCallback callback) { // Get the structure from the request List<FillContext> context = request.getFillContexts(); AssistStructure structure = context.get(context.size() - 1).getStructure(); // Traverse the structure looking for nodes to fill out ParsedStructure parsedStructure = parseStructure(structure); // Fetch user data that matches the fields UserData userData = fetchUserData(parsedStructure); // Build the presentation of the datasets RemoteViews usernamePresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1); usernamePresentation.setTextViewText(android.R.id.text1, "my_username"); RemoteViews passwordPresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1); passwordPresentation.setTextViewText(android.R.id.text1, "Password for my_username"); // Add a dataset to the response FillResponse fillResponse = new FillResponse.Builder() .addDataset(new Dataset.Builder() .setValue(parsedStructure.usernameId, AutofillValue.forText(userData.username), usernamePresentation) .setValue(parsedStructure.passwordId, AutofillValue.forText(userData.password), passwordPresentation) .build()) .build(); // If there are no errors, call onSuccess() and pass the response callback.onSuccess(fillResponse); } class ParsedStructure { AutofillId usernameId; AutofillId passwordId; } class UserData { String username; String password; }
Un servizio può avere più di un set di dati che soddisfano la richiesta. In questo caso, il sistema Android mostra più opzioni, una per ogni set di dati, nell'interfaccia utente di compilazione automatica. Il seguente esempio di codice mostra come fornire più set di dati in una risposta:
Kotlin
// Add multiple datasets to the response val fillResponse: FillResponse = FillResponse.Builder() .addDataset(Dataset.Builder() .setValue(parsedStructure.usernameId, AutofillValue.forText(user1Data.username), username1Presentation) .setValue(parsedStructure.passwordId, AutofillValue.forText(user1Data.password), password1Presentation) .build()) .addDataset(Dataset.Builder() .setValue(parsedStructure.usernameId, AutofillValue.forText(user2Data.username), username2Presentation) .setValue(parsedStructure.passwordId, AutofillValue.forText(user2Data.password), password2Presentation) .build()) .build()
Java
// Add multiple datasets to the response FillResponse fillResponse = new FillResponse.Builder() .addDataset(new Dataset.Builder() .setValue(parsedStructure.usernameId, AutofillValue.forText(user1Data.username), username1Presentation) .setValue(parsedStructure.passwordId, AutofillValue.forText(user1Data.password), password1Presentation) .build()) .addDataset(new Dataset.Builder() .setValue(parsedStructure.usernameId, AutofillValue.forText(user2Data.username), username2Presentation) .setValue(parsedStructure.passwordId, AutofillValue.forText(user2Data.password), password2Presentation) .build()) .build();
I servizi di compilazione automatica possono navigare negli oggetti ViewNode
in AssistStructure
per recuperare i dati di compilazione automatica necessari per soddisfare la richiesta. Un servizio può recuperare i dati di compilazione automatica utilizzando metodi della classe ViewNode
, ad esempio getAutofillId()
.
Un servizio deve essere in grado di descrivere i contenuti di una vista per verificare se
soddisfare la richiesta. Utilizzo del autofillHints
è il primo
che un servizio deve usare per descrivere i contenuti di una vista. Tuttavia,
le app client devono fornire esplicitamente l'attributo nelle loro visualizzazioni prima che sia
disponibile per il servizio.
Se un'app client non fornisce l'attributo autofillHints
, un servizio deve utilizzare le proprie strategie di euristica per descrivere i contenuti.
Il servizio può utilizzare i metodi di altri corsi, ad esempio getText()
o getHint()
,
per ottenere informazioni sui contenuti della vista.
Per ulteriori informazioni, consulta la sezione Fornire suggerimenti per la compilazione automatica.
L'esempio seguente mostra come attraversare AssistStructure
e recuperare
dati di compilazione automatica da un oggetto ViewNode
:
Kotlin
fun traverseStructure(structure: AssistStructure) { val windowNodes: List<AssistStructure.WindowNode> = structure.run { (0 until windowNodeCount).map { getWindowNodeAt(it) } } windowNodes.forEach { windowNode: AssistStructure.WindowNode -> val viewNode: ViewNode? = windowNode.rootViewNode traverseNode(viewNode) } } fun traverseNode(viewNode: ViewNode?) { if (viewNode?.autofillHints?.isNotEmpty() == true) { // If the client app provides autofill hints, you can obtain them using // viewNode.getAutofillHints(); } else { // Or use your own heuristics to describe the contents of a view // using methods such as getText() or getHint() } val children: List<ViewNode>? = viewNode?.run { (0 until childCount).map { getChildAt(it) } } children?.forEach { childNode: ViewNode -> traverseNode(childNode) } }
Java
public void traverseStructure(AssistStructure structure) { int nodes = structure.getWindowNodeCount(); for (int i = 0; i < nodes; i++) { WindowNode windowNode = structure.getWindowNodeAt(i); ViewNode viewNode = windowNode.getRootViewNode(); traverseNode(viewNode); } } public void traverseNode(ViewNode viewNode) { if(viewNode.getAutofillHints() != null && viewNode.getAutofillHints().length > 0) { // If the client app provides autofill hints, you can obtain them using // viewNode.getAutofillHints(); } else { // Or use your own heuristics to describe the contents of a view // using methods such as getText() or getHint() } for(int i = 0; i < viewNode.getChildCount(); i++) { ViewNode childNode = viewNode.getChildAt(i); traverseNode(childNode); } }
Salvare i dati degli utenti
Un servizio di compilazione automatica ha bisogno dei dati utente per compilare le visualizzazioni nelle app. Quando gli utenti compilare manualmente una vista, viene chiesto loro di salvare i dati come mostrato nella figura 2.
Per salvare i dati, il servizio deve indicare che è interessato a archiviarli per un uso futuro. Prima che il sistema Android invii una richiesta di salvataggio dei dati, viene inviata una richiesta di compilazione in cui il servizio ha la possibilità di compilare le visualizzazioni. Per indicare che è interessato a salvare i dati, il servizio include un oggetto SaveInfo
nella risposta alla richiesta di completamento. L'oggetto SaveInfo
contiene almeno i seguenti dati:
- Il tipo di dati utente salvati. Per un elenco dei valori
SAVE_DATA
disponibili, vediSaveInfo
. - L'insieme minimo di visualizzazioni che devono essere modificate per attivare una richiesta di salvataggio.
Ad esempio, un modulo di accesso in genere richiede all'utente di aggiornare le visualizzazioni
username
epassword
per attivare una richiesta di salvataggio.
Un oggetto SaveInfo
è associato a un oggetto FillResponse
, come mostrato nell'esempio di codice seguente:
Kotlin
override fun onFillRequest( request: FillRequest, cancellationSignal: CancellationSignal, callback: FillCallback ) { ... // Builder object requires a non-null presentation val notUsed = RemoteViews(packageName, android.R.layout.simple_list_item_1) val fillResponse: FillResponse = FillResponse.Builder() .addDataset( Dataset.Builder() .setValue(parsedStructure.usernameId, null, notUsed) .setValue(parsedStructure.passwordId, null, notUsed) .build() ) .setSaveInfo( SaveInfo.Builder( SaveInfo.SAVE_DATA_TYPE_USERNAME or SaveInfo.SAVE_DATA_TYPE_PASSWORD, arrayOf(parsedStructure.usernameId, parsedStructure.passwordId) ).build() ) .build() ... }
Java
@Override public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal, FillCallback callback) { ... // Builder object requires a non-null presentation RemoteViews notUsed = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1); FillResponse fillResponse = new FillResponse.Builder() .addDataset(new Dataset.Builder() .setValue(parsedStructure.usernameId, null, notUsed) .setValue(parsedStructure.passwordId, null, notUsed) .build()) .setSaveInfo(new SaveInfo.Builder( SaveInfo.SAVE_DATA_TYPE_USERNAME | SaveInfo.SAVE_DATA_TYPE_PASSWORD, new AutofillId[] {parsedStructure.usernameId, parsedStructure.passwordId}) .build()) .build(); ... }
Il servizio di compilazione automatica può implementare una logica per rendere persistenti i dati dell'utente nel
onSaveRequest()
, che di solito viene chiamato al termine dell'attività del client o quando
chiamate dell'app client commit()
.
Il seguente codice mostra un esempio del metodo onSaveRequest()
:
Kotlin
override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) { // Get the structure from the request val context: List<FillContext> = request.fillContexts val structure: AssistStructure = context[context.size - 1].structure // Traverse the structure looking for data to save traverseStructure(structure) // Persist the data - if there are no errors, call onSuccess() callback.onSuccess() }
Java
@Override public void onSaveRequest(SaveRequest request, SaveCallback callback) { // Get the structure from the request List<FillContext> context = request.getFillContexts(); AssistStructure structure = context.get(context.size() - 1).getStructure(); // Traverse the structure looking for data to save traverseStructure(structure); // Persist the data - if there are no errors, call onSuccess() callback.onSuccess(); }
I servizi di compilazione automatica devono criptare i dati sensibili prima di mantenerli. Tuttavia, i dati utente possono includere etichette o dati non sensibili. Ad esempio, un account utente può includere un'etichetta che contrassegna i dati come account di lavoro o personale. I servizi non devono criptare le etichette. Non crittografando le etichette, possono utilizzare le etichette nelle visualizzazioni delle presentazioni se l'utente non ha autenticati. Quindi, i servizi possono sostituire le etichette con i dati effettivi. dopo che l'utente ha eseguito l'autenticazione.
Posticipare l'interfaccia utente di salvataggio della compilazione automatica
A partire da Android 10, se utilizzi più schermate per implementare una compilazione automatica
ad esempio, una schermata per il campo del nome utente e un'altra per
la password, puoi posticipare la UI di salvataggio della compilazione automatica utilizzando
SaveInfo.FLAG_DELAY_SAVE
flag.
Se questo flag è impostato, l'interfaccia utente di salvataggio della compilazione automatica non viene attivata quando viene eseguito il commit del contesto della compilazione automatica associato alla risposta SaveInfo
. Puoi invece
utilizzare un'attività separata all'interno della stessa attività per consegnare le richieste di riempimento future
e poi mostrare la UI tramite una richiesta di salvataggio. Per ulteriori informazioni, consulta
SaveInfo.FLAG_DELAY_SAVE
.
Richiedi autenticazione utente
I servizi di compilazione automatica possono fornire un ulteriore livello di sicurezza richiedendo all'utente di autenticarsi prima di poter compilare le visualizzazioni. Scenari riportati di seguito sono ottimi candidati per implementare l'autenticazione degli utenti:
- I dati utente nell'app devono essere sbloccati utilizzando una password principale o un'analisi dell'impronta.
- È necessario sbloccare un set di dati specifico, ad esempio i dati della carta di credito, utilizzando un codice di sicurezza (CVC).
In uno scenario in cui il servizio richiede l'autenticazione dell'utente prima dello sblocco
i dati, il servizio può presentare dati boilerplate o un'etichetta e specificare
Intent
che si occupa di
autenticazione. Se hai bisogno di dati aggiuntivi per elaborare la richiesta al termine del flusso di autenticazione, puoi aggiungerli all'intent. La tua attività di autenticazione può quindi restituire i dati alla classe AutofillService
nella tua app.
Il seguente esempio di codice mostra come specificare che la richiesta richiede l'autenticazione:
Kotlin
val authPresentation = RemoteViews(packageName, android.R.layout.simple_list_item_1).apply { setTextViewText(android.R.id.text1, "requires authentication") } val authIntent = Intent(this, AuthActivity::class.java).apply { // Send any additional data required to complete the request putExtra(MY_EXTRA_DATASET_NAME, "my_dataset") } val intentSender: IntentSender = PendingIntent.getActivity( this, 1001, authIntent, PendingIntent.FLAG_CANCEL_CURRENT ).intentSender // Build a FillResponse object that requires authentication val fillResponse: FillResponse = FillResponse.Builder() .setAuthentication(autofillIds, intentSender, authPresentation) .build()
Java
RemoteViews authPresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1); authPresentation.setTextViewText(android.R.id.text1, "requires authentication"); Intent authIntent = new Intent(this, AuthActivity.class); // Send any additional data required to complete the request authIntent.putExtra(MY_EXTRA_DATASET_NAME, "my_dataset"); IntentSender intentSender = PendingIntent.getActivity( this, 1001, authIntent, PendingIntent.FLAG_CANCEL_CURRENT ).getIntentSender(); // Build a FillResponse object that requires authentication FillResponse fillResponse = new FillResponse.Builder() .setAuthentication(autofillIds, intentSender, authPresentation) .build();
Una volta completato il flusso di autenticazione, l'attività deve chiamare il metodo setResult()
, passando un valore RESULT_OK
e impostando l'extra EXTRA_AUTHENTICATION_RESULT
sull'oggetto FillResponse
che include il set di dati compilato. La
il seguente codice mostra un esempio di come restituire il risultato una volta che
I flussi di autenticazione completati:
Kotlin
// The data sent by the service and the structure are included in the intent val datasetName: String? = intent.getStringExtra(MY_EXTRA_DATASET_NAME) val structure: AssistStructure = intent.getParcelableExtra(EXTRA_ASSIST_STRUCTURE) val parsedStructure: ParsedStructure = parseStructure(structure) val (username, password) = fetchUserData(parsedStructure) // Build the presentation of the datasets val usernamePresentation = RemoteViews(packageName, android.R.layout.simple_list_item_1).apply { setTextViewText(android.R.id.text1, "my_username") } val passwordPresentation = RemoteViews(packageName, android.R.layout.simple_list_item_1).apply { setTextViewText(android.R.id.text1, "Password for my_username") } // Add the dataset to the response val fillResponse: FillResponse = FillResponse.Builder() .addDataset(Dataset.Builder() .setValue( parsedStructure.usernameId, AutofillValue.forText(username), usernamePresentation ) .setValue( parsedStructure.passwordId, AutofillValue.forText(password), passwordPresentation ) .build() ).build() val replyIntent = Intent().apply { // Send the data back to the service putExtra(MY_EXTRA_DATASET_NAME, datasetName) putExtra(EXTRA_AUTHENTICATION_RESULT, fillResponse) } setResult(Activity.RESULT_OK, replyIntent)
Java
Intent intent = getIntent(); // The data sent by the service and the structure are included in the intent String datasetName = intent.getStringExtra(MY_EXTRA_DATASET_NAME); AssistStructure structure = intent.getParcelableExtra(EXTRA_ASSIST_STRUCTURE); ParsedStructure parsedStructure = parseStructure(structure); UserData userData = fetchUserData(parsedStructure); // Build the presentation of the datasets RemoteViews usernamePresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1); usernamePresentation.setTextViewText(android.R.id.text1, "my_username"); RemoteViews passwordPresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1); passwordPresentation.setTextViewText(android.R.id.text1, "Password for my_username"); // Add the dataset to the response FillResponse fillResponse = new FillResponse.Builder() .addDataset(new Dataset.Builder() .setValue(parsedStructure.usernameId, AutofillValue.forText(userData.username), usernamePresentation) .setValue(parsedStructure.passwordId, AutofillValue.forText(userData.password), passwordPresentation) .build()) .build(); Intent replyIntent = new Intent(); // Send the data back to the service replyIntent.putExtra(MY_EXTRA_DATASET_NAME, datasetName); replyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, fillResponse); setResult(RESULT_OK, replyIntent);
Se è necessario sbloccare un set di dati della carta di credito, il servizio può mostrare un'interfaccia utente che richiede il CVC. Puoi nascondere i dati fino a quando il set di dati non viene sbloccato presentando dati standard, come il nome della banca e le ultime quattro cifre del numero della carta di credito. L'esempio seguente mostra come richiedere l'autenticazione per un set di dati e nascondere i dati finché l'utente non fornisce il CVC:
Kotlin
// Parse the structure and fetch payment data val parsedStructure: ParsedStructure = parseStructure(structure) val paymentData: Payment = fetchPaymentData(parsedStructure) // Build the presentation that shows the bank and the last four digits of the // credit card number, such as 'Bank-1234' val maskedPresentation: String = "${paymentData.bank}-" + paymentData.creditCardNumber.substring(paymentData.creditCardNumber.length - 4) val authPresentation = RemoteViews(packageName, android.R.layout.simple_list_item_1).apply { setTextViewText(android.R.id.text1, maskedPresentation) } // Prepare an intent that displays the UI that asks for the CVC val cvcIntent = Intent(this, CvcActivity::class.java) val cvcIntentSender: IntentSender = PendingIntent.getActivity( this, 1001, cvcIntent, PendingIntent.FLAG_CANCEL_CURRENT ).intentSender // Build a FillResponse object that includes a Dataset that requires authentication val fillResponse: FillResponse = FillResponse.Builder() .addDataset( Dataset.Builder() // The values in the dataset are replaced by the actual // data once the user provides the CVC .setValue(parsedStructure.creditCardId, null, authPresentation) .setValue(parsedStructure.expDateId, null, authPresentation) .setAuthentication(cvcIntentSender) .build() ).build()
Java
// Parse the structure and fetch payment data ParsedStructure parsedStructure = parseStructure(structure); Payment paymentData = fetchPaymentData(parsedStructure); // Build the presentation that shows the bank and the last four digits of the // credit card number, such as 'Bank-1234' String maskedPresentation = paymentData.bank + "-" + paymentData.creditCardNumber.subString(paymentData.creditCardNumber.length - 4); RemoteViews authPresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1); authPresentation.setTextViewText(android.R.id.text1, maskedPresentation); // Prepare an intent that displays the UI that asks for the CVC Intent cvcIntent = new Intent(this, CvcActivity.class); IntentSender cvcIntentSender = PendingIntent.getActivity( this, 1001, cvcIntent, PendingIntent.FLAG_CANCEL_CURRENT ).getIntentSender(); // Build a FillResponse object that includes a Dataset that requires authentication FillResponse fillResponse = new FillResponse.Builder() .addDataset(new Dataset.Builder() // The values in the dataset are replaced by the actual // data once the user provides the CVC .setValue(parsedStructure.creditCardId, null, authPresentation) .setValue(parsedStructure.expDateId, null, authPresentation) .setAuthentication(cvcIntentSender) .build()) .build();
Una volta che l'attività convalida il CVC, deve chiamare il metodo setResult()
,
passando un valore RESULT_OK
e imposta EXTRA_AUTHENTICATION_RESULT
extra su
un oggetto Dataset
che contiene il numero della carta di credito e la data di scadenza. La
il nuovo set di dati sostituisce il set di dati che richiede l'autenticazione e le viste sono
da compilare immediatamente. Il codice seguente mostra un esempio di come restituire il valore
una volta che l'utente fornisce il CVC:
Kotlin
// Parse the structure and fetch payment data. val parsedStructure: ParsedStructure = parseStructure(structure) val paymentData: Payment = fetchPaymentData(parsedStructure) // Build a non-null RemoteViews object to use as the presentation when // creating the Dataset object. This presentation isn't actually used, but the // Builder object requires a non-null presentation. val notUsed = RemoteViews(packageName, android.R.layout.simple_list_item_1) // Create a dataset with the credit card number and expiration date. val responseDataset: Dataset = Dataset.Builder() .setValue( parsedStructure.creditCardId, AutofillValue.forText(paymentData.creditCardNumber), notUsed ) .setValue( parsedStructure.expDateId, AutofillValue.forText(paymentData.expirationDate), notUsed ) .build() val replyIntent = Intent().apply { putExtra(EXTRA_AUTHENTICATION_RESULT, responseDataset) }
Java
// Parse the structure and fetch payment data. ParsedStructure parsedStructure = parseStructure(structure); Payment paymentData = fetchPaymentData(parsedStructure); // Build a non-null RemoteViews object to use as the presentation when // creating the Dataset object. This presentation isn't actually used, but the // Builder object requires a non-null presentation. RemoteViews notUsed = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1); // Create a dataset with the credit card number and expiration date. Dataset responseDataset = new Dataset.Builder() .setValue(parsedStructure.creditCardId, AutofillValue.forText(paymentData.creditCardNumber), notUsed) .setValue(parsedStructure.expDateId, AutofillValue.forText(paymentData.expirationDate), notUsed) .build(); Intent replyIntent = new Intent(); replyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, responseDataset);
Organizzare i dati in gruppi logici
I servizi di compilazione automatica devono organizzare i dati in gruppi logici che isolano concetti da domini diversi. In questa pagina, questi gruppi logici sono indicati come partizioni. L'elenco seguente mostra esempi tipici di partiti e campi:
- Credenziali, inclusi i campi nome utente e password.
- Indirizzo, che include i campi via, città, stato e codice postale.
- Dati di pagamento, inclusi i campi del numero di carta di credito, della data di scadenza e del codice di verifica.
Un servizio di compilazione automatica che partiziona correttamente i dati è in grado di proteggere meglio dei dati degli utenti, non esponendo i dati di più partizioni in del set di dati. Ad esempio, un set di dati che include le credenziali non deve includere i dati di pagamento. L'organizzazione dei dati in partizioni consente al tuo servizio di esporre la quantità minima di informazioni pertinenti necessarie per soddisfare una richiesta.
L'organizzazione dei dati in partizioni consente ai servizi di riempire le attività che da più partizioni inviando il numero minimo di visualizzazioni i dati all'app client. Ad esempio, considera un'attività che include le visualizzazioni per nome utente, password, via e città, oltre a un servizio di compilazione automatica con i seguenti dati:
Partizione | Campo 1 | Campo 2 |
---|---|---|
Credenziali | work_username | work_password |
personal_username | password_personale | |
Indirizzo | strada_lavoro | work_city |
personal_street | personal_city |
Il servizio può preparare un set di dati che includa la partizione delle credenziali sia per gli account di lavoro che per quelli personali. Quando l'utente sceglie un set di dati, una risposta di compilazione automatica successiva può fornire l'indirizzo di lavoro o personale, a seconda della prima scelta dell'utente.
Un servizio può identificare il campo che ha generato la richiesta chiamando il metodo isFocused()
durante l'esplorazione dell'oggetto AssistStructure
. In questo modo, il servizio può preparare un FillResponse
con i dati della partizione appropriati.
Compilazione automatica del codice monouso inviato tramite SMS
Il servizio di compilazione automatica può aiutare l'utente a inserire i codici monouso inviati via SMS utilizzando l'API SMS Retriever.
Per utilizzare questa funzionalità, è necessario soddisfare i seguenti requisiti:
- Il servizio di compilazione automatica è in esecuzione su Android 9 (livello API 28) o versioni successive.
- L'utente concede il consenso al servizio di compilazione automatica per la lettura dei codici monouso SMS.
- L'applicazione per cui stai fornendo la compilazione automatica non utilizza già l'API SMS Retriever per leggere i codici monouso.
Il servizio di compilazione automatica può utilizzare SmsCodeAutofillClient
,
disponibile chiamando SmsCodeRetriever.getAutofillClient()
da Google Play
Servizi 19.0.56 o successivi.
I passaggi principali per utilizzare questa API in un servizio di compilazione automatica sono:
- Nel servizio di compilazione automatica, utilizza
hasOngoingSmsRequest
. daSmsCodeAutofillClient
per determinare se sono presenti richieste attiva per il nome del pacchetto dell'applicazione che stai compilando. Il servizio di compilazione automatica deve mostrare una richiesta di suggerimento solo se viene restituitofalse
. - Nel servizio di compilazione automatica, utilizza
checkPermissionState
. daSmsCodeAutofillClient
per controllare se il servizio di compilazione automatica ha autorizzazione alla compilazione automatica dei codici monouso. Questo stato di autorizzazione può essereNONE
,GRANTED
oDENIED
. Il servizio di compilazione automatica deve mostrare una richiesta di suggerimento per gli statiNONE
eGRANTED
. - Nell'attività di autenticazione della compilazione automatica, utilizza l'autorizzazione
SmsRetriever.SEND_PERMISSION
per registrare un'BroadcastReceiver
ascolto diSmsCodeRetriever.SMS_CODE_RETRIEVED_ACTION
per ricevere il risultato del codice SMS quando è disponibile. Chiama il numero
startSmsCodeRetriever
il giornoSmsCodeAutofillClient
per iniziare ad ascoltare i codici monouso inviati tramite SMS. Se l'utente concede le autorizzazioni al servizio di compilazione automatica per recuperarle una tantum codici da SMS, cerca i messaggi SMS ricevuti negli ultimi 1-5 minuti da adesso.Se il servizio di compilazione automatica deve richiedere all'utente l'autorizzazione per leggere i codici di una volta, il valore
Task
restituito dastartSmsCodeRetriever
potrebbe non riuscire con un valoreResolvableApiException
restituito. In questo caso, devi chiamare il metodoResolvableApiException.startResolutionForResult()
per visualizzare una finestra di dialogo per il consenso per la richiesta di autorizzazione.Ricevi il risultato del codice SMS dall'intent e poi restituisce il codice SMS come risposta di compilazione automatica.
Scenari avanzati di compilazione automatica
- Integrazione con la tastiera
- A partire da Android 11, la piattaforma consente l'uso di tastiere e altri editor dei metodi di input (IME) per visualizzare i suggerimenti di compilazione automatica in linea, anziché utilizzare un menu a discesa. Per ulteriori informazioni sui modi in cui il servizio di compilazione automatica può supportare questa azione, consulta la sezione Integrare la compilazione automatica con .
- Impagina i set di dati
- Una risposta di compilazione automatica di grandi dimensioni può superare le dimensioni della transazione consentite dell'oggetto
Binder
che rappresenta l'oggetto remoto necessario per elaborare la richiesta. Per impedire che il sistema Android non venga generata un'eccezione in questi scenari, puoi impedire aFillResponse
piccolo aggiungendo non più di 20Dataset
oggetti alla volta. Se la risposta ha bisogno di più set di dati, puoi aggiungere un set di dati che consenta gli utenti sanno che ci sono più informazioni e recupera il gruppo successivo dei set di dati quando selezionati. Per ulteriori informazioni, vediaddDataset(Dataset)
. - Salva la suddivisione dei dati in più schermate
Spesso le app suddividono i dati utente in più schermate nella stessa attività, soprattutto nelle attività utilizzate per creare un nuovo account utente. Ad esempio, nella prima schermata viene chiesto un nome utente e, se quest'ultimo è disponibile, su un secondo schermo viene richiesta la password. In queste situazioni, il servizio di compilazione automatica deve attendere che l'utente inserisca entrambi i campi prima che possa essere visualizzata l'interfaccia utente di salvataggio della compilazione automatica. Per gestire questi scenari, segui questi passaggi:
- Nella prima richiesta di compilazione, aggiungi un pacchetto di stati client nella risposta contenente gli ID della compilazione automatica dei campi parziali presente sullo schermo.
- Nella seconda richiesta di compilazione, recupera il bundle dello stato del client, recupera gli ID di compilazione automatica impostati nella richiesta precedente dallo stato del client e aggiungi questi ID e il flag
FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE
all'oggettoSaveInfo
utilizzato nella seconda risposta. - Nella richiesta di salvataggio,
utilizza lo
FillContext
corretto per ottenere il valore di ciascun campo. Esiste un contesto di riempimento per richiesta di compilazione.
Per ulteriori informazioni, vedi Salvare quando i dati sono suddivisi in più schermi.
- Fornisci la logica di inizializzazione e smantellamento per ogni richiesta
Ogni volta che viene inviata una richiesta di compilazione automatica, il sistema Android si associa Service e chiama il relativo metodo
onConnected()
. Una volta che il servizio ha elaborato la richiesta, il sistema Android chiama il metodoonDisconnected()
e si scollega dal servizio. Puoi implementareonConnected()
per fornire che viene eseguito prima di elaborare una richiesta eonDisconnected()
per fornire che viene eseguito dopo l'elaborazione di una richiesta.- Personalizzare l'interfaccia utente del salvataggio della compilazione automatica
I servizi di compilazione automatica possono personalizzare l'interfaccia utente di salvataggio della compilazione automatica per aiutare gli utenti a decidere se consentire al servizio di salvare i loro dati. I servizi possono fornire informazioni aggiuntive su ciò che viene salvato tramite un semplice testo o tramite una visualizzazione personalizzata. I servizi possono anche modificare l'aspetto del pulsante che annulla la richiesta di salvataggio e ricevere una notifica quando l'utente tocca il pulsante. Per ulteriori informazioni, consulta la pagina di riferimento
SaveInfo
.- Modalità di compatibilità
La modalità di compatibilità consente ai servizi di compilazione automatica di usare l'accessibilità struttura virtuale per la compilazione automatica. È particolarmente utile per fornire funzionalità di compilazione automatica nei browser che non implementano esplicitamente le API di compilazione automatica.
Per testare il servizio di compilazione automatica utilizzando la modalità di compatibilità, esplicitamente inserisci nella lista consentita il browser o l'app che richiede la modalità di compatibilità. Puoi controllare i pacchetti già inclusi nella lista consentita eseguendo il seguente comando:
$ adb shell settings get global autofill_compat_mode_allowed_packages
Se il pacchetto che stai testando non è in elenco, aggiungilo eseguendo il test il comando seguente, dove
pkgX
è il pacchetto dell'app:$ adb shell settings put global autofill_compat_mode_allowed_packages pkg1[resId1]:pkg2[resId1,resId2]
Se l'app è un browser, utilizza
resIdx
per specificare l'ID risorsa del campo di immissione che contiene l'URL della pagina visualizzata.
La modalità di compatibilità presenta le seguenti limitazioni:
- Una richiesta di salvataggio viene attivata quando il servizio utilizza il flag
FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE
o viene chiamato il metodosetTrigger()
.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE
viene impostato per impostazione predefinita quando utilizzando la modalità di compatibilità. - Il valore del testo dei nodi potrebbe non essere disponibile nel metodo
onSaveRequest(SaveRequest, SaveCallback)
.
Per ulteriori informazioni sulla modalità di compatibilità, incluse le limitazioni
associate, consulta le
AutofillService
riferimento alla classe.