ตอบสนอง Use Case ทั่วไปในขณะที่มีระดับการเข้าถึงแพ็กเกจที่จำกัด

เอกสารนี้นำเสนอกรณีการใช้งานทั่วไปหลายรายการที่แอปโต้ตอบกับ แอปอื่นๆ แต่ละส่วนจะมีคำแนะนำเกี่ยวกับวิธีทำให้แอป ที่มีระดับการเข้าถึงแพ็กเกจจำกัด ซึ่งคุณต้องดูว่า แอปกำหนดเป้าหมายเป็น Android 11 (API ระดับ 30) ขึ้นไป

เมื่อแอปที่กำหนดเป้าหมายเป็น Android 11 ขึ้นไปใช้ Intent เริ่มกิจกรรมในแอปอื่น วิธีที่ง่ายที่สุดคือการเรียกใช้ ในความตั้งใจและจัดการ ActivityNotFoundException ข้อยกเว้นหากไม่มีแอปที่พร้อมใช้งาน

หากส่วนหนึ่งของแอปขึ้นอยู่กับการทราบว่าการเรียกใช้ startActivity() จะสำเร็จหรือไม่ เช่น การแสดง UI ให้เพิ่มองค์ประกอบลงในองค์ประกอบ <queries> ของไฟล์ Manifest ของแอป โดยปกติแล้วจะเป็นองค์ประกอบ <intent>

URL ที่เปิด

ส่วนนี้อธิบายถึงวิธีต่างๆ ในการเปิด URL ในแอปที่กำหนดเป้าหมาย Android 11 ขึ้นไป

เปิด URL ในเบราว์เซอร์หรือแอปอื่นๆ

หากต้องการเปิด URL ให้ใช้ Intent ที่มีการดำเนินการของ Intent ACTION_VIEW ตามที่อธิบายไว้ในคู่มือการโหลด URL ของเว็บ หลังจากโทรหา startActivity() โดยใช้ Intent ดังกล่าว จะเกิดสิ่งใดสิ่งหนึ่งต่อไปนี้

  • URL จะเปิดในแอปเว็บเบราว์เซอร์
  • URL จะเปิดขึ้นในแอปที่สนับสนุน URL นี้ในรูปแบบ Deep ลิงก์
  • กล่องโต้ตอบที่มีคำอธิบายจะปรากฏขึ้น ซึ่งช่วยให้ผู้ใช้เลือกแอปได้ เปิด URL
  • ActivityNotFoundException เกิดขึ้นเนื่องจากไม่มีแอปติดตั้งใน อุปกรณ์ที่สามารถเปิด URL ได้ (ซึ่งผิดปกติ)

    เราขอแนะนำให้แอปตรวจจับและจัดการ ActivityNotFoundException หากเกิดขึ้น

เนื่องจากเมธอด startActivity() ไม่ต้องใช้ระดับการเข้าถึงแพ็กเกจเพื่อ เริ่มกิจกรรมของแอปพลิเคชันอื่น คุณไม่จำเป็นต้องเพิ่ม <queries> ลงในไฟล์ Manifest ของแอปหรือทำการเปลี่ยนแปลง <queries> ที่มีอยู่ กรณีนี้จะเกิดขึ้นกับ 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() และส่ง 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 ซึ่งกำหนด FLAG_ACTIVITY_REQUIRE_NON_BROWSER การแจ้งเกี่ยวกับ Intent หากระบบแสดง ActivityNotFoundException แอปของคุณก็จะเปิด URL ในแท็บที่กำหนดเองได้

หาก Intent มีแฟล็กนี้ การเรียกใช้ไปยัง startActivity() จะทำให้มีการตั้งค่า จะมีการส่ง ActivityNotFoundException ในกรณีต่อไปนี้ เกิดขึ้น:

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

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

หาก Intent มี Flag นี้เอาไว้ การเรียกไปยัง startActivity() จะทำให้ ทิ้ง ActivityNotFoundException เมื่อการโทรจะแสดง กล่องโต้ตอบที่มีคำอธิบายให้ผู้ใช้ได้อย่างชัดเจน

หาก Intent มีทั้งแฟล็กนี้และ FLAG_ACTIVITY_REQUIRE_NON_BROWSER การแจ้ง Intent การเรียกไปยัง startActivity() จะทำให้เกิดActivityNotFoundException แสดงเมื่อเกิดเงื่อนไขข้อใดข้อหนึ่งต่อไปนี้

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

ข้อมูลโค้ดต่อไปนี้แสดงวิธีใช้ Flag 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 และ 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() ด้วยความตั้งใจของคุณ

ให้สิทธิ์เข้าถึง URI

หมายเหตุ: การประกาศสิทธิ์การเข้าถึง URI ตามที่อธิบายไว้ในส่วนนี้ จำเป็นสำหรับแอปที่กำหนดเป้าหมายเป็น Android 11 (API ระดับ 30) ขึ้นไปและ แนะนําสําหรับแอปทั้งหมด โดยไม่คํานึงถึง SDK เป้าหมายเวอร์ชันใด พวกเขาส่งออก ผู้ให้บริการเนื้อหาของตน

สำหรับแอปที่กำหนดเป้าหมายเป็น Android 11 ขึ้นไป เข้าถึง URI เนื้อหา Intent ของแอปต้องประกาศการเข้าถึง URI สิทธิ์ โดยการตั้งค่า Intent Flag ข้อใดข้อหนึ่งหรือทั้ง 2 อย่างต่อไปนี้ FLAG_GRANT_READ_URI_PERMISSION และ FLAG_GRANT_WRITE_URI_PERMISSION

ใน Android 11 ขึ้นไป สิทธิ์การเข้าถึง URI จะให้สิทธิ์ ความสามารถต่อไปนี้ของแอปที่ได้รับ Intent

  • อ่านจากหรือเขียนไปยังข้อมูลที่ URI เนื้อหาแสดง โดยขึ้นอยู่กับ สิทธิ์ URI ที่กำหนด
  • รับสิทธิ์เข้าถึงแอปที่มีผู้ให้บริการเนื้อหาที่ตรงกับ สิทธิ์ URI แอปที่มีผู้ให้บริการเนื้อหาอาจแตกต่างออกไป จากแอปที่ส่ง 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>

ระบุฟังก์ชันที่กำหนดเอง

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

สร้างชีตการแชร์ที่กำหนดเอง

หากเป็นไปได้ ให้ใช้ระบบที่จัดเตรียมไว้ Sharesheet หรือ รวมเอลิเมนต์ <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>

กระบวนการสร้าง Sharesheet ในตรรกะของแอป เช่น การเรียก 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>

แสดงแถวข้อมูลที่กำหนดเองสำหรับรายชื่อติดต่อ

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

  1. อ่านไฟล์ contacts.xml จากแอปอื่นๆ
  2. โหลดไอคอนที่สอดคล้องกับประเภท 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>