التحقّق من روابط تطبيقات 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". -->
    <!-- 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> من بدء عملية إثبات ملكية النطاق.

.

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

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

ملاحظة: في الإصدار 11 من نظام التشغيل Android (المستوى 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. ولذلك، عليك إنشاء فلاتر أهداف منفصلة عندما تريد تحديد مجموعات معيّنة من مخطّطات عناوين URL والنطاقات.

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

يتعامل بروتوكول 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>

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

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

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

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

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

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

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

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

  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، يمكنك طلب التحقّق من النطاق يدوياً لتطبيق مثبَّت على جهاز. يمكنك تنفيذ هذه الخطوات بغض النظر عمّا إذا كان تطبيقك يستهدف الإصدار 12 من نظام التشغيل Android.

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

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

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

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

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

adb shell am compat enable 175408749 PACKAGE_NAME

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

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

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 أو أكثر

رمز خطأ مخصّص خاص بمُثبِّت الهوية على الجهاز

تحقَّق من إتمام عملية الاتصال بالشبكة، وابدأ عملية verifying التحقّق من النطاق مرة أخرى.

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

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

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

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

  • واجهة برمجة تطبيقات DomainVerificationManager (في وقت التشغيل)
  • برنامج سطر أوامر (أثناء الاختبار)

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

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

KotlinJava
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 }
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 للتطبيق المستهدَف، كما هو موضّح في مقتطف الرمز البرمجي التالي:

KotlinJava
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)
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، تحقّق مما يلي من الرسائل الخطأ المشترَكة: يستخدم هذا القسم العنصر النائب 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

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

ثبات الخادم

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

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

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

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

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

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