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

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

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

ในกรณีที่เรียบง่ายที่สุด แท็บที่กำหนดเองสามารถเปิดขึ้นได้เพียงสั้นๆ ดังนี้

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

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

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

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

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

ใน 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

แม้ว่าแอปพลิเคชันอาจกำหนดเป้าหมายเป็น Android 11 หรือ API ระดับ 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;
}

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

จากนั้นให้ค้นหาแอปพลิเคชันที่จัดการ URL สำหรับ 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 และเราสามารถลองเปิดตัวแอป nativa ด้วยวิธีการใหม่ได้ ไม่เช่นนั้น เราจะพยายามเปิดตัวด้วยวิธีเดิม

หากเปิดแอปที่มาพร้อมเครื่องไม่สำเร็จ เราจะเปิดตัวแท็บที่กำหนดเองแทน

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

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

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

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

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

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

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

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

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

บทสรุป

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

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