การใช้แท็บที่กำหนดเองกับ Android 11

Android 11 เปิดตัวการเปลี่ยนแปลงเกี่ยวกับวิธีที่แอปโต้ตอบกับแอปอื่นๆ ที่ผู้ใช้ติดตั้งไว้ในอุปกรณ์ อ่านข้อมูลเพิ่มเติมเกี่ยวกับการเปลี่ยนแปลงดังกล่าวได้ในเอกสารประกอบของ Android

เมื่อแอป Android ที่ใช้ Custom Tabs กำหนดเป้าหมายเป็น SDK ระดับ 30 ขึ้นไป คุณอาจต้องทำการเปลี่ยนแปลงบางอย่าง บทความนี้จะกล่าวถึงการเปลี่ยนแปลงที่อาจจำเป็นสำหรับแอปเหล่านั้น

ในกรณีแบบง่ายที่สุด แท็บที่กำหนดเองจะเปิดได้ด้วยบรรทัดเดียว ดังนี้

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

แอปพลิเคชันที่เปิดแอปพลิเคชันโดยใช้แนวทางนี้ หรือแม้แต่การเพิ่มการปรับแต่ง UI เช่น การเปลี่ยนสีแถบเครื่องมือ การเพิ่มปุ่มดำเนินการ จะไม่ต้องทำการเปลี่ยนแปลงใดๆ ในแอปพลิเคชัน

การใช้แอปที่มาพร้อมเครื่อง

แต่หากคุณทำตามแนวทางปฏิบัติแนะนำ ก็อาจต้องเปลี่ยนแปลงบางอย่าง

แนวทางปฏิบัติแนะนำที่เกี่ยวข้องข้อแรกคือแอปพลิเคชันควรใช้แอปเนทีฟเพื่อจัดการ Intent แทนแท็บที่กำหนดเอง หากติดตั้งแอปที่จัดการ Intent ได้

ใน Android 11 ขึ้นไป

Android 11 เปิดตัว Flag Intent ใหม่ FLAG_ACTIVITY_REQUIRE_NON_BROWSER ซึ่งเป็นวิธีที่แนะนําในการลองเปิดแอปเนทีฟ เนื่องจากแอปไม่จําเป็นต้องประกาศการค้นหา Package Manager

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

แม้ว่าแอปพลิเคชันจะกำหนดเป้าหมายเป็น Android 11 หรือ API ระดับ 30 แต่ Android เวอร์ชันเก่าจะไม่เข้าใจ Flag FLAG_ACTIVITY_REQUIRE_NON_BROWSER เราจึงต้องหันไปใช้การค้นหา Package Manager ในกรณีเหล่านี้

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;
}

แนวทางที่ใช้ในที่นี้คือค้นหา Package Manager สําหรับแอปพลิเคชันที่รองรับ Intent แบบทั่วไป http แอปพลิเคชันเหล่านั้นอาจเป็นเบราว์เซอร์

จากนั้นค้นหาแอปพลิเคชันที่จัดการข้อมูลสำหรับ URL ที่เฉพาะเจาะจงซึ่งเราต้องการเปิดตัว ซึ่งจะแสดงทั้งเบราว์เซอร์และแอปพลิเคชันเนทีฟที่ตั้งค่าให้จัดการ URL นั้น

ตอนนี้ให้นําเบราว์เซอร์ทั้งหมดที่พบในรายการแรกออกจากรายการที่ 2 แล้วเราจะเหลือเพียงแอปเนทีฟเท่านั้น

หากรายการว่างเปล่า เราจะทราบว่าไม่มีตัวแฮนเดิลแบบเนทีฟและแสดงผลเป็นเท็จ มิเช่นนั้น เราจะเปิดใช้งาน Intent สําหรับตัวแฮนเดิลแบบเนทีฟ

สรุปข้อมูลทั้งหมด

เราต้องตรวจสอบว่าใช้วิธีการที่เหมาะสมกับแต่ละกรณี ดังนี้

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 และเราสามารถลองเปิดแอปเนทีฟด้วยแนวทางใหม่ มิเช่นนั้น เราจะลองเปิดตัวด้วยแนวทางเดิม

หากเปิดแอปเนทีฟไม่สำเร็จ เราจะเปิดแท็บที่กำหนดเอง

แนวทางปฏิบัติแนะนำนี้เกี่ยวข้องกับข้อความที่เขียนขึ้นไว้ล่วงหน้า เรากำลังดำเนินการทำให้การดำเนินการนี้ง่ายขึ้นด้วยการรวมความซับซ้อนไว้ในไลบรารี โปรดคอยติดตามการอัปเดตไลบรารีการสนับสนุน android-browser-helper

การตรวจหาเบราว์เซอร์ที่รองรับแท็บที่กำหนดเอง

รูปแบบที่พบบ่อยอีกอย่างหนึ่งคือการใช้ PackageManager เพื่อตรวจหาเบราว์เซอร์ที่รองรับแท็บที่กำหนดเองในอุปกรณ์ กรณีการใช้งานทั่วไปสำหรับกรณีนี้คือการตั้งค่าแพ็กเกจใน Intent เพื่อหลีกเลี่ยงกล่องโต้ตอบการแยกความแตกต่างของแอป หรือเลือกเบราว์เซอร์ที่จะเชื่อมต่อเมื่อเชื่อมต่อกับบริการแท็บที่กำหนดเอง

เมื่อกำหนดเป้าหมายเป็น API ระดับ 30 นักพัฒนาแอปจะต้องเพิ่มส่วนการค้นหาลงใน Android Manifest โดยประกาศตัวกรอง Intent ที่ตรงกับเบราว์เซอร์ที่รองรับแท็บที่กำหนดเอง

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

เมื่อมาร์กอัปพร้อมใช้งานแล้ว โค้ดที่มีอยู่ซึ่งใช้ค้นหาเบราว์เซอร์ที่รองรับแท็บที่กำหนดเองจะทำงานตามที่คาดไว้

คำถามที่พบบ่อย

ถาม: โค้ดที่ค้นหาผู้ให้บริการแท็บที่กำหนดเองจะค้นหาแอปพลิเคชันที่จัดการhttps:// Intent ได้ แต่ตัวกรองข้อความค้นหาจะประกาศเฉพาะข้อความค้นหา android.support.customtabs.action.CustomTabsService ไม่ควรประกาศคําค้นหาสําหรับhttps:// Intent

ตอบ: เมื่อประกาศตัวกรองข้อความค้นหา ระบบจะกรองการตอบกลับข้อความค้นหาไปยัง PackageManager ไม่ใช่ข้อความค้นหาเอง เนื่องจากเบราว์เซอร์ที่รองรับแท็บที่กำหนดเองจะประกาศการจัดการ CustomTabsService ระบบจึงไม่กรองเบราว์เซอร์เหล่านั้นออก ระบบจะกรองเบราว์เซอร์ที่ไม่รองรับแท็บที่กำหนดเองออก

บทสรุป

การเปลี่ยนแปลงทั้งหมดที่จําเป็นในการปรับการผสานรวมแท็บที่กําหนดเองที่มีอยู่ให้ทํางานกับ Android 11 หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับการผสานรวมแท็บที่กำหนดเองลงในแอป Android ให้เริ่มจากคู่มือการใช้งาน จากนั้นดูแนวทางปฏิบัติแนะนำเพื่อเรียนรู้เกี่ยวกับการผสานรวมที่ยอดเยี่ยม

โปรดแจ้งให้เราทราบหากมีคำถามหรือความคิดเห็น