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

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

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

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

فتح عناوين URL

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

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

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

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

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

فتح ملف

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

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

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

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

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

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 action المناسب ضمن عنصر <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>` في ملف البيان:<intent><queries>

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

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

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

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

إذا كان تطبيقك بحاجة إلى معلومات حول مجموعة تطبيقات الرسائل القصيرة المثبَّتة على جهاز، مثلاً للتحقّق من التطبيق الذي يتعامل مع الرسائل القصيرة التلقائي على الجهاز، أدرِج عنصر <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>