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

عندما يكون 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:///.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"

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

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

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

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

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

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

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

adb shell am compat enable 175408749 PACKAGE_NAME

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

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

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

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

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

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