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 ให้เริ่มต้นด้วยคู่มือการใช้งาน แล้วดูแนวทางปฏิบัติที่ดีที่สุดเพื่อเรียนรู้เกี่ยวกับการสร้างการผสานรวมระดับเฟิร์สคลาส
โปรดแจ้งให้เราทราบหากคุณมีคำถามหรือความคิดเห็นใดๆ