בדיקת קישורי אפליקציות

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

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

בקטעים הבאים מוסבר איך לבדוק את האימות של קישורי האפליקציה באופן ידני. אם אתם מעדיפים, אתם יכולים לבדוק את האימות באמצעות הכלי 'קישורי עומק ב-Play' או באמצעות הכלי 'App Links Assistant' ב-Android Studio.

אישור רשימת המארחים לאימות

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

  • מאפיין android:scheme עם הערך http או https
  • מאפיין android:host עם תבנית של כתובת URL של דומיין
  • android.intent.action.VIEW רכיב פעולה
  • רכיב קטגוריה: android.intent.category.BROWSABLE

אפשר להשתמש ברשימה הזו כדי לוודא שקובץ JSON עם Digital Asset Links מסופק בכל מארח וסאבדומיין שמופיעים בה.

אישור קובצי Digital Asset Links

לכל אתר, משתמשים ב-Digital Asset Links API כדי לוודא שקובץ ה-JSON של Digital Asset Links מתארח ומוגדר בצורה תקינה:

https://digitalassetlinks.googleapis.com/v1/statements:list?
   source.web.site=https://<var>domain.name</var>:<var>optional_port</var>&amp;
   relation=delegate_permission/common.handle_all_urls

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

https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://www.example.com&relation=delegate_permission/common.handle_all_urls&return_relation_extensions=true

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

adb shell dumpsys package domain-preferred-apps

הפקודה הבאה מבצעת את אותה פעולה:

adb shell dumpsys package d

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

App linkages for user 0:

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

Package: com.android.vending
Domains: play.google.com market.android.com
Status: always : 200000002

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

  • Package – מזהה אפליקציה לפי שם החבילה שלה, כפי שמוצה בקובץ המניפסט שלה.
  • Domains – מציג את הרשימה המלאה של המארחים שהאפליקציה הזו מטפלת בקישורי האינטרנט שלהם, תוך שימוש ברווחים כתווי הפרדה.
  • Status – מציג את ההגדרה הנוכחית לטיפול בקישורים באפליקציה הזו. אם האפליקציה עברה אימות וקובץ המניפסט שלה מכיל android:autoVerify="true", הסטטוס שיוצג הוא always. המספר ההקסהדצימלי אחרי הסטטוס הזה קשור לרישום של מערכת Android של העדפות המשתמש לגבי קישור אפליקציות. הערך הזה לא מציין אם האימות הצליח.

דוגמה לבדיקה

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

<activity android:name="MainActivity">
        <intent-filter android:autoVerify="true">
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="https" />
            <data android:scheme="https" />
            <data android:host="www.example.com" />
            <data android:host="mobile.example.com" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="https" />
            <data android:host="www.example2.com" />
        </intent-filter>
    </activity>

    <activity android:name="SecondActivity">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="https" />
            <data android:host="account.example.com" />
        </intent-filter>
    </activity>

      <activity android:name="ThirdActivity">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="https" />
            <data android:host="map.example.com" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="market" />
            <data android:host="example.com" />
        </intent-filter>
      </activity>

</application>

רשימת המארחים שהפלטפורמה תנסה לאמת מהמניפסט הקודם היא:

www.example.com
mobile.example.com
www.example2.com
account.example.com

רשימת המארחים שהפלטפורמה לא תנסה לאמת מהמניפסט הקודם היא:

map.example.com (it does not have android.intent.category.BROWSABLE)
market://example.com (it does not have either an "http" or "https" scheme)

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

החל מ-Android 17, אפשר להשתמש בדגל --debug-link עם הפקודה של מנהל הפעילות (am start) כדי לאבחן איך המערכת פותרת כתובת URL ספציפית. הכלי הזה מספק פירוט של אפליקציות מועמדות שתאמו לכוונה, יחד עם הכללים הספציפיים מקובץ המניפסט של האפליקציה וקובץ assetlinks.json (לקישורים דינמיים לאפליקציות) שנבדקו במהלך הפתרון.

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

adb shell am start --debug-link -a android.intent.action.VIEW -d "https://xyz.com/foo"

פלט האבחון מודפס מתחת לכותרת App Link Resolution Debug ומכיל את הקטעים הבאים שיעזרו לכם להבין את תהליך הפתרון:

  • פרטי היעד: מזהה כל אפליקציה מתאימה לפי שם החבילה ופעילות היעד שלה.
  • התאמה של מסנן Intent (AndroidManifest.xml): מראה אילו מאפיינים סטטיים במסנן Intent של המניפסט (כמו scheme,‏ host,‏ path,‏ pathPrefix או pathPattern) תאמו ל-URI.
  • אימות קישורי עומק לאפליקציה: מוצג הסטטוס הנוכחי של אימות הדומיין (למשל STATE_SUCCESS).
  • קישורי עומק דינמיים לאפליקציה: אם האפליקציה משתמשת בכללי התאמה של קישורי עומק דינמיים לאפליקציה בקובץ assetlinks.json שלה, בקטע הזה מפורטים כל הכללים שנבדקו מול ה-URI. כל כלל מציין את מסנני ה-URI התואמים (כמו קידומות או תבניות של נתיבים) ואת השדה allow:
    • allow = 0: כלל הרשאה/הכללה (allow: true). אם הכלל הזה תואם, האפליקציה מקבלת הרשאה לפתוח את ה-URI.
    • allow = 1: כלל חסימה/החרגה (allow: false / exclude: true). אם הכלל הזה מתאים, האפליקציה לא יכולה לפתוח את ה-URI.
    • הערה: מחרוזת מסנן ריקה (filter =) מציינת קידומת נתיב ריקה שתואמת לכל הנתיבים בדומיין (פועלת כתו כללי או כהתאמה לכל).

פלט לדוגמה של ניפוי באגים

נניח שיש אפליקציה (com.example.xyzapp) שמשויכת לדומיין https://xyz.com ומגדירה כללים דינמיים בקובץ assetlinks.json כדי להחריג את /foo* ולאפשר את כל הנתיבים האחרים:

[
  {
    "relation": [
      "delegate_permission/common.handle_all_urls"
    ],
    "target": {
      "namespace": "android_app",
      "package_name": "com.example.xyzapp",
      "sha256_cert_fingerprints": ["..."]
    },
    "relation_extensions": {
      "delegate_permission/common.handle_all_urls": {
        "dynamic_app_link_components": [
          {"/": "/foo*", "exclude": true},
          {"/": "*"}
        ]
      }
    }
  }
]

כשמאבחנים את כתובת ה-URL https://xyz.com/foo באמצעות --debug-link:

adb shell am start --debug-link -a android.intent.action.VIEW -d "https://xyz.com/foo"

הפלט של הפקודה כולל את פירוט האבחון הבא:

--- App Link Resolution Debug ---

URI: https://xyz.com/foo
Resolution: Ambiguous (Multiple apps or Browser fallback)
This usually happens when multiple apps can handle the link and no default is set.

All Matching Candidates:

Target:
  Package: com.example.xyzapp
  Activity: com.example.xyzapp.MainActivity

  Intent Filter Match (AndroidManifest.xml)
    Scheme: 'https' matched android:scheme="https"
    Host: 'xyz.com' matched android:host="xyz.com"

App Link Verification:
  Verification status: STATE_SUCCESS
  Dynamic App Links:
    -> Matched Rule 0: UriRelativeFilterGroup { allow = 1, uri_filters = {UriRelativeFilter { uriPart = PATH, patternType = PREFIX, filter = /foo }},  }
    -> Matched Rule 1: UriRelativeFilterGroup { allow = 0, uri_filters = {UriRelativeFilter { uriPart = PATH, patternType = PREFIX, filter =  }},  }

Target:
  Package: org.chromium.webview_shell
  Activity: org.chromium.webview_shell.WebViewBrowserActivity

  Intent Filter Match (AndroidManifest.xml)
    Scheme: 'https' matched android:scheme="https"

---------------------------------

Starting: Intent { act=android.intent.action.VIEW dat=https://xyz.com/foo }

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

  • כלל 0 (allow = 1, filter = /foo): נוצר מתוך {"/": "/foo*", "exclude": true}, זהו כלל החרגה (allow: false) שחוסם כתובות URL שמתחילות בקידומת הנתיב /foo.
  • כלל 1 (allow = 0, filter =): נוצר מ-{"/": "*"}, זהו כלל הכללה (allow: true) עם קידומת נתיב ריקה (filter =), שתואם לכל הנתיבים ב-xyz.com (כלל כללי).

איך פועל הפתרון בתרחיש הזה:

  1. גם כלל 0 וגם כלל 1 תואמים לכתובת ה-URL https://xyz.com/foo.
  2. הערכת הכללים של קישורי עומק לאפליקציה דינמיים מתבצעת בסדר רציף מלמעלה למטה (הכלל הראשון שתואם הוא זה שמופעל).
  3. מכיוון שכלל 0 מופיע ראשון ברשימת ההצהרות והוא כלל החרגה (allow = 1), הוא מקבל עדיפות על פני כלל ההרשאה הכללי (כלל 1).
  4. לכן האפליקציה לא מטפלת ב-https://xyz.com/foo, והמערכת חוזרת לדפדפן או מציגה תיבת דו-שיח לביטול דו-משמעות.