استخدام علامات التبويب المخصَّصة في Android 11

طرخ Android 11 تغييرات على كيفية تفاعل التطبيقات مع التطبيقات الأخرى التي ثبّتها المستخدم على الجهاز. يمكنك الاطّلاع على المزيد من المعلومات عن هذه التغييرات في مستندات Android.

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

في أبسط الحالات، يمكن تشغيل Custom Tabs باستخدام سطر واحد كما يلي:

new CustomTabsIntent.Builder().build()
        .launchUrl(this, Uri.parse("https://www.example.com"));

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

تفضيل التطبيقات الأصلية

ولكن في حال اتّباع أفضل الممارسات، قد تحتاج إلى إجراء بعض التغييرات.

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

على نظام التشغيل Android 11 والإصدارات الأحدث

يقدّم Android 11 علامة Intent جديدة، وهي FLAG_ACTIVITY_REQUIRE_NON_BROWSER، وهي الطريقة المقترَحة لفتح تطبيق محلي، لأنّه لا يتطلّب من التطبيق الإفصاح عن أي طلبات بحث خاصة بمدير الحزم.

static boolean launchNativeApi30(Context context, Uri uri) {
    Intent nativeAppIntent = new Intent(Intent.ACTION_VIEW, uri)
            .addCategory(Intent.CATEGORY_BROWSABLE)
            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                    Intent.FLAG_ACTIVITY_REQUIRE_NON_BROWSER);
    try {
        context.startActivity(nativeAppIntent);
        return true;
    } catch (ActivityNotFoundException ex) {
        return false;
    }
}

الحل هو محاولة تشغيل Intent واستخدام FLAG_ACTIVITY_REQUIRE_NON_BROWSER للطلب من Android تجنُّب المتصفّحات عند تشغيلها.

في حال عدم العثور على تطبيق محلي يستطيع التعامل مع Intent هذا، سيتم طرح ActivityNotFoundException.

قبل نظام التشغيل Android 11

على الرغم من أنّ التطبيق قد يستهدف المستوى 30 من نظام التشغيل Android أو المستوى 30 لواجهة برمجة التطبيقات، فإنّ إصدارات Android السابقة لن تفهم علامة FLAG_ACTIVITY_REQUIRE_NON_BROWSER، لذا علينا اللجوء إلى طلب البحث في "مدير الحزم" في الحالات التالية:

private static boolean launchNativeBeforeApi30(Context context, Uri uri) {
    PackageManager pm = context.getPackageManager();

    // Get all Apps that resolve a generic url
    Intent browserActivityIntent = new Intent()
            .setAction(Intent.ACTION_VIEW)
            .addCategory(Intent.CATEGORY_BROWSABLE)
            .setData(Uri.fromParts("http", "", null));
    Set<String> genericResolvedList = extractPackageNames(
            pm.queryIntentActivities(browserActivityIntent, 0));

    // Get all apps that resolve the specific Url
    Intent specializedActivityIntent = new Intent(Intent.ACTION_VIEW, uri)
            .addCategory(Intent.CATEGORY_BROWSABLE);
    Set<String> resolvedSpecializedList = extractPackageNames(
            pm.queryIntentActivities(specializedActivityIntent, 0));

    // Keep only the Urls that resolve the specific, but not the generic
    // urls.
    resolvedSpecializedList.removeAll(genericResolvedList);

    // If the list is empty, no native app handlers were found.
    if (resolvedSpecializedList.isEmpty()) {
        return false;
    }

    // We found native handlers. Launch the Intent.
    specializedActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(specializedActivityIntent);
    return true;
}

الأسلوب المستخدَم هنا هو طلب البحث في "مدير الحِزم" عن التطبيقات التي تتيح هدفًا عامًا باستخدام http. وهذه التطبيقات هي على الأرجح متصفحات.

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

والآن، احذف جميع المتصفحات الموجودة في القائمة الأولى من القائمة الثانية، وسنترك التطبيقات الأصلية فقط.

إذا كانت القائمة فارغة، نعلم أنّه ما من معالِجات أصلية ويعرض القيمة false. وإلا، نُطلق الهدف للمعالج الأصلي.

خلاصة ما سبق ذكره

نحتاج إلى التأكّد من استخدام الطريقة الصحيحة لكل مناسبة:

static void launchUri(Context context, Uri uri) {
    boolean launched = Build.VERSION.SDK_INT >= 30 ?
            launchNativeApi30(context, uri) :
            launchNativeBeforeApi30(context, uri);

    if (!launched) {
        new CustomTabsIntent.Builder()
                .build()
                .launchUrl(context, uri);
    }
}

يقدّم Build.VERSION.SDK_INT المعلومات التي نحتاجها. فإذا كانت القيمة تساوي 30 أو أكبر من ذلك، فإن Android على علم بـ FLAG_ACTIVITY_REQUIRE_NON_BROWSER ويمكننا محاولة إطلاق تطبيق nativa على النهج الجديد. وبخلاف ذلك، نحاول البدء بالنهج القديم.

في حالة فشل تشغيل تطبيق محلي، يتم تشغيل علامات تبويب مخصصة.

هناك بعض النصوص النموذجية التي تشملها أفضل الممارسات هذه. نحن نعمل على جعل هذا أكثر بساطة من خلال تغليف التعقيد في المكتبة. يُرجى متابعتنا لمعرفة آخر الأخبار حول مكتبة دعم android-browser-helper.

اكتشاف المتصفحات التي تدعم علامات التبويب المخصصة

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

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

<queries>
    <intent>
        <action android:name=
            "android.support.customtabs.action.CustomTabsService" />
    </intent>
</queries>

بعد تنفيذ الترميز، سيعمل الرمز الحالي المستخدَم لطلب البحث عن المتصفحات التي تتوافق مع "علامات التبويب المخصّصة" على النحو المتوقَّع.

الأسئلة الشائعة

س: الرمز الذي يبحث عن موفّري "علامات التبويب المخصّصة" عن التطبيقات التي يمكنها معالجة أهداف https://، لكنّ فلتر طلبات البحث يكشف فقط عن طلب android.support.customtabs.action.CustomTabsService ألا يجب تضمين طلب بحث عن أهداف https://؟

A: عند التعريف بعامل تصفية استعلام، فإنه يفرز الردود على استعلام بـ PackageManager، وليس الاستعلام نفسه. بما أنّ المتصفحات التي تتيح استخدام "علامات التبويب المخصّصة" تعلن أنّها تعاملت مع CustomTabsService، لن تتم فلترتها. وسيتم استبعاد المتصفحات التي لا تتيح استخدام "علامات التبويب المخصّصة".

الخلاصة

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

يُرجى إعلامنا إذا كانت لديك أيّ أسئلة أو ملاحظات.