אופטימיזציה של האפליקציה למילוי אוטומטי

אפליקציות שמשתמשות בתצוגות רגילות פועלות עם מסגרת המילוי האוטומטי בלי צורך בהגדרה מיוחדת. אתם גם יכולים לבצע אופטימיזציה של האופן שבו האפליקציה עובדת עם ה-framework.

הגדרת הסביבה של המילוי האוטומטי

בקטע הזה נסביר איך להגדיר פונקציונליות בסיסית של מילוי אוטומטי באפליקציה.

הגדרת שירות מילוי אוטומטי

כדי שהאפליקציה תוכל להשתמש במסגרת המילוי האוטומטי, צריך להגדיר שירות מילוי אוטומטי במכשיר. על אף שרוב הטלפונים והטאבלטים עם Android 8.0 (רמת API 26) כוללים שירות מילוי אוטומטי, מומלץ להשתמש בשירות בדיקה כשבודקים את האפליקציה, כמו שירות המילוי האוטומטי בדוגמה של מסגרת המילוי האוטומטי ל-Android. כשמשתמשים במהדר, צריך להגדיר שירות מילוי אוטומטי באופן מפורש, כי יכול להיות שהמהדר לא יכלול שירות ברירת מחדל.

אחרי שמתקינים את שירות המילוי האוטומטי לבדיקה מהאפליקציה לדוגמה, מפעילים את שירות המילוי האוטומטי. לשם כך, עוברים אל הגדרות > מערכת > שפות וקלט > מתקדם > עזרה בקלט > שירות מילוי אוטומטי.

מידע נוסף על הגדרת אמולטור לבדיקה של מילוי אוטומטי זמין במאמר בדיקת האפליקציה עם מילוי אוטומטי.

איך מספקים רמזים למילוי אוטומטי

שירות המילוי האוטומטי קובע את הסוג של כל תצוגה באמצעות שיטות ניתוח נתונים (heuristics). עם זאת, אם האפליקציה שלכם מסתמכת על שיטות הניתוח האלה, התנהגות המילוי האוטומטי עשויה להשתנות באופן בלתי צפוי כשאתם מעדכנים את האפליקציה. כדי לוודא ששירות המילוי האוטומטי מזהה בצורה נכונה את גורמי הצורה של האפליקציה, עליכם לספק רמזים למילוי אוטומטי.

אפשר להגדיר רמזים למילוי אוטומטי באמצעות המאפיין android:autofillHints. בדוגמה הבאה מוגדר רמז "password" ל-EditText:

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:autofillHints="password" />

אפשר גם להגדיר טיפים באופן פרוגרמטי באמצעות השיטה setAutofillHints(), כפי שמתואר בדוגמה הבאה:

Kotlin

val password = findViewById<EditText>(R.id.password)
password.setAutofillHints(View.AUTOFILL_HINT_PASSWORD)

Java

EditText password = findViewById(R.id.password);
password.setAutofillHints(View.AUTOFILL_HINT_PASSWORD);

הכללת קבועים מוגדרים מראש של רמזים

מסגרת המילוי האוטומטי לא מאמתת את הטיפים, אלא מעבירה אותם לשירות המילוי האוטומטי ללא שינוי או אימות. אפשר להשתמש בכל ערך, אבל הכיתות View ו-AndroidX‏ HintConstants מכילות רשימות של קבועי רמזים נתמכים באופן רשמי.

בעזרת שילוב של קבועים אלה, ניתן ליצור פריסות לתרחישים נפוצים של מילוי אוטומטי:

פרטי הכניסה לחשבון

בטופס כניסה, אפשר לכלול רמזים לפרטי הכניסה לחשבון, כמו AUTOFILL_HINT_USERNAME ו-AUTOFILL_HINT_PASSWORD.

כדי ליצור חשבון חדש או כשמשתמשים משנים את שם המשתמש והסיסמה שלהם, אפשר להשתמש ב-AUTOFILL_HINT_NEW_USERNAME וב-AUTOFILL_HINT_NEW_PASSWORD.

פרטי כרטיס אשראי

כשמבקשים פרטי כרטיס אשראי, אפשר להשתמש ברמזים כמו AUTOFILL_HINT_CREDIT_CARD_NUMBER ו-AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE.

לגבי תאריכי תפוגת תוקף של כרטיסי אשראי, מבצעים אחת מהפעולות הבאות:

כתובת פיזית

בשדות של טפסים עם כתובת פיזית, אפשר להשתמש בטיפים כמו:

שמות של אנשים

כשמבקשים שמות של אנשים, אפשר להשתמש ברמזים כמו:

מספרי טלפון

במספרי טלפון, אפשר להשתמש באפשרויות הבאות:

סיסמה חד-פעמית (OTP)

כדי להציג סיסמה חד-פעמית בתצוגה אחת, אפשר להשתמש ב-AUTOFILL_HINT_SMS_OTP.

אתם יכולים להשתמש בשיטה generateSmsOtpHintForCharacterPosition() כדי ליצור רמזים לכל תו בנפרד בתצוגות מרובות, שבהן כל תצוגה ממופה לספרה אחת של הסיסמה החד-פעמית (OTP).

סימון שדות כחשובים במילוי האוטומטי

אפשר לכלול את השדות הנפרדים באפליקציה במבנה תצוגה למטרות מילוי אוטומטי. כברירת מחדל, תצוגות משתמשות במצב IMPORTANT_FOR_AUTOFILL_AUTO, שמאפשר ל-Android להשתמש בהיוריסטיקה שלה כדי לקבוע אם תצוגה מפורטת חשובה למילוי אוטומטי.

עם זאת, יש מקרים שבהם תצוגה, מבנה של תצוגה או כל הפעילות אינם חשובים למילוי האוטומטי:

  • שדה CAPTCHA בפעילות התחברות
  • תצוגה שבה המשתמש יוצר תוכן, כמו עורך טקסט או גיליון אלקטרוני
  • הצפיות בחלק מהפעילויות במשחקים, כמו אלו שמציגות גיימפליי

אפשר להגדיר את מידת החשיבות של תצוגה למילוי אוטומטי באמצעות המאפיין android:importantForAutofill:

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:importantForAutofill="no" />

הערך של importantForAutofill יכול להיות כל אחת מהאפשרויות הבאות:

auto
לאפשר למערכת Android להשתמש בהיגוריית הניתוח שלה כדי לקבוע אם התצוגה חשובה למילוי האוטומטי.
no
התצוגה הזו לא חשובה במילוי האוטומטי.
noExcludeDescendants
התצוגה הזו והצאצאים שלה לא חשובים למילוי אוטומטי.
yes
התצוגה הזו חשובה למילוי אוטומטי.
yesExcludeDescendants
התצוגה הזו חשובה למילוי אוטומטי, אבל הצאצאים שלה לא חשובים למילוי אוטומטי.

אפשר גם להשתמש ב-method‏ setImportantForAutofill():

Kotlin

val captcha = findViewById<TextView>(R.id.captcha)
captcha.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO)

Java

TextView captcha = findViewById(R.id.captcha);
captcha.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO);

כך אפשר להצהיר על התרחישים לדוגמה שלמעלה שהם לא חשובים למילוי אוטומטי:

  • שדה CAPTCHA בפעילות כניסה לחשבון: משתמשים ב-android:importantForAutofill="no" או ב-IMPORTANT_FOR_AUTOFILL_NO כדי לסמן את התצוגה הזו כלא חשובה.
  • תצוגה שבה המשתמש יוצר תוכן: משתמשים ב-android:importantForAutofill="noExcludeDescendants" או ב-IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS כדי לסמן את כל מבנה התצוגה כלא חשוב.
  • התצוגות בחלק מהפעילויות במשחקים: משתמשים ב-android:importantForAutofill="noExcludeDescendants" או ב-IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS כדי לסמן את כל מבנה התצוגה כלא חשוב.

שיוך נתונים של האתר ושל האפליקציה לנייד

שירותי מילוי אוטומטי, כמו המילוי האוטומטי של Google, יכולים לשתף את נתוני הכניסה של המשתמשים בין הדפדפנים ומכשירי Android אחרי שמקשרים את האפליקציה לאתר. כשמשתמש בוחר באותו שירות מילוי אוטומטי בשתי הפלטפורמות, כניסה לאפליקציית האינטרנט מאפשרת למלא את פרטי הכניסה שלו באופן אוטומטי כשהוא נכנס לאפליקציה התואמת ל-Android.

כדי לשייך את האפליקציה ל-Android לאתר, צריך לארח באתר קישור של נכס דיגיטלי עם היחס delegate_permission/common.get_login_creds. לאחר מכן צריך להצהיר על השיוך בקובץ AndroidManifest.xml של האפליקציה. להוראות מפורטות על שיוך האתר לאפליקציה ל-Android, ראו הפעלת כניסה אוטומטית בין אפליקציות ואתרים.

השלמת תהליך עבודה של מילוי אוטומטי

בקטע הזה מתוארים תרחישים ספציפיים שבהם אפשר לבצע פעולות כדי לשפר את הפונקציונליות של המילוי האוטומטי למשתמשים באפליקציה.

איך לבדוק אם המילוי האוטומטי מופעל

המשתמשים יכולים להפעיל או להשבית את המילוי האוטומטי, וגם לשנות את שירות המילוי האוטומטי, על ידי מעבר אל הגדרות > מערכת > שפות וקלט > מתקדם > עזרה בקלט > שירות מילוי אוטומטי. האפליקציה לא יכולה לשנות את הגדרות המילוי האוטומטי של המשתמש, אבל אפשר להטמיע פונקציונליות נוספת של מילוי אוטומטי באפליקציה, או בתצוגות מסוימות של האפליקציה, אם המילוי האוטומטי זמין למשתמש.

לדוגמה, אם המילוי האוטומטי מופעל עבור המשתמש, יוצג רשומת מילוי אוטומטי בתפריט האפשרויות הנוספות של TextView. כדי לבדוק אם המילוי האוטומטי מופעל אצל המשתמש, קוראים ל-method isEnabled() של האובייקט AutofillManager.

כדי לוודא שחוויית ההרשמה וההתחברות היא אופטימלית למשתמשים ללא מילוי אוטומטי, כדאי להטמיע את התכונה כניסה באמצעות One Tap.

איך מפעילים בקשה למילוי אוטומטי

לפעמים צריך לאלץ בקשה של מילוי אוטומטי להתרחש בתגובה לפעולת משתמש. לדוגמה, TextView מציע פריט תפריט של מילוי אוטומטי כשהמשתמש מבצע לחיצה ארוכה על התצוגה. בדוגמה הבאה לקוד מוסבר איך לאלץ בקשה למילוי אוטומטי:

Kotlin

fun eventHandler(view: View) {
    val afm = requireContext().getSystemService(AutofillManager::class.java)
    afm?.requestAutofill(view)
}

Java

public void eventHandler(View view) {
    AutofillManager afm = context.getSystemService(AutofillManager.class);
    if (afm != null) {
        afm.requestAutofill(view);
    }
}

אפשר גם להשתמש בשיטה cancel() כדי לבטל את ההקשר הנוכחי של המילוי האוטומטי. האפשרות הזו יכולה להיות שימושית אם יש לכם לחצן שמאפס את השדות בדף התחברות.

שימוש בסוג המילוי האוטומטי הנכון לנתונים באמצעי הבקרה לבחירת פריטים

בוררים יכולים להיות שימושיים עם מילוי אוטומטי, כי הם מספקים ממשק משתמש שמאפשר למשתמשים לשנות את הערך של שדה שמאחסן נתוני תאריך או שעה. לדוגמה, בטופס של כרטיס אשראי, בורר תאריכים מאפשר למשתמשים להזין או לשנות את תאריך התפוגה של כרטיס האשראי. עם זאת, צריך להשתמש בתצוגה אחרת, כמו EditText, כדי להציג את הנתונים כשבורר הערכים לא גלוי.

אובייקט EditText מצפה באופן מקורי לנתוני מילוי אוטומטי מסוג AUTOFILL_TYPE_TEXT. אם משתמשים בסוג אחר של נתונים, צריך ליצור תצוגה בהתאמה אישית שירשה מ-EditText ולהטמיע את השיטות הנדרשות לטיפול בסוג הנתונים התואם. לדוגמה, אם יש לכם שדה תאריך, הטמיעו את השיטות עם לוגיקה שמטפלת בצורה נכונה בערכים מסוג AUTOFILL_TYPE_DATE.

כשמציינים את סוג הנתונים למילוי אוטומטי, שירות המילוי האוטומטי יכול ליצור ייצוג מתאים של הנתונים שמוצגים בתצוגה. למידע נוסף, ראו שימוש בבוררי בחירה עם מילוי אוטומטי.

השלמת ההקשר של המילוי האוטומטי

מסגרת המילוי האוטומטי שומרת את הקלט של המשתמש לשימוש עתידי על ידי הצגת תיבת דו-שיח עם השאלה 'לשמור למילוי אוטומטי?' אחרי שההקשר של המילוי האוטומטי מסתיים. בדרך כלל, ההקשר של המילוי האוטומטי מסתיים כשהפעילות מסתיימת. עם זאת, יש מצבים מסוימים שבהם צריך להודיע על כך במפורש למסגרת – לדוגמה, אם משתמשים באותה פעילות אבל בקטעים שונים בדפי הכניסה והתוכן. במצבים כאלה אפשר לסיים באופן מפורש את ההקשר על ידי שליחת קריאה ל-AutofillManager.commit().

תמיכה בתצוגות בהתאמה אישית

בתצוגות בהתאמה אישית אפשר לציין את המטא-נתונים שנחשפים למסגרת של המילוי האוטומטי באמצעות ממשק ה-API של המילוי האוטומטי. תצוגות מסוימות משמשות כמאגר של צאצאים וירטואליים, כמו תצוגות שמכילות ממשק משתמש שעבר עיבוד ב-OpenGL. בתצוגות האלה צריך להשתמש ב-API כדי לציין את מבנה המידע באפליקציה, לפני שהן יכולות לעבוד עם המסגרת של המילוי האוטומטי.

אם באפליקציה נעשה שימוש בתצוגות בהתאמה אישית, כדאי להביא בחשבון את התרחישים הבאים:

  • בתצוגה בהתאמה אישית יש מבנה תצוגה רגיל או מבנה תצוגה שמוגדר כברירת מחדל.
  • לתצוגה בהתאמה אישית יש מבנה וירטואלי או מבנה של תצוגה שלא זמין למסגרת של המילוי האוטומטי.

תצוגות בהתאמה אישית עם מבנה תצוגה סטנדרטי

תצוגות בהתאמה אישית יכולות להגדיר את המטא-נתונים הנדרשים למילוי האוטומטי כדי לפעול. חשוב לוודא שהתצוגה בהתאמה אישית מנהלת את המטא-נתונים בצורה מתאימה כדי שתעבוד עם מסגרת המילוי האוטומטי. בתצוגה המותאמת אישית צריך לבצע את הפעולות הבאות:

  • טיפול בערך המילוי האוטומטי שהמסגרת שולחת לאפליקציה.
  • מספקים את הסוג והערך של המילוי האוטומטי למסגרת.

כשהמילוי האוטומטי מופעל, מסגרת המילוי האוטומטי קוראת ל-autofill() בתצוגה שלכם ושולחת את הערך שבו התצוגה צריכה להשתמש. מטמיעים את autofill() כדי לציין איך התצוגה בהתאמה אישית מטפלת בערך המילוי האוטומטי.

בתצוגה צריך לציין סוג וערך של מילוי אוטומטי על ידי שינוי השיטות getAutofillType() ו-getAutofillValue() בהתאמה.

לבסוף, אי אפשר להשתמש במילוי אוטומטי כדי למלא את התצוגה אם המשתמש לא יכול לספק ערך לתצוגה במצב הנוכחי שלה – לדוגמה, אם התצוגה מושבתת. במקרים כאלה, הערך של getAutofillType() צריך להחזיר את הערך AUTOFILL_TYPE_NONE, עבור getAutofillValue() הוא צריך להחזיר את הערך null ו-autofill() לא צריך לעשות כלום.

במקרים הבאים נדרשים שלבים נוספים כדי לפעול כראוי בתוך המסגרת:

  • אפשר לערוך את התצוגה המותאמת אישית.
  • התצוגה בהתאמה אישית מכילה מידע אישי רגיש.

אפשר לערוך את התצוגה המותאמת אישית

אם אפשר לערוך את התצוגה, צריך להודיע למסגרת המילוי האוטומטי על השינויים באמצעות קריאה ל-notifyValueChanged() באובייקט AutofillManager.

התצוגה בהתאמה אישית מכילה מידע אישי רגיש

אם תצוגה מכילה פרטים אישיים מזהים (PII), כמו כתובות אימייל, מספרי כרטיסי אשראי וסיסמאות, צריך לסמן אותה כתוכן רגיש.

באופן כללי, תצוגות שהתוכן שלהן מגיע ממשאבים סטטיים לא מכילות מידע אישי רגיש, אבל תצוגות שהתוכן שלהן מוגדר באופן דינמי עשויות להכיל מידע אישי רגיש. לדוגמה, תווית שמכילה את הטקסט enter your username לא מכילה מידע אישי רגיש, אבל תווית שמכילה את הטקסט Hello, John כן מכילה מידע כזה.

במסגרת המילוי האוטומטי, ההנחה היא שכל הנתונים רגישים כברירת מחדל. אפשר לסמן נתונים שאינם רגישים.

כדי לסמן אם תצוגה מכילה מידע אישי רגיש, מטמיעים את onProvideAutofillStructure() ומפעילים את setDataIsSensitive() באובייקט ViewStructure.

הקוד לדוגמה הבא ממחיש איך לסמן את הנתונים במבנה התצוגה כלא רגישים:

Kotlin

override fun onProvideAutofillStructure(structure: ViewStructure, flags: Int) {
    super.onProvideAutofillStructure(structure, flags)

    structure.setDataIsSensitive(false)
}

Java

@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
    super.onProvideAutofillStructure(structure, flags);

    structure.setDataIsSensitive(false);
}

אם בתצוגה מפורטת רק ערכים מוגדרים מראש, אפשר להשתמש ב-method setAutofillOptions() כדי להגדיר את האפשרויות למילוי אוטומטי של התצוגה. באופן ספציפי, צריך להשתמש בשיטה הזו בתצוגות שהסוג של המילוי האוטומטי שלהן הוא AUTOFILL_TYPE_LIST, כי שירות המילוי האוטומטי יכול לבצע את הפעולה בצורה טובה יותר אם הוא יודע מהן האפשרויות הזמינות למילוי התצוגה.

תרחיש דומה הוא תצוגות שמשתמשות במתאם, כמו Spinner. לדוגמה, כדי ליצור ספינר שמספק שנים שנוצרו באופן דינמי על סמך השנה הנוכחית, לשימוש בשדות של תאריך התפוגה של כרטיס האשראי, אפשר להטמיע את השיטה getAutofillOptions() של הממשק Adapter כדי לספק רשימה של שנים.

תצוגות שמשתמשות ב-ArrayAdapter יכולות גם לספק רשימות של ערכים. ArrayAdapter מגדיר באופן אוטומטי אפשרויות למילוי אוטומטי למשאבים סטטיים. אם מספקים את הערכים באופן דינמי, משנים את הערך של getAutofillOptions().

תצוגות בהתאמה אישית עם מבנה וירטואלי

כדי שאפשר יהיה לערוך ולשמור את המידע בממשק המשתמש של האפליקציה, מסגרת המילוי האוטומטי דורשת מבנה תצוגה. מבנה התצוגה לא זמין למסגרת במקרים הבאים:

  • האפליקציה משתמשת במנוע רינדור ברמה נמוכה, כמו OpenGL, כדי ליצור את ממשק המשתמש.
  • האפליקציה משתמשת במופע של Canvas כדי לשרטט את ממשק המשתמש.

במקרים כאלה אפשר לציין מבנה של תצוגה על ידי הטמעה של onProvideAutofillVirtualStructure() וביצוע השלבים הבאים:

  1. כדי להגדיל את מספר הצאצאים של מבנה התצוגה, צריך להפעיל את הפונקציה addChildCount().
  2. כדי להוסיף ילד או ילדה, צריך להתקשר ל-newChild().
  3. כדי להגדיר את מזהה המילוי האוטומטי של הילד או הילדה, צריך להפעיל את הפונקציה setAutofillId().
  4. מגדירים מאפיינים רלוונטיים, כמו הערך והסוג של המילוי האוטומטי.
  5. אם הנתונים בחשבון הצאצא הווירטואלי רגישים, מעבירים את הערך true אל setDataIsSensitive(). אחרת, מעבירים את הערך false.

קטע הקוד הבא מראה איך יוצרים צאצא חדש במבנה הווירטואלי:

Kotlin

override fun onProvideAutofillVirtualStructure(structure: ViewStructure, flags: Int) {

    super.onProvideAutofillVirtualStructure(structure, flags)

    // Create a new child in the virtual structure.
    structure.addChildCount(1)
    val child = structure.newChild(childIndex)

    // Set the autofill ID for the child.
    child.setAutofillId(structure.autofillId!!, childVirtualId)

    // Populate the child by providing properties such as value and type.
    child.setAutofillValue(childAutofillValue)
    child.setAutofillType(childAutofillType)

    // Some children can provide a list of values, such as when the child is
    // a spinner.
    val childAutofillOptions = arrayOf<CharSequence>("option1", "option2")
    child.setAutofillOptions(childAutofillOptions)

    // Just like other types of views, mark the data as sensitive when
    // appropriate.
    val sensitive = !contentIsSetFromResources()
    child.setDataIsSensitive(sensitive)
}

Java

@Override
public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {

    super.onProvideAutofillVirtualStructure(structure, flags);

    // Create a new child in the virtual structure.
    structure.addChildCount(1);
    ViewStructure child =
            structure.newChild(childIndex);

    // Set the autofill ID for the child.
    child.setAutofillId(structure.getAutofillId(), childVirtualId);

    // Populate the child by providing properties such as value and type.
    child.setAutofillValue(childAutofillValue);
    child.setAutofillType(childAutofillType);

    // Some children can provide a list of values, such as when the child is
    // a spinner.
    CharSequence childAutofillOptions[] = { "option1", "option2" };
    child.setAutofillOptions(childAutofillOptions);

    // Just like other types of views, mark the data as sensitive when
    // appropriate.
    boolean sensitive = !contentIsSetFromResources();
    child.setDataIsSensitive(sensitive);
}

כשיש שינוי ברכיבים במבנה וירטואלי, צריך להודיע על כך למסגרת על ידי ביצוע המשימות הבאות:

  • אם המיקוד בתוך הצאצאים ישתנה, צריך להפעיל את notifyViewEntered() ואת notifyViewExited() באובייקט AutofillManager.
  • אם הערך של צאצא משתנה, מפעילים קריאה ל-notifyValueChanged() באובייקט AutofillManager.
  • אם היררכיית התצוגה כבר לא זמינה כי המשתמש השלים שלב בתהליך העבודה, למשל כשהוא נכנס באמצעות טופס כניסה, צריך לבצע קריאה ל-commit() באובייקט AutofillManager.
  • אם היררכיית התצוגה לא תקינה כי המשתמש ביטל שלב בתהליך העבודה, למשל כאשר המשתמש מקשיב על לחצן שמאפס את טופס ההתחברות, צריך לבצע קריאה ל-cancel() באובייקט AutofillManager.

שימוש בקריאות חוזרות (callbacks) באירועי מילוי אוטומטי

אם האפליקציה שלכם מספקת תצוגות השלמה אוטומטית משלה, נדרש מנגנון שמורה לאפליקציה להפעיל או להשבית את התצוגות בתגובה לשינויים בעלויות של המילוי האוטומטי בממשק המשתמש. מסגרת המילוי האוטומטי מספקת את המנגנון הזה בצורה של AutofillCallback.

הכיתה הזו מספקת את השיטה onAutofillEvent(View, int), שהאפליקציה קוראת לה אחרי שינוי במצב המילוי האוטומטי שמשויך לתצוגה. יש גם גרסה עם עומס יתר של השיטה הזו, שכוללת פרמטר childId שאפשר להשתמש בו באפליקציה עם תצוגות וירטואליות. המצבים הזמינים מוגדרים כקבועים בקריאה החוזרת.

אפשר לרשום קריאה חוזרת באמצעות השיטה registerCallback() מהמחלקה AutofillManager. בדוגמה הבאה מוסבר איך מגדירים קריאה חוזרת (callback) לאירועי מילוי אוטומטי:

Kotlin

val afm = context.getSystemService(AutofillManager::class.java)

afm?.registerCallback(object : AutofillManager.AutofillCallback() {
    // For virtual structures, override
    // onAutofillEvent(View view, int childId, int event) instead.
    override fun onAutofillEvent(view: View, event: Int) {
        super.onAutofillEvent(view, event)
        when (event) {
            EVENT_INPUT_HIDDEN -> {
                // The autofill affordance associated with the view was hidden.
            }
            EVENT_INPUT_SHOWN -> {
                // The autofill affordance associated with the view was shown.
            }
            EVENT_INPUT_UNAVAILABLE -> {
                // Autofill isn't available.
            }
        }

    }
})

Java

AutofillManager afm = getContext().getSystemService(AutofillManager.class);

afm.registerCallback(new AutofillManager.AutofillCallback() {
    // For virtual structures, override
    // onAutofillEvent(View view, int childId, int event) instead.
    @Override
    public void onAutofillEvent(@NonNull View view, int event) {
        super.onAutofillEvent(view, event);
        switch (event) {
            case EVENT_INPUT_HIDDEN:
                // The autofill affordance associated with the view was hidden.
                break;
            case EVENT_INPUT_SHOWN:
                // The autofill affordance associated with the view was shown.
                break;
            case EVENT_INPUT_UNAVAILABLE:
                // Autofill isn't available.
                break;
        }
    }
});

כשמגיע הזמן להסיר את הקריאה החוזרת, משתמשים ב-method‏ unregisterCallback().

התאמה אישית של המילוי האוטומטי שמודגש שאפשר לצייר

כשהמערכת ממלאת את התצוגה באופן אוטומטי, היא מציגה את הסמל Drawable מעל התצוגה כדי לציין שתוכן התצוגה ממולא באופן אוטומטי. כברירת מחדל, האובייקט הניתן לציור הוא מלבן אחיד בצבע שקוף כהה מעט מצבע העיצוב המשמש לציור הרקעים. אין צורך לשנות את ה-drawable, אבל אפשר להתאים אותו אישית על ידי שינוי הפריט android:autofilledHighlight בעיצוב שבו משתמשים באפליקציה או בפעילות, כפי שמתואר בדוגמה הבאה:

res/values/styles.xml

<resources>
    <style name="MyAutofilledHighlight" parent="...">
        <item name="android:autofilledHighlight">@drawable/my_drawable</item>
    </style>
</resources>

res/drawable/my_drawable.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#4DFF0000" />
</shape>

AndroidManifest.xml

<application ...
    android:theme="@style/MyAutofilledHighlight">
<!-- or -->
<activity ...
    android:theme="@style/MyAutofilledHighlight">

אימות למילוי אוטומטי

שירות מילוי אוטומטי יכול לדרוש מהמשתמש לבצע אימות כדי שהשירות יוכל למלא שדות באפליקציה. במקרה כזה, מערכת Android תפעיל את פעילות האימות של השירות כחלק ממקבץ הפעילות.

אין צורך לעדכן את האפליקציה כדי לתמוך באימות, כי האימות מתבצע בתוך השירות. עם זאת, חשוב לוודא שמבנה התצוגה של הפעילות נשמר כשמפעילים אותה מחדש. למשל, אפשר ליצור את מבנה התצוגה ב-onCreate() ולא ב-onStart() או ב-onResume().

כדי לבדוק איך האפליקציה מתנהגת כששירות מילוי אוטומטי מחייב אימות, אפשר להשתמש ב-HeuristicsService מהדוגמה של AutofillFramework ולהגדיר אותו כך שיחייב אימות של תגובת המילוי. אפשר גם להשתמש בדוגמה שלBadViewStructureCreationSignInActivity כדי לבצע אמולציה של הבעיה הזו.

הקצאת מזהים של מילוי אוטומטי לתצוגות שנעשה בהן שימוש חוזר

קונטיינרים שממחזרים תצוגות, כמו הכיתה RecyclerView, שימושיים באפליקציות שצריכות להציג רשימות גלילה של רכיבים על סמך קבוצות גדולות של נתונים. כאשר הקונטיינר גולל, המערכת עושה שימוש חוזר בתצוגות בפריסה, אבל התצוגות מכילות תוכן חדש.

אם התוכן הראשוני של תצוגה ששוחזר ממולא, שירות המילוי האוטומטי שומר את המשמעות הלוגית של התצוגות באמצעות מזהי המילוי האוטומטי שלהן. הבעיה מתרחשת כשהמערכת משתמשת שוב בתצוגות בפריסה, והמזהים הלוגיים של התצוגות נשארים זהים, וכתוצאה מכך נתוני המשתמש הלא נכונים למילוי אוטומטי משויכים למזהה מילוי אוטומטי.

כדי לפתור את הבעיה במכשירים עם Android 9 ואילך (API ברמה 28 ואילך), צריך לנהל באופן מפורש את מזהה המילוי האוטומטי של תצוגות שבהן RecyclerView משתמש, באמצעות השיטות הבאות:

  • לשיטה getNextAutofillId() מוקצה מזהה מילוי אוטומטי חדש שמיועד לפעילות הזו בלבד.
  • השיטה setAutofillId() מגדירה את המזהה הייחודי והלוגי של המילוי האוטומטי של התצוגה הזו בפעילות.

טיפול בבעיות ידועות

בקטע הזה מוצגות פתרונות לבעיות ידועות במסגרת המילוי האוטומטי.

המילוי האוטומטי גורם לקריסה של אפליקציות ב-Android 8.0, 8.1

ב-Android 8.0 (רמת API‏ 26) וב-Android 8.1 (רמת API‏ 27), מילוי אוטומטי עלול לגרום לקריסה של האפליקציה בתרחישים מסוימים. כדי לעקוף בעיות אפשריות, מסמנים את כל התצוגות שלא מולאו באופן אוטומטי באמצעות importantForAutofill=no. אפשר גם לתייג את כל הפעילות באמצעות importantForAutofill=noExcludeDescendants.

תיבות דו-שיח ששונו בגודל לא נלקחות בחשבון למילוי אוטומטי

ב-Android 8.1 (API ברמה 27) ובגרסאות ישנות יותר, אם משנים את הגודל של תצוגה בתיבת דו-שיח אחרי שהיא כבר מוצגת, התצוגה לא נלקחת בחשבון למילוי אוטומטי. התצוגות האלה לא נכללות באובייקט AssistStructure שמערכת Android שולחת לשירות המילוי האוטומטי. כתוצאה מכך, השירות לא יכול למלא את התצוגות.

כדי לפתור את הבעיה, צריך להחליף את המאפיין token של הפרמטרים של חלון תיבת הדו-שיח במאפיין token של הפעילות שיוצרת את תיבת הדו-שיח. אחרי שמוודאים שהאישור האוטומטי מופעל, שומרים את הפרמטרים של החלון ב-method‏ onWindowAttributesChanged() של הכיתה שעוברת בירושה מ-Dialog. לאחר מכן, מחליפים את המאפיין token של הפרמטרים השמורים במאפיין token של הפעילות ההורה בשיטה onAttachedToWindow().

בקטע הקוד הבא מוצגת מחלקה שמיישם את הפתרון הזה:

Kotlin

class MyDialog(context: Context) : Dialog(context) {

    // Used to store the dialog window parameters.
    private var token: IBinder? = null

    private val isDialogResizedWorkaroundRequired: Boolean
        get() {
            if (Build.VERSION.SDK_INT != Build.VERSION_CODES.O || Build.VERSION.SDK_INT != Build.VERSION_CODES.O_MR1) {
                return false
            }
            val autofillManager = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                context.getSystemService(AutofillManager::class.java)
            } else {
                null
            }
            return autofillManager?.isEnabled ?: false
        }

    override fun onWindowAttributesChanged(params: WindowManager.LayoutParams) {
        if (params.token == null && token != null) {
            params.token = token
        }

        super.onWindowAttributesChanged(params)
    }

    override fun onAttachedToWindow() {
        if (isDialogResizedWorkaroundRequired) {
            token = ownerActivity!!.window.attributes.token
        }

        super.onAttachedToWindow()
    }

}

Java

public class MyDialog extends Dialog {

    public MyDialog(Context context) {
        super(context);
    }

    // Used to store the dialog window parameters.
    private IBinder token;

    @Override
    public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
        if (params.token == null && token != null) {
            params.token = token;
        }

        super.onWindowAttributesChanged(params);
    }

    @Override
    public void onAttachedToWindow() {
        if (isDialogResizedWorkaroundRequired()) {
            token = getOwnerActivity().getWindow().getAttributes().token;
        }

        super.onAttachedToWindow();
    }

    private boolean isDialogResizedWorkaroundRequired() {
        if (Build.VERSION.SDK_INT != Build.VERSION_CODES.O
                || Build.VERSION.SDK_INT != Build.VERSION_CODES.O_MR1) {
            return false;
        }
        AutofillManager autofillManager =
                null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            autofillManager = getContext().getSystemService(AutofillManager.class);
        }
        return autofillManager != null && autofillManager.isEnabled();
    }

}

כדי להימנע מפעולות מיותרות, קטע הקוד הבא מראה איך לבדוק אם המילוי האוטומטי נתמך במכשיר ומופעל למשתמש הנוכחי, ואם הפתרון החלופי הזה נדרש:

Kotlin

// AutofillExtensions.kt

fun Context.isDialogResizedWorkaroundRequired(): Boolean {
    // After the issue is resolved on Android, check whether the
    // workaround is still required for the current device.
    return isAutofillAvailable()
}

fun Context.isAutofillAvailable(): Boolean {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
        // The autofill framework is available on Android 8.0
        // or higher.
        return false
    }

    val afm = getSystemService(AutofillManager::class.java)
    // Return true if autofill is supported by the device and enabled
    // for the current user.
    return afm != null && afm.isEnabled
}

Java

public class AutofillHelper {

    public static boolean isDialogResizedWorkaroundRequired(Context context) {
        // After the issue is resolved on Android, check whether the
        // workaround is still required for the current device.
        return isAutofillAvailable(context);
    }

    public static boolean isAutofillAvailable(Context context) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            // The autofill framework is available on Android 8.0
            // or higher.
            return false;
        }

        AutofillManager afm = context.getSystemService(AutofillManager.class);
        // Return true if autofill is supported by the device and enabled
        // for the current user.
        return afm != null && afm.isEnabled();
    }
}

בדיקת האפליקציה עם מילוי אוטומטי

אחרי שמבצעים אופטימיזציה של האפליקציה לעבודה עם שירותי מילוי אוטומטי, כדאי לבדוק אם היא פועלת כמצופה עם שירותי המילוי האוטומטי.

כדי לבדוק את האפליקציה, צריך להשתמש במהדר או במכשיר פיזי עם Android 8.0 (רמת API 26) ואילך. מידע נוסף על יצירת מהדר זמין במאמר יצירה וניהול של מכשירים וירטואליים.

התקנה של שירות מילוי אוטומטי

כדי לבדוק את האפליקציה עם מילוי אוטומטי, צריך להתקין אפליקציה אחרת שמספקת שירותי מילוי אוטומטי. אפשר להשתמש לאפליקציה של צד שלישי למטרה הזו, אבל קל יותר להשתמש בשירות מילוי אוטומטי לדוגמה כדי שלא תצטרכו להירשם לשירותים של צד שלישי.

אתם יכולים להשתמש בדוגמה של מסגרת המילוי האוטומטי של Android ב-Java כדי לבדוק את האפליקציה שלכם עם שירותי מילוי אוטומטי. האפליקציה לדוגמה מספקת שירות מילוי אוטומטי ומחלקות Activity לקוח שבהן אפשר להשתמש כדי לבדוק את תהליך העבודה לפני שמשתמשים בו באפליקציה. הדף הזה מפנה לאפליקציה לדוגמה android-AutofillFramework.

אחרי שמתקינים את האפליקציה, מפעילים את שירות המילוי האוטומטי בהגדרות המערכת של הסימולטור. לשם כך, עוברים אל הגדרות > מערכת > שפות וקלט > מתקדם > עזרה בקלט > שירות מילוי אוטומטי.

ניתוח הדרישות לגבי הנתונים

כדי לבדוק את האפליקציה באמצעות שירות המילוי האוטומטי, השירות צריך לכלול נתונים שבאמצעותם אפשר למלא את האפליקציה. השירות צריך גם להבין מה סוג הנתונים הצפוי בתצוגות של האפליקציה. לדוגמה, אם לאפליקציה יש תצוגה שמצפה לשם משתמש, השירות צריך לכלול מערך נתונים שמכיל שם משתמש ומנגנון מסוים כדי לדעת שהתצוגה מצפה לנתונים כאלה.

כדי להודיע לשירות איזה סוג נתונים צפוי בתצוגות, מגדירים את המאפיין android:autofillHints. בחלק מהשירותים נעשה שימוש בהיגוריית מתוחכמת כדי לקבוע את סוג הנתונים, אבל בשירותים אחרים, כמו האפליקציה לדוגמה, המפתח צריך לספק את המידע הזה. כדי שהאפליקציה תפעל טוב יותר עם שירותי מילוי אוטומטי, כדאי להגדיר את המאפיין android:autofillHints בתצוגות הרלוונטיות למילוי אוטומטי.

הרצת הבדיקה

אחרי שתנתחו את דרישות הנתונים, תוכלו להריץ את הבדיקה, שכוללת שמירת נתוני הבדיקה בשירות המילוי האוטומטי והפעלת המילוי האוטומטי באפליקציה.

שמירת נתונים בשירות

כדי לשמור נתונים בשירות המילוי האוטומטי הפעיל כרגע:

  1. פותחים אפליקציה שמכילה תצוגה שמתאימה לסוג הנתונים שבהם רוצים להשתמש במהלך הבדיקה. באפליקציית הדוגמה android-AutofillFramework, ממשק המשתמש כולל תצוגות שמתאימות למספר סוגי נתונים, כמו מספרי כרטיסי אשראי ושמות משתמשים.
  2. מקישים על התצוגה שמכילה את סוג הנתונים הרצוי.
  3. מזינים ערך בתצוגה.
  4. מקישים על לחצן האישור, למשל כניסה או שליחה. בדרך כלל צריך לשלוח את הטופס לפני שהשירות שומר את הנתונים.
  5. מאמתים את בקשת ההרשאה בתיבת הדו-שיח של המערכת. בתיבת הדו-שיח של המערכת יופיע שם השירות הפעיל כרגע, ותתבקשו לאשר שזה השירות שבו אתם רוצים להשתמש בבדיקה. אם רוצים להשתמש בשירות, מקישים על שמירה.

אם תיבת הדו-שיח של ההרשאה לא מוצגת ב-Android, או אם השירות הוא לא זה שבו אתם רוצים להשתמש בבדיקה, עליכם לבדוק אם השירות פעיל כרגע בהגדרות המערכת.

הפעלת מילוי אוטומטי באפליקציה

כדי להפעיל את המילוי האוטומטי באפליקציה, מבצעים את הפעולות הבאות:

  1. פותחים את האפליקציה ועוברים לפעילות שבה נמצאות התצוגות שרוצים לבדוק.
  2. מקישים על התצוגה שרוצים למלא.
  3. המערכת מציגה את ממשק המשתמש של המילוי האוטומטי, שמכיל את מערכי הנתונים שיכולים למלא את התצוגה, כפי שמוצג באיור 1.
  4. מקישים על מערך הנתונים שמכיל את הנתונים שבהם רוצים להשתמש. בתצוגה מוצגים הנתונים ששמורים בשירות.
ממשק משתמש של מילוי אוטומטי שבו מוצג 'dataset-2' כמערך נתונים זמין
איור 1. ממשק המשתמש של המילוי האוטומטי שבו מוצגים מערכי הנתונים הזמינים.

אם Android לא מציג את ממשק המשתמש של המילוי האוטומטי, תוכלו לנסות את האפשרויות הבאות לפתרון בעיות:

  • בודקים שהתצוגות באפליקציה משתמשות בערך הנכון במאפיין android:autofillHints. לרשימה של הערכים האפשריים למאפיין, אפשר לעיין בקבועים עם הקידומת AUTOFILL_HINT במחלקה View.
  • בודקים שהמאפיין android:importantForAutofill מוגדר לערך שאינו no בתצוגה שצריך למלא, או לערך שאינו noExcludeDescendants בתצוגה או באחד מההורים שלה.