Intent
คือออบเจ็กต์การรับส่งข้อความที่คุณใช้เพื่อขอการดำเนินการ
จากคอมโพเนนต์แอปอื่นได้
แม้ว่า Intent จะช่วยอำนวยความสะดวกในการสื่อสารระหว่างคอมโพเนนต์ได้หลายวิธี แต่ก็มีกรณีการใช้งานพื้นฐาน 3 กรณี ดังนี้
- การเริ่มกิจกรรม
Activity
แสดงถึงหน้าจอเดียวในแอป คุณเริ่มอินสแตนซ์ใหม่ของActivity
ได้โดยส่งIntent
ไปยังstartActivity()
Intent
อธิบายกิจกรรมที่จะเริ่มต้นและมีข้อมูลที่จำเป็นหากต้องการรับผลลัพธ์จากกิจกรรมเมื่อเสร็จสิ้น โปรดโทรหา
startActivityForResult()
กิจกรรมของคุณจะได้รับผลลัพธ์ เป็นออบเจ็กต์Intent
แยกต่างหากในonActivityResult()
Callback ของกิจกรรม ดูข้อมูลเพิ่มเติมได้ที่คู่มือกิจกรรม - การเริ่มบริการ
Service
คือคอมโพเนนต์ที่ดำเนินการในเบื้องหลัง โดยไม่มีอินเทอร์เฟซผู้ใช้ ใน Android 5.0 (API ระดับ 21) ขึ้นไป คุณจะเริ่มบริการได้ด้วยJobScheduler
ดูข้อมูลเพิ่มเติม เกี่ยวกับJobScheduler
ได้ที่API-reference documentation
สำหรับเวอร์ชันก่อน Android 5.0 (API ระดับ 21) คุณสามารถเริ่มบริการได้โดยใช้เมธอดของคลาส
Service
คุณสามารถเริ่มบริการ เพื่อดำเนินการแบบครั้งเดียว (เช่น ดาวน์โหลดไฟล์) ได้โดยส่งIntent
ไปยังstartService()
Intent
อธิบายบริการที่จะเริ่มต้นและมีข้อมูลที่จำเป็นหากบริการได้รับการออกแบบด้วยอินเทอร์เฟซไคลเอ็นต์-เซิร์ฟเวอร์ คุณจะเชื่อมโยงกับบริการ จากคอมโพเนนต์อื่นได้โดยส่ง
Intent
ไปยังbindService()
ดูข้อมูลเพิ่มเติมได้ในคู่มือบริการ - การออกอากาศ
การออกอากาศคือข้อความที่แอปใดก็ได้รับได้ ระบบจะส่ง การออกอากาศต่างๆ สำหรับเหตุการณ์ของระบบ เช่น เมื่อระบบบูตขึ้นหรืออุปกรณ์เริ่มชาร์จ คุณสามารถส่งการออกอากาศไปยังแอปอื่นๆ ได้โดยส่ง
Intent
ไปยังsendBroadcast()
หรือsendOrderedBroadcast()
ส่วนที่เหลือของหน้านี้จะอธิบายวิธีการทำงานของเจตนาและวิธีใช้เจตนา ดูข้อมูลที่เกี่ยวข้องได้ที่ การโต้ตอบกับแอปอื่นๆ และการแชร์เนื้อหา
ประเภท Intent
Intent มี 2 ประเภท ได้แก่
- Intent ที่ชัดแจ้งจะระบุคอมโพเนนต์ของแอปพลิเคชันที่จะตอบสนอง Intent โดยการระบุ
ComponentName
แบบเต็ม โดยปกติแล้ว คุณจะใช้ Intent ที่ชัดเจนเพื่อเริ่มคอมโพเนนต์ในแอปของคุณเอง เนื่องจากคุณทราบชื่อคลาสของกิจกรรมหรือบริการที่ต้องการเริ่ม ตัวอย่างเช่น คุณอาจเริ่มกิจกรรมใหม่ภายในแอปเพื่อตอบสนองต่อการดำเนินการของผู้ใช้ หรือเริ่มบริการเพื่อดาวน์โหลดไฟล์ในเบื้องหลัง - Intent แบบไม่เจาะจงปลายทางไม่ได้ระบุชื่อคอมโพเนนต์ที่เฉพาะเจาะจง แต่จะประกาศการดำเนินการทั่วไป ที่จะทำแทน ซึ่งจะช่วยให้คอมโพเนนต์จากแอปอื่นจัดการได้ ตัวอย่างเช่น หากต้องการ แสดงตำแหน่งบนแผนที่ให้ผู้ใช้เห็น คุณสามารถใช้ Intent โดยนัยเพื่อขอให้แอปอื่นที่ทำได้ แสดงตำแหน่งที่ระบุบนแผนที่
รูปที่ 1 แสดงวิธีใช้ Intent เมื่อเริ่มกิจกรรม เมื่อ
Intent
ระบุชื่อออบเจ็กต์ของคอมโพเนนต์กิจกรรมที่เฉพาะเจาะจงอย่างชัดเจน ระบบจะเริ่มคอมโพเนนต์นั้นทันที

รูปที่ 1 วิธีส่งเจตนาโดยนัยผ่านระบบเพื่อเริ่มกิจกรรมอื่น: [1] กิจกรรม ก สร้าง Intent
พร้อมคำอธิบายการดำเนินการและส่งไปยัง startActivity()
[2] ระบบ Android จะค้นหาตัวกรอง Intent ที่ตรงกับ Intent ในแอปทั้งหมด
เมื่อพบการจับคู่ที่ตรงกัน [3] ระบบ
จะเริ่มกิจกรรมการจับคู่ (กิจกรรม B) โดยเรียกใช้เมธอด onCreate()
และส่ง Intent
ไปให้
เมื่อใช้ Intent โดยนัย ระบบ Android จะค้นหาคอมโพเนนต์ที่เหมาะสมเพื่อเริ่มต้น
โดยการเปรียบเทียบเนื้อหาของ Intent กับตัวกรอง Intent ที่ประกาศไว้ในไฟล์ Manifest ของแอปอื่นๆ ใน
อุปกรณ์ หาก Intent ตรงกับตัวกรอง Intent ระบบจะเริ่มคอมโพเนนต์นั้นและส่งไปยังออบเจ็กต์ Intent
หากมีตัวกรอง Intent หลายรายการที่เข้ากันได้ ระบบจะแสดงกล่องโต้ตอบเพื่อให้ผู้ใช้เลือกแอปที่จะใช้
ตัวกรอง Intent คือนิพจน์ในไฟล์ Manifest ของแอปที่ ระบุประเภทของ Intent ที่คอมโพเนนต์ ต้องการรับ เช่น การประกาศตัวกรอง Intent สำหรับกิจกรรม จะช่วยให้แอปอื่นๆ เริ่มกิจกรรมของคุณโดยตรงด้วย Intent บางประเภทได้ ในทำนองเดียวกัน หากคุณไม่ประกาศตัวกรอง Intent สำหรับกิจกรรม ก็จะเริ่มกิจกรรมได้ ด้วย Intent ที่ชัดเจนเท่านั้น
ข้อควรระวัง: เพื่อให้มั่นใจว่าแอปของคุณปลอดภัย ให้ใช้
Intent ที่ชัดเจนเสมอ
เมื่อเริ่มต้น Service
และอย่า
ประกาศตัวกรอง Intent สำหรับบริการของคุณ การใช้อินเทนต์โดยนัยเพื่อเริ่มบริการเป็น
อันตรายด้านความปลอดภัยเนื่องจากคุณไม่สามารถมั่นใจได้ว่าบริการใดจะตอบสนองต่ออินเทนต์
และผู้ใช้ไม่สามารถดูได้ว่าบริการใดเริ่มทำงาน เริ่มตั้งแต่ Android 5.0 (API ระดับ 21) เป็นต้นไป ระบบจะ
ยกเว้นหากคุณเรียกใช้ bindService()
ด้วย Intent โดยนัย
การสร้างความตั้งใจ
ออบเจ็กต์ Intent
มีข้อมูลที่ระบบ Android ใช้
เพื่อกำหนดคอมโพเนนต์ที่จะเริ่มต้น (เช่น ชื่อคอมโพเนนต์ที่แน่นอนหรือหมวดหมู่คอมโพเนนต์
ที่ควรรับ Intent) รวมถึงข้อมูลที่คอมโพเนนต์ผู้รับใช้
เพื่อดำเนินการอย่างถูกต้อง (เช่น การดำเนินการที่จะทำและข้อมูลที่จะดำเนินการ)
ข้อมูลหลักที่อยู่ใน Intent
มีดังนี้
- ชื่อคอมโพเนนต์
- ชื่อของคอมโพเนนต์ที่จะเริ่มต้น
ซึ่งเป็นข้อมูลที่ไม่บังคับ แต่เป็นข้อมูลที่สำคัญซึ่งทำให้ Intent ชัดเจน ซึ่งหมายความว่าควรส่ง Intent ไปยังคอมโพเนนต์แอปที่กำหนดโดยชื่อคอมโพเนนต์เท่านั้น หากไม่มีชื่อคอมโพเนนต์ ความตั้งใจจะเป็นแบบโดยนัย และระบบจะตัดสินใจว่าคอมโพเนนต์ใดควรรับความตั้งใจโดยอิงตามข้อมูลความตั้งใจอื่นๆ (เช่น การดำเนินการ ข้อมูล และหมวดหมู่ ซึ่งอธิบายไว้ด้านล่าง) หากต้องการเริ่มคอมโพเนนต์ที่เฉพาะเจาะจงในแอป คุณควรระบุชื่อคอมโพเนนต์
หมายเหตุ: เมื่อเริ่มต้น
Service
, ให้ระบุชื่อคอมโพเนนต์เสมอ ไม่เช่นนั้น คุณจะไม่ทราบว่าบริการใด จะตอบสนองต่อความตั้งใจ และผู้ใช้จะไม่เห็นว่าบริการใดเริ่มทำงานฟิลด์นี้ของ
Intent
คือออบเจ็กต์ComponentName
ซึ่งคุณระบุได้โดยใช้ชื่อคลาสที่สมบูรณ์ของคอมโพเนนต์เป้าหมาย รวมถึงชื่อแพ็กเกจของแอป เช่นcom.example.ExampleActivity
คุณตั้งชื่อคอมโพเนนต์ได้ด้วยsetComponent()
,setClass()
,setClassName()
หรือด้วยตัวสร้างIntent
- การดำเนินการ
- สตริงที่ระบุการดำเนินการทั่วไปที่จะทำ (เช่น ดูหรือเลือก)
ในกรณีของ Intent การออกอากาศ นี่คือการดำเนินการที่เกิดขึ้นและกำลังรายงาน การดำเนินการส่วนใหญ่จะเป็นตัวกำหนดโครงสร้างของส่วนที่เหลือของ Intent โดยเฉพาะ ข้อมูลที่อยู่ในข้อมูลและส่วนเสริม
คุณสามารถระบุการดำเนินการของคุณเองเพื่อให้ Intent ภายในแอปใช้ (หรือเพื่อให้แอปอื่นๆ ใช้เรียกใช้คอมโพเนนต์ในแอป) แต่โดยปกติแล้วคุณจะระบุค่าคงที่ของการดำเนินการที่กำหนดโดยคลาส
Intent
หรือคลาสเฟรมเวิร์กอื่นๆ การดำเนินการทั่วไปบางอย่างสำหรับการเริ่มกิจกรรมมีดังนี้ACTION_VIEW
- ใช้การดำเนินการนี้ใน Intent ที่มี
startActivity()
เมื่อคุณมีข้อมูลบางอย่างที่ กิจกรรมสามารถแสดงต่อผู้ใช้ได้ เช่น รูปภาพที่จะดูในแอปแกลเลอรี หรือที่อยู่ที่จะ ดูในแอปแผนที่ ACTION_SEND
- คุณควรใช้เจตนาที่เรียกอีกอย่างว่าเจตนาแชร์ในเจตนาที่มี
startActivity()
เมื่อคุณมีข้อมูลที่ผู้ใช้สามารถ แชร์ผ่านแอปอื่น เช่น แอปอีเมลหรือแอปแชร์ในโซเชียล
ดูค่าคงที่เพิ่มเติมที่กำหนดการดำเนินการทั่วไปได้ที่การอ้างอิงคลาส
Intent
การดำเนินการอื่นๆ จะกำหนดไว้ ที่อื่นในเฟรมเวิร์ก Android เช่น ในSettings
สำหรับการดำเนินการ ที่เปิดหน้าจอที่เฉพาะเจาะจงในแอปการตั้งค่าของระบบคุณระบุการดำเนินการสำหรับ Intent ได้ด้วย
setAction()
หรือด้วยตัวสร้างIntent
หากกำหนดการดำเนินการของคุณเอง โปรดตรวจสอบว่าได้ใส่ชื่อแพ็กเกจของแอป เป็นคำนำหน้า ดังที่แสดงในตัวอย่างต่อไปนี้
Kotlin
const val ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL"
Java
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
- ข้อมูล
- URI (ออบเจ็กต์
Uri
) ที่อ้างอิงถึงข้อมูลที่จะ ดำเนินการและ/หรือ ประเภท MIME ของข้อมูลนั้น โดยทั่วไปแล้ว ประเภทของข้อมูลที่ให้จะขึ้นอยู่กับการดำเนินการของ Intent เช่น หากการดำเนินการคือACTION_EDIT
ข้อมูลควรมี URI ของเอกสารที่จะแก้ไขเมื่อสร้าง Intent มักจะต้องระบุประเภทข้อมูล (ประเภท MIME) นอกเหนือจาก URI ตัวอย่างเช่น กิจกรรมที่แสดงรูปภาพได้อาจเล่นไฟล์เสียงไม่ได้ แม้ว่ารูปแบบ URI จะคล้ายกันก็ตาม การระบุประเภท MIME ของข้อมูลจะช่วยให้ระบบ Android ค้นหาคอมโพเนนต์ที่ดีที่สุดเพื่อรับ Intent ของคุณได้ อย่างไรก็ตาม บางครั้งระบบอาจอนุมานประเภท MIME จาก URI ได้ โดยเฉพาะเมื่อข้อมูลเป็น URI ของ
content:
content:
URI ระบุว่าข้อมูลอยู่ในอุปกรณ์ และควบคุมโดยContentProvider
ซึ่งทำให้ระบบมองเห็นประเภท MIME ของข้อมูลหากต้องการตั้งค่าเฉพาะ URI ข้อมูล ให้เรียกใช้
setData()
หากต้องการตั้งค่าเฉพาะประเภท MIME ให้เรียกใช้setType()
หากจำเป็น คุณ สามารถตั้งค่าทั้ง 2 อย่างอย่างชัดเจนด้วยsetDataAndType()
ข้อควรระวัง: หากต้องการตั้งค่าทั้ง URI และประเภท MIME อย่าเรียกใช้
setData()
และsetType()
เนื่องจากแต่ละรายการจะลบล้างค่าของอีกรายการหนึ่ง ใช้setDataAndType()
เพื่อตั้งค่าทั้ง URI และประเภท MIME เสมอ - หมวดหมู่
- สตริงที่มีข้อมูลเพิ่มเติมเกี่ยวกับประเภทของคอมโพเนนต์
ที่ควรจัดการ Intent สามารถใส่คำอธิบายหมวดหมู่จำนวนเท่าใดก็ได้ใน Intent แต่ Intent ส่วนใหญ่ไม่จำเป็นต้องมีหมวดหมู่
หมวดหมู่ที่พบบ่อยมีดังนี้
CATEGORY_BROWSABLE
- กิจกรรมเป้าหมายอนุญาตให้เว็บเบราว์เซอร์เริ่มกิจกรรมเพื่อแสดงข้อมูล ที่ลิงก์อ้างอิง เช่น รูปภาพหรือข้อความอีเมล
CATEGORY_LAUNCHER
- กิจกรรมนี้เป็นกิจกรรมเริ่มต้นของงานและแสดงอยู่ในตัวเปิดแอปพลิเคชันของระบบ
ดูรายการหมวดหมู่ทั้งหมดได้ที่
Intent
คำอธิบายคลาสคุณระบุหมวดหมู่ได้ด้วย
addCategory()
พร็อพเพอร์ตี้ที่ระบุไว้ข้างต้น (ชื่อคอมโพเนนต์ การดำเนินการ ข้อมูล และหมวดหมู่) แสดงถึงลักษณะที่กำหนดของ Intent การอ่านพร็อพเพอร์ตี้เหล่านี้ช่วยให้ระบบ Android ระบุได้ว่าควรเริ่มต้นคอมโพเนนต์แอปใด อย่างไรก็ตาม Intent สามารถมี ข้อมูลเพิ่มเติมซึ่งไม่ส่งผลต่อ วิธีที่ Intent ได้รับการแก้ไขเป็นคอมโพเนนต์ของแอป นอกจากนี้ Intent ยังระบุข้อมูลต่อไปนี้ได้ด้วย
- ฟีเจอร์เพิ่มเติม
- คู่คีย์-ค่าที่มีข้อมูลเพิ่มเติมที่จำเป็นต่อการดำเนินการตามที่ขอ
เช่นเดียวกับการดำเนินการบางอย่างที่ใช้ URI ข้อมูลบางประเภท การดำเนินการบางอย่างก็ใช้ส่วนเสริมบางอย่างด้วย
คุณเพิ่มข้อมูลพิเศษได้ด้วย
putExtra()
เมธอดต่างๆ ซึ่งแต่ละเมธอดจะรับพารามิเตอร์ 2 รายการ ได้แก่ ชื่อคีย์และค่า นอกจากนี้ คุณยังสร้างออบเจ็กต์Bundle
ที่มีข้อมูลเพิ่มเติมทั้งหมด แล้วแทรกBundle
ในIntent
ด้วยputExtras()
ได้ด้วยเช่น เมื่อสร้าง Intent เพื่อส่งอีเมลด้วย
ACTION_SEND
คุณจะระบุผู้รับ to ด้วยคีย์EXTRA_EMAIL
และระบุเรื่องด้วยคีย์EXTRA_SUBJECT
ได้คลาส
Intent
ระบุค่าคงที่EXTRA_*
หลายรายการ สำหรับประเภทข้อมูลที่ได้มาตรฐาน หากต้องการประกาศคีย์เพิ่มเติมของคุณเอง (สำหรับ Intent ที่แอปได้รับ) โปรดตรวจสอบว่าได้รวมชื่อแพ็กเกจของแอปเป็นคำนำหน้าแล้ว ดังที่แสดงในตัวอย่างต่อไปนี้Kotlin
const val EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS"
Java
static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
ข้อควรระวัง: อย่าใช้ข้อมูล
Parcelable
หรือSerializable
เมื่อส่ง Intent ที่คุณคาดหวัง ให้แอปอื่นรับ หากแอป พยายามเข้าถึงข้อมูลในออบเจ็กต์Bundle
แต่ไม่มี สิทธิ์เข้าถึงคลาสที่แยกวิเคราะห์หรือซีเรียล ระบบจะแสดงRuntimeException
- Flags
- ระบบจะกำหนด Flag ในคลาส
Intent
ซึ่งทำหน้าที่เป็นข้อมูลเมตาสำหรับ Intent โดย Flag อาจสั่งให้ระบบ Android เปิดใช้งาน Activity (เช่น Task ที่ Activity ควรเป็นของ) และวิธีจัดการ Activity หลังจากเปิดใช้งาน (เช่น Activity ควรอยู่ในรายการกิจกรรมล่าสุดหรือไม่)ดูข้อมูลเพิ่มเติมได้ที่
setFlags()
วิธี
ตัวอย่าง Intent แบบเจาะจงปลายทาง
Explicit Intent คือ Intent ที่คุณใช้เพื่อเปิดใช้คอมโพเนนต์แอปที่เฉพาะเจาะจง เช่น
กิจกรรมหรือบริการที่เฉพาะเจาะจงในแอปของคุณ หากต้องการสร้าง Explicit Intent ให้กำหนด
ชื่อคอมโพเนนต์สำหรับออบเจ็กต์ Intent
คุณสมบัติ Intent อื่นๆ ทั้งหมด
เป็นแบบไม่บังคับ
เช่น หากคุณสร้างบริการในแอปชื่อ DownloadService
ซึ่งออกแบบมาเพื่อดาวน์โหลดไฟล์จากเว็บ คุณจะเริ่มบริการได้ด้วยโค้ดต่อไปนี้
Kotlin
// Executed in an Activity, so 'this' is theContext
// The fileUrl is a string URL, such as "http://www.example.com/image.png" val downloadIntent = Intent(this, DownloadService::class.java).apply { data =Uri.parse
(fileUrl) } startService(downloadIntent)
Java
// Executed in an Activity, so 'this' is theContext
// The fileUrl is a string URL, such as "http://www.example.com/image.png" Intent downloadIntent = new Intent(this, DownloadService.class); downloadIntent.setData(Uri.parse
(fileUrl)); startService(downloadIntent);
ตัวสร้าง Intent(Context, Class)
จะจัดหา Context
และ
คอมโพเนนต์ Class
ให้กับแอป ดังนั้น
ความตั้งใจนี้จึงเริ่มคลาส DownloadService
ในแอปอย่างชัดเจน
ดูข้อมูลเพิ่มเติมเกี่ยวกับการสร้างและเริ่มต้นบริการได้ที่คู่มือบริการ
ตัวอย่าง Intent แบบไม่เจาะจงปลายทาง
Intent แบบไม่เจาะจงปลายทางจะระบุการดำเนินการที่เรียกใช้แอปใดก็ได้ในอุปกรณ์ที่สามารถ ดำเนินการดังกล่าวได้ การใช้อินเทนต์โดยนัยจะมีประโยชน์เมื่อแอปของคุณดำเนินการ ไม่ได้ แต่แอปอื่นๆ อาจทำได้ และคุณต้องการให้ผู้ใช้เลือกแอปที่จะใช้
เช่น หากคุณมีเนื้อหาที่ต้องการให้ผู้ใช้แชร์กับผู้อื่น
ให้สร้าง Intent
ด้วย ACTION_SEND
action
และเพิ่มส่วนเสริมที่ระบุเนื้อหาที่จะแชร์ เมื่อคุณเรียกใช้
startActivity()
ด้วยความตั้งใจนั้น ผู้ใช้จะเลือกแอปที่จะแชร์เนื้อหาผ่านแอปนั้นได้
Kotlin
// Create the text message with a string. val sendIntent = Intent().apply { action = Intent.ACTION_SEND putExtra(Intent.EXTRA_TEXT, textMessage) type = "text/plain" } // Try to invoke the intent. try { startActivity(sendIntent) } catch (e: ActivityNotFoundException) { // Define what your app should do if no activity can handle the intent. }
Java
// Create the text message with a string. Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); sendIntent.setType("text/plain"); // Try to invoke the intent. try { startActivity(sendIntent); } catch (ActivityNotFoundException e) { // Define what your app should do if no activity can handle the intent. }
เมื่อมีการเรียกใช้ startActivity()
ระบบจะ
ตรวจสอบแอปที่ติดตั้งทั้งหมดเพื่อพิจารณาว่าแอปใดจัดการ Intent ประเภทนี้ได้ (Intent ที่มี
การดำเนินการ ACTION_SEND
และมีข้อมูล "text/plain"
) หากมีเพียงแอปเดียวที่จัดการได้ แอปนั้นจะเปิดขึ้นทันทีและได้รับ
Intent หากไม่มีแอปอื่นจัดการได้ แอปของคุณจะตรวจพบ
ActivityNotFoundException
ที่เกิดขึ้น หากมีกิจกรรมหลายอย่างที่ยอมรับ Intent ระบบจะแสดงกล่องโต้ตอบ เช่น กล่องโต้ตอบที่แสดงในรูปที่ 2 เพื่อให้ผู้ใช้เลือกแอปที่จะใช้ได้
นอกจากนี้ คู่มือยังให้ข้อมูลเพิ่มเติมเกี่ยวกับการเปิดตัวแอปอื่นๆ ในส่วนการส่งผู้ใช้ไปยัง แอปอื่น

รูปที่ 2 กล่องโต้ตอบตัวเลือก
บังคับให้แสดงตัวเลือกแอป
เมื่อมีแอปมากกว่า 1 แอปที่ตอบสนองต่อความตั้งใจโดยนัย ผู้ใช้จะเลือกแอปที่จะใช้และตั้งค่าแอปนั้นเป็นตัวเลือกเริ่มต้นสำหรับการดำเนินการได้ ความสามารถในการเลือกค่าเริ่มต้นมีประโยชน์เมื่อดำเนินการที่ผู้ใช้ อาจต้องการใช้แอปเดียวกันทุกครั้ง เช่น เมื่อเปิดหน้าเว็บ (ผู้ใช้ มักจะชอบใช้เว็บเบราว์เซอร์เพียงตัวเดียว)
อย่างไรก็ตาม หากมีแอปหลายแอปที่ตอบสนองต่อ Intent ได้ และผู้ใช้อาจต้องการใช้แอปอื่นในแต่ละครั้ง คุณควรแสดงกล่องโต้ตอบตัวเลือกอย่างชัดเจน กล่องโต้ตอบตัวเลือกจะขอให้ผู้ใช้เลือกแอปที่จะใช้สำหรับการดำเนินการ (ผู้ใช้ไม่สามารถเลือกแอปเริ่มต้นสำหรับการดำเนินการได้) ตัวอย่างเช่น เมื่อแอปของคุณดำเนินการ "แชร์" ด้วยACTION_SEND
การดำเนินการ ผู้ใช้อาจต้องการแชร์โดยใช้แอปอื่น ทั้งนี้ขึ้นอยู่กับสถานการณ์ปัจจุบัน ดังนั้นคุณควรใช้กล่องโต้ตอบตัวเลือกเสมอ ดังที่แสดงในรูปที่ 2
หากต้องการแสดงตัวเลือก ให้สร้าง Intent
โดยใช้ createChooser()
แล้วส่งไปยัง startActivity()
ดังที่แสดงในตัวอย่างต่อไปนี้
ตัวอย่างนี้แสดงกล่องโต้ตอบที่มีรายการแอปที่ตอบสนองต่อ Intent ที่ส่งไปยังเมธอด createChooser()
และใช้ข้อความที่ระบุเป็นชื่อกล่องโต้ตอบ
Kotlin
val sendIntent = Intent(Intent.ACTION_SEND) ... // Always use string resources for UI text. // This says something like "Share this photo with" val title: String = resources.getString(R.string.chooser_title) // Create intent to show the chooser dialog val chooser: Intent = Intent.createChooser(sendIntent, title) // Verify the original intent will resolve to at least one activity if (sendIntent.resolveActivity(packageManager) != null) { startActivity(chooser) }
Java
Intent sendIntent = new Intent(Intent.ACTION_SEND); ... // Always use string resources for UI text. // This says something like "Share this photo with" String title = getResources().getString(R.string.chooser_title); // Create intent to show the chooser dialog Intent chooser = Intent.createChooser(sendIntent, title); // Verify the original intent will resolve to at least one activity if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(chooser); }
ตรวจหาการเปิดใช้ Intent ที่ไม่ปลอดภัย
แอปอาจเปิด Intent เพื่อไปยังส่วนประกอบต่างๆ ภายในแอป หรือเพื่อดำเนินการในนามของแอปอื่น เพื่อปรับปรุงความปลอดภัยของแพลตฟอร์ม Android 12 (API ระดับ 31) ขึ้นไปมีฟีเจอร์การแก้ไขข้อบกพร่องที่จะเตือนคุณ หากแอปเปิด Intent อย่างไม่ปลอดภัย เช่น แอปของคุณอาจ เปิดใช้ Intent ที่ซ้อนกันอย่างไม่ปลอดภัย ซึ่งเป็น Intent ที่ส่ง เป็นส่วนเสริมใน Intent อื่น
หากแอปของคุณดำเนินการทั้ง 2 อย่างต่อไปนี้ ระบบจะตรวจพบการเปิด Intent ที่ไม่ปลอดภัยและเกิดการละเมิด StrictMode
- แอปของคุณยกเลิกการส่งผ่าน Intent ที่ซ้อนกันจากส่วนเสริมของ Intent ที่ส่ง
- แอปของคุณจะเริ่มคอมโพเนนต์
แอปทันทีโดยใช้ Intent ที่ซ้อนกันนั้น
เช่น การส่ง Intent ไปยัง
startActivity()
startService()
หรือbindService()
ดูรายละเอียดเพิ่มเติมเกี่ยวกับวิธีระบุสถานการณ์นี้และทำการเปลี่ยนแปลงในแอปได้ ในบล็อกโพสต์เกี่ยวกับ Android Nesting Intents บน Medium
ตรวจสอบการเปิดใช้ Intent ที่ไม่ปลอดภัย
หากต้องการตรวจสอบการเปิดใช้ Intent ที่ไม่ปลอดภัยในแอป ให้เรียกใช้
detectUnsafeIntentLaunch()
เมื่อกำหนดค่า VmPolicy
ดังที่แสดงในข้อมูลโค้ดต่อไปนี้ หากแอปตรวจพบการละเมิด StrictMode คุณอาจต้องหยุดการทำงานของแอปเพื่อ
ปกป้องข้อมูลที่อาจมีความละเอียดอ่อน
Kotlin
fun onCreate() { StrictMode.setVmPolicy(VmPolicy.Builder() // Other StrictMode checks that you've previously added. // ... .detectUnsafeIntentLaunch() .penaltyLog() // Consider also adding penaltyDeath() .build()) }
Java
protected void onCreate() { StrictMode.setVmPolicy(new VmPolicy.Builder() // Other StrictMode checks that you've previously added. // ... .detectUnsafeIntentLaunch() .penaltyLog() // Consider also adding penaltyDeath() .build()); }
ใช้ความตั้งใจอย่างมีความรับผิดชอบมากขึ้น
ทําตามแนวทางปฏิบัติแนะนําต่อไปนี้เพื่อลดโอกาสที่จะมีการเปิดใช้ Intent ที่ไม่ปลอดภัยและการละเมิด StrictMode
คัดลอกเฉพาะส่วนเสริมที่จำเป็นภายใน Intent และทำการล้างข้อมูลและการตรวจสอบที่จำเป็น แอปอาจคัดลอกข้อมูลพิเศษจาก Intent หนึ่งไปยัง Intent อื่นที่ใช้เพื่อเปิดคอมโพเนนต์ใหม่ ปัญหานี้เกิดขึ้นเมื่อแอปของคุณเรียกใช้
putExtras(Intent)
หรือ
putExtras(Bundle)
หากแอปของคุณดำเนินการอย่างใดอย่างหนึ่งต่อไปนี้ ให้คัดลอกเฉพาะส่วนเสริมที่คอมโพเนนต์ผู้รับคาดหวัง หาก Intent อื่น (ที่รับสำเนา)
เปิดใช้คอมโพเนนต์ที่ไม่ได้
ส่งออก ให้ล้างข้อมูลและ
ตรวจสอบข้อมูลเพิ่มเติมก่อนที่จะคัดลอกไปยัง Intent ที่เปิดใช้
คอมโพเนนต์
อย่าส่งออกคอมโพเนนต์ของแอปโดยไม่จำเป็น เช่น หากคุณ
ต้องการเปิดใช้คอมโพเนนต์แอปโดยใช้ Intent ที่ซ้อนกันภายใน ให้ตั้งค่าแอตทริบิวต์ android:exported
ของคอมโพเนนต์นั้นเป็น false
ใช้ PendingIntent
แทน
Intent ที่ซ้อนกัน ด้วยวิธีนี้ เมื่อแอปอื่นยกเลิกการส่งผ่านข้อมูล PendingIntent
ของ Intent
ที่มีอยู่ แอปอื่นจะเปิด PendingIntent
ได้โดยใช้ข้อมูลประจำตัวของแอปคุณ การกำหนดค่านี้ช่วยให้แอปอื่นเปิดคอมโพเนนต์ใดก็ได้ รวมถึงคอมโพเนนต์ที่ไม่ได้ส่งออกในแอปของคุณได้อย่างปลอดภัย
แผนภาพในรูปที่ 2 แสดงวิธีที่ระบบส่งการควบคุมจากแอป (ไคลเอ็นต์) ของคุณไปยังแอปอื่น (บริการ) และกลับมายังแอปของคุณ
- แอปของคุณสร้าง Intent ที่เรียกใช้กิจกรรมในแอปอื่น ภายใน Intent นั้น คุณจะเพิ่มออบเจ็กต์
PendingIntent
เป็นส่วนเสริมได้ PendingIntent นี้ เรียกใช้คอมโพเนนต์ในแอปของคุณ แต่คอมโพเนนต์นี้ไม่ได้ส่งออก - เมื่อได้รับ Intent ของแอปแล้ว แอปอื่นจะดึงออบเจ็กต์
PendingIntent
ที่ซ้อนกันออกมา - แอปอื่นจะเรียกใช้เมธอด
send()
ในออบเจ็กต์PendingIntent
- หลังจากส่งคืนการควบคุมไปยังแอปแล้ว ระบบจะเรียกใช้ Intent ที่รอดำเนินการโดยใช้บริบทของแอป
รูปที่ 2 แผนภาพการสื่อสารระหว่างแอปเมื่อใช้ PendingIntent ที่ซ้อนกัน
การรับ Intent โดยนัย
หากต้องการโฆษณาว่าแอปของคุณรับ Intent โดยนัยใดได้บ้าง ให้ประกาศตัวกรอง Intent อย่างน้อย 1 รายการสำหรับ
คอมโพเนนต์แอปแต่ละรายการด้วยองค์ประกอบ <intent-filter>
ในไฟล์ Manifest
ตัวกรอง Intent แต่ละรายการจะระบุประเภทของ Intent ที่ยอมรับตามการดำเนินการ ข้อมูล และหมวดหมู่ของ Intent
ระบบจะส่ง Intent โดยนัยไปยังคอมโพเนนต์ของแอปก็ต่อเมื่อ Intent ผ่านตัวกรอง Intent อย่างใดอย่างหนึ่งของคุณได้
หมายเหตุ: ระบบจะนำส่ง Intent แบบเจาะจงปลายทางไปยังเป้าหมายเสมอ โดยไม่คำนึงถึงตัวกรอง Intent ที่คอมโพเนนต์ประกาศ
คอมโพเนนต์แอปควรประกาศตัวกรองแยกต่างหากสำหรับแต่ละงานที่ไม่ซ้ำกันที่ทำได้
ตัวอย่างเช่น กิจกรรมหนึ่งในแอปแกลเลอรีรูปภาพอาจมีตัวกรอง 2 ตัว ได้แก่ ตัวกรองหนึ่ง
สำหรับดูรูปภาพ และอีกตัวกรองหนึ่งสำหรับแก้ไขรูปภาพ เมื่อกิจกรรมเริ่มต้น
กิจกรรมจะตรวจสอบ Intent
และตัดสินใจว่าจะทำงานอย่างไรตามข้อมูล
ใน Intent
(เช่น จะแสดงตัวควบคุมเอดิเตอร์หรือไม่)
ตัวกรอง Intent แต่ละรายการจะกำหนดโดยองค์ประกอบ <intent-filter>
ในไฟล์ Manifest ของแอป ซึ่งซ้อนอยู่ในคอมโพเนนต์แอปที่เกี่ยวข้อง (เช่น องค์ประกอบ <activity>
)
ในคอมโพเนนต์ของแอปแต่ละรายการที่มีองค์ประกอบ <intent-filter>
ให้
ตั้งค่าสำหรับ
android:exported
อย่างชัดเจน
แอตทริบิวต์นี้ระบุว่าแอปอื่นๆ เข้าถึงคอมโพเนนต์ของแอปได้หรือไม่ ในบางกรณี เช่น กิจกรรมที่มีตัวกรอง Intent ซึ่งรวมหมวดหมู่ LAUNCHER
การตั้งค่าแอตทริบิวต์นี้เป็น true
จะมีประโยชน์ มิเช่นนั้น การตั้งค่าแอตทริบิวต์นี้เป็น false
จะปลอดภัยกว่า
คำเตือน: หากกิจกรรม บริการ หรือ Broadcast
Receiver ในแอปของคุณใช้ตัวกรอง Intent และไม่ได้ตั้งค่าอย่างชัดเจน
สำหรับ android:exported
คุณจะติดตั้งแอปในอุปกรณ์ที่
ใช้ Android 12 ขึ้นไปไม่ได้
ภายใน <intent-filter>
คุณสามารถระบุประเภทของ Intent ที่จะยอมรับได้โดยใช้
องค์ประกอบ 3 อย่างนี้อย่างน้อย 1 รายการ
<action>
- ประกาศการดำเนินการตามความตั้งใจที่ยอมรับในแอตทริบิวต์
name
ค่า ต้องเป็นค่าสตริงตามตัวอักษรของการดำเนินการ ไม่ใช่ค่าคงที่ของคลาส <data>
- ประกาศประเภทข้อมูลที่ยอมรับโดยใช้แอตทริบิวต์อย่างน้อย 1 รายการที่ระบุลักษณะต่างๆ ของ URI ข้อมูล (
scheme
,host
,port
,path
) และประเภท MIME <category>
- ประกาศหมวดหมู่เจตนาที่ยอมรับในแอตทริบิวต์
name
ค่า ต้องเป็นค่าสตริงตามตัวอักษรของการดำเนินการ ไม่ใช่ค่าคงที่ของคลาสหมายเหตุ: หากต้องการรับ Intent โดยนัย คุณต้องรวมหมวดหมู่
CATEGORY_DEFAULT
ไว้ในตัวกรอง Intent เมธอดstartActivity()
และstartActivityForResult()
จะถือว่า Intent ทั้งหมด ประกาศหมวดหมู่CATEGORY_DEFAULT
หากคุณไม่ประกาศหมวดหมู่นี้ในตัวกรอง Intent จะไม่มี Intent โดยนัยใดๆ ที่จะส่งไปยังกิจกรรมของคุณ
ตัวอย่างเช่น นี่คือการประกาศกิจกรรมที่มีตัวกรอง Intent เพื่อรับ Intent ACTION_SEND
เมื่อประเภทข้อมูลเป็นข้อความ
<activity android:name="ShareActivity" android:exported="false"> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> </activity>
คุณสร้างตัวกรองที่มีอินสแตนซ์ของ
<action>
<data>
หรือ
<category>
มากกว่า 1 รายการได้
หากทำเช่นนั้น คุณต้องมั่นใจว่าคอมโพเนนต์สามารถจัดการกับ
การผสมผสานขององค์ประกอบตัวกรองเหล่านั้นได้ทั้งหมด
เมื่อต้องการจัดการ Intent หลายประเภท แต่เฉพาะในชุดค่าผสมที่เฉพาะเจาะจงของ การดำเนินการ ข้อมูล และประเภทหมวดหมู่ คุณจะต้องสร้างตัวกรอง Intent หลายรายการ
ระบบจะทดสอบ Intent โดยนัยกับตัวกรองโดยการเปรียบเทียบ Intent กับองค์ประกอบทั้ง 3 รายการ Intent ต้องผ่านการทดสอบทั้ง 3 รายการจึงจะส่งไปยังคอมโพเนนต์ได้ หากจับคู่ไม่สำเร็จแม้แต่รายการเดียว ระบบ Android จะไม่ส่ง Intent ไปยัง คอมโพเนนต์ อย่างไรก็ตาม เนื่องจากคอมโพเนนต์อาจมีตัวกรอง Intent หลายรายการ Intent ที่ไม่ผ่านตัวกรองรายการใดรายการหนึ่งของคอมโพเนนต์อาจผ่านตัวกรองอื่น ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่ระบบแก้ไขความตั้งใจได้ในส่วนด้านล่าง เกี่ยวกับการแก้ไขความตั้งใจ
ข้อควรระวัง: การใช้ตัวกรอง Intent ไม่ใช่วิธีที่ปลอดภัยในการป้องกันไม่ให้แอปอื่นๆ เริ่มต้น
คอมโพเนนต์ของคุณ แม้ว่าตัวกรอง Intent จะจำกัดคอมโพเนนต์ให้ตอบสนองต่อ Implicit Intent บางประเภทเท่านั้น แต่แอปอื่นก็อาจเริ่มคอมโพเนนต์แอปของคุณได้โดยใช้ Explicit Intent หากนักพัฒนาแอปทราบชื่อคอมโพเนนต์ของคุณ
หากคุณต้องการให้เฉพาะแอปของคุณเองที่สามารถเริ่มคอมโพเนนต์ใดคอมโพเนนต์หนึ่งได้
อย่าประกาศตัวกรอง Intent ในไฟล์ Manifest แต่ให้ตั้งค่าแอตทริบิวต์
exported
เป็น "false"
สำหรับคอมโพเนนต์นั้นแทน
ในทำนองเดียวกัน เพื่อหลีกเลี่ยงการเรียกใช้ Service
ของแอปอื่นโดยไม่ตั้งใจ ให้ใช้ Intent ที่ชัดเจนเพื่อเริ่มบริการของคุณเองเสมอ
หมายเหตุ:
สำหรับกิจกรรมทั้งหมด คุณต้องประกาศตัวกรอง Intent ในไฟล์ Manifest
อย่างไรก็ตาม ตัวกรองสำหรับเครื่องรับสัญญาณออกอากาศสามารถลงทะเบียนแบบไดนามิกได้โดยการเรียกใช้
registerReceiver()
จากนั้นคุณจะยกเลิกการลงทะเบียนผู้รับด้วย unregisterReceiver()
ได้ การทำเช่นนี้จะช่วยให้แอปของคุณ
รับฟังการออกอากาศที่เฉพาะเจาะจงได้ในช่วงเวลาที่กำหนดเท่านั้นขณะที่แอปของคุณ
กำลังทำงานอยู่
ตัวอย่างตัวกรอง
ตัวอย่างต่อไปนี้จากไฟล์ Manifest ของแอปแชร์ในโซเชียลจะแสดงลักษณะการทำงานบางอย่างของตัวกรอง Intent
<activity android:name="MainActivity" android:exported="true"> <!-- This activity is the main entry, should appear in app launcher --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="ShareActivity" android:exported="false"> <!-- This activity handles "SEND" actions with text data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <action android:name="android.intent.action.SEND_MULTIPLE"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="application/vnd.google.panorama360+jpg"/> <data android:mimeType="image/*"/> <data android:mimeType="video/*"/> </intent-filter> </activity>
กิจกรรมแรก MainActivity
คือจุดแรกเข้าหลักของแอป ซึ่งเป็นกิจกรรมที่เปิดขึ้นเมื่อผู้ใช้เปิดแอปเป็นครั้งแรกด้วยไอคอน Launcher
ACTION_MAIN
action ระบุว่านี่คือจุดแรกเข้าหลักและไม่คาดหวังข้อมูล Intent ใดๆ- หมวดหมู่
CATEGORY_LAUNCHER
แสดงว่าควรวางไอคอนของกิจกรรมนี้ ไว้ในตัวเรียกใช้แอปของระบบ หากองค์ประกอบ<activity>
ไม่ได้ระบุไอคอนที่มีicon
ระบบจะใช้ไอคอนจากองค์ประกอบ<application>
คุณต้องจับคู่ทั้ง 2 รายการนี้เพื่อให้กิจกรรมปรากฏในตัวเปิดแอป
กิจกรรมที่ 2 ShareActivity
มีจุดประสงค์เพื่ออำนวยความสะดวกในการแชร์ข้อความและเนื้อหาสื่อ
แม้ว่าผู้ใช้อาจเข้าสู่กิจกรรมนี้โดยไปที่กิจกรรมจาก MainActivity
แต่ก็สามารถเข้าสู่ ShareActivity
ได้โดยตรงจากแอปอื่นที่ออก Intent โดยนัย
ซึ่งตรงกับตัวกรอง Intent ตัวใดตัวหนึ่ง
หมายเหตุ: ประเภท MIME
application/vnd.google.panorama360+jpg
เป็นประเภทข้อมูลพิเศษที่ระบุ
รูปภาพพาโนรามา ซึ่งคุณจัดการได้ด้วย Google
Panorama APIs
จับคู่ Intent กับตัวกรอง Intent ของแอปอื่นๆ
หากแอปอื่นกำหนดเป้าหมายเป็น Android 13 (API ระดับ 33) ขึ้นไป แอปนั้นจะจัดการ Intent ของแอปได้ก็ต่อเมื่อ Intent ของคุณตรงกับการดำเนินการและหมวดหมู่ขององค์ประกอบ <intent-filter>
ในแอปอื่นนั้น หากระบบไม่พบรายการที่ตรงกัน ระบบจะแสดง ActivityNotFoundException
แอปที่ส่งต้องจัดการ
ข้อยกเว้นนี้
ในทำนองเดียวกัน หากคุณอัปเดตแอปให้กำหนดเป้าหมายเป็น Android 13
ขึ้นไป ระบบจะนำส่ง Intent ทั้งหมดที่มาจากแอปภายนอกไปยัง
คอมโพเนนต์ที่ส่งออกของแอปก็ต่อเมื่อ Intent นั้นตรงกับการดำเนินการและ
หมวดหมู่ของเอลิเมนต์ <intent-filter>
ที่แอปประกาศ ลักษณะการทำงานนี้
เกิดขึ้นโดยไม่คำนึงถึง SDK เวอร์ชันเป้าหมายของแอปที่ส่ง
ในกรณีต่อไปนี้ ระบบจะไม่บังคับใช้การจับคู่ความตั้งใจ
- Intent ที่ส่งไปยังคอมโพเนนต์ที่ไม่ได้ประกาศตัวกรอง Intent
- Intent ที่มาจากภายในแอปเดียวกัน
- Intent ที่มาจากระบบ นั่นคือ Intent ที่ส่งจาก "UID ของระบบ" (uid=1000) แอประบบรวมถึง
system_server
และแอปที่ตั้งค่าandroid:sharedUserId
เป็นandroid.uid.system
- Intent ที่มาจากรูท
ดูข้อมูลเพิ่มเติมเกี่ยวกับการจับคู่ตามความตั้งใจ
การใช้ความตั้งใจที่รอดำเนินการ
PendingIntent
ออบเจ็กต์คือ Wrapper รอบๆ Intent
ออบเจ็กต์ วัตถุประสงค์หลักของ PendingIntent
คือการให้สิทธิ์แก่แอปพลิเคชันภายนอก
เพื่อใช้ Intent
ที่มีอยู่ราวกับว่ามีการเรียกใช้จากกระบวนการของแอป
ของคุณเอง
กรณีการใช้งานที่สำคัญสำหรับ PendingIntent มีดังนี้
- ประกาศ Intent ที่จะดำเนินการเมื่อผู้ใช้ดำเนินการกับการแจ้งเตือน
(
NotificationManager
ของระบบ Android จะดำเนินการIntent
) - ประกาศ Intent ที่จะดำเนินการเมื่อผู้ใช้ดำเนินการกับวิดเจ็ตแอป
(แอปหน้าจอหลักจะเรียกใช้
Intent
) - การประกาศ Intent ที่จะดำเนินการในอนาคตตามเวลาที่ระบุ (ระบบ Android
AlarmManager
จะเรียกใช้Intent
)
เช่นเดียวกับที่ออบเจ็กต์ Intent
แต่ละรายการได้รับการออกแบบมาให้คอมโพเนนต์แอปประเภทหนึ่งๆ จัดการ (ไม่ว่าจะเป็น Activity
, Service
หรือ BroadcastReceiver
) PendingIntent
ก็ต้องสร้างขึ้นโดยคำนึงถึงสิ่งเดียวกัน เมื่อใช้ PendingIntent แอปจะไม่
เรียกใช้ Intent ด้วยการเรียกใช้ เช่น startActivity()
แต่คุณต้องประกาศประเภทคอมโพเนนต์ที่ต้องการเมื่อสร้าง
PendingIntent
โดยการเรียกใช้เมธอดครีเอเตอร์ที่เกี่ยวข้อง
PendingIntent.getActivity()
สำหรับIntent
ที่เริ่มActivity
PendingIntent.getService()
สำหรับIntent
ที่เริ่มต้นด้วยService
PendingIntent.getBroadcast()
สำหรับIntent
ที่เริ่มต้นด้วยBroadcastReceiver
เว้นแต่แอปจะรับ PendingIntent จากแอปอื่นๆ
วิธีข้างต้นในการสร้าง PendingIntent
อาจเป็นวิธีเดียว
PendingIntent
ที่คุณจะต้องใช้
แต่ละเมธอดจะใช้แอปปัจจุบัน Context
,
Intent
ที่คุณต้องการรวม และการตั้งค่าสถานะอย่างน้อย 1 รายการที่ระบุ
วิธีใช้ Intent (เช่น ใช้ Intent ได้มากกว่า 1 ครั้งหรือไม่)
ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ PendingIntent ได้ในเอกสารประกอบสำหรับแต่ละ กรณีการใช้งานที่เกี่ยวข้อง เช่น ในคำแนะนำเกี่ยวกับ API ของการแจ้งเตือน และวิดเจ็ตแอป
ระบุความสามารถในการเปลี่ยนแปลง
หากแอปกำหนดเป้าหมายเป็น Android 12 ขึ้นไป คุณต้องระบุ
การเปลี่ยนแปลงของออบเจ็กต์ PendingIntent
แต่ละรายการที่แอปสร้างขึ้น หากต้องการประกาศว่าออบเจ็กต์ PendingIntent
ที่ระบุเปลี่ยนแปลงได้หรือเปลี่ยนแปลงไม่ได้ ให้ใช้
PendingIntent.FLAG_MUTABLE
หรือ
PendingIntent.FLAG_IMMUTABLE
ตามลำดับ
หากแอปพยายามสร้างออบเจ็กต์ PendingIntent
โดยไม่ได้ตั้งค่าสถานะความสามารถในการเปลี่ยนแปลงได้ ระบบจะแสดง IllegalArgumentException
และ
ข้อความต่อไปนี้จะปรากฏใน Logcat
PACKAGE_NAME: Targeting S+ (version 31 and above) requires that one of \
FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if \
some functionality depends on the PendingIntent being mutable, e.g. if \
it needs to be used with inline replies or bubbles.
สร้าง PendingIntent ที่เปลี่ยนแปลงไม่ได้ทุกครั้งที่ทำได้
ในกรณีส่วนใหญ่ แอปควรสร้างออบเจ็กต์ PendingIntent
ที่เปลี่ยนแปลงไม่ได้ ดังที่แสดงในข้อมูลโค้ดต่อไปนี้
หากPendingIntent
ออบเจ็กต์เปลี่ยนแปลงไม่ได้
แอปอื่นๆ จะแก้ไข Intent เพื่อปรับผลลัพธ์ของการเรียกใช้
Intent ไม่ได้
Kotlin
val pendingIntent = PendingIntent.getActivity(applicationContext, REQUEST_CODE, intent, /* flags */ PendingIntent.FLAG_IMMUTABLE)
Java
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), REQUEST_CODE, intent, /* flags */ PendingIntent.FLAG_IMMUTABLE);
อย่างไรก็ตาม กรณีการใช้งานบางอย่างต้องใช้PendingIntent
ออบเจ็กต์ที่เปลี่ยนแปลงได้แทน
- รองรับการดำเนินการตอบกลับโดยตรงในการแจ้งเตือน การตอบกลับโดยตรงต้องมีการเปลี่ยนแปลงข้อมูลคลิปในออบเจ็กต์ PendingIntent
ที่เชื่อมโยงกับการตอบกลับ โดยปกติแล้ว คุณจะขอเปลี่ยนแปลงนี้โดยส่ง
FILL_IN_CLIP_DATA
เป็นแฟล็กไปยังเมธอดfillIn()
- เชื่อมโยงการแจ้งเตือนกับเฟรมเวิร์ก Android Auto โดยใช้อินสแตนซ์ของ
CarAppExtender
- วางการสนทนาในบับเบิลโดยใช้อินสแตนซ์
ของ
PendingIntent
ออบเจ็กต์PendingIntent
ที่เปลี่ยนแปลงได้ช่วยให้ระบบใช้ แฟล็กที่ถูกต้อง เช่นFLAG_ACTIVITY_MULTIPLE_TASK
และFLAG_ACTIVITY_NEW_DOCUMENT
- การขอข้อมูลตำแหน่งอุปกรณ์โดยการเรียกใช้
requestLocationUpdates()
หรือ API ที่คล้ายกัน ออบเจ็กต์PendingIntent
ที่เปลี่ยนแปลงได้ช่วยให้ระบบเพิ่ม ส่วนเสริมของ Intent ที่แสดงถึงเหตุการณ์วงจรของตำแหน่งได้ เหตุการณ์เหล่านี้รวมถึงการเปลี่ยนแปลงสถานที่ตั้งและการที่ผู้ให้บริการพร้อมให้บริการ - ตั้งเวลาปลุกโดยใช้
AlarmManager
ออบเจ็กต์PendingIntent
ที่เปลี่ยนแปลงได้ช่วยให้ระบบเพิ่มEXTRA_ALARM_COUNT
Intent Extra ได้ โดยค่านี้จะแสดงจำนวนครั้งที่ระบบทริกเกอร์การปลุกซ้ำ การใส่ข้อมูลเพิ่มเติมนี้ช่วยให้ Intent สามารถแจ้งเตือนแอปได้อย่างถูกต้องว่ามีการทริกเกอร์การปลุกที่ทำซ้ำหลายครั้งหรือไม่ เช่น เมื่ออุปกรณ์อยู่ในโหมดสลีป
หากแอปสร้างออบเจ็กต์ PendingIntent
ที่เปลี่ยนแปลงได้ เราขอแนะนำอย่างยิ่ง
ให้คุณใช้ Intent ที่ชัดเจนและกรอกข้อมูลใน
ComponentName
ด้วยวิธีนี้ เมื่อใดก็ตามที่
แอปอื่นเรียกใช้ PendingIntent
และส่งการควบคุมกลับไปยังแอปของคุณ คอมโพเนนต์เดียวกันในแอปของคุณจะเริ่มทำงานเสมอ
ใช้ Intent ที่ชัดเจนภายใน PendingIntent
หากต้องการกำหนดวิธีที่แอปอื่นๆ สามารถใช้ PendingIntent ของแอปให้ดียิ่งขึ้น ให้ห่อ PendingIntent ด้วย Intent ที่ชัดเจนเสมอ หากต้องการช่วยให้ปฏิบัติตามแนวทางปฏิบัติแนะนำนี้ ให้ทำดังนี้
- ตรวจสอบว่ามีการตั้งค่าฟิลด์การดำเนินการ แพ็กเกจ และคอมโพเนนต์ของ Intent พื้นฐาน
-
ใช้
FLAG_IMMUTABLE
ซึ่งเพิ่มใน Android 6.0 (API ระดับ 23) เพื่อสร้าง PendingIntent แฟล็กนี้ จะป้องกันไม่ให้แอปที่ได้รับPendingIntent
ทำการเติม พร็อพเพอร์ตี้ที่ไม่ได้สร้างไว้ หากminSdkVersion
ของแอปเป็น22
หรือต่ำกว่า คุณจะระบุความปลอดภัยและความเข้ากันได้พร้อมกันได้ โดยใช้โค้ดต่อไปนี้if (Build.VERSION.SDK_INT >= 23) { // Create a PendingIntent using FLAG_IMMUTABLE. } else { // Existing code that creates a PendingIntent. }
การแก้ปัญหาความตั้งใจ
เมื่อระบบได้รับ Intent โดยนัยเพื่อเริ่มกิจกรรม ระบบจะค้นหากิจกรรมที่ดีที่สุดสำหรับ Intent โดยเปรียบเทียบกับตัวกรอง Intent ตาม 3 ด้านต่อไปนี้
- เริ่มถ่ายเลย
- ข้อมูล (ทั้ง URI และประเภทข้อมูล)
- หมวดหมู่
ส่วนต่อไปนี้อธิบายวิธีจับคู่ Intent กับคอมโพเนนต์ที่เหมาะสม ตามการประกาศตัวกรอง Intent ในไฟล์ Manifest ของแอป
การทดสอบการดำเนินการ
หากต้องการระบุการดำเนินการตาม Intent ที่ยอมรับได้ ตัวกรอง Intent จะประกาศองค์ประกอบ <action>
ได้ตั้งแต่ 0 รายการขึ้นไป ดังตัวอย่างต่อไปนี้
<intent-filter> <action android:name="android.intent.action.EDIT" /> <action android:name="android.intent.action.VIEW" /> ... </intent-filter>
หากต้องการผ่านตัวกรองนี้ การกระทำที่ระบุใน Intent
ต้องตรงกับการกระทำอย่างใดอย่างหนึ่งที่แสดงในตัวกรอง
หากตัวกรองไม่ได้แสดงการดำเนินการใดๆ ก็จะไม่มีสิ่งใดที่
Intent จะจับคู่ได้ ดังนั้น Intent ทั้งหมดจะทดสอบไม่ผ่าน อย่างไรก็ตาม หาก Intent
ไม่ได้ระบุการดำเนินการ ระบบจะถือว่าผ่านการทดสอบตราบใดที่ตัวกรอง
มีการดำเนินการอย่างน้อย 1 รายการ
การทดสอบหมวดหมู่
หากต้องการระบุหมวดหมู่ Intent ที่ยอมรับ ตัวกรอง Intent สามารถประกาศองค์ประกอบ <category>
ได้ตั้งแต่ 0 รายการขึ้นไป ดังตัวอย่างต่อไปนี้
<intent-filter> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> ... </intent-filter>
หากต้องการให้ความตั้งใจผ่านการทดสอบหมวดหมู่ ทุกหมวดหมู่ในIntent
ต้องตรงกับหมวดหมู่ในตัวกรอง ไม่จำเป็นต้องทำในทางกลับกัน กล่าวคือ ตัวกรอง Intent อาจประกาศหมวดหมู่มากกว่าที่ระบุไว้ใน Intent
และ Intent
ก็ยังคงผ่าน ดังนั้น Intent ที่ไม่มีหมวดหมู่จะผ่านการทดสอบนี้เสมอ ไม่ว่าหมวดหมู่ใดจะประกาศไว้ในตัวกรองก็ตาม
หมายเหตุ:
Android จะใช้CATEGORY_DEFAULT
หมวดหมู่
กับ Intent โดยนัยทั้งหมดที่ส่งไปยัง startActivity()
และ startActivityForResult()
โดยอัตโนมัติ
หากต้องการให้กิจกรรมรับ Intent โดยนัย กิจกรรมนั้นต้องมีหมวดหมู่สำหรับ "android.intent.category.DEFAULT"
ในตัวกรอง Intent ดังที่แสดงในตัวอย่าง <intent-filter>
ก่อนหน้า
การทดสอบข้อมูล
หากต้องการระบุข้อมูล Intent ที่ยอมรับ ตัวกรอง Intent สามารถประกาศองค์ประกอบ 0 รายการขึ้นไป
<data>
ดังตัวอย่างต่อไปนี้
<intent-filter> <data android:mimeType="video/mpeg" android:scheme="http" ... /> <data android:mimeType="audio/mpeg" android:scheme="http" ... /> ... </intent-filter>
องค์ประกอบ <data>
แต่ละรายการสามารถระบุโครงสร้าง URI และประเภทข้อมูล (ประเภทสื่อ MIME)
แต่ละส่วนของ URI เป็นแอตทริบิวต์แยกกัน ได้แก่ scheme
, host
, port
และ path
<scheme>://<host>:<port>/<path>
ตัวอย่างต่อไปนี้แสดงค่าที่เป็นไปได้สำหรับแอตทริบิวต์เหล่านี้
content://com.example.project:200/folder/subfolder/etc
ใน URI นี้ รูปแบบคือ content
โฮสต์คือ com.example.project
พอร์ตคือ 200
และเส้นทางคือ folder/subfolder/etc
แอตทริบิวต์แต่ละรายการเหล่านี้เป็นแอตทริบิวต์ที่ไม่บังคับในองค์ประกอบ <data>
แต่มีความขึ้นต่อกันแบบเชิงเส้น ดังนี้
- หากไม่ได้ระบุรูปแบบ ระบบจะละเว้นโฮสต์
- หากไม่ได้ระบุโฮสต์ ระบบจะไม่สนใจพอร์ต
- หากไม่ได้ระบุทั้งรูปแบบและโฮสต์ ระบบจะละเว้นเส้นทาง
เมื่อเปรียบเทียบ URI ใน Intent กับข้อกำหนด URI ในตัวกรอง ระบบจะเปรียบเทียบเฉพาะส่วนของ URI ที่รวมอยู่ในตัวกรอง เช่น
- หากตัวกรองระบุเฉพาะรูปแบบ URI ทั้งหมดที่มีรูปแบบนั้นจะตรงกับตัวกรอง
- หากตัวกรองระบุรูปแบบและอำนาจ แต่ไม่มีเส้นทาง URI ทั้งหมดที่มีรูปแบบและอำนาจเดียวกันจะผ่านตัวกรอง ไม่ว่าจะมีเส้นทางใดก็ตาม
- หากตัวกรองระบุรูปแบบ, Authority และเส้นทาง จะมีเพียง URI ที่มีรูปแบบ, Authority และเส้นทางเดียวกันเท่านั้นที่ผ่านตัวกรอง
หมายเหตุ: ข้อกำหนดพาธสามารถ มีเครื่องหมายดอกจัน (*) ซึ่งเป็นไวลด์การ์ดเพื่อกำหนดให้ตรงกับชื่อพาธเพียงบางส่วนเท่านั้น
การทดสอบข้อมูลจะเปรียบเทียบทั้ง URI และประเภท MIME ใน Intent กับ URI และประเภท MIME ที่ระบุในตัวกรอง กฎมีดังนี้
- Intent ที่ไม่มีทั้ง URI และประเภท MIME จะผ่านการทดสอบก็ต่อเมื่อตัวกรองไม่ได้ระบุ URI หรือประเภท MIME ใดๆ
- Intent ที่มี URI แต่ไม่มีประเภท MIME (ทั้งที่ระบุอย่างชัดเจนและที่อนุมานได้จาก URI) จะผ่านการทดสอบก็ต่อเมื่อ URI ตรงกับรูปแบบ URI ของตัวกรอง และตัวกรองก็ไม่ได้ระบุประเภท MIME เช่นกัน
- Intent ที่มีประเภท MIME แต่ไม่มี URI จะผ่านการทดสอบ ก็ต่อเมื่อตัวกรองแสดงประเภท MIME เดียวกันและไม่ได้ระบุรูปแบบ URI
- Intent ที่มีทั้ง URI และประเภท MIME (ไม่ว่าจะระบุอย่างชัดเจนหรืออนุมานจาก
URI) จะผ่านส่วนประเภท MIME ของการทดสอบก็ต่อเมื่อ
ประเภทนั้นตรงกับประเภทที่แสดงในตัวกรอง โดยจะผ่านส่วน URI ของการทดสอบ
ไม่ว่า URI จะตรงกับ URI ในตัวกรองหรือไม่ หรือหากมี URI
content:
หรือfile:
และตัวกรองไม่ได้ระบุ URI กล่าวคือ ระบบจะถือว่าคอมโพเนนต์รองรับข้อมูลcontent:
และfile:
หากรายการตัวกรองของคอมโพเนนต์มีประเภท MIME เพียงประเภทเดียว
หมายเหตุ: หาก Intent ระบุ URI หรือประเภท MIME การทดสอบข้อมูลจะล้มเหลวหากไม่มีองค์ประกอบ <data>
ใน <intent-filter>
กฎสุดท้ายนี้ ซึ่งก็คือกฎ (ง) แสดงให้เห็นถึงความคาดหวัง
ว่าคอมโพเนนต์จะสามารถรับข้อมูลในเครื่องจากผู้ให้บริการไฟล์หรือเนื้อหาได้
ดังนั้น ตัวกรองจึงแสดงได้เฉพาะประเภทข้อมูล และไม่จำเป็นต้องตั้งชื่อสคีมา content:
และ file:
อย่างชัดเจน
ตัวอย่างต่อไปนี้แสดงกรณีทั่วไปที่องค์ประกอบ <data>
บอก Android ว่าคอมโพเนนต์สามารถรับข้อมูลรูปภาพจาก Content
Provider และแสดงได้
<intent-filter> <data android:mimeType="image/*" /> ... </intent-filter>
ตัวกรองที่ ระบุประเภทข้อมูลแต่ไม่ได้ระบุ URI อาจเป็นตัวกรองที่พบบ่อยที่สุด เนื่องจากผู้ให้บริการเนื้อหาส่วนใหญ่ จะจัดเตรียมข้อมูลที่มีอยู่
การกำหนดค่าที่พบบ่อยอีกอย่างคือตัวกรองที่มีสคีมาและประเภทข้อมูล ตัวอย่างเช่น องค์ประกอบ <data>
ต่อไปนี้จะบอก Android ว่า
คอมโพเนนต์สามารถดึงข้อมูลวิดีโอจากเครือข่ายเพื่อดำเนินการได้
<intent-filter> <data android:scheme="http" android:mimeType="video/*" /> ... </intent-filter>
การจับคู่ตามความตั้งใจ
ระบบจะจับคู่ Intent กับตัวกรอง Intent ไม่เพียงเพื่อค้นหาคอมโพเนนต์เป้าหมายที่จะเปิดใช้งาน แต่ยังเพื่อค้นหาข้อมูลเกี่ยวกับชุดคอมโพเนนต์ในอุปกรณ์ด้วย
ตัวอย่างเช่น แอป Home จะป้อนข้อมูลตัวเรียกใช้แอป
โดยการค้นหากิจกรรมทั้งหมดที่มีตัวกรอง Intent ที่ระบุACTION_MAIN
การดำเนินการและCATEGORY_LAUNCHER
หมวดหมู่
การจับคู่จะสำเร็จก็ต่อเมื่อการดำเนินการและหมวดหมู่ใน Intent ตรงกับตัวกรองตามที่อธิบายไว้ในเอกสารประกอบสำหรับคลาส IntentFilter
แอปพลิเคชันของคุณสามารถใช้การจับคู่ Intent ในลักษณะเดียวกับที่แอป Home ทำ
PackageManager
มีชุดquery...()
เมธอดที่แสดงผลคอมโพเนนต์ทั้งหมดที่ยอมรับ Intent ที่เฉพาะเจาะจงได้ และ
ชุดเมธอด resolve...()
ที่คล้ายกันซึ่งกำหนดคอมโพเนนต์ที่ดีที่สุด
เพื่อตอบสนองต่อ Intent ตัวอย่างเช่น
queryIntentActivities()
จะแสดงรายการกิจกรรมทั้งหมดที่สามารถดำเนินการ
Intent ที่ส่งผ่านเป็นอาร์กิวเมนต์ และ queryIntentServices()
จะแสดงรายการบริการที่คล้ายกัน
ทั้ง 2 วิธีนี้จะไม่เปิดใช้งานคอมโพเนนต์ แต่จะแสดงเฉพาะคอมโพเนนต์ที่
ตอบสนองได้ มีวิธีการที่คล้ายกัน
queryBroadcastReceivers()
สำหรับ Broadcast Receiver