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

رابط تطبيق Android هو نوع خاص من الروابط المؤدية إلى صفحات في التطبيق يسمح لعناوين URL لموقعك الإلكتروني بفتح المحتوى المقابل على الفور في تطبيق Android، بدون طلب من المستخدم اختيار التطبيق. وتستخدم ميزة Android App 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". -->
    <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> يحتوي على التنسيق الدقيق المحدّد في مقتطف الرمز السابق.

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

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

ملاحظة: في الإصدار 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).

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

يتعامل بروتوكول "روابط مواد العرض الرقمية" مع النطاقات الفرعية في فلاتر الأهداف كمضيفين فريدين ومنفصلين. وبالتالي، إذا كان فلتر الأهداف يُدرج مضيفين متعددين بنطاقات فرعية مختلفة، يجب نشر 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 لشهادة توقيع تطبيقك ويمكنك استخدام الأمر التالي لإنشاء بصمة الإصبع من خلال أداة مفاتيح 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"]
  }
}]

يمكن لتطبيقات مختلفة معالجة روابط موارد مختلفة ضمن مضيف الويب نفسه. على سبيل المثال، قد يفصح app1 عن فلتر أهداف للسمة https://example.com/articles، وقد يعلن app2 عن فلتر أهداف لـ 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 خاصة بمطوّري البرامج أو الاختبار في ملف البيان لا يمكن للجمهور الوصول إليه (مثل أي عناوين لا يمكن الوصول إليها إلا باستخدام شبكة VPN). هناك حل بديل في مثل هذه الحالات، وهو ضبط متغيرات الإصدار لإنشاء ملف بيان مختلف للإصدارات الخاصة بالمطوّرين.

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

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

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

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

  1. يفحص النظام جميع فلاتر الأهداف التي تتضمّن أيًا مما يلي:
    • الإجراء: android.intent.action.VIEW
    • الفئتان: android.intent.category.BROWSABLE وandroid.intent.category.DEFAULT
    • مخطط البيانات: http أو https
  2. لكل اسم مضيف فريد تم العثور عليه في فلاتر الأهداف أعلاه، يطلب Android من المواقع الإلكترونية المقابلة لملف "روابط مواد العرض الرقمية" على 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، يمكنك استدعاء إثبات ملكية النطاق يدويًا لتطبيق مُثبَّت على جهاز. يمكنك تنفيذ هذه العملية بغض النظر عمّا إذا كان تطبيقك يستهدف نظام التشغيل Android 12 أم لا.

يجب إعداد اتصال بالإنترنت.

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

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

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

وبخلاف ذلك، يمكنك تفعيل عملية إثبات الهوية المعدَّلة يدويًا. لإجراء ذلك، شغِّل الأمر التالي في نافذة طرفية:

adb shell am compat enable 175408749 PACKAGE_NAME

إعادة ضبط حالة Android App Links على جهاز

قبل استدعاء إثبات ملكية النطاق يدويًا على جهاز، يجب إعادة ضبط حالة Android App Links على جهاز الاختبار. للقيام بذلك، قم بتشغيل الأمر التالي في نافذة طرفية:

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

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

استدعاء عملية إثبات ملكية النطاق

بعد إعادة ضبط حالة Android App Links على جهاز، يمكنك إجراء عملية إثبات الملكية بنفسه. لإجراء ذلك، شغِّل الأمر التالي في نافذة طرفية:

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

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

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

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

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

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

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

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

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

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

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

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

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

قوة الخادم

يُرجى التحقق مما إذا كان يمكن للخادم الاتصال بتطبيقات العميل أم لا.

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

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

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

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

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