Odbiorniki emisji na platformie Xamarin.Android

W tej sekcji omówiono sposób używania odbiornika emisji.

Omówienie odbiornika emisji

Odbiornik emisji jest składnikiem systemu Android, który umożliwia aplikacji odpowiadanie na komunikaty (Android ), które są emitowane przez system operacyjny Android Intentlub przez aplikację. Emisje są zgodne z modelem publikowania-subskrybowania — zdarzenie powoduje opublikowanie i odebranie emisji przez te składniki, które są zainteresowane zdarzeniem.

System Android identyfikuje dwa typy emisji:

  • Jawna emisja — te typy emisji dotyczą określonej aplikacji. Najczęstszym zastosowaniem jawnej emisji jest uruchomienie działania. Przykład jawnej emisji, gdy aplikacja musi wybrać numer telefonu; wyśle intencję docelową aplikacji Telefon w systemie Android i przekaże numer telefonu, który ma zostać wybrany. Następnie system Android będzie kierować intencję do aplikacji Telefon.
  • Niejawna emisja — te emisje są wysyłane do wszystkich aplikacji na urządzeniu. Przykładem niejawnej emisji jest intencja ACTION_POWER_CONNECTED . Ta intencja jest publikowana za każdym razem, gdy system Android wykryje, że bateria na urządzeniu jest ładowana. System Android będzie kierować tę intencję do wszystkich aplikacji zarejestrowanych na potrzeby tego zdarzenia.

Odbiornik emisji jest podklasą BroadcastReceiver typu i musi zastąpić metodę OnReceive . System Android zostanie wykonany OnReceive w głównym wątku, więc ta metoda powinna zostać zaprojektowana do szybkiego wykonania. Należy zachować ostrożność podczas tworzenia wątków OnReceive , ponieważ system Android może zakończyć proces po zakończeniu działania metody. Jeśli odbiornik emisji musi wykonywać długotrwałą pracę, zaleca się zaplanowanie zadania przy użyciu JobScheduler dyspozytora zadań programu Firebase. Planowanie pracy z zadaniem zostanie omówione w osobnym przewodniku.

Filtr intencji służy do rejestrowania odbiornika emisji, aby system Android mógł prawidłowo kierować komunikaty. Filtr intencji można określić w czasie wykonywania (jest to czasami określane jako odbiornik zarejestrowany kontekstowo lub jako rejestracja dynamiczna) lub może być statycznie zdefiniowane w manifeście systemu Android ( odbiornik zarejestrowany w manifeście). Platforma Xamarin.Android udostępnia atrybut języka C#, IntentFilterAttributektóry statycznie zarejestruje filtr intencji (zostanie on omówiony bardziej szczegółowo w dalszej części tego przewodnika). Począwszy od systemu Android 8.0, nie można statycznie zarejestrować aplikacji na potrzeby niejawnej emisji.

Podstawową różnicą między odbiornikiem zarejestrowanym w manifeście a odbiornikiem zarejestrowanym kontekstowo jest to, że odbiornik zarejestrowany w kontekście będzie reagować tylko na emisje, gdy aplikacja jest uruchomiona, podczas gdy odbiornik zarejestrowany w manifeście może reagować na emisje, mimo że aplikacja może nie działać.

Istnieją dwa zestawy interfejsów API do zarządzania odbiornikiem emisji i wysyłania emisji:

  1. Context — Klasa Android.Content.Context może służyć do rejestrowania odbiornika emisji, który będzie reagować na zdarzenia całego systemu. Służy Context również do publikowania emisji w całym systemie.
  2. LocalBroadcastManager — Jest to interfejs API dostępny za pośrednictwem pakietu NuGet biblioteki pomocy technicznej platformy Xamarin w wersji 4. Ta klasa służy do przechowywania emisji i odbiorników emisji izolowanych w kontekście aplikacji, która ich używa. Ta klasa może być przydatna w celu uniemożliwienia innym aplikacjom odpowiadania na emisje tylko przez aplikację lub wysyłanie komunikatów do prywatnych odbiorników.

Odbiornik emisji może nie wyświetlać okien dialogowych i zdecydowanie odradza się uruchamianie działania z poziomu odbiornika emisji. Jeśli odbiornik emisji musi powiadomić użytkownika, powinien opublikować powiadomienie.

Nie można powiązać ani uruchomić usługi z poziomu odbiornika emisji.

W tym przewodniku opisano sposób tworzenia odbiornika emisji i rejestrowania go w taki sposób, aby mógł odbierać emisje.

Tworzenie odbiornika emisji

Aby utworzyć odbiornik emisji na platformie Xamarin.Android, aplikacja powinna podklasować BroadcastReceiver klasę , a BroadcastReceiverAttributenastępnie zastąpić metodę OnReceive :

[BroadcastReceiver(Enabled = true, Exported = false)]
public class SampleReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        // Do stuff here.

        String value = intent.GetStringExtra("key");
    }
}

Po skompilowaniu klasy Xamarin.Android zaktualizuje również narzędzie AndroidManifest przy użyciu niezbędnych metadanych w celu zarejestrowania odbiornika. W przypadku statycznie zarejestrowanego odbiornika Enabled emisji należy odpowiednio ustawić wartość true, w przeciwnym razie system Android nie będzie mógł utworzyć wystąpienia odbiornika.

Właściwość Exported określa, czy odbiornik emisji może odbierać komunikaty spoza aplikacji. Jeśli właściwość nie jest jawnie ustawiona, wartość domyślna właściwości jest określana przez system Android na podstawie tego, czy istnieją jakiekolwiek filtry intencji skojarzone z odbiornikiem emisji. Jeśli dla odbiornika emisji istnieje co najmniej jeden filtr intencji, system Android przyjmie, że Exported właściwość to true. Jeśli nie ma żadnych filtrów intencji skojarzonych z odbiornikiem emisji, system Android przyjmie, że wartość to false.

Metoda OnReceive odbiera odwołanie do Intent wysłanego do odbiornika emisji. Dzięki temu nadawca intencji może przekazać wartości do odbiornika emisji.

Statyczne rejestrowanie odbiornika emisji za pomocą filtru intencji

Gdy element BroadcastReceiver zostanie ozdobiony elementem , platforma Xamarin.Android doda element niezbędny <intent-filter> do manifestu IntentFilterAttributesystemu Android w czasie kompilacji. Poniższy fragment kodu jest przykładem odbiornika emisji, który będzie uruchamiany po zakończeniu rozruchu urządzenia (jeśli odpowiednie uprawnienia systemu Android zostały przyznane przez użytkownika):

[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { Android.Content.Intent.ActionBootCompleted })]
public class MyBootReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        // Work that should be done when the device boots.     
    }
}

Uwaga

W systemie Android 8.0 (interfejs API 26 i nowszych) firma Google wprowadziła ograniczenia dotyczące tego, co aplikacje mogą robić, gdy użytkownicy nie wchodzą z nimi bezpośrednio w interakcje. Te ograniczenia dotyczą usług w tle i niejawnych odbiorników emisji, takich jak Android.Content.Intent.ActionBootCompleted. Ze względu na te ograniczenia mogą wystąpić problemy z rejestrowaniem odbiornika Boot Completed emisji w nowszych wersjach systemu Android. W takim przypadku należy pamiętać, że te ograniczenia nie mają zastosowania do usług pierwszego planu, które mogą być wywoływane z odbiornika emisji.

Istnieje również możliwość utworzenia filtru intencji, który będzie reagować na intencje niestandardowe. Rozważmy następujący przykład:

[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { "com.xamarin.example.TEST" })]
public class MySampleBroadcastReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        // Do stuff here
    }
}

Aplikacje przeznaczone dla systemu Android 8.0 (poziom 26 interfejsu API) lub nowsze mogą nie być statycznie rejestrowane na potrzeby niejawnej emisji. Aplikacje mogą nadal statycznie rejestrować się w celu jawnego rozgłaszania. Istnieje niewielka lista niejawnych emisji, które są zwolnione z tego ograniczenia. Te wyjątki opisano w przewodniku Niejawne wyjątki emisji w dokumentacji systemu Android. Aplikacje, które są zainteresowane niejawnymi emisjami, muszą to zrobić dynamicznie przy użyciu RegisterReceiver metody . Jest to opisane w dalszej części.

Rejestrowanie kontekstu odbiornika emisji

Rejestracja kontekstowa (nazywana również rejestracją dynamiczną) odbiornika jest wykonywana przez wywołanie RegisterReceiver metody, a odbiornik emisji musi być wyrejestrowany za pomocą wywołania UnregisterReceiver metody . Aby zapobiec wyciekowi zasobów, ważne jest wyrejestrowanie odbiornika, gdy nie jest już istotne dla kontekstu (działanie lub usługa). Na przykład usługa może rozgłaszać intencję informowania działania, że aktualizacje są dostępne do wyświetlenia użytkownikowi. Po uruchomieniu działania zostanie on zarejestrowany dla tych intencji. Gdy działanie zostanie przeniesione do tła i nie będzie już widoczne dla użytkownika, powinno wyrejestrować odbiornik, ponieważ interfejs użytkownika do wyświetlania aktualizacji nie jest już widoczny. Poniższy fragment kodu to przykład rejestrowania i wyrejestrowania odbiornika emisji w kontekście działania:

[Activity(Label = "MainActivity", MainLauncher = true, Icon = "@mipmap/icon")]
public class MainActivity: Activity
{
    MySampleBroadcastReceiver receiver;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        receiver = new MySampleBroadcastReceiver();

        // Code omitted for clarity
    }

    protected override void OnResume()
    {
        base.OnResume();
        RegisterReceiver(receiver, new IntentFilter("com.xamarin.example.TEST"));
        // Code omitted for clarity
    }

    protected override void OnPause()
    {
        UnregisterReceiver(receiver);
        // Code omitted for clarity
        base.OnPause();
    }
}

W poprzednim przykładzie, gdy działanie zostanie wprowadzone na pierwszym planie, zarejestruje odbiornik emisji, który będzie nasłuchiwać intencji niestandardowej OnResume przy użyciu metody cyklu życia. Gdy działanie przechodzi do tła, OnPause() metoda wyrejestruje odbiornik.

Publikowanie emisji

Emisja może zostać opublikowana dla wszystkich aplikacji zainstalowanych na urządzeniu, tworząc obiekt Intent i wysyłając ją za pomocą SendBroadcast metody lub SendOrderedBroadcast .

  1. Context.SendBroadcast methods — istnieje kilka implementacji tej metody. Te metody będą emitować intencję do całego systemu. Odbiorniki emisji, które otrzymają intencję w nieokreślonej kolejności. Zapewnia to dużą elastyczność, ale oznacza, że istnieje możliwość zarejestrowania i odebrania intencji przez inne aplikacje. Może to stanowić potencjalne zagrożenie bezpieczeństwa. Aplikacje mogą wymagać zaimplementowania dodatkowych zabezpieczeń, aby zapobiec nieautoryzowanemu dostępowi. Jednym z możliwych rozwiązań jest użycie funkcji LocalBroadcastManager , która będzie wysyłać komunikaty tylko w prywatnej przestrzeni aplikacji. Ten fragment kodu jest jednym z przykładów sposobu wysyłania intencji przy użyciu jednej z SendBroadcast metod:

    Intent message = new Intent("com.xamarin.example.TEST");
    // If desired, pass some values to the broadcast receiver.
    message.PutExtra("key", "value");
    SendBroadcast(message);
    

    Ten fragment kodu to kolejny przykład wysyłania emisji przy użyciu Intent.SetAction metody w celu zidentyfikowania akcji:

    Intent intent = new Intent();
    intent.SetAction("com.xamarin.example.TEST");
    intent.PutExtra("key", "value");
    SendBroadcast(intent);
    
  2. Context.SendOrderedBroadcast — jest to metoda bardzo podobna do Context.SendBroadcastmetody , a różnica polega na tym, że intencja zostanie opublikowana pojedynczo dla odbiorników w kolejności zarejestrowania odbiorników.

LocalBroadcastManager

Biblioteka pomocy technicznej platformy Xamarin w wersji 4 udostępnia klasę pomocnika o nazwie LocalBroadcastManager. Jest LocalBroadcastManager przeznaczony dla aplikacji, które nie chcą wysyłać ani odbierać emisji z innych aplikacji na urządzeniu. Funkcja LocalBroadcastManager będzie publikować komunikaty tylko w kontekście aplikacji i tylko do tych odbiorników emisji zarejestrowanych w programie LocalBroadcastManager. Ten fragment kodu jest przykładem rejestrowania odbiornika emisji za pomocą polecenia LocalBroadcastManager:

Android.Support.V4.Content.LocalBroadcastManager.GetInstance(this). RegisterReceiver(receiver, new IntentFilter("com.xamarin.example.TEST"));

Inne aplikacje na urządzeniu nie mogą odbierać komunikatów publikowanych za pomocą polecenia LocalBroadcastManager. Ten fragment kodu pokazuje, jak wysłać intencję przy użyciu elementu LocalBroadcastManager:

Intent message = new Intent("com.xamarin.example.TEST");
// If desired, pass some values to the broadcast receiver.
message.PutExtra("key", "value");
Android.Support.V4.Content.LocalBroadcastManager.GetInstance(this).SendBroadcast(message);