แอป Android ส่งและรับข้อความประกาศจากระบบ Android และแอป Android อื่นๆ ซึ่งคล้ายกับรูปแบบการออกแบบเผยแพร่-สมัครรับข้อมูล โดยปกติแล้ว ระบบและแอปจะส่งการออกอากาศเมื่อมีเหตุการณ์บางอย่างเกิดขึ้น เช่น ระบบ Android จะส่งการออกอากาศเมื่อมีเหตุการณ์ต่างๆ เกิดขึ้นในระบบ เช่น การบูตระบบหรือการชาร์จอุปกรณ์ นอกจากนี้ แอปยังส่งการออกอากาศที่กำหนดเองด้วย เช่น เพื่อแจ้งให้แอปอื่นๆ ทราบเกี่ยวกับสิ่งที่อาจสนใจ (เช่น การดาวน์โหลดข้อมูลใหม่)
แอปสามารถลงทะเบียนเพื่อรับการออกอากาศที่เฉพาะเจาะจง เมื่อส่งการออกอากาศ ระบบจะกำหนดเส้นทางการออกอากาศไปยังแอปที่สมัครรับการออกอากาศประเภทนั้นโดยอัตโนมัติ
โดยทั่วไปแล้ว คุณสามารถใช้เป็นระบบการรับส่งข้อความในแอปต่างๆ และนอกเส้นทางปกติของผู้ใช้ อย่างไรก็ตาม คุณต้องระมัดระวังอย่าใช้โอกาสในการตอบกลับการออกอากาศและเรียกใช้งานในเบื้องหลังซึ่งอาจทําให้ระบบทำงานช้า
เกี่ยวกับประกาศของระบบ
ระบบจะส่งการออกอากาศโดยอัตโนมัติเมื่อเกิดเหตุการณ์ต่างๆ ของระบบ เช่น เมื่อระบบเปิดและปิดโหมดบนเครื่องบิน แอปที่สมัครรับข้อมูลทั้งหมดจะได้รับการออกอากาศเหล่านี้
ออบเจ็กต์ Intent
จะตัดข้อความประกาศ สตริง action
จะระบุเหตุการณ์ที่เกิดขึ้น เช่น android.intent.action.AIRPLANE_MODE
เจตนาอาจรวมข้อมูลเพิ่มเติมที่รวมอยู่ในช่องเพิ่มเติมด้วย
เช่น Intent โหมดเครื่องบินมีข้อมูลเพิ่มเติมแบบบูลีนซึ่งระบุว่าโหมดเครื่องบินเปิดอยู่หรือไม่
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีอ่าน Intent และรับสตริงการดำเนินการจาก Intent ได้ที่Intent และตัวกรอง Intent
การดําเนินการของประกาศของระบบ
ดูรายการการดำเนินการออกอากาศของระบบทั้งหมดได้ที่BROADCAST_ACTIONS.TXT
ไฟล์ใน Android SDK การดําเนินการออกอากาศแต่ละรายการจะมีช่องคงที่ที่เชื่อมโยงอยู่ เช่น ค่าของค่าคงที่
ACTION_AIRPLANE_MODE_CHANGED
คือ android.intent.action.AIRPLANE_MODE
เอกสารประกอบสําหรับการดําเนินการออกอากาศแต่ละรายการมีอยู่ในช่องค่าคงที่ที่เกี่ยวข้อง
การเปลี่ยนแปลงการออกอากาศของระบบ
เมื่อแพลตฟอร์ม Android พัฒนาขึ้น ระบบจะเปลี่ยนลักษณะการออกอากาศเป็นระยะๆ โปรดคำนึงถึงการเปลี่ยนแปลงต่อไปนี้เพื่อรองรับ Android ทุกเวอร์ชัน
Android 14
ขณะที่แอปอยู่ในสถานะแคช ระบบจะเพิ่มประสิทธิภาพการส่งออกการออกอากาศเพื่อรักษาประสิทธิภาพของระบบ เช่น ระบบจะเลื่อนการออกอากาศของระบบที่ไม่สำคัญมาก เช่น ACTION_SCREEN_ON
ออกไปขณะที่แอปอยู่ในสถานะแคช
เมื่อแอปเปลี่ยนจากสถานะแคชเป็นวงจรกระบวนการที่ใช้งานอยู่ ระบบจะส่งการออกอากาศที่เลื่อนออกไป
การออกอากาศที่สําคัญซึ่งประกาศในไฟล์ Manifest จะนําแอปออกจากสถานะแคชไว้ชั่วคราวสําหรับการนำส่ง
Android 9
ตั้งแต่ Android 9 (API ระดับ 28) เป็นต้นไป การออกอากาศ NETWORK_STATE_CHANGED_ACTION
จะไม่รับข้อมูลเกี่ยวกับตําแหน่งของผู้ใช้หรือข้อมูลส่วนบุคคลที่ระบุตัวบุคคลนั้นได้
หากติดตั้งแอปในอุปกรณ์ที่ใช้ Android 9.0 (API ระดับ 28) ขึ้นไป ระบบจะไม่รวม SSID, BSSID, ข้อมูลการเชื่อมต่อ หรือผลการสแกนในการออกอากาศ Wi-Fi หากต้องการทราบข้อมูลนี้ ให้โทรไปที่ getConnectionInfo()
แทน
Android 8.0
ตั้งแต่ Android 8.0 (API ระดับ 26) เป็นต้นไป ระบบจะกำหนดข้อจำกัดเพิ่มเติมสำหรับตัวรับที่ประกาศในไฟล์ Manifest
หากแอปกำหนดเป้าหมายเป็น Android 8.0 ขึ้นไป คุณจะใช้ไฟล์ Manifest เพื่อประกาศตัวรับสำหรับประกาศโดยนัยส่วนใหญ่ (ประกาศที่ไม่ได้กำหนดเป้าหมายแอปของคุณโดยเฉพาะ) ไม่ได้ คุณจะยังใช้ตัวรับที่ลงทะเบียนตามบริบทได้เมื่อผู้ใช้กำลังใช้งานแอปอยู่
Android 7.0
Android 7.0 (API ระดับ 24) ขึ้นไปจะไม่ส่งการออกอากาศของระบบต่อไปนี้
นอกจากนี้ แอปที่กำหนดเป้าหมายเป็น Android 7.0 ขึ้นไปต้องลงทะเบียนการออกอากาศ CONNECTIVITY_ACTION
โดยใช้ registerReceiver(BroadcastReceiver, IntentFilter)
การประกาศตัวรับในไฟล์ Manifest ไม่ทํางาน
รับการออกอากาศ
แอปรับการออกอากาศได้ 2 วิธี ได้แก่ ผ่านตัวรับที่ลงทะเบียนตามบริบทและตัวรับที่ประกาศในไฟล์ Manifest
ผู้รับที่ลงทะเบียนตามบริบท
ตัวรับที่ลงทะเบียนตามบริบทจะรับการออกอากาศตราบใดที่บริบทการลงทะเบียนถูกต้อง ซึ่งโดยปกติจะอยู่ระหว่างการเรียกใช้ registerReceiver
และ unregisterReceiver
บริบทการลงทะเบียนจะใช้งานไม่ได้เมื่อระบบทำลายบริบทที่เกี่ยวข้อง ตัวอย่างเช่น หากคุณลงทะเบียนภายในบริบท Activity
คุณจะได้รับข้อความประกาศตราบใดที่กิจกรรมยังคงทำงานอยู่ หากลงทะเบียนด้วยบริบทแอปพลิเคชัน คุณจะได้รับการออกอากาศตราบใดที่แอปทำงานอยู่
หากต้องการลงทะเบียนตัวรับที่มีบริบท ให้ทําตามขั้นตอนต่อไปนี้
ในไฟล์บิลด์ระดับโมดูลของแอป ให้รวมคลัง AndroidX Core เวอร์ชัน 1.9.0 ขึ้นไป
ดึงดูด
dependencies { def core_version = "1.13.1" // Java language implementation implementation "androidx.core:core:$core_version" // Kotlin implementation "androidx.core:core-ktx:$core_version" // To use RoleManagerCompat implementation "androidx.core:core-role:1.0.0" // To use the Animator APIs implementation "androidx.core:core-animation:1.0.0" // To test the Animator APIs androidTestImplementation "androidx.core:core-animation-testing:1.0.0" // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation "androidx.core:core-performance:1.0.0" // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation "androidx.core:core-google-shortcuts:1.1.0" // Optional - to support backwards compatibility of RemoteViews implementation "androidx.core:core-remoteviews:1.1.0" // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation "androidx.core:core-splashscreen:1.2.0-alpha02" }
Kotlin
dependencies { val core_version = "1.13.1" // Java language implementation implementation("androidx.core:core:$core_version") // Kotlin implementation("androidx.core:core-ktx:$core_version") // To use RoleManagerCompat implementation("androidx.core:core-role:1.0.0") // To use the Animator APIs implementation("androidx.core:core-animation:1.0.0") // To test the Animator APIs androidTestImplementation("androidx.core:core-animation-testing:1.0.0") // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation("androidx.core:core-performance:1.0.0") // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation("androidx.core:core-google-shortcuts:1.1.0") // Optional - to support backwards compatibility of RemoteViews implementation("androidx.core:core-remoteviews:1.1.0") // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation("androidx.core:core-splashscreen:1.2.0-alpha02") }
สร้างอินสแตนซ์ของ
BroadcastReceiver
Kotlin
val myBroadcastReceiver = MyBroadcastReceiver()
Java
MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();
สร้างอินสแตนซ์ของ
IntentFilter
Kotlin
val filter = IntentFilter("com.example.snippets.ACTION_UPDATE_DATA")
Java
IntentFilter filter = new IntentFilter("com.example.snippets.ACTION_UPDATE_DATA");
เลือกว่าควรส่งออกตัวรับสัญญาณการออกอากาศและแสดงให้แอปอื่นๆ ในอุปกรณ์เห็นหรือไม่ หากตัวรับนี้กำลังรับฟังการออกอากาศที่ส่งจากระบบหรือจากแอปอื่นๆ รวมถึงแอปอื่นๆ ที่คุณเป็นเจ้าของ ให้ใช้ Flag
RECEIVER_EXPORTED
หากตัวรับนี้คอยฟังเฉพาะการออกอากาศที่ส่งโดยแอปของคุณ ให้ใช้ FlagRECEIVER_NOT_EXPORTED
Kotlin
val listenToBroadcastsFromOtherApps = false val receiverFlags = if (listenToBroadcastsFromOtherApps) { ContextCompat.RECEIVER_EXPORTED } else { ContextCompat.RECEIVER_NOT_EXPORTED }
Java
boolean listenToBroadcastsFromOtherApps = false; int receiverFlags = listenToBroadcastsFromOtherApps ? ContextCompat.RECEIVER_EXPORTED : ContextCompat.RECEIVER_NOT_EXPORTED;
ลงทะเบียนผู้รับโดยโทรไปที่
registerReceiver()
Kotlin
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags)
Java
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);
หากต้องการหยุดรับการออกอากาศ ให้โทรไปที่
unregisterReceiver(android.content.BroadcastReceiver)
อย่าลืมยกเลิกการลงทะเบียนตัวรับเมื่อไม่ต้องการหรือบริบทใช้งานไม่ได้แล้ว
ยกเลิกการลงทะเบียน Broadcast Receiver
ขณะที่ลงทะเบียนตัวรับการออกอากาศ ตัวรับจะเก็บข้อมูลอ้างอิงถึงบริบทที่คุณใช้จดทะเบียนไว้ ซึ่งอาจทำให้เกิดการรั่วไหลได้หากขอบเขตที่ลงทะเบียนของผู้รับเกินขอบเขตวงจรชีวิตของบริบท ตัวอย่างเช่น กรณีนี้อาจเกิดขึ้นเมื่อคุณลงทะเบียนตัวรับในขอบเขตกิจกรรม แต่ลืมยกเลิกการลงทะเบียนเมื่อระบบทำลายกิจกรรม ดังนั้น ให้ยกเลิกการลงทะเบียน Broadcast Receiver เสมอ
Kotlin
class MyActivity : ComponentActivity() {
private val myBroadcastReceiver = MyBroadcastReceiver()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags)
setContent { MyApp() }
}
override fun onDestroy() {
super.onDestroy()
// When you forget to unregister your receiver here, you're causing a leak!
this.unregisterReceiver(myBroadcastReceiver)
}
}
Java
class MyActivity extends ComponentActivity {
MyBroadcastReceiver myBroadcastReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags);
// Set content
}
}
ลงทะเบียนตัวรับในขอบเขตที่เล็กที่สุด
คุณควรลงทะเบียนตัวรับการออกอากาศเฉพาะในกรณีที่คุณสนใจผลลัพธ์จริงๆ เลือกขอบเขตผู้รับที่เล็กที่สุดเท่าที่จะเป็นไปได้ ดังนี้
LifecycleResumeEffect
หรือวิธีการเกี่ยวกับวงจรชีวิตของกิจกรรมonResume
/onPause
: ตัวรับการออกอากาศจะได้รับการอัปเดตเฉพาะในขณะที่แอปอยู่ในสถานะ "กลับมาทํางานอีกครั้ง"LifecycleStartEffect
หรือวิธีการเกี่ยวกับวงจรชีวิตของกิจกรรมonStart
/onStop
: ตัวรับการออกอากาศจะได้รับการอัปเดตเฉพาะในขณะที่แอปอยู่ในสถานะ "กลับมาทํางานอีกครั้ง"DisposableEffect
: Broadcast Receiver จะได้รับการอัปเดตก็ต่อเมื่อคอมโพสิชันอยู่ในต้นไม้การคอมโพสิชันเท่านั้น ขอบเขตนี้ไม่ได้แนบมากับขอบเขตวงจรกิจกรรม ลองลงทะเบียนผู้รับในบริบทแอปพลิเคชัน เนื่องจากในทางทฤษฎีแล้ว Composable อาจอยู่ได้นานกว่าขอบเขตวงจรชีวิตของกิจกรรมและทำให้กิจกรรมรั่วไหล- กิจกรรม
onCreate
/onDestroy
: ตัวรับการออกอากาศจะได้รับการอัปเดตขณะที่กิจกรรมอยู่ในสถานะ "สร้างแล้ว" อย่าลืมยกเลิกการลงทะเบียนในonDestroy()
ไม่ใช่onSaveInstanceState(Bundle)
เนื่องจากระบบอาจไม่เรียกใช้ - ขอบเขตที่กำหนดเอง: เช่น คุณสามารถลงทะเบียนตัวรับใน
ViewModel
ขอบเขตเพื่อให้ตัวรับยังคงอยู่หลังจากสร้างกิจกรรมอีกครั้ง อย่าลืมใช้บริบทแอปพลิเคชันเพื่อลงทะเบียนตัวรับ เนื่องจากตัวรับอาจอยู่ได้นานกว่าขอบเขตวงจรชีวิตของกิจกรรมและทำให้กิจกรรมรั่วไหล
สร้างคอมโพสิเบิลที่มีสถานะและไม่มีสถานะ
Compose มีส่วนประกอบแบบมีสถานะและแบบไม่มีสถานะ การลงทะเบียนหรือยกเลิกการลงทะเบียน Broadcast Receiver ภายในคอมโพสิเบิลจะทำให้คอมโพสิเบิลมีสถานะ ฟังก์ชันที่ประกอบกันได้ไม่ใช่ฟังก์ชันที่แน่นอนซึ่งแสดงผลเนื้อหาเดียวกันเมื่อส่งพารามิเตอร์เดียวกัน สถานะภายในอาจเปลี่ยนแปลงตามการเรียกใช้ตัวรับสัญญาณออกอากาศที่ลงทะเบียน
แนวทางปฏิบัติแนะนำใน Compose คือให้แยกคอมโพสิเบิลออกเป็นเวอร์ชันที่มีสถานะและไม่มีสถานะ ดังนั้น เราขอแนะนำให้คุณยกระดับการสร้างตัวรับการออกอากาศออกจาก Composable เพื่อให้เป็นแบบไม่มีสถานะ
@Composable
fun MyStatefulScreen() {
val myBroadcastReceiver = remember { MyBroadcastReceiver() }
val context = LocalContext.current
LifecycleStartEffect(true) {
// ...
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, flags)
onStopOrDispose { context.unregisterReceiver(myBroadcastReceiver) }
}
MyStatelessScreen()
}
@Composable
fun MyStatelessScreen() {
// Implement your screen
}
ตัวรับที่ประกาศในไฟล์ Manifest
หากคุณประกาศตัวรับการออกอากาศในไฟล์ Manifest ระบบจะเปิดแอปของคุณเมื่อมีการออกอากาศ หากแอปไม่ได้ทำงานอยู่ ระบบจะเปิดแอป
หากต้องการประกาศตัวรับการออกอากาศในไฟล์ Manifest ให้ทําตามขั้นตอนต่อไปนี้
ระบุองค์ประกอบ
<receiver>
ในไฟล์ Manifest ของแอป<!-- If this receiver listens for broadcasts sent from the system or from other apps, even other apps that you own, set android:exported to "true". --> <receiver android:name=".MyBroadcastReceiver" android:exported="false"> <intent-filter> <action android:name="com.example.snippets.ACTION_UPDATE_DATA" /> </intent-filter> </receiver>
ตัวกรอง Intent จะระบุการดำเนินการของ Broadcast ที่ตัวรับสมัครรับข้อมูล
คลาสย่อย
BroadcastReceiver
และนำไปใช้onReceive(Context, Intent)
ตัวรับการออกอากาศในตัวอย่างต่อไปนี้จะบันทึกและแสดงเนื้อหาของการออกอากาศKotlin
class MyBroadcastReceiver : BroadcastReceiver() { @Inject lateinit var dataRepository: DataRepository override fun onReceive(context: Context, intent: Intent) { if (intent.action == "com.example.snippets.ACTION_UPDATE_DATA") { val data = intent.getStringExtra("com.example.snippets.DATA") ?: "No data" // Do something with the data, for example send it to a data repository: dataRepository.updateData(data) } } }
Java
public static class MyBroadcastReceiver extends BroadcastReceiver { @Inject DataRepository dataRepository; @Override public void onReceive(Context context, Intent intent) { if (Objects.equals(intent.getAction(), "com.example.snippets.ACTION_UPDATE_DATA")) { String data = intent.getStringExtra("com.example.snippets.DATA"); // Do something with the data, for example send it to a data repository: if (data != null) { dataRepository.updateData(data); } } } }
เครื่องมือจัดการแพ็กเกจของระบบจะลงทะเบียนตัวรับเมื่อติดตั้งแอป จากนั้นตัวรับจะกลายเป็นจุดแรกเข้าแยกต่างหากของแอป ซึ่งหมายความว่าระบบจะเริ่มต้นแอปและส่งออกการออกอากาศได้หากแอปไม่ทำงาน
ระบบจะสร้างออบเจ็กต์คอมโพเนนต์ BroadcastReceiver
ใหม่เพื่อจัดการการออกอากาศแต่ละรายการที่ได้รับ ออบเจ็กต์นี้จะใช้งานได้เฉพาะระหว่างการเรียกใช้ onReceive(Context, Intent)
เมื่อโค้ดของคุณแสดงผลจากเมธอดนี้ ระบบจะถือว่าคอมโพเนนต์ไม่มีการใช้งานแล้ว
ผลกระทบต่อสถานะการประมวลผล
การที่ BroadcastReceiver
ทำงานหรือไม่จะส่งผลต่อกระบวนการที่อยู่ในนั้น ซึ่งอาจทำให้โอกาสที่ระบบจะเสียหายเปลี่ยนแปลงไป กระบวนการที่ทำงานอยู่เบื้องหน้าจะเรียกใช้เมธอด onReceive()
ของผู้รับ ระบบจะเรียกใช้กระบวนการนี้ ยกเว้นในกรณีที่หน่วยความจํามีภาระงานสูงมาก
ระบบจะปิดใช้งาน BroadcastReceiver
หลังจาก onReceive()
ความสำคัญของกระบวนการโฮสต์ของผู้รับจะขึ้นอยู่กับคอมโพเนนต์แอป หากกระบวนการนั้นโฮสต์เฉพาะตัวรับที่ประกาศในไฟล์ Manifest ระบบอาจหยุดกระบวนการดังกล่าวหลังจาก onReceive()
เพื่อเพิ่มทรัพยากรให้กับกระบวนการอื่นๆ ที่สำคัญกว่า กรณีนี้พบได้ทั่วไปในแอปที่ผู้ใช้ไม่เคยหรือไม่ได้โต้ตอบด้วยเมื่อเร็วๆ นี้
ดังนั้น ตัวรับการออกอากาศไม่ควรเริ่มต้นเธรดเบื้องหลังที่ทำงานเป็นเวลานาน
ระบบสามารถหยุดกระบวนการได้ทุกเมื่อหลังจาก onReceive()
เพื่อเรียกคืนหน่วยความจำและสิ้นสุดเธรดที่สร้างขึ้น หากต้องการให้กระบวนการทำงานต่อไป ให้กำหนดเวลาJobService
จากเครื่องรับโดยใช้ JobScheduler
เพื่อให้ระบบทราบว่ากระบวนการยังคงทำงานอยู่ ภาพรวมของงานที่ทำอยู่เบื้องหลังมีรายละเอียดเพิ่มเติม
ส่งประกาศ
Android มี 2 วิธีที่แอปใช้ส่งการออกอากาศได้ ดังนี้
- วิธีการ
sendOrderedBroadcast(Intent, String)
จะส่งการออกอากาศไปยังผู้รับทีละราย เมื่อตัวรับแต่ละตัวดำเนินการตามลำดับ ตัวรับจะส่งต่อผลลัพธ์ไปยังตัวรับถัดไปได้ และยังยกเลิกการออกอากาศได้ทั้งหมดเพื่อไม่ให้สัญญาณไปถึงเครื่องรับอื่นๆ คุณควบคุมลําดับการทำงานของตัวรับได้ ซึ่งทำได้โดยใช้แอตทริบิวต์ android:priority ของตัวกรอง Intent ที่ตรงกัน ตัวรับที่มีลําดับความสําคัญเดียวกันจะทํางานตามลําดับที่กําหนด - เมธอด
sendBroadcast(Intent)
จะส่งการออกอากาศไปยังผู้รับทั้งหมดในลําดับที่ไม่ระบุ ซึ่งเรียกว่าการออกอากาศแบบปกติ วิธีนี้มีประสิทธิภาพมากกว่า แต่หมายความว่าผู้รับจะอ่านผลลัพธ์จากผู้รับรายอื่น เผยแพร่ข้อมูลที่รับจากการออกอากาศ หรือยกเลิกการออกอากาศไม่ได้
ข้อมูลโค้ดต่อไปนี้แสดงวิธีส่งการออกอากาศด้วยการสร้าง Intent และเรียกใช้ sendBroadcast(Intent)
Kotlin
val intent = Intent("com.example.snippets.ACTION_UPDATE_DATA").apply {
putExtra("com.example.snippets.DATA", newData)
setPackage("com.example.snippets")
}
context.sendBroadcast(intent)
Java
Intent intent = new Intent("com.example.snippets.ACTION_UPDATE_DATA");
intent.putExtra("com.example.snippets.DATA", newData);
intent.setPackage("com.example.snippets");
context.sendBroadcast(intent);
ข้อความประกาศจะรวมอยู่ในออบเจ็กต์ Intent
สตริง action
ของ Intent ต้องมีไวยากรณ์ชื่อแพ็กเกจ Java ของแอปและระบุเหตุการณ์การออกอากาศที่ไม่ซ้ำกัน คุณสามารถแนบข้อมูลเพิ่มเติมไปกับความตั้งใจได้โดยใช้ putExtra(String, Bundle)
นอกจากนี้ คุณยังจํากัดการออกอากาศให้กลุ่มแอปในองค์กรเดียวกันได้ด้วยโดยเรียกใช้ setPackage(String)
ใน Intent
จำกัดการออกอากาศด้วยสิทธิ์
สิทธิ์ช่วยให้คุณจำกัดการออกอากาศไว้เฉพาะชุดแอปที่มีสิทธิ์บางอย่าง คุณสามารถบังคับใช้ข้อจำกัดกับผู้ส่งหรือผู้รับการออกอากาศได้
ส่งประกาศพร้อมสิทธิ์
เมื่อเรียกใช้ sendBroadcast(Intent, String)
หรือ
sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String,
Bundle)
คุณจะระบุพารามิเตอร์สิทธิ์ได้ เฉพาะผู้รับที่ขอสิทธิ์ดังกล่าวด้วยแท็ก <uses-permission>
ในไฟล์ Manifest เท่านั้นที่จะรับการออกอากาศได้ หากสิทธิ์เป็นอันตราย คุณต้องให้สิทธิ์ก่อนเพื่อให้ผู้รับรับการออกอากาศได้ เช่น โค้ดต่อไปนี้จะส่งการออกอากาศที่มีสิทธิ์
Kotlin
context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION)
Java
context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION);
หากต้องการรับการออกอากาศ แอปฝั่งที่รับต้องขอสิทธิ์ดังนี้
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
คุณสามารถระบุสิทธิ์ของระบบที่มีอยู่ เช่น BLUETOOTH_CONNECT
หรือกำหนดสิทธิ์ที่กำหนดเองด้วยองค์ประกอบ <permission>
โปรดดูข้อมูลเกี่ยวกับสิทธิ์และความปลอดภัยโดยทั่วไปที่หัวข้อสิทธิ์ของระบบ
รับการออกอากาศที่มีสิทธิ์
หากคุณระบุพารามิเตอร์สิทธิ์เมื่อลงทะเบียนตัวรับการออกอากาศ (ไม่ว่าจะใช้แท็ก registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
หรือในแท็ก <receiver>
ในไฟล์ Manifest) เฉพาะผู้ออกอากาศที่ขอสิทธิ์ด้วยแท็ก <uses-permission>
ในไฟล์ Manifest เท่านั้นที่จะส่ง Intent ไปยังตัวรับได้ หากสิทธิ์เป็นอันตราย ผู้ออกอากาศจะต้องได้รับสิทธิ์ด้วย
ตัวอย่างเช่น สมมติว่าแอปฝั่งที่รับมีตัวรับที่ประกาศในไฟล์ Manifest ดังนี้
<!-- If this receiver listens for broadcasts sent from the system or from
other apps, even other apps that you own, set android:exported to "true". -->
<receiver
android:name=".MyBroadcastReceiverWithPermission"
android:permission="android.permission.ACCESS_COARSE_LOCATION"
android:exported="true">
<intent-filter>
<action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
</intent-filter>
</receiver>
หรือแอปที่รับของคุณมี Receiver ที่ลงทะเบียนตามบริบทดังต่อไปนี้
Kotlin
ContextCompat.registerReceiver(
context, myBroadcastReceiver, filter,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
null, // scheduler that defines thread, null means run on main thread
receiverFlags
)
Java
ContextCompat.registerReceiver(
context, myBroadcastReceiver, filter,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
null, // scheduler that defines thread, null means run on main thread
receiverFlags
);
จากนั้นแอปที่ส่งจะต้องขอสิทธิ์ต่อไปนี้เพื่อส่งการออกอากาศไปยังผู้รับเหล่านั้น
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
ข้อควรพิจารณาด้านความปลอดภัย
ข้อควรพิจารณาด้านความปลอดภัยในการส่งและรับการออกอากาศมีดังนี้
หากแอปหลายแอปลงทะเบียนเพื่อรับการออกอากาศเดียวกันในไฟล์ Manifest อาจทำให้ระบบเปิดแอปหลายแอป ซึ่งจะส่งผลอย่างมากต่อทั้งประสิทธิภาพของอุปกรณ์และประสบการณ์ของผู้ใช้ หากต้องการหลีกเลี่ยงปัญหานี้ ให้ใช้การลงทะเบียนบริบทแทนการประกาศไฟล์ Manifest บางครั้งระบบ Android จะบังคับใช้ตัวรับที่ลงทะเบียนตามบริบท เช่น ระบบจะส่งการออกอากาศ
CONNECTIVITY_ACTION
ไปยังผู้รับที่ลงทะเบียนตามบริบทเท่านั้นอย่าเผยแพร่ข้อมูลที่ละเอียดอ่อนโดยใช้ Intent ที่ไม่ชัดแจ้ง แอปใดก็ได้จะอ่านข้อมูลได้หากลงทะเบียนเพื่อรับการออกอากาศ คุณควบคุมผู้ที่สามารถรับการออกอากาศของคุณได้ 3 วิธีดังนี้
- คุณสามารถระบุสิทธิ์เมื่อส่งการประกาศได้
- ใน Android 4.0 (API ระดับ 14) ขึ้นไป คุณสามารถระบุ package ด้วย
setPackage(String)
เมื่อส่งการออกอากาศ ระบบจะจำกัดการออกอากาศไว้ที่ชุดแอปที่ตรงกับแพ็กเกจ
เมื่อคุณลงทะเบียนตัวรับ แอปใดก็ได้ที่จะส่งการออกอากาศที่อาจเป็นอันตรายไปยังตัวรับของแอปคุณ การจํากัดการออกอากาศที่แอปของคุณได้รับทำได้หลายวิธีดังนี้
- คุณสามารถระบุสิทธิ์เมื่อลงทะเบียนตัวรับการออกอากาศ
- สําหรับตัวรับที่ประกาศในไฟล์ Manifest คุณสามารถตั้งค่าแอตทริบิวต์ android:exported เป็น "false" ในไฟล์ Manifest ได้ ผู้รับจะไม่ได้รับการออกอากาศจากแหล่งที่มาภายนอกแอป
เนมสเปซสําหรับการดําเนินการแบบออกอากาศเป็นแบบส่วนกลาง ตรวจสอบว่าชื่อการดำเนินการและสตริงอื่นๆ เขียนในเนมสเปซที่คุณเป็นเจ้าของ ไม่เช่นนั้นคุณอาจแย่งสิทธิ์กับแอปอื่นๆ โดยไม่ได้ตั้งใจ
เนื่องจากเมธอด
onReceive(Context, Intent)
ของผู้รับทำงานบนเธรดหลัก จึงควรดำเนินการและแสดงผลได้อย่างรวดเร็ว หากต้องทํางานที่ทํางานเป็นเวลานาน โปรดระมัดระวังเกี่ยวกับการสร้างเธรดหรือเริ่มบริการที่ทำงานอยู่เบื้องหลัง เนื่องจากระบบอาจหยุดทั้งกระบวนการหลังจากonReceive()
แสดงผล ดูข้อมูลเพิ่มเติมได้ในผลต่อสถานะกระบวนการ หากต้องการทำงานที่ใช้เวลานาน เราขอแนะนําให้ทําดังนี้- การเรียก
goAsync()
ในเมธอดonReceive()
ของผู้รับ และส่งBroadcastReceiver.PendingResult
ไปยังเธรดเบื้องหลัง ซึ่งจะทำให้การออกอากาศทำงานต่อไปได้หลังจากกลับมาจากonReceive()
อย่างไรก็ตาม แม้จะใช้วิธีนี้ ระบบก็คาดหวังให้คุณออกอากาศให้เสร็จสิ้นอย่างรวดเร็ว (ภายใน 10 วินาที) แต่คุณสามารถย้ายงานไปยังชุดข้อความอื่นได้เพื่อหลีกเลี่ยงข้อบกพร่องของชุดข้อความหลัก - การกำหนดเวลางานด้วย
JobScheduler
ดูข้อมูลเพิ่มเติมได้ที่การกำหนดเวลางานอัจฉริยะ
- การเรียก
อย่าเริ่มกิจกรรมจากตัวรับการออกอากาศเนื่องจากประสบการณ์ของผู้ใช้จะแย่ลง โดยเฉพาะอย่างยิ่งหากมีตัวรับมากกว่า 1 ตัว แต่ให้พิจารณาแสดงการแจ้งเตือนแทน