เอกสารนี้จะนำเสนอ Use Case ทั่วไปหลายกรณีที่แอปโต้ตอบกับ แอปอื่นๆ แต่ละส่วนจะให้คำแนะนำเกี่ยวกับวิธีทำให้ฟังก์ชันการทำงานของแอป สำเร็จโดยมีการจำกัดระดับการมองเห็นแพ็กเกจ ซึ่งคุณต้องพิจารณาหากแอปกำหนดเป้าหมายเป็น Android 11 (API ระดับ 30) ขึ้นไป
เมื่อแอปที่กำหนดเป้าหมายเป็น Android 11 ขึ้นไปใช้ Intent เพื่อ
เริ่มกิจกรรมในแอปอื่น วิธีที่ตรงไปตรงมาที่สุดคือการเรียกใช้
Intent และจัดการข้อยกเว้น
ActivityNotFoundException
หากไม่มีแอปที่พร้อมใช้งาน
หากส่วนหนึ่งของแอปขึ้นอยู่กับการทราบว่าการเรียกใช้
startActivity()
จะสำเร็จหรือไม่ เช่น การแสดง UI ให้เพิ่มองค์ประกอบลงในองค์ประกอบ
<queries>
ของไฟล์
Manifest ของแอป โดยปกติแล้วจะเป็นองค์ประกอบ <intent>
เปิด URL
ส่วนนี้อธิบายวิธีต่างๆ ในการเปิด URL ในแอปที่กำหนดเป้าหมายเป็น Android 11 ขึ้นไป
เปิด URL ในเบราว์เซอร์หรือแอปอื่น
หากต้องการเปิด URL ให้ใช้ Intent ที่มี
การดำเนินการ Intent ACTION_VIEW
ตามที่อธิบายไว้ในคำแนะนำเกี่ยวกับการโหลด URL ของเว็บ หลังจากเรียกใช้ startActivity()
โดยใช้อินเทนต์นี้แล้ว ระบบจะดำเนินการอย่างใดอย่างหนึ่งต่อไปนี้
- URL จะเปิดในแอปเว็บเบราว์เซอร์
- URL จะเปิดในแอปที่รองรับ URL เป็น Deep Link
- กล่องโต้ตอบที่มีคำอธิบายจะปรากฏขึ้น ซึ่งช่วยให้ผู้ใช้เลือกแอปที่เปิด URL ได้
ActivityNotFoundException
เกิดขึ้นเนื่องจากไม่มีแอปที่ติดตั้งใน อุปกรณ์ที่เปิด URL ได้ (ซึ่งเป็นเรื่องผิดปกติ)เราขอแนะนําให้แอปของคุณตรวจจับและจัดการ
ActivityNotFoundException
หากเกิดขึ้น
เนื่องจากวิธี startActivity()
ไม่ต้องใช้ระดับการเข้าถึงแพ็กเกจเพื่อ
เริ่มกิจกรรมของแอปพลิเคชันอื่น คุณจึงไม่จำเป็นต้องเพิ่มองค์ประกอบ <queries>
ลงในไฟล์ Manifest ของแอป หรือทำการเปลี่ยนแปลงใดๆ กับองค์ประกอบ <queries>
ที่มีอยู่ ซึ่งใช้ได้กับทั้ง Intent โดยนัยและ Intent โดยชัดแจ้งที่เปิด URL
ตรวจสอบว่ามีเบราว์เซอร์พร้อมใช้งานหรือไม่
ในบางกรณี แอปอาจต้องการยืนยันว่ามีเบราว์เซอร์อย่างน้อย 1 รายการ
ในอุปกรณ์ หรือเบราว์เซอร์ที่เฉพาะเจาะจงเป็นเบราว์เซอร์เริ่มต้น
ก่อนที่จะพยายามเปิด URL ในกรณีดังกล่าว ให้รวมองค์ประกอบ <intent>
ต่อไปนี้เป็นส่วนหนึ่งขององค์ประกอบ <queries>
ในไฟล์ Manifest
<!-- 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()
และส่ง Web Intent เป็นอาร์กิวเมนต์
รายการที่ส่งคืนจะมีแอปเบราว์เซอร์ที่พร้อมใช้งานในบางกรณี รายการ
จะไม่รวมแอปเบราว์เซอร์หากผู้ใช้กำหนดค่า URL ให้เปิดใน
แอปที่ไม่ใช่เบราว์เซอร์โดยค่าเริ่มต้น
เปิด URL ในแท็บที่กำหนดเอง
แท็บที่กำหนดเองช่วยให้แอปปรับแต่งรูปลักษณ์ของเบราว์เซอร์ได้ คุณสามารถเปิด URL ใน
แท็บที่กำหนดเอง
ได้โดยไม่ต้องเพิ่มหรือเปลี่ยนองค์ประกอบ <queries>
ในไฟล์ Manifest ของแอป
อย่างไรก็ตาม คุณอาจต้องตรวจสอบว่าอุปกรณ์มีเบราว์เซอร์ที่รองรับ
แท็บที่กำหนดเอง
หรือไม่ หรือเลือกเบราว์เซอร์ที่ต้องการเปิดด้วยแท็บที่กำหนดเองโดยใช้
CustomTabsClient.getPackageName()
ในกรณีดังกล่าว ให้รวมองค์ประกอบ <intent>
ต่อไปนี้เป็นส่วนหนึ่งขององค์ประกอบ
<queries>
ในไฟล์ Manifest
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.support.customtabs.action.CustomTabsService" /> </intent>
อนุญาตให้แอปที่ไม่ใช่เบราว์เซอร์จัดการ URL
แม้ว่าแอปจะเปิด URL โดยใช้แท็บที่กำหนดเองได้ แต่เราขอแนะนำให้คุณ
อนุญาตให้แอปที่ไม่ใช่เบราว์เซอร์เปิด URL หากเป็นไปได้ หากต้องการให้ความสามารถนี้ในแอปของคุณ ให้ลองโทรหา startActivity()
โดยใช้ Intent
ที่ตั้งค่าแฟล็ก Intent
FLAG_ACTIVITY_REQUIRE_NON_BROWSER
หากระบบแสดง ActivityNotFoundException
แอปของคุณจะ
เปิด URL ในแท็บที่กำหนดเองได้
หาก Intent มีแฟล็กนี้ การเรียก 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 ด้วยตนเองในสถานการณ์เหล่านี้ คุณสามารถใช้ Intent ที่ตั้งค่าแฟล็ก Intent FLAG_ACTIVITY_REQUIRE_DEFAULT
ได้
หากความตั้งใจมีแฟล็กนี้ การเรียกไปยัง startActivity()
จะทำให้เกิด
ActivityNotFoundException
เมื่อการเรียกจะแสดง
กล่องโต้ตอบการแยกความกำกวมต่อผู้ใช้
หาก Intent มีทั้งแฟล็กนี้และแฟล็ก
FLAG_ACTIVITY_REQUIRE_NON_BROWSER
ของ Intent การเรียกใช้ 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); }
เปิดไฟล์
หากแอปจัดการไฟล์หรือไฟล์แนบ เช่น ตรวจสอบว่าอุปกรณ์เปิดไฟล์ที่ระบุได้หรือไม่ วิธีที่ง่ายที่สุดมักจะเป็นการลองเริ่มกิจกรรมที่จัดการไฟล์ได้ โดยให้ใช้ Intent ที่มี ACTION_VIEW
Intent
Action และ URI ที่แสดงถึงไฟล์ที่เฉพาะเจาะจง หากไม่มีแอปในอุปกรณ์ แอปของคุณจะจับActivityNotFoundException
ได้ ในตรรกะการจัดการข้อยกเว้น คุณจะแสดงข้อผิดพลาดหรือพยายามจัดการไฟล์ด้วยตนเองก็ได้
หากแอปของคุณต้องทราบล่วงหน้าว่าแอปอื่นเปิดไฟล์ที่กำหนดได้หรือไม่
ให้รวมองค์ประกอบ <intent>
ในข้อมูลโค้ดต่อไปนี้เป็นส่วนหนึ่งขององค์ประกอบ
<queries>
ในไฟล์ Manifest ระบุประเภทไฟล์หากทราบอยู่แล้ว
ว่าไฟล์นั้นคืออะไรในเวลาคอมไพล์
<!-- 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()
พร้อมกับ Intent ของคุณ
ให้สิทธิ์เข้าถึง URI
หมายเหตุ: แอปที่กำหนดเป้าหมายเป็น Android 11 (API ระดับ 30) ขึ้นไปจะต้องประกาศสิทธิ์เข้าถึง URI ตามที่อธิบายไว้ในส่วนนี้ และขอแนะนำให้แอปทั้งหมดทำเช่นนี้ ไม่ว่า SDK เวอร์ชันเป้าหมายจะเป็นเวอร์ชันใดและไม่ว่าแอปจะส่งออก Content Provider หรือไม่ก็ตาม
สำหรับแอปที่กำหนดเป้าหมายเป็น Android 11 ขึ้นไปเพื่อเข้าถึง URI ของเนื้อหา Intent ของแอปต้องประกาศสิทธิ์เข้าถึง URI
โดยการตั้งค่า Flag ของ Intent อย่างใดอย่างหนึ่งหรือทั้ง 2 รายการต่อไปนี้
FLAG_GRANT_READ_URI_PERMISSION
และ
FLAG_GRANT_WRITE_URI_PERMISSION
ใน Android 11 ขึ้นไป สิทธิ์เข้าถึง URI จะให้ความสามารถต่อไปนี้แก่แอปที่รับ Intent
- อ่านหรือเขียนข้อมูลที่ URI ของเนื้อหาแสดง โดยขึ้นอยู่กับ สิทธิ์ URI ที่ระบุ
- รับสิทธิ์เข้าถึงแอปที่มีผู้ให้บริการเนื้อหาที่ตรงกับ URI Authority แอปที่มีผู้ให้บริการเนื้อหาอาจแตกต่าง จากแอปที่ส่ง Intent
ข้อมูลโค้ดต่อไปนี้แสดงวิธีเพิ่ม Flag Intent สิทธิ์ URI เพื่อให้แอปอื่นที่กำหนดเป้าหมายเป็น Android 11 ขึ้นไปดู ข้อมูลใน URI เนื้อหาได้
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 ที่เหมาะสมภายในองค์ประกอบ <queries>
ได้ ส่วนต่อไปนี้
จะแสดงตัวอย่างการใช้บริการที่เข้าถึงกันโดยทั่วไป
เชื่อมต่อกับเครื่องมือการอ่านออกเสียงข้อความ
หากแอปโต้ตอบกับเครื่องมืออ่านออกเสียงข้อความ (TTS) ให้รวมองค์ประกอบต่อไปนี้
<intent>
เป็นส่วนหนึ่งขององค์ประกอบ <queries>
ในไฟล์ Manifest
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.TTS_SERVICE" /> </intent>
เชื่อมต่อกับบริการการรู้จำคำพูด
หากแอปโต้ตอบกับบริการการจดจำคำพูด ให้ใส่องค์ประกอบ <intent>
ต่อไปนี้เป็นส่วนหนึ่งขององค์ประกอบ <queries>
ในไฟล์ Manifest
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.speech.RecognitionService" /> </intent>
เชื่อมต่อกับบริการเบราว์เซอร์สื่อ
หากแอปของคุณเป็นแอปเบราว์เซอร์สื่อฝั่งไคลเอ็นต์ ให้รวม
องค์ประกอบ <intent>
ต่อไปนี้เป็นส่วนหนึ่งขององค์ประกอบ <queries>
ในไฟล์
Manifest
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.media.browse.MediaBrowserService" /> </intent>
ระบุฟังก์ชันการทำงานที่กำหนดเอง
หากแอปต้องดำเนินการที่ปรับแต่งได้หรือแสดงข้อมูลที่ปรับแต่งได้โดยอิงตามการโต้ตอบกับแอปอื่นๆ คุณสามารถแสดงลักษณะการทำงานที่กำหนดเองนั้นได้โดยใช้ลายเซ็นของตัวกรอง Intent เป็นส่วนหนึ่งขององค์ประกอบ <queries>
ในไฟล์ Manifest ส่วนต่อไปนี้จะให้
คำแนะนำโดยละเอียดสำหรับสถานการณ์ที่พบบ่อยหลายอย่าง
ค้นหาแอป SMS
หากแอปของคุณต้องการข้อมูลเกี่ยวกับชุดแอป SMS ที่ติดตั้งในอุปกรณ์ เช่น เพื่อตรวจสอบว่าแอปใดเป็นตัวแฮนเดิล SMS เริ่มต้นของอุปกรณ์ ให้รวมองค์ประกอบ <intent>
ต่อไปนี้เป็นส่วนหนึ่งขององค์ประกอบ <queries>
ในไฟล์ Manifest
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.SENDTO"/> <data android:scheme="smsto" android:host="*" /> </intent>
สร้างชีตการแชร์ที่กำหนดเอง
ใช้ชีตการแชร์ที่ระบบมีให้ทุกครั้งที่ทำได้ หรือ
รวมองค์ประกอบ <intent>
ต่อไปนี้เป็นส่วนหนึ่งขององค์ประกอบ <queries>
ใน
ไฟล์ Manifest
<!-- 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>
ในไฟล์ Manifest
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.PROCESS_TEXT" /> <data android:mimeType="text/plain" /> </intent>
แสดงแถวข้อมูลที่กำหนดเองสำหรับรายชื่อติดต่อ
แอปสามารถเพิ่มแถว ข้อมูลที่กำหนดเองไปยัง Contacts Provider ได้ แอปรายชื่อติดต่อต้องทำสิ่งต่อไปนี้ได้จึงจะแสดงข้อมูลที่กำหนดเองนี้ได้
- อ่าน
contacts.xml
ไฟล์จากแอปอื่นๆ - โหลดไอคอนที่สอดคล้องกับประเภท MIME ที่กำหนดเอง
หากแอปเป็นแอปรายชื่อติดต่อ ให้รวมองค์ประกอบ <intent>
ต่อไปนี้เป็นส่วนหนึ่งขององค์ประกอบ <queries>
ในไฟล์ Manifest
<!-- 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>