التحقّق من روابط تطبيقات Android

رابط التطبيق المتوافق مع Android هو نوع خاص من الروابط لصفحات في التطبيق يتيح لعناوين URL الخاصة بموقعك الإلكتروني فتح المحتوى ذي الصلة في تطبيق Android على الفور، بدون أن يضطر المستخدم إلى اختيار التطبيق. تستخدم روابط التطبيقات المتوافقة مع Android واجهة برمجة التطبيقات Digital Asset Links لإثبات أنّ موقعك الإلكتروني قد وافق على فتح الروابط تلقائيًا لهذا النطاق في تطبيقك. إذا تحقّق النظام بنجاح من أنّك تملك عناوين URL، سيوّجه النظام تلقائيًا طلبات البحث عن عناوين URL هذه إلى تطبيقك.

لإثبات ملكيتك لكل من تطبيقك وعناوين URL للموقع الإلكتروني، أكمِل الخطوات التالية:

  1. أضِف فلاتر أهداف تحتوي على السمة autoVerify. تشير هذه السمة إلى النظام بأنّه يجب التحقّق مما إذا كان تطبيقك ينتمي إلى نطاقات عناوين URL المستخدَمة في فلاتر الأهداف.

  2. حدِّد الربط بين موقعك الإلكتروني وفلاتر الأهداف من خلال استضافة ملف JSON الذي يحتوي على روابط تنقل إلى مواد عرض رقمية في الموقع التالي:

    https://domain.name/.well-known/assetlinks.json

يمكنك العثور على معلومات ذات صلة في المَراجع التالية:

إضافة فلاتر الأهداف للتحقّق من روابط التطبيق

لتفعيل عملية التحقّق من إمكانية معالجة الروابط في تطبيقك، أضِف فلاتر الأهداف التي تتطابق مع التنسيق التالي:

<!-- Make sure you explicitly set android:autoVerify to "true". -->
<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" />

    <!-- If a user clicks on a shared link that uses the "http" scheme, your
         app should be able to delegate that traffic to "https". -->
    <!-- Do not include other schemes. -->
    <data android:scheme="http" />
    <data android:scheme="https" />

    <!-- Include one or more domains that should be verified. -->
    <data android:host="..." />
</intent-filter>

على الرغم من أنّه يكفي تضمين autoVerify في بيان <intent-filter> واحد فقط لكل مضيف، حتى إذا كان هذا المضيف مستخدَمًا في بيانات أخرى غير موسومة، ننصحك بإضافة autoVerify إلى كل عنصر <intent-filter> للحفاظ على الاتساق. يضمن ذلك أيضًا أن يظل تطبيقك مرتبطًا بجميع النطاقات التي لا تزال تحدّدها بعد إزالة العناصر أو إعادة هيكلتها في ملف البيان.

تتطلّب عملية إثبات ملكية النطاق الاتصال بالإنترنت وقد تستغرق بعض الوقت. للمساعدة في تحسين كفاءة العملية، يتحقّق النظام من صحة نطاق لتطبيق يستهدف الإصدار 12 من نظام التشغيل Android أو الإصدارات الأحدث فقط إذا كان هذا النطاق ضِمن عنصر <intent-filter> يحتوي على التنسيق الدقيق المحدّد في مقتطف الرمز السابق. على سبيل المثال، ستؤدي المخططات بخلاف "http" و "https"، مثل <data android:scheme="custom" />، إلى منع <intent-filter> من بدء عملية إثبات ملكية النطاق.

إتاحة ربط التطبيقات بمواقع إلكترونية متعددة

يجب أن يتمكّن النظام من التحقّق من المضيف المحدّد في عناصر البيانات الخاصة بفلاتر الأهداف الخاصة بعناوين URL للتطبيقات، وذلك من خلال مقارنتها بملفات Digital Asset Links المستضافة على نطاقات الويب المعنية في فلتر الأهداف هذا. وفي حال تعذُّر إثبات الملكية، يعود النظام إلى سلوكه العادي لتنفيذ الغرض، كما هو موضّح في مقالة إنشاء روابط لصفحات معيّنة في التطبيق. ومع ذلك، سيظل بإمكانك إثبات ملكية التطبيق كمعالج تلقائي لأي من أنماط عناوين URL المحدّدة في فلاتر intent الأخرى الخاصة بالتطبيق.

ملاحظة: على نظام التشغيل Android 11 (المستوى 30 لواجهة برمجة التطبيقات) والإصدارات الأقدم، لا يتحقّق النظام من أنّ تطبيقك هو المعالج التلقائي إلا إذا عثر على ملف روابط التنقل إلى مواد العرض الرقمية مطابق لجميع المضيفين الذين تحدّدهم في ملف البيان.

على سبيل المثال، لن يجتاز تطبيق يتضمّن فلاتر الأهداف التالية عملية التحقّق إلا بالنسبة إلى https://www.example.com إذا تم العثور على ملف assetlinks.json في https://www.example.com/.well-known/assetlinks.json وليس في https://www.example.net/.well-known/assetlinks.json:

<application>

  <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="http" />
      <data android:scheme="https" />
      <data android:host="www.example.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="www.example.net" />
    </intent-filter>
  </activity>

</application>

ملاحظة: يتم دمج جميع عناصر <data> في فلتر الأهداف نفسه معًا لاحتساب جميع أشكال سماتها المجمّعة. على سبيل المثال، يتضمّن فلتر الأهداف الأول أعلاه عنصر <data> يعرّف مخطط HTTPS فقط. ولكن يتم دمجه مع عنصر <data> الآخر لكي يتيح فلتر الأهداف كلاً من http://www.example.com وhttps://www.example.com. وبناءً على ذلك، يجب إنشاء فلاتر أهداف منفصلة عند تحديد مجموعات معيّنة من مخططات URI والنطاقات.

إتاحة ربط التطبيقات بنطاقات فرعية متعددة

يتعامل بروتوكول Digital Asset Links مع النطاقات الفرعية في فلاتر الأهداف على أنّها مضيفات فريدة ومنفصلة. لذلك، إذا كان فلتر الأهداف يتضمّن عدة مضيفين بنطاقات فرعية مختلفة، عليك نشر ملف assetlinks.json صالح على كل نطاق. على سبيل المثال، يتضمّن فلتر الأهداف التالي www.example.com وmobile.example.com كمضيفَين مقبولَين لعنوان URL الخاص بالهدف. لذلك، يجب نشر assetlinks.json صالح في كل من https://www.example.com/.well-known/assetlinks.json وhttps://mobile.example.com/.well-known/assetlinks.json.

<application>
  <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>
  </activity>
</application>

بدلاً من ذلك، إذا حدّدت اسم المضيف باستخدام حرف بدل (مثل *.example.com)، عليك نشر ملف assetlinks.json في اسم المضيف الجذر (example.com). على سبيل المثال، سيتجاوز تطبيق يتضمّن فلتر الأهداف التالي عملية التحقّق لأي اسم فرعي من example.com (مثل foo.example.com) طالما تم نشر ملف assetlinks.json في https://example.com/.well-known/assetlinks.json:

<application>
  <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:host="*.example.com" />
    </intent-filter>
  </activity>
</application>

التحقّق من وجود تطبيقات متعدّدة مرتبطة بالنطاق نفسه

إذا نشرت تطبيقات متعددة يرتبط كل منها بالنطاق نفسه، يمكن إثبات ملكية كل تطبيق بنجاح. ومع ذلك، إذا كانت التطبيقات يمكنها تحديد المضيف والمسار نفسهما للنطاق، كما هو الحال مع الإصدارات المخفّفة والكاملة من التطبيق، لن يتمكّن سوى التطبيق الذي تم تثبيته مؤخرًا من تحديد طلبات البحث على الويب لهذا النطاق.

في مثل هذه الحالة، تحقَّق من التطبيقات التي قد تتعارض مع بعضها على جهاز المستخدم، شرط أن يكون لديك إذن الوصول إلى حزمة التطبيق اللازم. بعد ذلك، في تطبيقك، اعرض مربّع حوار مخصّصًا لاختيار التطبيق يتضمّن النتائج التي تم الحصول عليها من خلال استدعاء queryIntentActivities(). يمكن للمستخدم اختيار التطبيق المفضّل من قائمة التطبيقات المطابقة التي تظهر في مربّع الحوار.

تحديد عمليات الربط بالمواقع الإلكترونية

يجب نشر ملف بتنسيق JSON لروابط التنقل إلى مواد العرض الرقمية على موقعك الإلكتروني للإشارة إلى تطبيقات Android المرتبطة بالموقع الإلكتروني والتحقّق من صحة نوايا عناوين URL للتطبيق. يستخدم ملف JSON الحقول التالية لتحديد التطبيقات المرتبطة:

  • package_name: معرّف التطبيق المحدّد في ملف build.gradle الخاص بالتطبيق
  • sha256_cert_fingerprints: الملفات المرجعية لخوارزمية SHA256 لشهادة توقيع تطبيقك يمكنك استخدام الأمر التالي لإنشاء بصمة الإصبع من خلال أداة keytool في Java:
    keytool -list -v -keystore my-release-key.keystore
    
    يتيح هذا الحقل استخدام بصمات متعددة يمكن استخدامها لتوفير الدعم لإصدارات مختلفة من تطبيقك، مثل إصدارات تصحيح الأخطاء وإصدارات الإنتاج.

    إذا كنت تستخدم خدمة "توقيع التطبيق" من Play لتطبيقك، لن يتطابق ملف الشهادة المرجعي الذي يتم إنشاؤه من خلال تنفيذ keytool محليًا مع الملف الموجود على أجهزة المستخدمين. يمكنك التحقّق مما إذا كنت تستخدم ميزة "توقيع التطبيق" من Play لتطبيقك في حساب المطوِّر الخاص بك على Play Console ضمن Release > Setup > App signing. وفي حال استخدامها، ستعثر أيضًا على المقتطف الصحيح لملف JSON الخاص بروابط التنقل إلى مواد العرض الرقمية لتطبيقك في الصفحة نفسها.

يمنح ملف المثال التالي assetlinks.json حقوق فتح الروابط إلى تطبيق Android com.example:

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example",
    "sha256_cert_fingerprints":
    ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
  }
}]

ربط موقع إلكتروني بعدة تطبيقات

يمكن للموقع الإلكتروني الإعلان عن عمليات ربط بتطبيقات متعددة ضمن ملف assetlinks.json نفسه. تعرض قائمة الملفات التالية مثالاً لملف بيان يوضّح الربط بتطبيقَين بشكل منفصل، ويقع في https://www.example.com/.well-known/assetlinks.json:

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example.puppies.app",
    "sha256_cert_fingerprints":
    ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
  }
  },
  {
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example.monkeys.app",
    "sha256_cert_fingerprints":
    ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
  }
}]

قد تتعامل تطبيقات مختلفة مع روابط لموارد مختلفة ضمن مضيف الويب نفسه. على سبيل المثال، قد يعلن التطبيق 1 عن فلتر هدف لـ https://example.com/articles، وقد يعلن التطبيق 2 عن فلتر هدف لـ https://example.com/videos.

ملاحظة: قد يتم توقيع تطبيقات متعددة مرتبطة بنطاق باستخدام الشهادة نفسها أو شهادات مختلفة.

ربط مواقع إلكترونية متعدّدة بتطبيق واحد

يمكن أن تعلن مواقع إلكترونية متعددة عن ارتباطها بالتطبيق نفسه في ملفات assetlinks.json الخاصة بها. توضّح القوائم التالية للملفات مثالاً على كيفية الإفصاح عن الربط بين example.com وexample.net بالتطبيق app1. تعرض البطاقة الأولى عملية الربط بين example.com وapp1:

https://www.example.com/.well-known/assetlinks.json

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.mycompany.app1",
    "sha256_cert_fingerprints":
    ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
  }
}]

تعرض البطاقة التالية ربط example.net بتطبيق app1. يختلف فقط الموقع الذي تتم استضافة هذه الملفات فيه (.com و.net):

https://www.example.net/.well-known/assetlinks.json

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.mycompany.app1",
    "sha256_cert_fingerprints":
    ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
  }
}]

نشر ملف التحقّق بتنسيق JSON

يجب نشر ملف إثبات صحة JSON في الموقع التالي:

https://domain.name/.well-known/assetlinks.json

يُرجى التأكّد مما يلي:

  • يتم عرض الملف assetlinks.json مع نوع المحتوى application/json.
  • يجب أن يكون ملف assetlinks.json قابلاً للوصول إليه عبر اتصال HTTPS، بغض النظر عمّا إذا كانت فلاتر الأهداف في تطبيقك تحدّد HTTPS كمخطط للبيانات.
  • يجب أن يكون ملف assetlinks.json قابلاً للوصول إليه بدون أي عمليات إعادة توجيه (بدون عمليات إعادة توجيه 301 أو 302).
  • إذا كانت روابط تطبيقك تتيح استخدام نطاقات مضيفة متعددة، عليك نشر ملف assetlinks.json على كل نطاق. اطّلِع على إتاحة ربط التطبيقات بمضيفين متعدّدين.
  • يُرجى عدم نشر تطبيقك مع عناوين URL خاصة بالتطوير/الاختبار في ملف البيان قد لا تكون متاحة للجميع (مثل أي عناوين URL لا يمكن الوصول إليها إلا من خلال شبكة VPN). في مثل هذه الحالات، يمكنك ضبط صيغ الإنشاء لإنشاء ملف بيان مختلف لإصدارات التطبيق المخصّصة للمطوّرين.

التحقّق من روابط التطبيقات المتوافقة مع Android

عندما تكون السمة android:autoVerify="true" متوفّرة في فلتر واحد على الأقل من فلاتر الأهداف في تطبيقك، يؤدي تثبيت تطبيقك على جهاز يعمل بالإصدار 6.0 من نظام التشغيل Android (المستوى 23 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث إلى أن يتحقّق النظام تلقائيًا من المضيفين المرتبطين بعناوين URL في فلاتر الأهداف في تطبيقك. على نظام التشغيل Android 12 والإصدارات الأحدث، يمكنك أيضًا بدء عملية إثبات الهوية يدويًا لاختبار منطق إثبات الهوية.

التحقّق التلقائي

تتضمّن عملية التحقّق التلقائي من النظام ما يلي:

  1. يفحص النظام جميع فلاتر الأهداف التي تتضمّن أيًا مما يلي:
    • الإجراء: android.intent.action.VIEW
    • الفئات: android.intent.category.BROWSABLE وandroid.intent.category.DEFAULT
    • مخطط البيانات: http أو https
  2. بالنسبة إلى كل اسم مضيف فريد تم العثور عليه في فلاتر الأهداف أعلاه، يطلب نظام التشغيل Android ملف Digital Asset Links من المواقع الإلكترونية المقابلة على https://hostname/.well-known/assetlinks.json.

بعد تأكيد قائمة المواقع الإلكترونية التي تريد ربطها بتطبيقك، وبعد التأكّد من أنّ ملف JSON المستضاف صالح، ثبِّت التطبيق على جهازك. انتظِر لمدة 20 ثانية على الأقل كي تكتمل عملية إثبات الهوية غير المتزامنة. استخدِم الأمر التالي للتحقّق مما إذا كان النظام قد تحقّق من تطبيقك وضبط سياسات معالجة الروابط الصحيحة:

adb shell am start -a android.intent.action.VIEW \
    -c android.intent.category.BROWSABLE \
    -d "http://domain.name:optional_port"

التحقّق اليدوي

بدءًا من الإصدار 12 من نظام التشغيل Android، يمكنك تفعيل عملية إثبات ملكية النطاق يدويًا لتطبيق مثبَّت على جهاز. يمكنك تنفيذ هذه العملية بغض النظر عمّا إذا كان تطبيقك يستهدف الإصدار 12 من نظام التشغيل Android.

الاتصال بالإنترنت

لإثبات ملكية النطاق، يجب أن يكون جهاز الاختبار متصلاً بالإنترنت.

إتاحة عملية إثبات ملكية النطاق المعدَّلة

إذا كان تطبيقك يستهدف الإصدار 12 من نظام التشغيل Android أو الإصدارات الأحدث، سيستخدم النظام تلقائيًا عملية إثبات ملكية النطاق المعدَّلة.

ويمكنك بدلاً من ذلك تفعيل عملية تأكيد الحساب المعدَّلة يدويًا. لإجراء ذلك، نفِّذ الأمر التالي في نافذة الوحدة الطرفية:

adb shell am compat enable 175408749 PACKAGE_NAME

إعادة ضبط حالة "روابط تطبيقات Android" على جهاز

قبل تفعيل عملية تأكيد النطاق يدويًا على أحد الأجهزة، عليك إعادة ضبط حالة &quot;روابط تطبيقات Android&quot; على الجهاز الاختباري. لإجراء ذلك، نفِّذ الأمر التالي في نافذة الوحدة الطرفية:

adb shell pm set-app-links --package PACKAGE_NAME 0 all

يضع هذا الأمر الجهاز في الحالة نفسها التي كان عليها قبل أن يختار المستخدم التطبيقات التلقائية لأي نطاقات.

بدء عملية تأكيد النطاق

بعد إعادة ضبط حالة "روابط تطبيقات Android" على أحد الأجهزة، يمكنك إجراء عملية التحقّق نفسها. لإجراء ذلك، نفِّذ الأمر التالي في نافذة الوحدة الطرفية:

adb shell pm verify-app-links --re-verify PACKAGE_NAME

مراجعة نتائج إثبات الملكية

بعد السماح لوكيل التحقّق بإنهاء طلباته، راجِع نتائج التحقّق. لإجراء ذلك، شغِّل الأمر التالي:

adb shell pm get-app-links PACKAGE_NAME

يكون ناتج هذا الأمر مشابهًا لما يلي:

com.example.pkg:
    ID: 01234567-89ab-cdef-0123-456789abcdef
    Signatures: [***]
    Domain verification state:
      example.com: verified
      sub.example.com: legacy_failure
      example.net: verified
      example.org: 1026

النطاقات التي تجتاز عملية إثبات الملكية بنجاح تكون حالة إثبات ملكية النطاق فيها verified. تشير أي حالة أخرى إلى أنّه تعذّر إثبات ملكية النطاق. على وجه الخصوص، تشير الحالة none إلى أنّ وكيل التحقّق ربما لم يكمل عملية التحقّق بعد.

تعرض القائمة التالية قيم العائد المحتملة التي يمكن أن تعرضها عملية إثبات ملكية النطاق لنطاق معيّن:

none
لم يتم تسجيل أي شيء لهذا النطاق. انتظِر بضع دقائق إضافية إلى أن ينهي وكيل التأكيد الطلبات المتعلقة بتأكيد النطاق، ثم ابدأ عملية تأكيد النطاق مرة أخرى.
verified
تم إثبات ملكية النطاق بنجاح للتطبيق المعلِن.
approved
تمت الموافقة على النطاق بشكل إلزامي، وعادةً ما يتم ذلك من خلال تنفيذ أمر shell.
denied
تم رفض النطاق بشكل إجباري، وعادةً ما يتم ذلك من خلال تنفيذ أمر shell.
migrated
احتفظ النظام بنتيجة عملية سابقة استخدمت طريقة التحقّق القديمة من النطاق.
restored
تمت الموافقة على النطاق بعد أن نفّذ المستخدم عملية استعادة البيانات. يُفترض أنّه تم إثبات ملكية النطاق من قبل.
legacy_failure
رفضت أداة التحقّق القديمة النطاق. سبب تعذّر النقل غير معروف.
system_configured
تمت الموافقة على النطاق تلقائيًا من خلال إعدادات الجهاز.
رمز الخطأ 1024 أو أكبر

رمز خطأ مخصّص خاص بأداة التحقّق من الجهاز.

يُرجى التأكّد من إنشاء اتصال بالشبكة، ثم تكرار عملية إثبات ملكية النطاق.

أن تطلب من المستخدم ربط تطبيقك بنطاق

هناك طريقة أخرى للحصول على الموافقة على استخدام نطاق معيّن في تطبيقك، وهي أن تطلب من المستخدم ربط تطبيقك بهذا النطاق.

التحقّق مما إذا تمت الموافقة على تطبيقك من قبل للنطاق

قبل أن تطلب من المستخدم ذلك، تحقَّق مما إذا كان تطبيقك هو المعالج التلقائي للنطاقات التي تحدّدها في عناصر <intent-filter>. يمكنك طلب حالة الموافقة باستخدام إحدى الطرق التالية:

DomainVerificationManager

يوضّح مقتطف الرمز التالي كيفية استخدام واجهة برمجة التطبيقات DomainVerificationManager:

Kotlin

val context: Context = TODO("Your activity or fragment's Context")
val manager = context.getSystemService(DomainVerificationManager::class.java)
val userState = manager.getDomainVerificationUserState(context.packageName)

// Domains that have passed Android App Links verification.
val verifiedDomains = userState?.hostToStateMap
    ?.filterValues { it == DomainVerificationUserState.DOMAIN_STATE_VERIFIED }

// Domains that haven't passed Android App Links verification but that the user
// has associated with an app.
val selectedDomains = userState?.hostToStateMap
    ?.filterValues { it == DomainVerificationUserState.DOMAIN_STATE_SELECTED }

// All other domains.
val unapprovedDomains = userState?.hostToStateMap
    ?.filterValues { it == DomainVerificationUserState.DOMAIN_STATE_NONE }

Java

Context context = TODO("Your activity or fragment's Context");
DomainVerificationManager manager =
        context.getSystemService(DomainVerificationManager.class);
DomainVerificationUserState userState =
        manager.getDomainVerificationUserState(context.getPackageName());

Map<String, Integer> hostToStateMap = userState.getHostToStateMap();
List<String> verifiedDomains = new ArrayList<>();
List<String> selectedDomains = new ArrayList<>();
List<String> unapprovedDomains = new ArrayList<>();
for (String key : hostToStateMap.keySet()) {
    Integer stateValue = hostToStateMap.get(key);
    if (stateValue == DomainVerificationUserState.DOMAIN_STATE_VERIFIED) {
        // Domain has passed Android App Links verification.
        verifiedDomains.add(key);
    } else if (stateValue == DomainVerificationUserState.DOMAIN_STATE_SELECTED) {
        // Domain hasn't passed Android App Links verification, but the user has
        // associated it with an app.
        selectedDomains.add(key);
    } else {
        // All other domains.
        unapprovedDomains.add(key);
    }
}

برنامج سطر الأوامر

عند اختبار تطبيقك أثناء عملية التطوير، يمكنك تنفيذ الأمر التالي للاستعلام عن حالة التحقّق من النطاقات التي تملكها مؤسستك:

adb shell pm get-app-links --user cur PACKAGE_NAME

في المثال التالي، على الرغم من تعذُّر إثبات ملكية التطبيق للنطاق "example.org"، وافق المستخدم 0 يدويًا على التطبيق في إعدادات النظام، ولم يتم إثبات ملكية أي حزمة أخرى لهذا النطاق.

com.example.pkg:
ID: ***
Signatures: [***]
Domain verification state:
  example.com: verified
  example.net: verified
  example.org: 1026
User 0:
  Verification link handling allowed: true
  Selection state:
    Enabled:
      example.org
    Disabled:
      example.com
      example.net

يمكنك أيضًا استخدام أوامر shell لمحاكاة العملية التي يختار فيها المستخدم التطبيق المرتبط بنطاق معيّن. يمكنك الاطّلاع على شرح كامل لهذه الأوامر من خلال ناتج adb shell pm.

توفير سياق للطلب

قبل تقديم طلب الموافقة على النطاق، قدِّم بعض المعلومات الأساسية للمستخدم. على سبيل المثال، يمكنك عرض شاشة البداية أو مربّع حوار أو عنصر مشابه لواجهة المستخدم يوضّح للمستخدم سبب وجوب أن يكون تطبيقك هو المعالج التلقائي لنطاق معيّن.

تقديم الطلب

بعد أن يفهم المستخدم ما يطلبه منه تطبيقك، قدِّم الطلب. لإجراء ذلك، استدعِ هدفًا يتضمّن ACTION_APP_OPEN_BY_DEFAULT_SETTINGS إجراء الهدف وسلسلة بيانات تطابق package:com.example.pkg للتطبيق المستهدف، كما هو موضّح في مقتطف الرمز التالي:

Kotlin

val context: Context = TODO("Your activity or fragment's Context")
val intent = Intent(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS,
    Uri.parse("package:${context.packageName}"))
context.startActivity(intent)

Java

Context context = TODO("Your activity or fragment's Context");
Intent intent = new Intent(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS,
    Uri.parse("package:" + context.getPackageName()));
context.startActivity(intent);

عندما يتم استدعاء الغرض، تظهر للمستخدمين شاشة إعدادات باسم الفتح تلقائيًا. تحتوي هذه الشاشة على زر اختيار باسم فتح الروابط المتوافقة، كما هو موضّح في الشكل 1.

عندما يفعّل المستخدم خيار فتح الروابط المتوافقة، تظهر مجموعة من مربّعات الاختيار ضمن قسم بعنوان الروابط التي سيتم فتحها في هذا التطبيق. ومن هنا، يمكن للمستخدمين اختيار النطاقات التي يريدون ربطها بتطبيقك. ويمكنهم أيضًا النقر على إضافة رابط لإضافة نطاقات، كما هو موضّح في الشكل 2. عندما يختار المستخدمون لاحقًا أي رابط ضمن النطاقات التي يضيفونها، سيتم فتح الرابط في تطبيقك تلقائيًا.

عند تفعيل زر الاختيار، يظهر قسم بالقرب من أسفل الصفحة يتضمّن مربّعات اختيار بالإضافة إلى زر باسم &quot;إضافة رابط&quot;.
الشكل 1. شاشة إعدادات النظام التي يمكن للمستخدمين من خلالها اختيار الروابط التي يتم فتحها في تطبيقك تلقائيًا
يمثّل كل مربّع اختيار نطاقًا يمكنك إضافته. يحتوي مربّع الحوار على الزرَّين &quot;إلغاء&quot; و&quot;إضافة&quot;.
الشكل 2. مربّع حوار يمكن للمستخدمين من خلاله اختيار نطاقات إضافية لربطها بتطبيقك.

نطاقات مفتوحة في تطبيقك لا يمكن لتطبيقك إثبات ملكيتها

قد تكون الوظيفة الرئيسية لتطبيقك هي فتح الروابط كجهة خارجية، بدون إمكانية التحقّق من النطاقات التي يتعامل معها. في هذه الحالة، عليك توضيح للمستخدمين أنّه عند النقر على رابط ويب، لن يتمكّنوا من الاختيار بين تطبيق تابع للجهة الأولى وتطبيقك (التابع لجهة خارجية)، بل عليهم ربط النطاقات يدويًا بتطبيقك التابع لجهة خارجية.

بالإضافة إلى ذلك، ننصحك بعرض مربّع حوار أو نشاط "القفز" يتيح للمستخدم فتح الرابط في تطبيق الطرف الأول إذا كان يفضّل ذلك، ما يجعله يعمل كخادم وكيل. قبل إعداد مربع حوار أو نشاط "ترامبولين"، يجب إعداد تطبيقك ليتضمّن إذن الوصول إلى الحزمة للتطبيقات التابعة للجهة الأولى التي تتطابق مع فلتر الأهداف على الويب في تطبيقك.

اختبار روابط التطبيقات

عند تنفيذ ميزة ربط التطبيق، يجب اختبار وظيفة الربط للتأكّد من أنّ النظام يمكنه ربط تطبيقك بمواقعك الإلكترونية والتعامل مع طلبات عناوين URL على النحو المتوقّع.

لاختبار ملف بيان حالي، يمكنك استخدام أداة إنشاء قائمة البيانات واختبارها.

تأكيد قائمة المضيفين المطلوب إثبات ملكيتهم

عند إجراء الاختبار، عليك التأكّد من قائمة المضيفين المرتبطين التي يجب أن يتحقّق منها النظام لتطبيقك. أنشئ قائمة بجميع عناوين URL التي تتضمّن فلاتر الأهداف المقابلة السمات والعناصر التالية:

  • السمة android:scheme مع القيمة http أو https
  • السمة android:host التي تتضمّن نمط عنوان URL للنطاق
  • عنصر الإجراء android.intent.action.VIEW
  • عنصر الفئة android.intent.category.BROWSABLE

استخدِم هذه القائمة للتأكّد من توفير ملف بتنسيق JSON يتضمّن روابط تنقل إلى مواد عرض رقمية على كل مضيف ونطاق فرعي محدّدَين.

تأكيد ملفات Digital Asset Links

بالنسبة إلى كل موقع إلكتروني، استخدِم واجهة برمجة التطبيقات Digital Asset Links للتأكّد من أنّ ملف JSON الخاص بروابط التنقل إلى مواد العرض الرقمية مستضاف ومحدّد بشكل صحيح:

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

في إطار عملية الاختبار، يمكنك التحقّق من إعدادات النظام الحالية للتعامل مع الروابط. استخدِم الأمر التالي للحصول على قائمة بسياسات معالجة الروابط الحالية لجميع التطبيقات على جهازك المتصل:

adb shell dumpsys package domain-preferred-apps

أو يمكن استخدام ما يلي لتنفيذ الإجراء نفسه:

adb shell dumpsys package d

ملاحظة: احرص على الانتظار لمدة 20 ثانية على الأقل بعد تثبيت تطبيقك للسماح للنظام بإكمال عملية التحقّق.

يعرض الأمر قائمة بكل مستخدم أو ملف شخصي محدّد على الجهاز، ويسبقها عنوان بالتنسيق التالي:

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 الخاص بالإعدادات المفضّلة لربط التطبيقات لدى المستخدم. لا تشير هذه القيمة إلى ما إذا كانت عملية التحقّق قد نجحت.

ملاحظة: إذا غيَّر المستخدم إعدادات روابط التطبيقات لتطبيق معيّن قبل اكتمال عملية التحقّق، قد تظهر لك نتيجة إيجابية خاطئة لعملية تحقّق ناجحة، حتى إذا تعذّر إكمال عملية التحقّق. ومع ذلك، لا يهم تعذُّر إكمال عملية التحقّق هذه إذا فعّل المستخدم صراحةً إمكانية فتح التطبيق للروابط المتوافقة بدون طلب ذلك. ويرجع ذلك إلى أنّ الإعدادات المفضَّلة للمستخدم تحظى بالأولوية على عملية التحقّق الآلية (أو عدم توفّرها). نتيجةً لذلك، سينتقل المستخدم مباشرةً إلى تطبيقك بدون ظهور مربّع حوار، كما لو كان قد تم إثبات الملكية بنجاح.

مثال على الاختبار

لكي تنجح عملية التحقّق من روابط التطبيقات، يجب أن يتمكّن النظام من التحقّق من تطبيقك باستخدام كل المواقع الإلكترونية التي تحدّدها في فلتر intent معيّن يستوفي معايير روابط التطبيقات. يوضّح المثال التالي إعدادات البيان التي تتضمّن العديد من روابط التطبيق المحدّدة:

<application>

    <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، تحقَّق من الأخطاء الشائعة التالية. يستخدم هذا القسم example.com كاسم نطاق نائب. عند إجراء عمليات التحقّق هذه، استبدِل example.com باسم النطاق الفعلي للخادم.

إعداد فلتر intent غير صحيح
تحقَّق مما إذا كنت قد أدرجت عنوان URL لا يملكه تطبيقك في عنصر <intent-filter>.
إعدادات الخادم غير صحيحة

تحقَّق من إعدادات JSON الخاصة بالخادم، وتأكَّد من أنّ قيمة SHA صحيحة.

عليك أيضًا التأكّد من أنّ example.com. (مع النقطة الأخيرة) يعرض المحتوى نفسه الذي يعرضه example.com.

عمليات إعادة التوجيه من جهة الخادم

لا يتحقّق النظام من أي روابط لتطبيقات Android في تطبيقك إذا أعددت عملية إعادة توجيه مثل ما يلي:

  • من ‎http://example.com إلى ‎https://example.com
  • من ‎example.com إلى ‎www.example.com

ويحمي هذا السلوك أمان تطبيقك.

متانة الخادم

تحقَّق مما إذا كان بإمكان الخادم الاتصال بتطبيقات العميل.

الروابط التي لا يمكن التحقّق منها

لأغراض الاختبار، يمكنك إضافة روابط لا يمكن التحقّق منها عن قصد. يُرجى العِلم أنّه على نظام التشغيل Android 11 والإصدارات الأقدم، تؤدي هذه الروابط إلى عدم تحقّق النظام من جميع روابط التطبيقات على Android لتطبيقك.

توقيع غير صحيح في ملف assetlinks.json

تأكَّد من أنّ توقيعك صحيح ويتطابق مع التوقيع المستخدَم لتوقيع تطبيقك. تشمل الأخطاء الشائعة ما يلي:

  • توقيع التطبيق باستخدام شهادة تصحيح الأخطاء وتضمين توقيع الإصدار فقط في assetlinks.json
  • أن يكون لديك توقيع بأحرف صغيرة في assetlinks.json يجب أن يكون التوقيع بالأحرف الكبيرة.
  • إذا كنت تستخدم ميزة "توقيع التطبيق" من Play، تأكَّد من استخدام التوقيع الذي تستخدمه Google لتوقيع كل إصدار من إصداراتك. يمكنك التحقّق من هذه التفاصيل، بما في ذلك مقتطف JSON كامل، باتّباع التعليمات حول تحديد المواقع الإلكترونية المرتبطة.