Aplikacje na Androida mogą wysyłać i odbierać komunikaty z systemu Android oraz innych aplikacji na Androida, podobnych opublikuj i zasubskrybuj i wzorca projektowy. Te komunikaty są wysyłane, gdy zdarzy się coś interesującego. Na przykład Android wysyła komunikaty, gdy różne zdarzenia systemowe na przykład podczas uruchamiania systemu lub rozpoczęcia ładowania urządzenia. aplikacji; może również wysyłać własne komunikaty, aby na przykład powiadamiać inne aplikacje o tym, co może ich zainteresować (np. nowe dane pobrane).
System optymalizuje dostarczanie transmisji, aby utrzymać w optymalnym stanie systemu. Dlatego czasy dostarczania transmisji nie są podawane gwarantowane. Aplikacje, które wymagają komunikacji międzyprocesowej z krótkim czasem oczekiwania, jako powiązane usługi.
Aplikacje mogą się rejestrować, aby odbierać określone komunikaty. Po wysłaniu transmisji system automatycznie kieruje komunikaty do aplikacji, które subskrybują w konkretny sposób.
Ogólnie komunikaty mogą służyć jako system przesyłania wiadomości w różnych aplikacjach. poza typowym ruchem w przeglądarce. Trzeba jednak uważać, aby nie nadużywać umożliwia reagowanie na komunikaty i uruchamianie zadań w tle, może przyczyniać się do powolnego działania systemu.
Komunikaty systemowe
System automatycznie wysyła komunikaty po wystąpieniu różnych zdarzeń systemowych, na przykład gdy system włącza i wyłącza tryb samolotowy. Systemowy wiadomości są wysyłane do wszystkich aplikacji, które subskrybują .
Sama transmisja wiadomości jest zawijana w element Intent
obiektu, którego ciąg działania identyfikuje zdarzenie, które wystąpiło (na przykład
android.intent.action.AIRPLANE_MODE
). Intencja może też obejmować
informacje zawarte w dodatkowym polu. Na przykład:
intencja trybu zawiera dodatkową wartość logiczną, która wskazuje, czy tryb samolotowy
Tryb jest włączony.
Więcej informacji o tym, jak odczytywać intencje i uzyskiwać ciąg znaków działania z intencja, zapoznaj się z sekcją Intencje i intencja Filtry.
Pełną listę działań związanych z transmisją systemu znajdziesz w
BROADCAST_ACTIONS.TXT
w pakiecie Android SDK. Każde transmitowane zdarzenie ma
pole stałe. Na przykład wartość stałej
ACTION_AIRPLANE_MODE_CHANGED
to
android.intent.action.AIRPLANE_MODE
Dokumentacja każdego działania związanego z transmisją
jest dostępna w powiązanym polu stałym.
Zmiany w komunikatach systemowych
W miarę rozwoju platformy Android co jakiś czas zmienia ona sposób transmisji systemu. działania. We wszystkich wersjach Androida pamiętaj o tych zmianach.
Android 14
Gdy aplikacje są w pamięci podręcznej
województwo, przesyłanie transmisji to
są zoptymalizowane pod kątem stanu systemu. Na przykład mniej ważne komunikaty systemowe, takie jak
bo ACTION_SCREEN_ON
są
jest odroczone, gdy aplikacja jest przechowywana w pamięci podręcznej. Gdy aplikacja zostanie usunięta z pamięci podręcznej,
w aktywny proces,
cyklu życia usługi,
wszystkich odroczonych transmisji.
Ważne komunikaty zadeklarowane w manifest tymczasowo usuwa aplikacje z pamięci podręcznej. stan dostawy.
Android 9
Począwszy od Androida 9 (poziom interfejsu API 28)
NETWORK_STATE_CHANGED_ACTION
komunikat nie otrzymuje informacji o lokalizacji użytkownika ani danych osobowych
dane umożliwiające identyfikację.
Jeśli aplikacja jest zainstalowana na urządzeniu z Androidem 9 lub nowszym,
komunikaty systemowe z Wi-Fi nie zawierają identyfikatorów SSID, identyfikatorów BSSID ani połączeń.
lub skanowanie wyników. Aby uzyskać te informacje, zadzwoń pod numer
getConnectionInfo()
.
Android 8.0
Począwszy od Androida 8.0 (poziom interfejsu API 26) system nakłada dodatkowe ograniczeń dotyczących odbiorców zadeklarowanych w pliku manifestu.
Jeśli Twoja aplikacja jest kierowana na Androida 8.0 lub nowszego, nie możesz użyć pliku manifestu, aby deklaracja odbiornika dla większości wiadomości niejawnych (transmisji, które nie są celem kierowania) w konkretnej aplikacji). Nadal możesz używać odbiorcy zarejestrowany w kontekście, gdy aktywnie korzysta z aplikacji.
Android 7.0
Android 7.0 (poziom interfejsu API 24) i nowsze wersje nie wysyłają poniższego systemu komunikaty:
Oprócz tego aplikacje kierowane na Androida 7.0 lub nowszego muszą rejestrować transmisję CONNECTIVITY_ACTION
za pomocą: registerReceiver(BroadcastReceiver, IntentFilter)
.
Nie można zadeklarować w pliku manifestu odbiorcy.
Odbieranie komunikatów
Aplikacje mogą odbierać komunikaty na 2 sposoby: przez odbiorniki zadeklarowane w pliku manifestu i odbiorców zarejestrowanych na podstawie kontekstu.
Odbiorcy zadeklarowani w pliku manifestu
Jeśli zadeklarujesz w pliku manifestu odbiornik, system uruchomi (jeśli nie jest ona jeszcze uruchomiona).
Aby zadeklarować odbiornik w pliku manifestu, wykonaj te czynności:
Określanie elementu
<receiver>
w pliku manifestu aplikacji.<!-- 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="APP_SPECIFIC_BROADCAST" /> </intent-filter> </receiver>
Filtry intencji określają działania związane z transmisją subskrybowane przez odbiornik.
Podklasa
BroadcastReceiver
i implementacjaonReceive(Context, Intent)
. odbiornika w poniższych przykładowych logach i wyświetla ich zawartość transmisji:Kotlin
private const val TAG = "MyBroadcastReceiver" class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { StringBuilder().apply { append("Action: ${intent.action}\n") append("URI: ${intent.toUri(Intent.URI_INTENT_SCHEME)}\n") toString().also { log -> Log.d(TAG, log) val binding = ActivityNameBinding.inflate(layoutInflater) val view = binding.root setContentView(view) Snackbar.make(view, log, Snackbar.LENGTH_LONG).show() } } } }
Java
public class MyBroadcastReceiver extends BroadcastReceiver { private static final String TAG = "MyBroadcastReceiver"; @Override public void onReceive(Context context, Intent intent) { StringBuilder sb = new StringBuilder(); sb.append("Action: " + intent.getAction() + "\n"); sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n"); String log = sb.toString(); Log.d(TAG, log); ActivityNameBinding binding = ActivityNameBinding.inflate(layoutInflater); val view = binding.root; setContentView(view); Snackbar.make(view, log, Snackbar.LENGTH_LONG).show(); } }
Aby włączyć powiązanie widoków: skonfiguruj viewBinding na poziomie modułu. build.gradle.
Systemowy menedżer pakietów rejestruje odbiorcę, gdy aplikacja jest zainstalowana. Odbiorca staje się wówczas osobnym punktem wejścia do aplikacji, że system może uruchomić aplikację i przekazać transmisję, jeśli aplikacja nie uruchomione.
System tworzy nowy komponent BroadcastReceiver
.
który obsługuje każdą odebraną transmisję. Ten obiekt jest prawidłowy tylko
przez cały czas trwania połączenia z numerem onReceive(Context, Intent)
. Gdy kod
zwraca tę metodę, system uzna, że komponent nie jest już
aktywne.
Odbiorcy zarejestrowani na podstawie kontekstu
Odbiorcy zarejestrowani w określonym kontekście otrzymują transmisje, dopóki ich rejestracja
jest prawidłowy. Jeśli na przykład zarejestrujesz się w
Activity
otrzymujesz komunikaty, o ile aktywność nie zostanie zniszczona. Jeśli
zarejestrować się z kontekstem aplikacji, będziesz otrzymywać komunikaty, jeśli aplikacja
jest uruchomiony.
Aby zarejestrować odbiorcę z użyciem kontekstu, wykonaj te czynności:
W pliku kompilacji na poziomie modułu aplikacji umieść wersję 1.9.0 lub nowszą bibliotekę AndroidX Core:
Odlotowe
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-alpha01" }
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-alpha01") }
Utwórz instancję
BroadcastReceiver
:Kotlin
val br: BroadcastReceiver = MyBroadcastReceiver()
Java
BroadcastReceiver br = new MyBroadcastReceiver();
Utwórz instancję
IntentFilter
:Kotlin
val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
Java
IntentFilter filter = new IntentFilter(APP_SPECIFIC_BROADCAST);
Wybierz, czy odbiornik ma być eksportowany i widoczny dla z innych aplikacji na urządzeniu. Jeśli ten odbiornik nasłuchuje wysyłanych wiadomości z systemu lub innych aplikacji, nawet innych należących do Ciebie, użyj flaga
RECEIVER_EXPORTED
. Jeśli zamiast tego ten odbiornik nasłuchuje tylko przez komunikatów wysyłanych przez Twoją aplikację, użyj flagiRECEIVER_NOT_EXPORTED
Kotlin
val listenToBroadcastsFromOtherApps = false val receiverFlags = if (listenToBroadcastsFromOtherApps) { ContextCompat.RECEIVER_EXPORTED } else { ContextCompat.RECEIVER_NOT_EXPORTED }
Java
boolean listenToBroadcastsFromOtherApps = false; if (listenToBroadcastsFromOtherApps) { receiverFlags = ContextCompat.RECEIVER_EXPORTED; } else { receiverFlags = ContextCompat.RECEIVER_NOT_EXPORTED; }
Zarejestruj odbiorcę, dzwoniąc
registerReceiver()
:Kotlin
ContextCompat.registerReceiver(context, br, filter, receiverFlags)
Java
ContextCompat.registerReceiver(context, br, filter, receiverFlags);
Aby przestać otrzymywać komunikaty, zadzwoń pod numer
unregisterReceiver(android.content.BroadcastReceiver)
. Pamiętaj, aby wyrejestrować odbiornik, gdy już go nie potrzebujesz lub Kontekst nie jest już prawidłowy.Zastanów się, gdzie rejestrujesz i wyrejestrowujesz odbiorcę, ponieważ Jeśli na przykład zarejestrujesz odbiorcę w usłudze
onCreate(Bundle)
przy użyciu kontekstu aktywności, powinien wyrejestrować go w usłudzeonDestroy()
w zapobiec wyciekom odbiorcy z kontekstu aktywności. Jeśli zarejestrujesz się odbiornika wonResume()
, musisz wyrejestruj go wonPause()
, aby zapobiec rejestrując go wielokrotnie (jeśli nie chcesz otrzymywać komunikatów po wstrzymaniu, co może ograniczyć niepotrzebne koszty systemu). Nie wolno wyrejestruj się w:onSaveInstanceState(Bundle)
, ponieważ ta funkcja nie jest wywoływana, gdy użytkownik wróci do stosu historii.
Wpływ na stan procesu
Niezależnie od tego, czy BroadcastReceiver
działa lub nie ma wpływu na zawarty w nim proces, który może zmieniać
skutkuje zniszczeniem systemu. Proces na pierwszym planie wykonuje metodę onReceive()
odbiorcy.
system uruchamia proces poza nadmiernym obciążeniem pamięci.
Odbiornik BroadcastReceiver zostanie wyłączony po onReceive()
. Host odbiorcy
jest tak istotny,
co jej składniki. Jeśli ten proces obsługuje tylko hosty
odbiornik zadeklarowany w pliku manifestu (często występujące w przypadku aplikacji, których użytkownik nigdy
lub nie wchodził w interakcję z nim w ostatnim czasie), system może go zamknąć po onReceive()
, aby wykonać
zasobów dostępnych na potrzeby
innych procesów o znaczeniu krytycznym.
Dlatego odbiorniki nie powinny inicjować długotrwałych wątków w tle.
Aby odzyskać dane, system może zatrzymać ten proces w dowolnym momencie po onReceive()
, zamykając utworzony wątek. Aby kontynuować proces, zaplanuj
JobService
od odbiornika za pomocą funkcji JobScheduler
dzięki czemu system będzie wiedział, że proces wciąż trwa.
Więcej informacji zawiera artykuł Omówienie pracy w tle.
Wysyłanie komunikatów
Android umożliwia aplikacjom wysyłanie komunikatów na 3 sposoby:
sendOrderedBroadcast(Intent, String)
wysyła komunikaty do jednego odbiornika w danym momencie. Gdy wykonuje się każdy odbiorca z kolei może przekazać wynik do następnego odbiorcy lub całkowicie przerwać transmisję, aby nie została przekazana do innych odbiorców. Kolejność odbiorców, do których trafiają odbiorcy, można kontrolować za pomocą atrybutu android:Priority pasującego filtra intencji; odbiorników z będzie uruchamiany w dowolnej kolejności.- Metoda
sendBroadcast(Intent)
wysyła – komunikaty są wysyłane do wszystkich odbiorników w nieokreślonej kolejności. Jest to tzw. Normalny Transmisja. Jest to bardziej wydajne, ale oznacza, że odbiorcy nie mogą odczytywać wyników od innych odbiorców, propagować dane otrzymane z transmisji; przerwać transmisję.
Fragment kodu poniżej pokazuje, jak wysłać transmisję przez utworzenie
Intencja i wywoływanie: sendBroadcast(Intent)
.
Kotlin
Intent().also { intent -> intent.setAction("com.example.broadcast.MY_NOTIFICATION") intent.putExtra("data", "Nothing to see here, move along.") sendBroadcast(intent) }
Java
Intent intent = new Intent(); intent.setAction("com.example.broadcast.MY_NOTIFICATION"); intent.putExtra("data", "Nothing to see here, move along."); sendBroadcast(intent);
Przesłany komunikat jest zapakowany w obiekt Intent
.
Ciąg działania intencji musi zawierać składnię nazwy pakietu Java oraz
jednoznacznie identyfikują transmitowane wydarzenie. Możesz dołączyć dodatkowe informacje
do intencji za pomocą funkcji putExtra(String, Bundle)
.
Możesz też ograniczyć transmisję do zestawu aplikacji w tej samej organizacji przez:
Wywołuję funkcję setPackage(String)
w intencji.
Ograniczanie transmisji z uprawnieniami
Uprawnienia pozwalają ograniczyć transmisję do grupy aplikacji, które pewnych uprawnień. Możesz egzekwować ograniczenia na poziomie nadawcy lub odbiornikiem komunikatu.
Wysyłanie z uprawnieniami
Gdy zadzwonisz do: sendBroadcast(Intent, String)
lub
sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
, możesz określić
Uprawnienia. Tylko odbiorcy, którzy poprosili o to uprawnienie w
Kotlin
sendBroadcast(Intent(BluetoothDevice.ACTION_FOUND), Manifest.permission.BLUETOOTH_CONNECT)
Java
sendBroadcast(new Intent(BluetoothDevice.ACTION_FOUND), Manifest.permission.BLUETOOTH_CONNECT)
Aby odebrać transmisję, aplikacja odbierająca musi poprosić o uprawnienie poniżej:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
Możesz określić istniejące uprawnienia systemowe, takie jak
BLUETOOTH_CONNECT
lub zdefiniuj uprawnienia niestandardowe za pomocą
Element <permission>
. Dla:
informacji na temat uprawnień i bezpieczeństwa można znaleźć w sekcji System
Uprawnienia.
Odbieranie z uprawnieniami
Jeśli określisz parametr uprawnień podczas rejestrowania odbiornika
(z registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
lub w
Tag <receiver>
w
manifestu), to jedynie nadawcy, którzy poprosili o to uprawnienie
Tag <uses-permission>
w pliku manifestu (a później otrzymał odpowiednie uprawnienia, jeśli
niebezpieczny) może wysłać intencję do odbiorcy.
Załóżmy na przykład, że aplikacja odbierająca ma zadeklarowany w pliku manifestu odbiornik jako poniżej:
<receiver android:name=".MyBroadcastReceiver"
android:permission="android.permission.BLUETOOTH_CONNECT">
<intent-filter>
<action android:name="android.intent.action.ACTION_FOUND"/>
</intent-filter>
</receiver>
Aplikacja odbierająca ma też odbiornik zarejestrowany kontekstowo, jak pokazano poniżej:
Kotlin
var filter = IntentFilter(Intent.ACTION_FOUND) registerReceiver(receiver, filter, Manifest.permission.BLUETOOTH_CONNECT, null )
Java
IntentFilter filter = new IntentFilter(Intent.ACTION_FOUND); registerReceiver(receiver, filter, Manifest.permission.BLUETOOTH_CONNECT, null );
Następnie, aby móc wysyłać komunikaty do tych odbiorców, aplikacja wysyłająca musi poproś o pozwolenie, jak pokazano poniżej:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
Kwestie bezpieczeństwa i sprawdzone metody
Poniżej przedstawiamy kilka kwestii związanych z bezpieczeństwem oraz sprawdzone metody wysyłania i odbieranie komunikatów:
Jeśli wiele aplikacji zarejestrowało się, by odbierać tę samą transmisję na swoim pliku manifestu, może on powodować uruchamianie przez system wielu aplikacji, powodując mają duży wpływ na wydajność urządzenia i wrażenia użytkownika. Aby unikać lepiej korzystać z rejestracji kontekstu zamiast deklaracji w pliku manifestu. Czasami system Android wymusza użycie odbiorców. Na przykład dostarczana jest transmisja
CONNECTIVITY_ACTION
tylko do odbiorców zarejestrowanych na podstawie kontekstu.Nie rozpowszechniaj informacji poufnych, nie mając intencji. informacje mogą być odczytywane przez każdą aplikację rejestrującą się, aby odbierać transmisję. Istnieją 3 sposoby określania, kto może odbierać Twoje komunikaty:
- Uprawnienia możesz określić podczas wysyłania transmisji.
- W Androidzie 4.0 i nowszych możesz określić
package z
setPackage(String)
podczas wysyłania transmisję. System ogranicza transmisję do zestawu aplikacji, które pasujące do pakietu.
Gdy zarejestrujesz odbiorcę, każda aplikacja może wysyłać potencjalnie szkodliwe aplikacje do odbiornika. Istnieje kilka sposobów na ograniczenie komunikaty wysyłane przez aplikację:
- Uprawnienia możesz określić podczas rejestrowania odbiornika.
- W przypadku odbiorców zadeklarowanych w pliku manifestu możesz ustawić android:exported ma wartość „false”; w pliku manifestu. Odbiorca nie otrzymuje komunikaty ze źródeł spoza aplikacji.
Przestrzeń nazw działań związanych z transmisją jest globalna. Upewnij się, że nazwy działań a inne ciągi są zapisane w Twojej przestrzeni nazw. W przeciwnym razie możesz niechętnie kolidują z innymi aplikacjami.
Ponieważ metoda
onReceive(Context, Intent)
odbiorcy działa na w wątku głównym, powinien zostać wykonany i szybko zwrócony. W razie potrzeby długotrwała praca, uważaj na pojawianie się wątków i usług w tle, ponieważ system może zakończyć cały procesonReceive()
za możliwość zwrotu. Więcej informacji znajdziesz w sekcji Wpływ na proces stan Aby przeprowadzić długotrwałą pracę, Rekomendacja:- Dzwonię pod
goAsync()
wonReceive()
odbiorcy i przekazywanie źródłaBroadcastReceiver.PendingResult
do wątku w tle. Dzięki temu transmisja pozostanie aktywna, gdy wrócisz z:onReceive()
. Jednak nawet przy takim podejściu system wymaga, aby użytkownik transmitowanie bardzo szybko (poniżej 10 sekund). Pozwala przenosić w innym wątku, aby uniknąć zakłóceń w wątku głównym. - Planujesz zadanie za pomocą
JobScheduler
. Więcej Więcej informacji na ten temat można znaleźć w artykule Intelligent Job (Inteligentne zadanie) Harmonogram.
- Dzwonię pod
Nie uruchamiaj działań od odbiorników, ponieważ jest drażniący; zwłaszcza wtedy, gdy jest więcej niż jeden odbiornik. Zamiast tego rozważ wyświetlanie powiadomienia.