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

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

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

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

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

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

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

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

הצגת רמזים למילוי אוטומטי

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

אפשר להגדיר רמזים למילוי אוטומטי באמצעות המאפיין 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.

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

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

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

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

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

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

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

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

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

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

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

לפעמים צריך לכפות על בקשת מילוי אוטומטי להתרחש בתגובה לפעולת משתמש. לדוגמה, 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);
}

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

מקרים דומים הם תצוגות שמשתמשות במתאם, כמו Spinner. לדוגמה, רכיב 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 שהאפליקציה יכולה להשתמש בו עם תצוגות וירטואליות. המצבים הזמינים מוגדרים כקבועים בקריאה החוזרת.

אפשר לרשום קריאה חוזרת באמצעות ה-method‏ registerCallback() של המחלקה AutofillManager. בדוגמת הקוד הבאה מוצג אופן ההצהרה על קריאה חוזרת לאירועי מילוי אוטומטי:

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;
        }
    }
});

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

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

כשמערכת הפלטפורמה ממלאת תצוגה באופן אוטומטי, היא מציגה מעליה את הסמל Drawable כדי לציין שהתוכן שלה מולא באופן אוטומטי. כברירת מחדל, רכיב ה-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) וב-8.1 (רמת API‏ 27), המילוי האוטומטי עלול לגרום לקריסת האפליקציה בתרחישים מסוימים. כדי לעקוף בעיות אפשריות, צריך לתייג את כל הצפיות שלא מתמלאות אוטומטית באמצעות importantForAutofill=no. אפשר גם לתייג את כל הפעילות באמצעות importantForAutofill=noExcludeDescendants.

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

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

כדי לפתור את הבעיה הזו, צריך להחליף את המאפיין token של הפרמטרים של חלון הדו-שיח במאפיין token של הפעילות שיצרה את הדו-שיח. אחרי שמוודאים שההשלמה האוטומטית מופעלת, שומרים את פרמטרים של החלון בשיטה 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 בתצוגה או באחת מהתצוגות ברמת ההורה.