تلبية حالات الاستخدام الشائعة مع توفُّر إمكانية رؤية محدودة للحزمة

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

إذا كان هناك تطبيق يستهدف الإصدار Android 11 أو الإصدارات الأحدث يستخدم نية بدء نشاط في تطبيق آخر، تكون الوسيلة الأكثر سهولة هي استدعاء الهدف والتعامل مع ActivityNotFoundException، وذلك في حال عدم توفّر أي تطبيق.

إذا كان جزء من تطبيقك يعتمد على معرفة ما إذا كان الطلب من startActivity() ينجح أم لا، مثل عرض واجهة مستخدم، يمكنك إضافة عنصر إلى العنصر <queries> في بيان تطبيقك. ويكون ذلك عادةً عنصر <intent>.

عناوين URL المفتوحة

يوضّح هذا القسم طرقًا مختلفة لفتح عناوين URL في تطبيق يستهدف الإصدار 11 من نظام التشغيل Android أو الإصدارات الأحدث.

فتح عناوين URL في متصفّح أو تطبيق آخر

لفتح عنوان URL، استخدِم هدفًا يتضمّن إجراء intent ACTION_VIEW على النحو الموضّح في الدليل حول تحميل عنوان URL على الويب. بعد طلب startActivity() باستخدام هذا الغرض، سيحدث أحد الأمرَين التاليَين:

  • يفتح عنوان URL في تطبيق متصفّح الويب.
  • يتم فتح عنوان URL في تطبيق يتوافق مع عنوان URL على أنه رابط لصفحة في التطبيق.
  • سيظهر مربّع حوار توضيحي يتيح للمستخدم اختيار التطبيق الذي سيفتح عنوان URL.
  • يحدث ActivityNotFoundException بسبب عدم توفّر تطبيق مثبَّت على الجهاز يمكنه فتح عنوان URL. (هذا أمر غير عادي).

    ننصح تطبيقك بأن يرصد ActivityNotFoundException ويعالجها في حال حدوثها.

وبما أنّ طريقة startActivity() لا تتطلّب رؤية الحزمة لبدء نشاط تطبيق آخر، لن تحتاج إلى إضافة عنصر <queries> إلى ملف بيان تطبيقك أو إجراء أي تغييرات على عنصر <queries> حالي. وينطبق ذلك على كلّ من الأهداف الضمنية والصريحة التي تفتح عنوان URL.

التحقُّق من توفُّر متصفِّح

في بعض الحالات، قد يحتاج تطبيقك إلى التحقق من توفُّر متصفّح واحد على الأقل على الجهاز، أو من أنّ متصفّحًا معيّنًا هو المتصفح التلقائي، قبل محاولة فتح عنوان URL. في هذه الحالات، يجب تضمين عنصر <intent> التالي كجزء من العنصر <queries> في ملف البيان:

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="https" />
</intent>

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

فتح عناوين URL في علامات تبويب مخصَّصة

تتيح علامات التبويب المخصصة للتطبيق تخصيص شكل المتصفح وأسلوبه. يمكنك فتح عنوان URL في علامة تبويب مخصَّصة بدون الحاجة إلى إضافة العنصر <queries> أو تغييره في بيان التطبيق.

مع ذلك، يمكنك التحقّق مما إذا كان الجهاز يحتوي على متصفّح متوافق مع "علامات التبويب المخصّصة" أو اختيار متصفّح معيّن لتشغيله باستخدام "علامات التبويب المخصّصة" باستخدام CustomTabsClient.getPackageName(). في هذه الحالات، عليك تضمين العنصر <intent> التالي كجزء من العنصر <queries> في البيان:

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.support.customtabs.action.CustomTabsService" />
</intent>

السماح للتطبيقات التي لا تستخدم متصفّحًا بالتعامل مع عناوين URL

حتى إذا كان يمكن لتطبيقك فتح عناوين URL باستخدام علامات التبويب المخصصة، ننصحك بالسماح لتطبيق لا يعمل بمتصفح بفتح عنوان URL إن أمكن ذلك. ولتوفير هذه الإمكانية في تطبيقك، يمكنك إجراء طلب إلى startActivity() باستخدام هدف يحدّد علامة نية FLAG_ACTIVITY_REQUIRE_NON_BROWSER. وإذا عرض النظام علامة ActivityNotFoundException، سيتمكّن تطبيقك من فتح عنوان URL في علامة تبويب مخصَّصة.

إذا تضمّن الغرض من هذه العلامة، يؤدّي استدعاء startActivity() إلى وضع ActivityNotFoundException عند حدوث أيّ من الشرطَين التاليَين:

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

يعرض مقتطف الرمز التالي كيفية تعديل المنطق لاستخدام علامة intent في FLAG_ACTIVITY_REQUIRE_NON_BROWSER:

Kotlin

try {
    val intent = Intent(ACTION_VIEW, Uri.parse(url)).apply {
        // The URL should either launch directly in a non-browser app (if it's
        // the default) or in the disambiguation dialog.
        addCategory(CATEGORY_BROWSABLE)
        flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER
    }
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    // Only browser apps are available, or a browser is the default.
    // So you can open the URL directly in your app, for example in a
    // Custom Tab.
    openInCustomTabs(url)
}

Java

try {
    Intent intent = new Intent(ACTION_VIEW, Uri.parse(url));
    // The URL should either launch directly in a non-browser app (if it's the
    // default) or in the disambiguation dialog.
    intent.addCategory(CATEGORY_BROWSABLE);
    intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REQUIRE_NON_BROWSER);
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // Only browser apps are available, or a browser is the default.
    // So you can open the URL directly in your app, for example in a
    // Custom Tab.
    openInCustomTabs(url);
}

تجنب مربع حوار توضيحي

إذا أردت تجنُّب عرض مربّع حوار التوضيح الذي قد يظهر للمستخدمين عند فتح عنوان URL، وبدلاً من ذلك يفضّلون معالجة عنوان URL بنفسك في هذه الحالات، يمكنك استخدام نية تحدد علامة النية في FLAG_ACTIVITY_REQUIRE_DEFAULT.

إذا تضمّن الغرض هذه العلامة، سيؤدي الاستدعاء إلى startActivity() إلى طرح ActivityNotFoundException عندما كانت المكالمة تعرض مربّع حوار توضيحي للمستخدم.

إذا تضمّن الغرض كلاً من هذه العلامة وعلامة FLAG_ACTIVITY_REQUIRE_NON_BROWSER النية، سيؤدي الاتصال إلى startActivity() إلى عرض ActivityNotFoundException عند حدوث أيّ من الشروط التالية:

  • كان من الممكن أن تؤدي المكالمة إلى تشغيل تطبيق المتصفح مباشرةً.
  • ستظهر المكالمة للمستخدم مربّع حوار توضيحي.

يعرض مقتطف الرمز التالي كيفية استخدام علامتَي FLAG_ACTIVITY_REQUIRE_NON_BROWSER وFLAG_ACTIVITY_REQUIRE_DEFAULT معًا:

Kotlin

val url = URL_TO_LOAD
try {
    // For this intent to be invoked, the system must directly launch a
    // non-browser app.
    val intent = Intent(ACTION_VIEW, Uri.parse(url)).apply {
        addCategory(CATEGORY_BROWSABLE)
        flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER or
                FLAG_ACTIVITY_REQUIRE_DEFAULT
    }
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    // This code executes in one of the following cases:
    // 1. Only browser apps can handle the intent.
    // 2. The user has set a browser app as the default app.
    // 3. The user hasn't set any app as the default for handling this URL.
    openInCustomTabs(url)
}

Java

String url = URL_TO_LOAD;
try {
    // For this intent to be invoked, the system must directly launch a
    // non-browser app.
    Intent intent = new Intent(ACTION_VIEW, Uri.parse(url));
    intent.addCategory(CATEGORY_BROWSABLE);
    intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REQUIRE_NON_BROWSER |
            FLAG_ACTIVITY_REQUIRE_DEFAULT);
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // This code executes in one of the following cases:
    // 1. Only browser apps can handle the intent.
    // 2. The user has set a browser app as the default app.
    // 3. The user hasn't set any app as the default for handling this URL.
    openInCustomTabs(url);
}

فتح ملف

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

إذا كان على تطبيقك أن يعرف مسبقًا ما إذا كان بإمكان تطبيق آخر فتح ملف معيّن، عليك تضمين عنصر <intent> في مقتطف الرمز التالي كجزء من عنصر <queries> في ملف البيان. قم بتضمين نوع الملف إذا كنت تعرف بالفعل ما هو في وقت التجميع.

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.VIEW" />
  <!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
  <data android:mimeType="application/pdf" />
</intent>

يمكنك بعد ذلك التحقّق ممّا إذا كان التطبيق متوفّرًا من خلال طلب الرقم resolveActivity() إذا أردت ذلك.

منح إمكانية الدخول إلى معرف الموارد المنتظم (URI)

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

بالنسبة إلى التطبيقات التي تستهدف Android 11 أو الإصدارات الأحدث للوصول إلى معرّف الموارد المنتظم (URI) الخاص بالمحتوى، يجب أن يحدّد قصد تطبيقك أذونات الوصول إلى معرّف الموارد المنتظم (URI) من خلال ضبط إحدى علامتَي intent التاليتَين أو كلتيهما: FLAG_GRANT_READ_URI_PERMISSION وFLAG_GRANT_WRITE_URI_PERMISSION.

في نظام التشغيل Android 11 والإصدارات الأحدث، تمنح أذونات الوصول إلى معرّف الموارد المنتظم (URI) الإمكانات التالية للتطبيق الذي يتلقّى intent:

  • القراءة من البيانات التي يمثلها معرف الموارد المنتظم (URI) للمحتوى أو الكتابة إليها، بناءً على أذونات معرف الموارد المنتظم (URI) المحددة.
  • الحصول على مستوى رؤية للتطبيق الذي يحتوي على موفِّر المحتوى الذي يتطابق مع مرجع عنوان URI. قد يكون التطبيق الذي يحتوي على موفر المحتوى مختلفًا عن التطبيق الذي يرسل intent.

يوضّح مقتطف الرمز التالي كيفية إضافة علامة intent لأذونات معرّف الموارد المنتظم (URI) كي يتمكّن تطبيق آخر يستهدف الإصدار 11 من نظام التشغيل Android أو الإصدارات الأحدث من عرض البيانات في معرّف الموارد المنتظم (URI) للمحتوى:

Kotlin

val shareIntent = Intent(Intent.ACTION_VIEW).apply {
    flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
    data = CONTENT_URI_TO_SHARE_WITH_OTHER_APP
}

Java

Intent shareIntent = new Intent(Intent.ACTION_VIEW);
shareIntent.setFlags(FLAG_GRANT_READ_URI_PERMISSION);
shareIntent.setData(CONTENT_URI_TO_SHARE_WITH_OTHER_APP);

الربط بالخدمات

إذا كان تطبيقك يحتاج إلى التفاعل مع خدمة غير مرئية تلقائيًا، يمكنك توضيح إجراء intent المناسب ضمن عنصر <queries>. تقدم الأقسام التالية أمثلة على استخدام الخدمات التي يشيع الوصول إليها.

الربط بمحرك لتحويل النص إلى كلام

إذا كان تطبيقك يتفاعل مع محرك لتحويل النص إلى كلام، يجب تضمين عنصر <intent> التالي كجزء من العنصر <queries> في ملف البيان:

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.TTS_SERVICE" />
</intent>

الاتصال بخدمة التعرّف على الكلام

إذا تفاعل تطبيقك مع إحدى خدمات التعرّف على الكلام، يُرجى تضمين عنصر <intent> التالي كجزء من عنصر <queries> في ملف البيان:

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.speech.RecognitionService" />
</intent>

الاتصال بخدمات متصفِّح الوسائط

إذا كان تطبيقك تطبيقًا لمتصفِّح وسائط العميل، يمكنك تضمين عنصر <intent> التالي كجزء من العنصر <queries> في البيان:

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.media.browse.MediaBrowserService" />
</intent>

توفير وظائف مخصصة

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

طلب تطبيقات الرسائل القصيرة SMS

إذا كان تطبيقك يحتاج إلى معلومات حول مجموعة تطبيقات الرسائل القصيرة SMS المثبّتة على جهاز، مثلاً لمعرفة التطبيق الذي يُعدّ المعالج التلقائي للرسائل القصيرة على الجهاز، يجب تضمين عنصر <intent> التالي كجزء من عنصر <queries> في ملف البيان:

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.SENDTO"/>
  <data android:scheme="smsto" android:host="*" />
</intent>

إنشاء ورقة مشاركة مخصّصة

استخدِم قائمة مشاركة البيانات المقدّمة من النظام كلما أمكن ذلك. يمكنك بدلاً من ذلك تضمين عنصر <intent> التالي كجزء من العنصر <queries> في ملف البيان:

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.SEND" />
  <!-- Replace with the MIME type that your app works with, if needed. -->
  <data android:mimeType="image/jpeg" />
</intent>

إنّ عملية إنشاء لوحة المشاركة في منطق تطبيقك، مثل الاتصال بـ queryIntentActivities()، ستبقى بدون تغيير مقارنةً بإصدارات Android الأقدم من Android 11.

إظهار إجراءات تحديد النص المخصّص

عندما يحدّد المستخدمون نصًا في تطبيقك، يعرض شريط أدوات تحديد النص مجموعة العمليات المحتملة التي يمكن إجراؤها على النص المُختار. إذا كان شريط الأدوات هذا يعرض إجراءات مخصّصة من تطبيقات أخرى، يمكنك تضمين عنصر <intent> التالي كجزء من عنصر <queries> في البيان:

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.PROCESS_TEXT" />
  <data android:mimeType="text/plain" />
</intent>

إظهار صفوف البيانات المخصّصة لجهة اتصال

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

  1. اقرأ الملف contacts.xml من التطبيقات الأخرى.
  2. حمِّل رمزًا يتوافق مع نوع MIME المخصّص.

إذا كان تطبيقك هو تطبيق جهات اتصال، عليك تضمين عناصر <intent> التالية كجزء من عنصر <queries> في ملف البيان:

<!-- Place inside the <queries> element. -->
<!-- Lets the app read the contacts.xml file from other apps. -->
<intent>
  <action android:name="android.accounts.AccountAuthenticator" />
</intent>
<!-- Lets the app load an icon corresponding to the custom MIME type. -->
<intent>
  <action android:name="android.intent.action.VIEW" />
  <data android:scheme="content" android:host="com.android.contacts"
        android:mimeType="vnd.android.cursor.item/*" />
</intent>