Otomatik doldurma hizmeti, diğer uygulamaların görünümlerine veri yerleştirerek kullanıcıların formları daha kolay doldurmasını sağlayan bir uygulamadır. Otomatik doldurma hizmetleri, uygulamalardaki görünümlerden kullanıcı verilerini de alabilir ve daha sonra kullanmak üzere saklayabilir. Otomatik doldurma hizmetleri genellikle kullanıcı verilerini yöneten uygulamalar (ör. şifre yöneticileri) tarafından sağlanır.
Android, Android 8.0 (API düzeyi 26) ve sonraki sürümlerde kullanılabilen otomatik doldurma çerçevesiyle form doldurmayı kolaylaştırır. Kullanıcılar, cihazlarında otomatik doldurma hizmetleri sağlayan bir uygulama varsa otomatik doldurma özelliklerinden yararlanabilir.
Bu sayfada, uygulamanızda otomatik doldurma hizmetinin nasıl uygulanacağı gösterilmektedir. Hizmetin nasıl uygulanacağını gösteren bir kod örneği arıyorsanız Java veya Kotlin'deki AutofillFramework örneğine bakın.
Otomatik doldurma hizmetlerinin işleyiş şekli hakkında daha fazla bilgi için AutofillService
ve AutofillManager
sınıflarının referans sayfalarına bakın.
Manifest bildirimleri ve izinleri
Otomatik doldurma hizmetleri sunan uygulamalar, hizmetin uygulanmasını açıklayan bir beyan içermelidir. Bildirimi belirtmek için <service>
öğesini uygulama manifestine ekleyin. <service>
öğesi aşağıdaki özellikleri ve öğeleri içermelidir:
- Hizmeti uygulayan uygulamadaki
AutofillService
alt sınıfını gösterenandroid:name
özelliği. android:permission
BIND_AUTOFILL_SERVICE
iznini beyan eden özellik.- Zorunlu
<intent-filter>
öğesi. Bu öğenin<action>
alt öğesi,android.service.autofill.AutofillService
işlemini belirtir. - Hizmet için ek yapılandırma parametreleri sağlamak üzere kullanabileceğiniz isteğe bağlı
<meta-data>
öğesi.
Aşağıdaki örnekte bir otomatik doldurma hizmeti bildirimi gösterilmektedir:
<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>
<meta-data>
öğesi, hizmetle ilgili daha fazla ayrıntı içeren bir XML kaynağını işaret eden bir android:resource
özelliği içerir.
Önceki örnekteki service_configuration
kaynağı, kullanıcıların hizmeti yapılandırmasına olanak tanıyan bir etkinliği belirtir. Aşağıdaki örnekte service_configuration
XML kaynağı gösterilmektedir:
<autofill-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="com.example.android.SettingsActivity" />
XML kaynakları hakkında daha fazla bilgi için Uygulama kaynaklarına genel bakış başlıklı makaleyi inceleyin.
Hizmeti etkinleştirme istemi
Bir uygulama, BIND_AUTOFILL_SERVICE
iznini bildirdikten ve kullanıcı cihaz ayarlarında bu izni etkinleştirdikten sonra otomatik doldurma hizmeti olarak kullanılır. Bir uygulama, AutofillManager
sınıfının hasEnabledAutofillServices()
yöntemini çağırarak şu anda etkinleştirilmiş hizmet olup olmadığını doğrulayabilir.
Uygulama, mevcut otomatik doldurma hizmeti değilse ACTION_REQUEST_SET_AUTOFILL_SERVICE
amacını kullanarak kullanıcının otomatik doldurma ayarlarını değiştirmesini isteyebilir. Kullanıcı, arayanın paketiyle eşleşen bir otomatik doldurma hizmeti seçerse amaç RESULT_OK
değerini döndürür.
Müşteri görüşlerini doldurma
Otomatik doldurma hizmeti, kullanıcı diğer uygulamalarla etkileşime girdiğinde istemci görünümlerini doldurma istekleri alır. Otomatik doldurma hizmetinde isteği karşılayan kullanıcı verileri varsa yanıtta bu veriler gönderilir. Android sistemi, Şekil 1'de gösterildiği gibi, mevcut verileri içeren bir otomatik doldurma kullanıcı arayüzü gösterir:
1.şekil Bir veri kümesini gösteren otomatik doldurma kullanıcı arayüzü.
Otomatik doldurma çerçevesi, Android sisteminin otomatik doldurma hizmetine bağlı olduğu süreyi en aza indirmek için tasarlanmış, görünümleri doldurmaya yönelik bir iş akışı tanımlar. Android sistemi, her istekte AssistStructure
nesnesini onFillRequest()
yöntemini çağırarak hizmete gönderir.
Otomatik doldurma hizmeti, daha önce depoladığı kullanıcı verileriyle isteği karşılayıp karşılayamayacağını kontrol eder. İsteği karşılayabiliyorsa hizmet, verileri Dataset
nesneleri halinde paketler. Hizmet, Dataset
nesnelerini içeren bir FillResponse
nesnesi ileterek onSuccess()
yöntemini çağırır. Hizmette isteği karşılayacak veri yoksa null
, onSuccess()
yöntemine iletilir.
İstek işlenirken bir hata oluşursa hizmet, onFailure()
yöntemini çağırır. İş akışıyla ilgili ayrıntılı açıklama için AutofillService
referans sayfasındaki açıklamaya bakın.
Aşağıdaki kodda onFillRequest()
yönteminin bir örneği gösterilmektedir:
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; }
Bir hizmet, isteği karşılayan birden fazla veri kümesine sahip olabilir. Bu durumda, Android sistemi otomatik doldurma kullanıcı arayüzünde her veri kümesi için bir tane olmak üzere birden fazla seçenek gösterir. Aşağıdaki kod örneğinde, yanıtta birden fazla veri kümesinin nasıl sağlanacağı gösterilmektedir:
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();
Otomatik doldurma hizmetleri, isteği karşılamak için gereken otomatik doldurma verilerini almak üzere AssistStructure
içindeki ViewNode
nesnelerinde gezinebilir. Bir hizmet, ViewNode
sınıfının getAutofillId()
gibi yöntemlerini kullanarak otomatik doldurma verilerini alabilir.
Bir hizmetin, isteği karşılayıp karşılayamayacağını kontrol etmek için görünümün içeriğini açıklayabilmesi gerekir. autofillHints
özelliğini kullanmak, bir hizmetin görünüm içeriklerini açıklamak için kullanması gereken ilk yaklaşımdır. Ancak istemci uygulamaları, hizmette kullanılabilir hale gelmeden önce bu özelliği görünümlerinde açıkça sağlamalıdır.
Bir istemci uygulaması autofillHints
özelliğini sağlamıyorsa bir hizmet, içeriği açıklamak için kendi sezgisel yöntemlerini kullanmalıdır.
Hizmet, görünümün içeriği hakkında bilgi almak için getText()
veya getHint()
gibi diğer sınıflardaki yöntemleri kullanabilir.
Daha fazla bilgi için Otomatik doldurma için ipuçları sağlama başlıklı makaleyi inceleyin.
Aşağıdaki örnekte, AssistStructure
öğesinde nasıl gezinileceği ve ViewNode
nesnesinden otomatik doldurma verilerinin nasıl alınacağı gösterilmektedir:
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); } }
Kullanıcı verilerini kaydetme
Otomatik doldurma hizmetinin, uygulamalardaki görünümleri doldurmak için kullanıcı verilerine ihtiyacı vardır. Kullanıcılar bir görünümü manuel olarak doldurduğunda Şekil 2'de gösterildiği gibi verileri mevcut otomatik doldurma hizmetine kaydetmeleri istenir.
Şekil 2. Otomatik doldurma kaydetme kullanıcı arayüzü.
Verilerin kaydedilmesi için hizmetin, verileri gelecekte kullanmak üzere depolamak istediğini belirtmesi gerekir. Android sistemi verileri kaydetme isteği göndermeden önce, hizmetin görünümleri doldurma fırsatı bulduğu bir doldurma isteği vardır. Verileri kaydetmek istediğini belirtmek için hizmet, doldurma isteğine verilen yanıta bir SaveInfo
nesnesi ekler. SaveInfo
nesnesi en azından aşağıdaki verileri içermelidir:
- Kaydedilen kullanıcı verilerinin türü. Kullanılabilir
SAVE_DATA
değerlerinin listesi içinSaveInfo
bölümüne bakın. - Kaydetme isteğini tetiklemek için değiştirilmesi gereken minimum görünüm grubu.
Örneğin, bir giriş formu genellikle kullanıcının kaydetme isteğini tetiklemek için
username
vepassword
görünümlerini güncellemesini gerektirir.
Aşağıdaki kod örneğinde gösterildiği gibi, bir SaveInfo
nesnesi bir FillResponse
nesnesiyle ilişkilendirilir:
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(); ... }
Otomatik doldurma hizmeti, kullanıcı verilerini onSaveRequest()
yönteminde kalıcı hale getirmek için mantık uygulayabilir. Bu yöntem genellikle istemci etkinliği tamamlandıktan sonra veya istemci uygulaması commit()
yöntemini çağırdığında çağrılır.
Aşağıdaki kodda onSaveRequest()
yönteminin bir örneği gösterilmektedir:
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(); }
Otomatik doldurma hizmetleri, hassas verileri kalıcı hale getirmeden önce şifrelemelidir. Ancak kullanıcı verileri, hassas olmayan etiketler veya veriler içerebilir. Örneğin, bir kullanıcı hesabı, verileri iş veya kişisel hesap olarak işaretleyen bir etiket içerebilir. Hizmetler etiketleri şifrelememelidir. Etiketler şifrelenmediğinde, kullanıcı kimlik doğrulaması yapmamışsa hizmetler etiketleri sunum görünümlerinde kullanabilir. Ardından, kullanıcı kimliğini doğruladıktan sonra hizmetler etiketleri gerçek verilerle değiştirebilir.
Otomatik doldurma kaydetme kullanıcı arayüzünü erteleme
Android 10'dan itibaren, otomatik doldurma iş akışını uygulamak için birden fazla ekran kullanıyorsanız (ör. kullanıcı adı alanı için bir ekran, şifre için başka bir ekran) SaveInfo.FLAG_DELAY_SAVE
işaretini kullanarak otomatik doldurma kaydetme kullanıcı arayüzünü erteleyebilirsiniz.
Bu işaret ayarlanırsa SaveInfo
yanıtıyla ilişkili otomatik doldurma bağlamı kaydedildiğinde otomatik doldurma kaydetme kullanıcı arayüzü tetiklenmez. Bunun yerine, gelecekteki doldurma isteklerini sunmak için aynı görevde ayrı bir etkinlik kullanabilir ve ardından kullanıcı arayüzünü bir kaydetme isteği aracılığıyla gösterebilirsiniz. Daha fazla bilgi için SaveInfo.FLAG_DELAY_SAVE
konusuna bakın.
Kullanıcı kimlik doğrulamasını zorunlu kılma
Otomatik doldurma hizmetleri, kullanıcıdan görünümleri doldurmadan önce kimliğini doğrulamasını isteyerek ek bir güvenlik düzeyi sağlayabilir. Aşağıdaki senaryolarda kullanıcı kimlik doğrulaması uygulanabilir:
- Uygulamadaki kullanıcı verilerinin, birincil şifre veya parmak izi taraması kullanılarak kilidinin açılması gerekir.
- Kart doğrulama kodu (CVC) kullanılarak kredi kartı bilgileri gibi belirli bir veri kümesinin kilidinin açılması gerekir.
Hizmetin, verilerin kilidini açmadan önce kullanıcı kimlik doğrulaması gerektirdiği bir senaryoda hizmet, standart veriler veya bir etiket sunabilir ve kimlik doğrulama işlemini gerçekleştiren Intent
'yı belirtebilir. Kimlik doğrulama akışı tamamlandıktan sonra isteği işlemek için ek veriye ihtiyacınız varsa bu verileri amaca ekleyebilirsiniz. Ardından kimlik doğrulama etkinliğiniz, verileri uygulamanızdaki AutofillService
sınıfına döndürebilir.
Aşağıdaki kod örneğinde, isteğin kimlik doğrulama gerektirdiğinin nasıl belirtileceği gösterilmektedir:
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();
Etkinlik, kimlik doğrulama akışını tamamladıktan sonra setResult()
yöntemini çağırmalı, RESULT_OK
değerini iletmeli ve EXTRA_AUTHENTICATION_RESULT
ekstrasını, doldurulmuş veri kümesini içeren FillResponse
nesnesine ayarlamalıdır. Aşağıdaki kodda, kimlik doğrulama akışları tamamlandıktan sonra sonucun nasıl döndürüleceğine dair bir örnek gösterilmektedir:
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);
Bir kredi kartı veri kümesinin kilidinin açılması gerektiği senaryoda hizmet, CVC'yi isteyen bir kullanıcı arayüzü gösterebilir. Banka adı ve kredi kartı numarasının son dört hanesi gibi standart veriler sunarak veri kümesinin kilidi açılana kadar verileri gizleyebilirsiniz. Aşağıdaki örnekte, bir veri kümesi için kimlik doğrulamanın nasıl zorunlu kılınacağı ve kullanıcı CVC'yi sağlayana kadar verilerin nasıl gizleneceği gösterilmektedir:
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();
Etkinlik, CVC'yi doğruladıktan sonra setResult()
yöntemini çağırıp RESULT_OK
değerini iletmeli ve EXTRA_AUTHENTICATION_RESULT
ekstrasını kredi kartı numarasını ve son kullanma tarihini içeren bir Dataset
nesnesi olarak ayarlamalıdır. Yeni veri kümesi, kimlik doğrulama gerektiren veri kümesinin yerini alır ve görünümler hemen doldurulur. Aşağıdaki kodda, kullanıcı CVC'yi sağladıktan sonra veri kümesinin nasıl döndürüleceğine dair bir örnek gösterilmektedir:
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);
Verileri mantıksal gruplar halinde düzenleme
Otomatik doldurma hizmetleri, verileri farklı alanlardaki kavramları birbirinden ayıran mantıksal gruplar halinde düzenlemelidir. Bu sayfada, bu mantıksal gruplara bölümler adı verilir. Aşağıdaki listede, bölümler ve alanlarla ilgili tipik örnekler verilmiştir:
- Kullanıcı adı ve şifre alanlarını içeren kimlik bilgileri.
- Sokak, şehir, eyalet ve posta kodu alanlarını içeren adres.
- Kredi kartı numarası, son kullanma tarihi ve doğrulama kodu alanlarını içeren ödeme bilgileri.
Verileri doğru şekilde bölümlendiren bir otomatik doldurma hizmeti, bir veri kümesinde birden fazla bölümden veri göstermeyerek kullanıcılarının verilerini daha iyi koruyabilir. Örneğin, kimlik bilgilerini içeren bir veri kümesinin ödeme bilgilerini içermesi gerekmez. Verileri bölümler halinde düzenlemek, hizmetinizin bir isteği karşılamak için gereken minimum miktarda alakalı bilgiyi kullanıma sunmasına olanak tanır.
Verileri bölümlere ayırarak düzenlemek, hizmetlerin birden fazla bölümden görünümler içeren etkinlikleri doldurmasını ve istemci uygulamasına minimum miktarda alakalı veri göndermesini sağlar. Örneğin, kullanıcı adı, şifre, sokak ve şehir görünümlerini içeren bir etkinlik ile aşağıdaki verilere sahip bir otomatik doldurma hizmetini ele alalım:
Bölüm | Alan 1 | Alan 2 |
---|---|---|
Kimlik Bilgisi | work_username | work_password |
personal_username | personal_password | |
Adres | work_street | work_city |
personal_street | personal_city |
Hizmet, hem iş hem de kişisel hesaplar için kimlik bilgileri bölümünü içeren bir veri kümesi hazırlayabilir. Kullanıcı bir veri kümesi seçtiğinde, sonraki otomatik doldurma yanıtı, kullanıcının ilk seçimine bağlı olarak iş veya kişisel adresi sağlayabilir.
Bir hizmet, AssistStructure
nesnesinde gezinirken isFocused()
yöntemini çağırarak isteği başlatan alanı tanımlayabilir. Bu sayede hizmet, uygun bölüm verileriyle bir FillResponse
hazırlayabilir.
SMS tek seferlik kodunu otomatik doldurma
Otomatik doldurma hizmetiniz, SMS Retriever API'yi kullanarak SMS ile gönderilen tek seferlik kodları doldurma konusunda kullanıcıya yardımcı olabilir.
Bu özelliği kullanmak için aşağıdaki koşulların karşılanması gerekir:
- Otomatik doldurma hizmeti, Android 9 (API düzeyi 28) veya sonraki sürümlerde çalışıyor olmalıdır.
- Kullanıcı, otomatik doldurma hizmetinizin SMS'ten tek seferlik kodları okumasına izin verir.
- Otomatik doldurma sağladığınız uygulama, tek kullanımlık kodları okumak için SMS Retriever API'yi kullanmıyor olmalıdır.
Otomatik doldurma hizmetiniz, Google Play Hizmetleri 19.0.56 veya sonraki sürümlerden SmsCodeRetriever.getAutofillClient()
çağrılarak kullanılabilen SmsCodeAutofillClient
'ı kullanabilir.
Bu API'yi otomatik doldurma hizmetinde kullanmak için temel adımlar şunlardır:
- Otomatik doldurma hizmetinde, otomatik doldurma işlemini yaptığınız uygulamanın paket adı için etkin istek olup olmadığını belirlemek üzere
hasOngoingSmsRequest
SmsCodeAutofillClient
seçeneğini kullanın. Otomatik doldurma hizmetiniz yalnızca bu işlevfalse
değerini döndürürse öneri istemi göstermelidir. - Otomatik doldurma hizmetinde, otomatik doldurma hizmetinin tek seferlik kodları otomatik olarak doldurma izni olup olmadığını kontrol etmek için
checkPermissionState
SmsCodeAutofillClient
'ı kullanın. Bu izin durumuNONE
,GRANTED
veyaDENIED
olabilir. Otomatik doldurma hizmeti,NONE
veGRANTED
durumları için bir öneri istemi göstermelidir. - Otomatik doldurma kimlik doğrulama etkinliğinde,
BroadcastReceiver
SmsRetriever.SEND_PERMISSION
iznini kullanarakSmsCodeRetriever.SMS_CODE_RETRIEVED_ACTION
dinleyen birBroadcastReceiver
kaydedin. Bu sayede, SMS kodu sonucu kullanılabilir olduğunda alınır. SMS ile gönderilen tek seferlik kodları dinlemeye başlamak için
startSmsCodeRetriever
numaralı telefonuSmsCodeAutofillClient
arayın. Kullanıcı, otomatik doldurma hizmetinizin SMS'ten tek seferlik kodları almasına izin verirse bu hizmet, son bir ila beş dakika içinde alınan SMS mesajlarını arar.Otomatik doldurma hizmetinizin tek kullanımlık kodları okumak için kullanıcı izni istemesi gerekiyorsa
Task
,startSmsCodeRetriever
tarafındanResolvableApiException
döndürülerek başarısız olabilir. Bu durumda, izin isteği için bir izin iletişim kutusu göstermek üzereResolvableApiException.startResolutionForResult()
yöntemini çağırmanız gerekir.Amaçtan SMS kodu sonucunu alın ve SMS kodunu otomatik doldurma yanıtı olarak döndürün.
Chrome'da otomatik doldurmayı etkinleştirme
Chrome, üçüncü taraf otomatik doldurma hizmetlerinin formları yerel olarak otomatik doldurmasına olanak tanır. Bu sayede kullanıcılara daha sorunsuz ve basit bir kullanıcı deneyimi sunulur. Şifreleri, geçiş anahtarlarını ve adresler ile ödeme verileri gibi diğer bilgileri otomatik doldurmak için üçüncü taraf otomatik doldurma hizmetlerini kullanmak isteyen kullanıcılar, Chrome ayarlarında Başka bir hizmet kullanarak otomatik doldur'u seçmelidir.
Kullanıcıların hizmetiniz ve Android'deki Chrome ile mümkün olan en iyi otomatik doldurma deneyimini yaşaması için otomatik doldurma hizmeti sağlayıcıları, kullanıcılarını Chrome ayarlarında tercih ettikleri hizmet sağlayıcıyı belirtmeye teşvik etmelidir.
Geliştiriciler, kullanıcıların açma/kapatma düğmesini etkinleştirmesine yardımcı olmak için şunları yapabilir:
- Chrome ayarlarını sorgulayın ve kullanıcının üçüncü taraf otomatik doldurma hizmeti kullanmak isteyip istemediğini öğrenin.
- Kullanıcıların üçüncü taraf otomatik doldurma hizmetlerini etkinleştirebileceği Chrome ayarları sayfasına giden derin bağlantı.
Chrome ayarlarını okuma
Herhangi bir uygulama, Chrome'un Android otomatik doldurma özelliğini kullanmasına olanak tanıyan 3. taraf otomatik doldurma modunu kullanıp kullanmadığını okuyabilir. Chrome, bu bilgileri iletmek için Android'in
ContentProvider
özelliğini kullanır. Android manifest dosyanızda hangi kanallardan ayarları okumak istediğinizi belirtin:
<uses-permission android:name="android.permission.READ_USER_DICTIONARY"/>
<queries>
<!-- To Query Chrome Beta: -->
<package android:name="com.chrome.beta" />
<!-- To Query Chrome Stable: -->
<package android:name="com.android.chrome" />
</queries>
Ardından, içerik URI'sini oluşturarak bu bilgileri istemek için Android'in ContentResolver
özelliğini kullanın:
Kotlin
val CHROME_CHANNEL_PACKAGE = "com.android.chrome" // Chrome Stable. val CONTENT_PROVIDER_NAME = ".AutofillThirdPartyModeContentProvider" val THIRD_PARTY_MODE_COLUMN = "autofill_third_party_state" val THIRD_PARTY_MODE_ACTIONS_URI_PATH = "autofill_third_party_mode" val uri = Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(CHROME_CHANNEL_PACKAGE + CONTENT_PROVIDER_NAME) .path(THIRD_PARTY_MODE_ACTIONS_URI_PATH) .build() val cursor = contentResolver.query( uri, arrayOf(THIRD_PARTY_MODE_COLUMN), // projection null, // selection null, // selectionArgs null // sortOrder ) if (cursor == null) { // Terminate now! Older versions of Chromium don't provide this information. } cursor?.use { // Use the safe call operator and the use function for auto-closing if (it.moveToFirst()) { // Check if the cursor has any rows val index = it.getColumnIndex(THIRD_PARTY_MODE_COLUMN) if (index != -1) { // Check if the column exists val value = it.getInt(index) if (0 == value) { // 0 means that the third party mode is turned off. Chrome uses its built-in // password manager. This is the default for new users. } else { // 1 means that the third party mode is turned on. Chrome uses forwards all // autofill requests to Android Autofill. Users have to opt-in for this. } } else { // Handle the case where the column doesn't exist. Log a warning, perhaps. Log.w("Autofill", "Column $THIRD_PARTY_MODE_COLUMN not found in cursor") } } } // The cursor is automatically closed here
Java
final String CHROME_CHANNEL_PACKAGE = "com.android.chrome"; // Chrome Stable. final String CONTENT_PROVIDER_NAME = ".AutofillThirdPartyModeContentProvider"; final String THIRD_PARTY_MODE_COLUMN = "autofill_third_party_state"; final String THIRD_PARTY_MODE_ACTIONS_URI_PATH = "autofill_third_party_mode"; final Uri uri = new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(CHROME_CHANNEL_PACKAGE + CONTENT_PROVIDER_NAME) .path(THIRD_PARTY_MODE_ACTIONS_URI_PATH) .build(); final Cursor cursor = getContentResolver().query( uri, /*projection=*/new String[] {THIRD_PARTY_MODE_COLUMN}, /*selection=*/ null, /*selectionArgs=*/ null, /*sortOrder=*/ null); if (cursor == null) { // Terminate now! Older versions of Chromium don't provide this information. } cursor.moveToFirst(); // Retrieve the result; int index = cursor.getColumnIndex(THIRD_PARTY_MODE_COLUMN); if (0 == cursor.getInt(index)) { // 0 means that the third party mode is turned off. Chrome uses its built-in // password manager. This is the default for new users. } else { // 1 means that the third party mode is turned on. Chrome uses forwards all // autofill requests to Android Autofill. Users have to opt-in for this. }
Chrome ayarlarına derin bağlantı oluşturma
Kullanıcıların üçüncü taraf otomatik doldurma hizmetlerini etkinleştirebileceği Chrome ayarları sayfasına doğrudan bağlantı vermek için Android Intent
kullanın.
İşlemi ve kategorileri bu örnekte gösterildiği gibi yapılandırdığınızdan emin olun:
Kotlin
val autofillSettingsIntent = Intent(Intent.ACTION_APPLICATION_PREFERENCES) autofillSettingsIntent.addCategory(Intent.CATEGORY_DEFAULT) autofillSettingsIntent.addCategory(Intent.CATEGORY_APP_BROWSER) autofillSettingsIntent.addCategory(Intent.CATEGORY_PREFERENCE) // Invoking the intent with a chooser allows users to select the channel they // want to configure. If only one browser reacts to the intent, the chooser is // skipped. val chooser = Intent.createChooser(autofillSettingsIntent, "Pick Chrome Channel") startActivity(chooser) // If the caller knows which Chrome channel they want to configure, // they can instead add a package hint to the intent, e.g. val specificChromeIntent = Intent(Intent.ACTION_APPLICATION_PREFERENCES) // Create a *new* intent specificChromeIntent.addCategory(Intent.CATEGORY_DEFAULT) specificChromeIntent.addCategory(Intent.CATEGORY_APP_BROWSER) specificChromeIntent.addCategory(Intent.CATEGORY_PREFERENCE) specificChromeIntent.setPackage("com.android.chrome") // Set the package on the *new* intent startActivity(specificChromeIntent) // Start the *new* intent
Java
Intent autofillSettingsIntent = new Intent(Intent.ACTION_APPLICATION_PREFERENCES); autofillSettingsIntent.addCategory(Intent.CATEGORY_DEFAULT); autofillSettingsIntent.addCategory(Intent.CATEGORY_APP_BROWSER); autofillSettingsIntent.addCategory(Intent.CATEGORY_PREFERENCE); // Invoking the intent with a chooser allows users to select the channel they // want to configure. If only one browser reacts to the intent, the chooser is // skipped. Intent chooser = Intent.createChooser(autofillSettingsIntent, "Pick Chrome Channel"); startActivity(chooser); // If the caller knows which Chrome channel they want to configure, // they can instead add a package hint to the intent, e.g. autofillSettingsIntent.setPackage("com.android.chrome"); startActivity(autofillSettingsInstent);
Gelişmiş otomatik doldurma senaryoları
- Klavyeyle entegrasyon
- Android 11'den itibaren platform, klavyelerin ve diğer giriş yöntemi düzenleyicilerinin (IME'ler) açılır menü kullanmak yerine otomatik doldurma önerilerini satır içi olarak göstermesine olanak tanır. Otomatik doldurma hizmetinizin bu işlevi nasıl destekleyebileceği hakkında daha fazla bilgi için Otomatik doldurmayı klavyelerle entegre etme başlıklı makaleyi inceleyin.
- Veri kümelerini sayfalandırma
- Büyük bir otomatik doldurma yanıtı, isteği işlemek için gereken uzaktan erişilebilir nesneyi temsil eden
Binder
nesnesinin izin verilen işlem boyutunu aşabilir. Android sisteminin bu senaryolarda istisna oluşturmasını önlemek içinFillResponse
öğesini küçük tutabilir, yani tek seferde en fazla 20Dataset
nesnesi ekleyebilirsiniz. Yanıtınız için daha fazla veri kümesi gerekiyorsa kullanıcıların daha fazla bilgi olduğunu bilmesini sağlayan ve seçildiğinde sonraki veri kümesi grubunu alan bir veri kümesi ekleyebilirsiniz. Daha fazla bilgi içinaddDataset(Dataset)
başlıklı makaleyi inceleyin. - Birden çok ekrana bölünmüş verileri kaydetme
Uygulamalar genellikle kullanıcı verilerini aynı etkinlikteki birden fazla ekrana böler. Bu durum özellikle yeni kullanıcı hesabı oluşturmak için kullanılan etkinliklerde görülür. Örneğin, ilk ekranda kullanıcı adı istenir ve kullanıcı adı kullanılabilirse ikinci ekranda şifre istenir. Bu durumlarda, otomatik doldurma hizmeti, otomatik doldurma kaydetme kullanıcı arayüzünün gösterilebilmesi için kullanıcının her iki alanı da girmesini beklemelidir. Bu tür senaryoları ele almak için aşağıdaki adımları uygulayın:
- İlk doldurma isteğinde, ekranda bulunan kısmi alanların otomatik doldurma kimliklerini içeren yanıta bir istemci durumu paketi ekleyin.
- İkinci doldurma isteğinde, istemci durumu paketini alın, önceki istekte istemci durumunda ayarlanan otomatik doldurma kimliklerini alın ve bu kimlikleri ve
FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE
işaretini ikinci yanıtta kullanılanSaveInfo
nesnesine ekleyin. - Kaydetme isteğinde,
her alanın değerini almak için uygun
FillContext
nesnelerini kullanın. Her doldurma isteği için bir doldurma bağlamı vardır.
Daha fazla bilgi için Veriler birden fazla ekrana bölündüğünde kaydetme başlıklı makaleyi inceleyin.
- Her istek için başlatma ve kapatma mantığı sağlama
Android sistemi, her otomatik doldurma isteğinde hizmete bağlanır ve hizmetin
onConnected()
yöntemini çağırır. Hizmet isteği işledikten sonra Android sistemionDisconnected()
yöntemini çağırır ve hizmetten bağlantıyı kaldırır.onConnected()
, bir istek işlenmeden önce çalışan kodu sağlamak için,onDisconnected()
ise bir istek işlendikten sonra çalışan kodu sağlamak için uygulanabilir.- Otomatik doldurma kaydetme kullanıcı arayüzünü özelleştirme
Otomatik doldurma hizmetleri, kullanıcıların hizmetin verilerini kaydetmesine izin verip vermeyeceklerine karar vermelerine yardımcı olmak için otomatik doldurma kaydetme kullanıcı arayüzünü özelleştirebilir. Hizmetler, kaydedilenler hakkında basit bir metin veya özelleştirilmiş bir görünüm aracılığıyla ek bilgiler sağlayabilir. Hizmetler, kaydetme isteğini iptal eden düğmenin görünümünü de değiştirebilir ve kullanıcı bu düğmeye dokunduğunda bildirim alabilir. Daha fazla bilgi için
SaveInfo
referans sayfasına bakın.- Uyumluluk modu
Uyumluluk modu, otomatik doldurma hizmetlerinin otomatik doldurma amacıyla erişilebilirlik sanal yapısını kullanmasına olanak tanır. Bu özellik, özellikle otomatik doldurma API'lerini açıkça uygulamayan tarayıcılarda otomatik doldurma işlevi sağlamak için yararlıdır.
Otomatik doldurma hizmetinizi uyumluluk modunu kullanarak test etmek için uyumluluk modu gerektiren tarayıcıyı veya uygulamayı açıkça izin verilenler listesine ekleyin. Aşağıdaki komutu çalıştırarak hangi paketlerin izin verilenler listesine eklendiğini kontrol edebilirsiniz:
$ adb shell settings get global autofill_compat_mode_allowed_packages
Test ettiğiniz paket listelenmiyorsa aşağıdaki komutu çalıştırarak paketi ekleyin. Burada
pkgX
, uygulamanın paketidir:$ adb shell settings put global autofill_compat_mode_allowed_packages pkg1[resId1]:pkg2[resId1,resId2]
Uygulama bir tarayıcıysa oluşturulan sayfanın URL'sini içeren giriş alanının kaynak kimliğini belirtmek için
resIdx
öğesini kullanın.
Uyumluluk modunda aşağıdaki sınırlamalar vardır:
- Hizmet,
FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE
işaretini kullandığında veyasetTrigger()
yöntemi çağrıldığında kaydetme isteği tetiklenir. Uyumluluk modu kullanılırkenFLAG_SAVE_ON_ALL_VIEWS_INVISIBLE
varsayılan olarak ayarlanır. - Düğümlerin metin değeri,
onSaveRequest(SaveRequest, SaveCallback)
yönteminde kullanılamayabilir.
Uyumluluk modu ve bununla ilişkili sınırlamalar hakkında daha fazla bilgi için AutofillService
sınıf referansına bakın.