Intent
เป็นออบเจ็กต์การรับส่งข้อความที่คุณใช้เพื่อขอการดำเนินการได้
จากคอมโพเนนต์ของแอปอื่น
แม้ว่า Intent จะอำนวยความสะดวกในการสื่อสารระหว่างองค์ประกอบต่างๆ หลายวิธี แต่มีสามวิธี
กรณีการใช้งานพื้นฐาน
- การเริ่มกิจกรรม
Activity
หมายถึงหน้าจอเดียวในแอป คุณสามารถเริ่ม ของActivity
โดยการส่งIntent
ไปยังstartActivity()
Intent
อธิบายกิจกรรมที่จะเริ่มต้นและเก็บข้อมูลที่จำเป็นหากคุณต้องการรับผลลัพธ์จากกิจกรรมเมื่อกิจกรรมเสร็จสิ้นแล้ว โทรหา
startActivityForResult()
กิจกรรมจะได้รับผลลัพธ์ เป็นออบเจ็กต์Intent
แยกต่างหากใน CallbackonActivityResult()
ของกิจกรรม ดูข้อมูลเพิ่มเติมได้ในคู่มือกิจกรรม - การเริ่มบริการ
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
ตั้งชื่อคอมโพเนนต์กิจกรรมที่เจาะจงอย่างชัดเจน ระบบ
คอมโพเนนต์ดังกล่าวจะเริ่มทำงานทันที
เมื่อคุณใช้ Intent แบบไม่เจาะจงปลายทาง ระบบ Android จะค้นหาคอมโพเนนต์ที่เหมาะสมเพื่อเริ่ม
โดยเปรียบเทียบเนื้อหาของ Intent กับตัวกรองความตั้งใจที่ประกาศไว้ในไฟล์ Manifest ของแอปอื่นๆ บน
อุปกรณ์ หาก Intent ตรงกับตัวกรอง Intent ระบบจะเริ่มคอมโพเนนต์นั้นและส่งออบเจ็กต์ Intent
หากตัวกรอง Intent หลายรายการเข้ากันได้ ระบบจะแสดงกล่องโต้ตอบเพื่อให้ผู้ใช้เลือกแอปที่จะใช้
ตัวกรอง Intent คือนิพจน์ในไฟล์ Manifest ของแอปที่ ระบุประเภทของ Intent ที่คอมโพเนนต์ ต้องการได้รับ เช่น ด้วยการประกาศตัวกรอง Intent สำหรับกิจกรรม ทำให้แอปอื่นๆ สามารถเริ่มกิจกรรมได้โดยตรงด้วยความตั้งใจบางอย่าง ในทำนองเดียวกัน หากคุณไม่ได้ประกาศตัวกรอง Intent สำหรับกิจกรรม ตัวกรองดังกล่าวก็เริ่มต้นใช้งานได้ ด้วยเจตนาที่ชัดแจ้งเท่านั้น
ข้อควรระวัง: เพื่อดูแลให้แอปปลอดภัย ให้ดำเนินการดังนี้
ใช้ภาษาที่ไม่เหมาะสม
Intent เมื่อเริ่มต้น Service
และไม่
ประกาศตัวกรอง Intent สำหรับบริการของคุณ การใช้ Intent แบบไม่เจาะจงปลายทางเพื่อเริ่มบริการเป็น
เนื่องจากคุณไม่สามารถแน่ใจได้ว่าบริการใดจะตอบสนองต่อจุดประสงค์นั้น
และผู้ใช้ไม่สามารถเห็นได้ว่าบริการใดเริ่มทำงานบ้าง ใน Android 5.0 (API ระดับ 21) ระบบจะเลือกใช้
จะมีข้อยกเว้นหากคุณโทรหา bindService()
โดยมีเจตนาโดยนัย
การสร้างความตั้งใจ
ออบเจ็กต์ Intent
มีข้อมูลที่ระบบ Android ใช้
กำหนดคอมโพเนนต์ที่จะเริ่ม (เช่น ชื่อคอมโพเนนต์หรือคอมโพเนนต์ที่ตรงกันทั้งหมด
ที่ควรได้รับความตั้งใจ) รวมถึงข้อมูลที่คอมโพเนนต์ผู้รับใช้
เพื่อดำเนินการอย่างเหมาะสม (เช่น การดำเนินการที่ต้องทำและข้อมูลในการดำเนินการ)
ข้อมูลหลักที่อยู่ใน Intent
คือ
- ชื่อคอมโพเนนต์
- ชื่อของคอมโพเนนต์ที่จะเริ่มต้น
ขั้นตอนนี้เป็นขั้นตอนที่ไม่บังคับ แต่เป็นข้อมูลสำคัญที่ช่วยสร้างความตั้งใจ Explicit ซึ่งหมายความว่าควรแสดง Intent ไปยังคอมโพเนนต์ของแอปเท่านั้น กำหนดโดยชื่อคอมโพเนนต์ หากไม่มีชื่อคอมโพเนนต์ Intent จะเป็น implicit และ ระบบจะพิจารณาว่าคอมโพเนนต์ใดควรได้รับ Intent โดยพิจารณาจากข้อมูล Intent อื่นๆ (เช่น การกระทำ ข้อมูล และหมวดหมู่ตามที่อธิบายไว้ด้านล่าง) หากต้องการเริ่มคอมโพเนนต์ที่เฉพาะเจาะจงในแอป คุณควรระบุชื่อคอมโพเนนต์
หมายเหตุ: เมื่อเริ่ม
Service
ให้ระบุชื่อคอมโพเนนต์เสมอ มิฉะนั้น คุณไม่สามารถ แน่ใจ ได้ว่า บริการใด จะตอบสนองต่อความตั้งใจ และผู้ใช้ไม่สามารถเห็นได้ว่าบริการใดเริ่มทำงานใดช่องนี้ของ
Intent
คือComponentName
ซึ่งคุณระบุได้โดยใช้ ชื่อคลาสที่มีคุณสมบัติตามเกณฑ์ของคอมโพเนนต์เป้าหมาย รวมถึงชื่อแพ็กเกจของแอป ตัวอย่างเช่นcom.example.ExampleActivity
คุณตั้งชื่อคอมโพเนนต์ได้ด้วยsetComponent()
,setClass()
,setClassName()
, หรือด้วยเมธอด เครื่องมือสร้างIntent
- การดำเนินการ
- สตริงที่ระบุการดำเนินการทั่วไปที่จะดำเนินการ (เช่น ดูหรือเลือก)
ในกรณีของความตั้งใจในการออกอากาศ นี่คือการดำเนินการที่เกิดขึ้นและมีการรายงาน การดำเนินการจะเป็นตัวกำหนดโครงสร้างของความตั้งใจที่เหลือเป็นหลัก โดยเฉพาะอย่างยิ่ง ข้อมูลที่อยู่ในข้อมูลและอื่นๆ
คุณสามารถระบุการทำงานของคุณเองเพื่อใช้โดย Intent ภายในแอป (หรือสำหรับการใช้งานโดยบุคคลอื่น แอปเพื่อเรียกคอมโพเนนต์ในแอป) แต่โดยปกติแล้ว คุณมักจะระบุค่าคงที่การดำเนินการ กำหนดโดยคลาส
Intent
หรือคลาสเฟรมเวิร์กอื่นๆ นี่คือบางส่วน การทำงานทั่วไปสำหรับการเริ่มกิจกรรมACTION_VIEW
- ใช้การดำเนินการนี้ใน Intent กับ
startActivity()
เมื่อคุณมีข้อมูลบางอย่างที่ กิจกรรมสามารถแสดงต่อผู้ใช้ เช่น รูปภาพที่จะดูในแอปแกลเลอรี หรือที่อยู่ที่จะ ดูในแอปแผนที่ ACTION_SEND
- หรือที่เรียกว่า Intent share คุณควรใช้ Intent นี้ใน Intent ที่มี
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";
- ข้อมูล
- URL (ออบเจ็กต์
Uri
) ที่อ้างอิงข้อมูล ดำเนินการและ/หรือ ประเภท MIME ของข้อมูลนั้น โดยทั่วไปประเภทของข้อมูลที่ระบุจะกำหนดโดยการดำเนินการของ Intent สำหรับ เช่น หากการดำเนินการคือACTION_EDIT
ข้อมูลควรมี URI ของเอกสารที่จะแก้ไขเมื่อสร้าง Intent สิ่งสำคัญคือต้องระบุประเภทข้อมูล (ประเภท MIME) นอกเหนือจาก URI ตัวอย่างเช่น กิจกรรมที่สามารถแสดงภาพได้คงไม่สามารถ เพื่อเล่นไฟล์เสียง แม้ว่ารูปแบบ URI อาจคล้ายกันก็ตาม การระบุประเภท MIME ของข้อมูลจะช่วยให้ Android ระบบจะค้นหาองค์ประกอบที่ดีที่สุดเพื่อให้ได้รับความตั้งใจของคุณ อย่างไรก็ตาม บางครั้งประเภท MIME สามารถอนุมานได้จาก URI โดยเฉพาะอย่างยิ่งเมื่อข้อมูลเป็น URI
content:
URIcontent:
บ่งบอกว่าข้อมูลอยู่ในอุปกรณ์ และควบคุมโดยContentProvider
ซึ่งทำให้ระบบมองเห็นประเภท MIME ของข้อมูลหากต้องการตั้งค่าเฉพาะ URI ข้อมูล ให้เรียก
setData()
หากต้องการตั้งค่าเฉพาะประเภท MIME ให้เรียกใช้setType()
หากจำเป็น คุณสามารถตั้งค่าทั้ง 2 รายการอย่างชัดเจนด้วยsetDataAndType()
ข้อควรระวัง: หากต้องการตั้งค่าทั้ง URI และประเภท MIME ให้อย่าเรียกใช้
setData()
และsetType()
เนื่องจากค่าของกันและกันจะลบล้างกัน ใช้setDataAndType()
เสมอเพื่อตั้งค่าทั้ง 2 แบบ URI และ ประเภท MIME - หมวดหมู่
- สตริงที่มีข้อมูลเพิ่มเติมเกี่ยวกับประเภทของคอมโพเนนต์
ที่ควรจัดการกับความตั้งใจ คำอธิบายหมวดหมู่กี่รายการก็ได้
อยู่ใน Intent แต่ Intent ส่วนใหญ่ไม่จำเป็นต้องมีหมวดหมู่
ต่อไปนี้คือหมวดหมู่ทั่วไปบางส่วน
CATEGORY_BROWSABLE
- กิจกรรมเป้าหมายอนุญาตให้เว็บเบราว์เซอร์เริ่มดำเนินการเองเพื่อแสดงข้อมูล อ้างอิงโดยลิงก์ เช่น รูปภาพหรือข้อความอีเมล
CATEGORY_LAUNCHER
- กิจกรรมเป็นกิจกรรมเริ่มต้นของงานและแสดงอยู่ใน Launcher ของแอปพลิเคชันของระบบ
ดูรายการหมวดหมู่ทั้งหมดได้ที่คำอธิบายคลาส
Intent
คุณระบุหมวดหมู่ได้ด้วย
addCategory()
พร็อพเพอร์ตี้ที่แสดงด้านบน (ชื่อคอมโพเนนต์ การทำงาน ข้อมูล และหมวดหมู่) แสดง ซึ่งเป็นการกำหนดลักษณะของเจตนา เมื่ออ่านคุณสมบัติเหล่านี้ ระบบ Android กำหนดคอมโพเนนต์ของแอปที่ควรเริ่มทำงานได้ อย่างไรก็ตาม Intent สามารถนําข้อมูลเพิ่มเติมที่ไม่ได้ส่งผลต่อวิธีแก้ไขไปยังคอมโพเนนต์แอปได้ Intent ยังจะให้ข้อมูลต่อไปนี้ได้ด้วย
- เพิ่มเติม
- คู่คีย์-ค่าที่มีข้อมูลเพิ่มเติมที่จำเป็นในการบรรลุ
การทำงานที่ขอ
เช่นเดียวกับการทำงานบางอย่างใช้ URI ข้อมูลบางประเภท การทำงานบางอย่างจะใช้ส่วนเพิ่มเติมบางอย่างด้วย
คุณเพิ่มข้อมูลเพิ่มเติมได้ด้วยวิธีการ
putExtra()
หลายวิธี แต่ละรายการยอมรับพารามิเตอร์ 2 ตัว ได้แก่ ชื่อคีย์และค่า นอกจากนี้ คุณยังสร้างออบเจ็กต์Bundle
ที่มีข้อมูลเพิ่มเติมทั้งหมด แล้วแทรกBundle
ในIntent
ด้วยputExtras()
ได้ด้วยตัวอย่างเช่น เมื่อสร้างความตั้งใจที่จะส่งอีเมลด้วย
ACTION_SEND
คุณสามารถระบุผู้รับถึงด้วยแอตทริบิวต์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
- การแจ้งว่าไม่เหมาะสม
- แฟล็กได้รับการกำหนดไว้ในคลาส
Intent
ซึ่งทำหน้าที่เป็นข้อมูลเมตาสำหรับ Intent การรายงานปัญหาอาจสั่งให้ระบบ Android เปิดใช้งานกิจกรรม (ตัวอย่างเช่น งาน กิจกรรมควรเป็น กับ) และวิธีจัดการกับผลิตภัณฑ์หลังเปิดตัว (เช่น ระบุว่าอยู่ในรายการล่าสุดของ กิจกรรม)สำหรับข้อมูลเพิ่มเติม โปรดดูเมธอด
setFlags()
ตัวอย่าง Intent แบบเจาะจง
Intent แบบเจาะจงคือสิ่งที่คุณใช้เพื่อเปิดคอมโพเนนต์แอปที่เจาะจง เช่น
กิจกรรมหรือบริการหนึ่งๆ ในแอป หากต้องการสร้าง 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
ด้วยเหตุนี้
Intent นี้จะเริ่มต้นคลาส DownloadService
ในแอปอย่างชัดเจน
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการสร้างและเริ่มต้นบริการ โปรดดูที่ คู่มือบริการ
ตัวอย่าง Intent แบบไม่เจาะจงปลายทาง
Intent แบบไม่เจาะจงปลายทางจะระบุการดำเนินการที่สามารถเรียกใช้แอปในอุปกรณ์ที่สามารถเรียกใช้ เพื่อดำเนินการ การใช้ Intent ที่ไม่ชัดจะมีประโยชน์เมื่อแอปของคุณดำเนินการไม่ได้ แต่แอปอื่นๆ อาจดำเนินการได้ และคุณต้องการให้ผู้ใช้เลือกแอปที่จะใช้
เช่น หากคุณมีเนื้อหาที่ต้องการให้ผู้ใช้แชร์กับผู้อื่น ให้สร้าง Intent ด้วยการดำเนินการ ACTION_SEND
และเพิ่มข้อมูลเพิ่มเติมที่ระบุเนื้อหาที่จะแชร์ เมื่อคุณเรียกใช้ startActivity()
ด้วย Intent ดังกล่าว ผู้ใช้จะเลือกแอปที่จะแชร์เนื้อหาได้
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 ที่มีการดำเนินการ ACTION_SEND
ที่มี "ข้อความ/ธรรมดา"
ข้อมูล) หากมีเพียงแอปเดียวที่จัดการได้ แอปนั้นจะเปิดขึ้นทันทีและ
Intent หากไม่มีแอปอื่นๆ ที่สามารถจัดการได้ แอปของคุณจะสามารถตรวจจับ
ActivityNotFoundException
ที่เกิดขึ้น หากมีหลายกิจกรรมยอมรับ Intent
แสดงกล่องโต้ตอบ เช่น กล่องโต้ตอบที่แสดงในรูปที่ 2 เพื่อให้ผู้ใช้เลือกได้ว่าจะใช้แอปใด
ข้อมูลเพิ่มเติมเกี่ยวกับการเปิดตัวแอปอื่นๆ มีอยู่ในคำแนะนำแล้ว เกี่ยวกับการส่งผู้ใช้ไปยัง แอปอื่น
การบังคับตัวเลือกแอป
เมื่อมีแอปมากกว่า 1 แอปที่ตอบสนองต่อความตั้งใจโดยนัยของคุณ ผู้ใช้สามารถเลือกแอปที่จะใช้ และทำให้แอปนั้นเป็นตัวเลือกเริ่มต้นสำหรับ การดำเนินการ ความสามารถในการเลือกค่าเริ่มต้นจะเป็นประโยชน์ในการดำเนินการที่ผู้ใช้ อาจต้องการใช้แอปเดิมทุกครั้ง เช่น เมื่อเปิดหน้าเว็บ (ผู้ใช้ มักจะใช้เว็บเบราว์เซอร์เพียงรายการเดียว)
แต่ถ้าแอปหลายแอปสามารถตอบสนองต่อความตั้งใจได้ และผู้ใช้อาจต้องการใช้แอปอื่น
ทุกครั้ง คุณควรแสดงกล่องโต้ตอบตัวเลือกอย่างชัดเจน กล่องโต้ตอบตัวเลือกจะถามว่า
ให้ผู้ใช้เลือกแอปที่จะใช้ในการทำงาน (ผู้ใช้ไม่สามารถเลือกแอปเริ่มต้นให้
การดำเนินการดังกล่าว) เช่น เมื่อแอปของคุณทำการ "แชร์" เมื่อมีการดําเนินการ 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 ซ้อนนั้น
เช่น การส่งผ่านความตั้งใจไปยัง
startActivity()
,startService()
, หรือbindService()
สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับวิธีระบุสถานการณ์นี้และทำการเปลี่ยนแปลงแอป อ่านบล็อกโพสต์เกี่ยวกับการวางอุปกรณ์ Android Intent ใน 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 อย่างมีความรับผิดชอบมากขึ้น
หากต้องการลดโอกาสในการเปิดตัว Intent ที่ไม่ปลอดภัยและการละเมิด StrictMode ให้ทำตามแนวทางปฏิบัติที่ดีที่สุดเหล่านี้
คัดลอกเฉพาะส่วนเสริมที่จำเป็นภายใน Intent และดำเนินการล้างข้อมูลและตรวจสอบที่จำเป็น แอปอาจคัดลอกบริการเพิ่มเติมจาก Intent หนึ่งไปยัง
อีก Intent หนึ่งที่ใช้เพื่อเปิดตัวคอมโพเนนต์ใหม่ กรณีนี้เกิดขึ้นเมื่อแอปเรียกใช้ putExtras(Intent)
หรือ putExtras(Bundle)
หากแอปทำอย่างใดอย่างหนึ่งต่อไปนี้ ให้คัดลอกเฉพาะส่วนเพิ่มเติมที่
ต้องการคอมโพเนนต์ที่รับ หากเจตนาอื่นๆ (ที่ได้รับสำเนา)
เปิดใช้คอมโพเนนต์ที่ไม่ใช่
ส่งออกแล้ว ทำความสะอาดข้อมูล และ
ตรวจสอบความถูกต้องของส่วนเพิ่มเติมก่อนที่จะคัดลอกโดยมีเจตนาที่จะเปิดตัว
คอมโพเนนต์
อย่าส่งออกคอมโพเนนต์ของแอปโดยไม่จำเป็น ตัวอย่างเช่น หากคุณ
ต้องการเปิดใช้งานคอมโพเนนต์แอปโดยใช้ Intent ที่ฝังไว้ภายใน ให้ตั้งค่า
แอตทริบิวต์ android:exported
ของคอมโพเนนต์เป็น false
ใช้ PendingIntent
แทน
Intent ซ้อนกัน ด้วยวิธีนี้ เมื่อแอปอื่นยกเลิกการแปลง PendingIntent
ที่มี Intent
แอปอื่นสามารถเปิด PendingIntent
โดยใช้
เฉพาะตัวของแอปคุณ การกำหนดค่านี้ช่วยให้แอปอื่นเปิดใช้งานได้อย่างปลอดภัย
คอมโพเนนต์ใดๆ ก็ตามในแอป ซึ่งรวมถึงคอมโพเนนต์ที่ไม่ได้ส่งออก
แผนภาพที่ 2 แสดงให้เห็นว่าระบบส่งการควบคุมจาก (ไคลเอ็นต์) อย่างไร ไปยังแอป (บริการ) อื่น แล้วกลับไปยังแอปของคุณ
- แอปของคุณสร้าง Intent ที่เรียกใช้กิจกรรมในแอปอื่น ภายใน
เพื่อเพิ่มออบเจ็กต์
PendingIntent
เป็นส่วนเสริม PendingIntent นี้เรียกใช้คอมโพเนนต์ในแอปของคุณ ซึ่งไม่ได้ส่งออกคอมโพเนนต์นี้ - เมื่อได้รับ Intent ของแอปคุณ แอปอื่นจะดึงข้อมูลออบเจ็กต์
PendingIntent
ที่ฝังอยู่ - แอปอื่นเรียกใช้เมธอด
send()
ในออบเจ็กต์PendingIntent
- เมื่อส่งการควบคุมกลับไปยังแอปของคุณแล้ว ระบบจะเรียกใช้การตั้งค่าที่รอดำเนินการ โดยใช้บริบทของแอป
รูปที่ 2 แผนภาพการสื่อสารระหว่างแอปเมื่อใช้ Intent ที่รอดำเนินการที่ฝังอยู่
การรับ Intent แบบไม่เจาะจงปลายทาง
หากต้องการโฆษณา Intent แบบไม่เจาะจงปลายทางที่แอปของคุณรับได้ ให้ประกาศตัวกรอง Intent อย่างน้อย 1 รายการสำหรับ
คอมโพเนนต์ของแอปแต่ละรายการด้วย <intent-filter>
ในไฟล์ Manifest ของคุณ
ตัวกรอง Intent แต่ละรายการจะระบุประเภทของ Intent ที่
ตัวกรองยอมรับ โดยอิงตามการดำเนินการของ Intent
ข้อมูล และหมวดหมู่ ระบบจะนำส่ง Intent ที่ไม่ชัดแจ้งไปยังคอมโพเนนต์แอปของคุณก็ต่อเมื่อ Intent ดังกล่าวผ่านตัวกรอง Intent รายการใดรายการหนึ่งของคุณ
หมายเหตุ: ระบบจะส่ง Intent แบบเจาะจงปลายทางเสมอ โดยไม่คำนึงถึงตัวกรอง Intent ที่คอมโพเนนต์ประกาศ
คอมโพเนนต์แอปควรประกาศตัวกรองแยกกันสำหรับงานที่ไม่ซ้ำกันแต่ละอย่างที่ทำได้
เช่น กิจกรรมหนึ่งในแอปแกลเลอรีรูปภาพอาจมีตัวกรอง 2 รายการ คือ 1 ตัวกรอง
เพื่อดูรูปภาพ และใช้ตัวกรองอื่นเพื่อแก้ไขรูปภาพ เมื่อกิจกรรมเริ่ม
ระบบจะตรวจสอบ Intent
และตัดสินใจเลือกลักษณะการทํางานโดยอิงตามข้อมูล
ใน Intent
(เช่น แสดงการควบคุมเครื่องมือแก้ไขหรือไม่)
ตัวกรอง Intent แต่ละรายการจะกำหนดโดยองค์ประกอบ <intent-filter>
ในไฟล์ Manifest ของแอป ซึ่งฝังอยู่ในคอมโพเนนต์แอปที่เกี่ยวข้อง (เช่น องค์ประกอบ <activity>
)
ในแต่ละคอมโพเนนต์ของแอปที่มีองค์ประกอบ <intent-filter>
ตั้งค่าอย่างชัดแจ้งสำหรับ
android:exported
แอตทริบิวต์นี้ระบุว่าแอปอื่นๆ สามารถเข้าถึงคอมโพเนนต์ของแอปได้หรือไม่ ในบางส่วน
เช่น กิจกรรมที่มีตัวกรอง Intent
LAUNCHER
หมวดหมู่ คุณควรตั้งค่าแอตทริบิวต์นี้เป็น true
มิเช่นนั้น การตั้งค่าแอตทริบิวต์นี้เป็น false
จะปลอดภัยกว่า
คำเตือน: หากกิจกรรม บริการ หรือการออกอากาศ
รีซีฟเวอร์ในแอปของคุณใช้ตัวกรอง Intent และไม่ได้กำหนดค่าอย่างชัดแจ้ง
สำหรับ android:exported
แอปของคุณไม่สามารถติดตั้งได้ในอุปกรณ์ที่
ใช้ Android 12 ขึ้นไป
ภายใน<intent-filter>
คุณสามารถระบุประเภทของ Intent ที่จะยอมรับโดยใช้
จากองค์ประกอบ 3 อย่างนี้
<action>
- ประกาศการดำเนินการตาม Intent ที่ยอมรับในแอตทริบิวต์
name
ค่า ต้องเป็นค่าสตริงตรงตัวของการกระทำ ไม่ใช่ค่าคงที่ของคลาส <data>
- ประกาศประเภทข้อมูลที่ยอมรับโดยใช้แอตทริบิวต์อย่างน้อย 1 รายการที่ระบุหลากหลาย
ด้านของ URI ข้อมูล (
scheme
,host
,port
,path
) และประเภท MIME <category>
- ประกาศหมวดหมู่ Intent ที่ยอมรับในแอตทริบิวต์
name
ค่า ต้องเป็นค่าสตริงตรงตัวของการทำงาน ไม่ใช่ค่าคงที่ของคลาสหมายเหตุ: หากต้องการรับ Intent แบบไม่เจาะจงปลายทาง คุณต้อง ต้องมีฟิลด์
CATEGORY_DEFAULT
ในตัวกรอง Intent วิธีการstartActivity()
และstartActivityForResult()
จะถือว่า Intent ทั้งหมด เหมือนกับว่าได้ประกาศหมวดหมู่CATEGORY_DEFAULT
ไว้ หากคุณไม่ประกาศหมวดหมู่นี้ในตัวกรอง Intent จะไม่มีการแก้ไข Intent แบบไม่เจาะจงปลายทางเป็น กิจกรรมของคุณ
ลองดูตัวอย่างการประกาศกิจกรรมที่มีตัวกรอง Intent เพื่อรับ
ACTION_SEND
Intent เมื่อประเภทข้อมูลเป็นข้อความ:
<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>
หากใช้ คุณต้องตรวจสอบว่าคอมโพเนนต์จัดการกับองค์ประกอบตัวกรองเหล่านั้นได้ทั้งหมด
เมื่อคุณต้องการจัดการ Intent หลายประเภท การดำเนินการ ข้อมูล และประเภทหมวดหมู่ คุณจะต้องสร้างตัวกรอง Intent หลายรายการ
ระบบจะทดสอบ Intent แบบไม่เจาะจงปลายทางกับตัวกรองโดยเปรียบเทียบความตั้งใจกับแต่ละรายการ องค์ประกอบ 3 อย่าง Intent ต้องผ่านการทดสอบทั้ง 3 รายการจึงจะแสดงไปยังคอมโพเนนต์ได้ หากไม่มีการจับคู่ที่ตรงกันเลย ระบบ Android จะไม่มอบความตั้งใจไปยัง คอมโพเนนต์ แต่เนื่องจากคอมโพเนนต์หนึ่งอาจมีตัวกรอง Intent หลายรายการ Intent ที่มี ไม่ผ่านตัวกรองใดคอมโพเนนต์หนึ่ง อาจทะลุผ่านตัวกรองอื่นได้ ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่ระบบแก้ไข Intent ได้ที่ส่วนด้านล่าง เกี่ยวกับความละเอียดของความตั้งใจ
ข้อควรระวัง: การใช้ตัวกรอง Intent ไม่ใช่วิธีที่ปลอดภัยในการป้องกันไม่ให้แอปอื่นๆ เริ่มทำงาน
คอมโพเนนต์ของคุณ แม้ว่าตัวกรอง Intent จะจำกัดคอมโพเนนต์ให้ตอบสนองต่อ
Intent แบบไม่เจาะจงปลายทางบางประเภท แอปอื่นอาจเริ่มคอมโพเนนต์ของแอปได้
โดยการใช้เจตนาที่ชัดแจ้งหากนักพัฒนาซอฟต์แวร์กำหนดชื่อคอมโพเนนต์ของคุณ
หากสิ่งสำคัญคือมีแต่แอปของคุณเองเท่านั้นที่เริ่มต้นคอมโพเนนต์ได้
อย่าประกาศตัวกรอง Intent ในไฟล์ Manifest แต่ให้ตั้งค่า
แอตทริบิวต์ของ exported
เป็น "false"
สำหรับคอมโพเนนต์นั้น
ในทำนองเดียวกัน เพื่อหลีกเลี่ยงการเรียกใช้แอปพลิเคชันอื่นโดยไม่ตั้งใจ
Service
โปรดใช้ Intent แบบเจาะจงปลายทางเพื่อเริ่มบริการของคุณเองเสมอ
หมายเหตุ:
คุณต้องประกาศตัวกรอง Intent ในไฟล์ Manifest สำหรับกิจกรรมทั้งหมด
อย่างไรก็ตาม ตัวกรองสำหรับเครื่องรับสัญญาณออกอากาศสามารถลงทะเบียนแบบไดนามิกโดยการเรียกใช้
registerReceiver()
จากนั้นคุณจะยกเลิกการลงทะเบียนตัวรับกับ unregisterReceiver()
ได้ การทำเช่นนี้จะช่วยให้แอปของคุณ
เพื่อฟังการออกอากาศเฉพาะในช่วงระยะเวลาที่กำหนดขณะที่แอปของคุณ
กำลังทำงาน
ตัวอย่างตัวกรอง
ตัวอย่างในการสาธิตลักษณะการทำงานของตัวกรอง Intent บางรายการมีดังนี้ จากไฟล์ Manifest ของแอปการแชร์ผ่านโซเชียล
<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
บ่งบอกว่านี่คือจุดแรกเข้าหลักและไม่ได้คาดหวังข้อมูล Intent - หมวดหมู่
CATEGORY_LAUNCHER
บ่งชี้ว่ากิจกรรมนี้ ควรวางในตัวเปิดแอปของระบบ หากองค์ประกอบ<activity>
ไม่ได้ระบุไอคอนด้วยicon
ระบบจะใช้ไอคอนจาก<application>
ทั้ง 2 สิ่งนี้ต้องจับคู่เข้าด้วยกันเพื่อให้กิจกรรมปรากฏในเครื่องเรียกใช้งานแอป
กิจกรรมที่ 2 ShareActivity
มีจุดประสงค์เพื่ออำนวยความสะดวกในการแชร์ข้อความและสื่อ
เนื้อหา แม้ว่าผู้ใช้อาจเข้าสู่กิจกรรมนี้โดยไปที่กิจกรรมจาก MainActivity
ผู้ใช้ยังสามารถป้อน ShareActivity
โดยตรงจากแอปอื่นที่ออกคำสั่งเป็นนัย
Intent ตรงกับตัวกรอง Intent 1 จาก 2 รายการ
หมายเหตุ: ประเภท MIME
application/vnd.google.panorama360+jpg
คือประเภทข้อมูลพิเศษที่ระบุ
ภาพพาโนรามา ซึ่งคุณจัดการได้ด้วย Google
panorama API
จับคู่ Intent กับตัวกรอง Intent ของแอปอื่นๆ
หากแอปอื่นกำหนดเป้าหมายเป็น Android 13 (API ระดับ 33) ขึ้นไป ก็จะสามารถจัดการ
Intent ของแอปเฉพาะในกรณีที่ Intent ตรงกับการดำเนินการและหมวดหมู่ของ
<intent-filter>
ในแอปนั้น หากระบบไม่พบ
เกมจะแสดงข้อผิดพลาด
ActivityNotFoundException
แอปที่ส่งต้องจัดการ
ข้อยกเว้นนี้
ในทำนองเดียวกัน หากคุณอัปเดตแอปเพื่อให้กำหนดเป้าหมายเป็น Android 13
ขึ้นไป ระบบจะนำส่ง Intent ทั้งหมดที่มาจากแอปภายนอกไปยัง
คอมโพเนนต์ที่ส่งออกมาก็ต่อเมื่อ Intent นั้นตรงกับการดำเนินการ และ
หมวดหมู่ขององค์ประกอบ <intent-filter>
ที่แอปของคุณประกาศ ลักษณะการทำงานนี้
เกิดขึ้นไม่ว่าแอปที่ส่งเวอร์ชัน SDK เป้าหมายจะเป็นอย่างไรก็ตาม
ในกรณีต่อไปนี้ ระบบจะไม่บังคับใช้การจับคู่ Intent
- Intent ที่ส่งไปยังคอมโพเนนต์ที่ไม่ได้ประกาศตัวกรอง Intent ใดๆ
- Intent ที่มาจากภายในแอปเดียวกัน
- Intent ที่มาจากระบบ นั่นคือ Intent ที่ส่งจาก
"UID ของระบบ" (uid=1000) แอประบบรวมถึง
system_server
และแอปที่ตั้งค่าandroid:sharedUserId
ถึงandroid.uid.system
- Intent ที่มาจากรูท
ดูข้อมูลเพิ่มเติมเกี่ยวกับการจับคู่ความตั้งใจ
ใช้ Intent ที่รอดำเนินการ
ออบเจ็กต์ PendingIntent
คือ Wrapper ที่อยู่รอบๆ ออบเจ็กต์ Intent
วัตถุประสงค์หลักของ PendingIntent
คือการให้สิทธิ์กับแอปพลิเคชันในต่างประเทศ
เพื่อใช้ Intent
ที่มีอยู่ประหนึ่งว่าได้ดำเนินการจาก
กระบวนการของแอปเอง
กรณีการใช้งานหลักๆ สำหรับ Intent ที่รอดำเนินการมีดังนี้
- ประกาศความตั้งใจที่จะดำเนินการเมื่อผู้ใช้ดำเนินการด้วยการแจ้งเตือนของคุณ
(
NotificationManager
ของระบบ Android จะเรียกใช้Intent
) - ประกาศความตั้งใจที่จะดำเนินการเมื่อผู้ใช้ดำเนินการ
วิดเจ็ตแอป
(แอปหน้าจอหลักจะเรียกใช้
Intent
) - ประกาศความตั้งใจที่จะดำเนินการในอนาคตที่ระบุไว้ (Android
AlarmManager
ของระบบเรียกใช้Intent
)
เช่นเดียวกับที่ออบเจ็กต์ Intent
แต่ละรายการออกแบบมาให้ได้รับการจัดการโดย
ประเภทคอมโพเนนต์แอป (Activity
, Service
หรือ
BroadcastReceiver
) ดังนั้น PendingIntent
ก็ต้องเป็น
ที่เราพิจารณาแบบเดียวกัน เมื่อใช้ Intent ที่รอดำเนินการ แอปของคุณจะไม่
เรียกใช้ Intent ด้วยการเรียก เช่น startActivity()
คุณต้องประกาศประเภทคอมโพเนนต์ที่ต้องการแทนเมื่อสร้างคอมโพเนนต์
PendingIntent
โดยเรียกวิธีการของครีเอเตอร์ที่เกี่ยวข้องดังนี้
PendingIntent.getActivity()
สำหรับIntent
ที่ขึ้นต้นActivity
PendingIntent.getService()
สำหรับIntent
ที่เริ่มต้นService
PendingIntent.getBroadcast()
สำหรับIntent
ที่เริ่มต้นBroadcastReceiver
เว้นแต่ว่าแอปของคุณจะได้รับ Intent ที่รอดำเนินการจากแอปอื่นๆ
วิธีการข้างต้นในการสร้าง PendingIntent
น่าจะเป็นเพียงวิธีเดียว
PendingIntent
วิธีการที่คุณจำเป็นต้องใช้
แต่ละวิธีจะใช้แอปปัจจุบัน Context
ค่า
Intent
ที่ต้องการรวม และแฟล็กอย่างน้อย 1 รายการที่ระบุ
ควรใช้ Intent อย่างไร (เช่น สามารถใช้ Intent ได้มากกว่า 1 ครั้งหรือไม่)
หากต้องการข้อมูลเพิ่มเติมเกี่ยวกับการใช้ Intent ที่รอดำเนินการ โปรดดูเอกสารสำหรับแต่ละ ของ Use Case ที่เกี่ยวข้อง เช่น ในการแจ้งเตือน และคำแนะนำ API ของ App Widgets
ระบุการเปลี่ยนแปลง
หากแอปกำหนดเป้าหมายเป็น Android 12 ขึ้นไป คุณต้องระบุ
การเปลี่ยนแปลงของออบเจ็กต์ PendingIntent
แต่ละรายการที่แอปสร้าง ในการประกาศว่า
ออบเจ็กต์ PendingIntent
ที่ระบุจะเปลี่ยนแปลงหรือเปลี่ยนแปลงไม่ได้ ให้ใช้
PendingIntent.FLAG_MUTABLE
หรือ
PendingIntent.FLAG_IMMUTABLE
ตามลำดับ
หากแอปพยายามสร้างออบเจ็กต์ PendingIntent
โดยไม่ตั้งค่า Flag การเปลี่ยนแปลง ระบบจะแสดงข้อผิดพลาด
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.
สร้าง Intent ที่รอดำเนินการที่เปลี่ยนแปลงไม่ได้เมื่อเป็นไปได้
ในกรณีส่วนใหญ่ แอปควรสร้างออบเจ็กต์ 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
เป็น Flag ไปยังเมธอดfillIn()
- การเชื่อมโยงการแจ้งเตือนกับเฟรมเวิร์ก Android Auto โดยใช้อินสแตนซ์ของ
CarAppExtender
- การวางการสนทนาในลูกโป่งโดยใช้อินสแตนซ์
จาก
PendingIntent
ออบเจ็กต์PendingIntent
ที่เปลี่ยนแปลงได้ช่วยให้ระบบนำไปใช้ได้ ค่าสถานะที่ถูกต้อง เช่นFLAG_ACTIVITY_MULTIPLE_TASK
และFLAG_ACTIVITY_NEW_DOCUMENT
- ขอข้อมูลตำแหน่งอุปกรณ์ด้วยการโทร
requestLocationUpdates()
หรือ API ที่คล้ายกัน ออบเจ็กต์PendingIntent
ที่เปลี่ยนแปลงได้ช่วยให้ระบบเพิ่ม Intent เพิ่มเติมที่แสดงเหตุการณ์ในวงจรสถานที่ตั้ง เหตุการณ์เหล่านี้ประกอบไปด้วย การเปลี่ยนแปลงสถานที่ตั้งและผู้ให้บริการที่พร้อมให้บริการ - ตั้งเวลาปลุกโดยใช้
AlarmManager
ออบเจ็กต์PendingIntent
ที่เปลี่ยนแปลงได้ช่วยให้ระบบเพิ่มEXTRA_ALARM_COUNT
Intent เพิ่มเติม ส่วนเกินนี้แสดงจำนวนครั้งที่การปลุกซ้ำ ถูกเรียกใช้แล้ว ด้วยการใส่ข้อมูลเพิ่มเติมนี้ Intent สามารถแจ้งเตือน แอปว่าการปลุกซ้ำถูกเรียกใช้หลายครั้งหรือไม่ เช่น เมื่ออุปกรณ์อยู่ในโหมดสลีป
หากแอปของคุณสร้างออบเจ็กต์ PendingIntent
ที่เปลี่ยนแปลงได้ เราขอแนะนําอย่างยิ่งให้คุณใช้ Intent ที่ชัดเจนและป้อน ComponentName
วิธีนี้จะทำให้เมื่อใดก็ได้
แอปอื่นจะเรียกใช้ PendingIntent
และตัวควบคุมบัตรกลับไปยังแอปของคุณ
คอมโพเนนต์เดียวกันในแอปจะเริ่มต้นเสมอ
ใช้ Intent ที่ชัดเจนภายใน Intent ที่รอดำเนินการ
หากต้องการระบุวิธีที่แอปอื่นๆ สามารถใช้ Intent ที่รอดำเนินการของแอปได้ดีขึ้น โปรดทำดังนี้ ใส่ Intent ที่รอดำเนินการรอบๆ เจตนาที่ชัดแจ้งไว้ด้วย เพื่อช่วยทำตามแนวทางปฏิบัติแนะนำดังกล่าว โปรดทำตามขั้นตอนต่อไปนี้
- ตรวจสอบว่าฟิลด์การดำเนินการ แพ็กเกจ และคอมโพเนนต์ของ Intent พื้นฐาน ได้รับการตั้งค่าแล้ว
-
ใช้
FLAG_IMMUTABLE
ซึ่งเพิ่มเข้ามาใน Android 6.0 (API ระดับ 23) เพื่อสร้าง Intent ที่รอดำเนินการ ธงนี้ ป้องกันไม่ให้แอปที่ได้รับ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>
อย่างน้อย 1 รายการ ดังที่แสดงในตัวอย่างต่อไปนี้
<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 จะประกาศเป็น 0 ขึ้นไปได้
<category>
ดังที่แสดงในตัวอย่างต่อไปนี้
<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>
แต่มีทรัพยากร Dependency แบบเชิงเส้น เช่น
- หากไม่ได้ระบุรูปแบบ ระบบจะละเว้นโฮสต์
- หากไม่ได้ระบุโฮสต์ ระบบจะไม่สนใจพอร์ต
- หากไม่ได้ระบุทั้งรูปแบบและโฮสต์ ระบบจะไม่สนใจเส้นทาง
เมื่อเปรียบเทียบ URI ใน Intent กับข้อกำหนด URI ในตัวกรอง ระบบจะเปรียบเทียบเฉพาะในส่วนของ URI ที่รวมอยู่ในตัวกรองเท่านั้น เช่น
- หากตัวกรองระบุเฉพาะสคีม URI ทั้งหมดที่มีรูปแบบนั้นตรงกัน ตัวกรอง
- หากตัวกรองระบุรูปแบบและสิทธิ์แต่ไม่มีเส้นทาง URI ทั้งหมด ที่มีรูปแบบและสิทธิ์เดียวกันจะผ่านตัวกรอง โดยไม่คำนึงถึงเส้นทาง
- หากตัวกรองระบุสคีม สิทธิ์ และเส้นทาง จะมีเพียง URI ที่มีรูปแบบเดียวกันเท่านั้น ที่เหมาะสม และเส้นทางการผ่านตัวกรอง
หมายเหตุ: ข้อกําหนดเฉพาะของพาธอาจมีเครื่องหมายดอกจัน (*) ไวลด์การ์ดเพื่อให้จับคู่ชื่อพาธได้เพียงบางส่วน
การทดสอบข้อมูลจะเปรียบเทียบทั้ง 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 ว่าคอมโพเนนต์สามารถรับข้อมูลรูปภาพจากเนื้อหาได้
ของผู้ให้บริการ และแสดงไว้ดังนี้
<intent-filter> <data android:mimeType="image/*" /> ... </intent-filter>
ตัวกรองที่ ระบุประเภทข้อมูล แต่ไม่ใช่ URI อาจเป็นข้อมูลที่ใช้กันมากที่สุด เนื่องจากมีข้อมูลมากที่สุด ข้อมูลจะจ่ายโดยผู้ให้บริการเนื้อหา
การกำหนดค่าทั่วไปอีกแบบหนึ่งคือตัวกรองที่มีรูปแบบและประเภทข้อมูล สำหรับ
ตัวอย่างเช่น <data>
ดังเช่นตัวอย่างต่อไปนี้บอกให้ Android ทราบว่า
คอมโพเนนต์สามารถดึงข้อมูลวิดีโอจากเครือข่ายเพื่อนำมาใช้งาน ดังนี้
<intent-filter> <data android:scheme="http" android:mimeType="video/*" /> ... </intent-filter>
การจับคู่ Intent
ระบบจะจับคู่ Intent กับตัวกรอง Intent ที่ไม่ใช่เพียงเพื่อค้นพบเป้าหมาย
สำหรับเปิดใช้งาน และยังพบบางอย่างเกี่ยวกับชุดของ
คอมโพเนนต์ต่างๆ ในอุปกรณ์ ตัวอย่างเช่น แอป Home จะเติมตัวเปิดแอป
ด้วยการค้นหากิจกรรมทั้งหมดด้วยตัวกรอง Intent ที่ระบุ
ACTION_MAIN
การดำเนินการและ
CATEGORY_LAUNCHER
หมวดหมู่
การจับคู่จะสําเร็จก็ต่อเมื่อการกระทําและหมวดหมู่ใน Intent ตรงกัน
ตามตัวกรองตามที่อธิบายไว้ในเอกสารสำหรับ IntentFilter
แอปพลิเคชันของคุณใช้การจับคู่ Intent ได้ในลักษณะที่คล้ายกับการทำงานของแอป Home
PackageManager
มีชุดของ query...()
ซึ่งแสดงผลคอมโพเนนต์ทั้งหมดที่สามารถยอมรับความตั้งใจที่เฉพาะเจาะจงและ
ชุดเมธอดของ resolve...()
ที่คล้ายกันซึ่งตัดสินว่าวิธีที่ดีที่สุด
ในการตอบสนองต่อความตั้งใจ ตัวอย่างเช่น
queryIntentActivities()
แสดงรายการกิจกรรมทั้งหมดที่สามารถทำได้
ความตั้งใจที่ส่งผ่านเป็นอาร์กิวเมนต์ และ queryIntentServices()
แสดงรายการบริการที่คล้ายกัน
ไม่มีวิธีใดเปิดใช้งานคอมโพเนนต์ เพียงแค่ระบุรายการข้อมูลที่
ตอบกลับได้ มีวิธีที่คล้ายกัน
queryBroadcastReceivers()
สำหรับ Broadcast Receiver