Intencje i filtry intencji

Intent to obiekt komunikacji, którego możesz użyć, aby poprosić o działanie z innego komponentu aplikacji. Choć intencje ułatwiają komunikację między komponentami na kilka sposobów, wyróżniamy trzy podstawowe przypadki użycia:

  • Rozpoczynanie aktywności

    Activity oznacza jeden ekran w aplikacji. Możesz rozpocząć nowe wystąpienie Activity, przekazując Intent do startActivity(). Intent opisuje aktywność, która ma zostać rozpoczęta i zawiera wszelkie niezbędne dane.

    Jeśli chcesz otrzymać wynik ćwiczenia po jego zakończeniu, Zadzwoń pod numer startActivityForResult(). Wynik Twojej aktywności jako osobny obiekt Intent w wywołaniu zwrotnym onActivityResult() Twojej aktywności. Więcej informacji znajdziesz w przewodniku po ćwiczeniach.

  • Uruchamianie usługi

    Service to komponent, który wykonuje działania w tle bez użycia interfejsu użytkownika. W Androidzie 5.0 (poziom interfejsu API 21) i nowszych możesz uruchomić usługę dzięki JobScheduler. Więcej informacji o JobScheduler znajdziesz na stronie API-reference documentation.

    W przypadku wersji Androida starszych niż 5.0 (poziom interfejsu API 21) możesz uruchomić usługę za pomocą polecenia metod klasy Service. Możesz uruchomić usługę aby wykonać jednorazową operację (np. pobranie pliku), przekazując Intent do: startService(). Intent opisuje usługę, która ma ją uruchomić i przekazuje wszelkie niezbędne dane.

    Jeśli usługa jest zaprojektowana z interfejsem klient-serwer, możesz ją powiązać z innym komponentem, przekazując obiekt Intent do obiektu bindService(). Więcej informacji znajdziesz w przewodniku po usługach.

  • Przesyłanie transmisji

    Komunikat to wiadomość, którą może odebrać każda aplikacja. System udostępnia różne komunikatów dotyczących zdarzeń systemowych, takich jak uruchomienie systemu lub rozpoczęcie ładowania urządzenia. Możesz przesłać komunikat do innych aplikacji, przekazując Intent do sendBroadcast() lub sendOrderedBroadcast()

W dalszej części tej strony wyjaśniamy, jak działają intencje i jak z nich korzystać. Powiązane informacje: Interakcje z innymi aplikacjami oraz Udostępnianie treści.

Typy intencji

Istnieją 2 typy intencji:

  • Jasne intencje określają, który komponent której aplikacji ma spełnić intencję, przez podanie pełnego ComponentName. Zazwyczaj do uruchamiania komponentu w własnej aplikacji używasz wyraźnego zamiaru, ponieważ znasz nazwę klasy aktywności lub usługi, którą chcesz uruchomić. Dla: możesz na przykład rozpocząć w aplikacji nową aktywność w odpowiedzi na działanie użytkownika usługa pobierania pliku w tle.
  • Intencje ogólne nie wskazują konkretnego komponentu, ale deklarują ogólne działanie, co pozwala komponentowi z innej aplikacji na obsłużenie tej intencji. Jeśli chcesz na przykład pokazać użytkownikowi lokalizację na mapie, możesz użyć niejawnej intencji, by poprosić inną pokazują określoną lokalizację na mapie.

Rysunek 1 pokazuje, w jaki sposób intencja jest wykorzystywana podczas rozpoczynania działania. Gdy obiekt Intent wprost określa nazwę konkretnego komponentu aktywności, od razu uruchamia dany komponent.

Rysunek 1. Sposób, w jaki system przekazuje domyślny zamiar, aby rozpocząć inną aktywność: [1] Aktywność A tworzy Intent z opisem działania i przekazuje go do startActivity(). [2] System Android przeszukuje wszystkie aby utworzyć filtr intencji, który pasuje do intencji. Po znalezieniu dopasowania [3] system rozpoczyna pasującą aktywność (działanie B) przez wywołanie metody onCreate() i przekazywanie jej Intent.

Gdy używasz intencji niejawnej, system Android znajduje odpowiedni komponent, by uruchomić porównując zawartość intencji z filtrami intencji zadeklarowanych w pliku manifestu innych aplikacji na stronie urządzenia. Jeśli intencja pasuje do filtra intencji, system uruchamia ten komponent i go dostarcza. obiekt Intent. Jeśli pasuje kilka filtrów intencji, wyświetla okno, w którym użytkownik może wybrać aplikację, której chce użyć.

Filtr intencji to wyrażenie w pliku manifestu aplikacji, które określa typ intencji, które komponent który chce otrzymywać. Na przykład zadeklarowanie filtra intencji dla działania umożliwiasz innym aplikacjom bezpośrednie rozpoczęcie Twojej aktywności z określonym zamiarem. Podobnie, jeśli nie zadeklarujesz żadnych filtrów intencji dla danej aktywności, możesz ją uruchomić. tylko z wyraźnym zamiarem.

Uwaga: aby mieć pewność, że aplikacja jest bezpieczna, zawsze użyj jednoznacznego przy uruchamianiu funkcji Service i nie zadeklarować filtry intencji dla usług. Używanie do uruchomienia usługi domyślnego zamiaru jest zagrożeniem dla bezpieczeństwa, ponieważ nie można mieć pewności, która usługa odpowie na zamiar, a użytkownik nie widzi, która usługa się uruchamia. Począwszy od Androida 5.0 (poziom interfejsu API 21) system zgłasza wyjątek, jeśli wywołasz bindService()z użyciem niejawnej intencji.

Budowanie zamiaru

Obiekt Intent zawiera informacje, których system Android używa do określenia, który komponent uruchomić (np. dokładną nazwę komponentu lub kategorię komponentu, który powinien otrzymać intencję), a także informacje, których komponent odbiorczy używa do prawidłowego wykonania działania (np. działanie do wykonania i dane, na których ma ono polegać).

Intent zawiera następujące informacje:

Nazwa komponentu
Nazwa komponentu, który ma zostać uruchomiony.

Nie jest to jednak wymagane, ale jest to kluczowa informacja, dzięki której explicit, co oznacza, że intencja powinna być dostarczana tylko do komponentu aplikacji. zdefiniowane przez nazwę komponentu. Bez nazwy komponentu intencja jest implicit, a system decyduje, który komponent powinien otrzymać intencję na podstawie innych informacji o intencji (takich jak działanie, dane i kategoria opisane poniżej). Jeśli chcesz utworzyć określony URL w swojej aplikacji, podaj nazwę komponentu.

Uwaga: gdy uruchamiasz Service, zawsze określaj nazwę komponentu. W przeciwnym razie nie będziesz mieć pewności, która usługa odpowie na intencję, a użytkownik nie będzie widzieć, która usługa się uruchamia.

To pole Intent jest ComponentName, który możesz określić za pomocą kwalifikowana nazwa klasy komponentu docelowego, w tym nazwa pakietu aplikacji, np. com.example.ExampleActivity Nazwę komponentu możesz ustawić za pomocą tych właściwości: setComponent(), setClass(), setClassName(), lub za pomocą Intent.

Działanie
Ciąg tekstowy określający ogólne działanie do wykonania (np. view lub pick).

W przypadku intencji transmisji jest to działanie, które miało miejsce i jest raportowane. Działanie to w dużym stopniu określa strukturę reszty intencji, a w szczególności zawarte w danych i dodatki.

Możesz określić własne działania do wykorzystania przez intencje w aplikacji (lub do wykorzystania przez inne aplikacji do wywoływania komponentów w aplikacji), ale zwykle określasz stałe działania. zdefiniowane przez klasę Intent lub inne klasy platformy. Oto kilka typowe czynności związane z rozpoczynaniem aktywności:

ACTION_VIEW
Wykonaj to działanie w zamiarze użycia: startActivity(), gdy masz informacje, które aktywność może być widoczna dla użytkownika, na przykład zdjęcie do wyświetlenia w aplikacji Galeria lub adres wyświetlić w aplikacji z mapami.
ACTION_SEND
Nazywa się to też intencją udostępniania. Należy jej używać w intencji startActivity(), gdy masz dane, które użytkownik może udostępniać za pomocą innej aplikacji, np. do poczty e-mail lub aplikacji do udostępniania w mediach społecznościowych.

Więcej stałych definiujących ogólne działania znajdziesz w dokumentacji klasy Intent. Inne działania są definiowane w innych miejscach w ramach Androida, np. w Settings w przypadku działań, które otwierają określone ekrany w aplikacji Ustawienia systemu.

Działanie możesz określić w przypadku intencji za pomocą setAction() lub konstruktora Intent.

Jeśli określisz własne działania, pamiętaj o podaniu nazwy pakietu aplikacji jak w tym przykładzie:

Kotlin

const val ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL"

Java

static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
Dane
Identyfikator URI (obiekt Uri), który odwołuje się do danych do podejmowanych w związku z typu MIME. Typ dostarczanych danych jest zwykle określany przez działanie intencji. Dla: na przykład jeśli działaniem jest ACTION_EDIT, dane powinny zawierać parametr Identyfikator URI dokumentu do edycji.

Podczas tworzenia intencji często warto określić typ danych (typ MIME) oprócz jego identyfikatora URI. Na przykład aktywność, która może wyświetlać obrazy, prawdopodobnie nie będzie w stanie odtworzyć plik audio, chociaż formaty URI mogą być podobne. Określenie typu MIME danych ułatwia system znajduje najlepszy komponent, który dostanie intencję. Jednak typ MIME można czasem wywnioskować na podstawie identyfikatora URI, zwłaszcza jeśli dane są Identyfikator URI content:. Identyfikator URI content: wskazuje, że dane znajdują się na urządzeniu i kontrolowane przez ContentProvider, dzięki czemu typ MIME danych jest widoczny dla systemu.

Aby ustawić tylko identyfikator URI danych, wywołaj setData(). Aby ustawić tylko typ MIME, wywołaj setType(). W razie potrzeby obie te wartości można ustawić bezpośrednio za pomocą funkcji setDataAndType().

Uwaga: jeśli chcesz ustawić zarówno URI, jak i typ MIME, nie wywołuj funkcji setData() ani setType(), ponieważ każda z nich anuluje wartość drugiej. Zawsze używaj setDataAndType(), aby ustawić typ URI i MIME.

Kategoria
Ciąg tekstowy zawierający dodatkowe informacje o rodzaju komponentu który powinien obsługiwać intencję. W intencji można umieścić dowolną liczbę opisów kategorii, ale większość intencji nie wymaga kategorii. Oto kilka popularnych kategorii:
CATEGORY_BROWSABLE
Docelowa aktywność może zostać uruchomiona przez przeglądarkę w celu wyświetlenia danych do którego odwołuje się link, np. zdjęcie lub wiadomość e-mail.
CATEGORY_LAUNCHER
Aktywność to początkowa aktywność w ramach zadania i jest widoczna w program uruchamiający aplikacje.

Pełną listę znajdziesz w opisie zajęć Intent kategorii zainteresowań.

Możesz określić kategorię za pomocą atrybutu addCategory().

Te wymienione powyżej właściwości (nazwa komponentu, działanie, dane i kategoria) reprezentują określając cechy intencji. Odczytując te właściwości, system Android jest w stanie określić komponent aplikacji, który ma zostać uruchomiony. Intencja może jednak przenosić zawiera dodatkowe informacje, które nie mają wpływu jak jest on przekształcany w komponent aplikacji. Intencja może też dostarczać te informacje:

Dodatki
Pary klucz-wartość zawierające dodatkowe informacje wymagane do osiągnięcia żądanego działania. Niektóre działania używają określonych rodzajów identyfikatorów URI danych, tak samo niektóre działania wykorzystują też określone dodatki.

Dodatkowe dane możesz dodawać za pomocą różnych metod putExtra(), z których każda przyjmuje 2 parametry: nazwę klucza i wartość. Możesz też utworzyć obiekt Bundle ze wszystkimi dodatkowymi danymi, a następnie wstawić Bundle w Intent z putExtras().

Na przykład podczas tworzenia zamiaru wysłania e-maila z ACTION_SEND, możesz określić adresata to za pomocą atrybutu EXTRA_EMAIL i określ subject za pomocą atrybutu EXTRA_SUBJECT klawisz.

Klasa Intent definiuje wiele stałych EXTRA_* dla ujednoliconych typów danych. Jeśli musisz zadeklarować własne dodatkowe klucze (na potrzeby intencji, aplikacji), pamiętaj o umieszczeniu nazwy pakietu aplikacji jak w tym przykładzie:

Kotlin

const val EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS"

Java

static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";

Uwaga: nie używaj właściwości Parcelable ani dane Serializable podczas wysyłania oczekiwanej intencji kolejną aplikację do odbioru. Jeśli aplikacja próbuje uzyskać dostęp do danych w obiekcie Bundle, ale nie próbuje dostępu do klasy spakowanej lub serializowanej, system podnosi RuntimeException

Flagi
Flagi są zdefiniowane w klasie Intent, które działają jako metadane intencji. Flagi mogą instruować system Android, jak uruchomić działanie (na przykład które zadanie aktywność powinna należeć ) oraz jak postępować z nimi po uruchomieniu (np. czy znajduje się na liście ostatnich aktywności).

Więcej informacji znajdziesz w metodzie setFlags().

Przykładowa jawna intencja

Intencja jawna to taka, której używasz do uruchamiania konkretnego komponentu aplikacji, np. do określonej aktywności lub usługi w aplikacji. Aby utworzyć intencję, zdefiniuj nazwę komponentu Intent. inne właściwości intencji są opcjonalne.

Jeśli na przykład w aplikacji masz utworzoną usługę o nazwie DownloadService, przeznaczony do pobierania pliku z internetu, możesz rozpocząć go za pomocą tego kodu:

Kotlin

// Executed in an Activity, so 'this' is the Context
// 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 the Context
// 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) Konstruktor dostarcza aplikację Context oraz do obiektu Class. W związku z tym: ta intencja wyraźnie rozpoczyna w aplikacji klasę DownloadService.

Więcej informacji o tworzeniu i uruchamianiu usługi znajdziesz w przewodniku Usługi.

Przykładowa intencja ogólna

Intencja niejawna określa działanie, które może wywołać dowolną aplikację na urządzeniu, która może wykonanie działania. Użycie intencji niejawnej jest przydatne, gdy aplikacja nie może wykonać ale inne aplikacje prawdopodobnie już tak i chcesz, aby to użytkownik sam wybierał, której chce użyć.

Jeśli na przykład masz treści, które użytkownicy mają udostępniać innym osobom, utwórz intencję z działaniem ACTION_SEND i dodać dodatki określające treści do udostępnienia. Gdy wywołasz intent startActivity(), użytkownik może wybrać aplikację, za pomocą której udostępni treści.

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.
}

Po wywołaniu funkcji startActivity() system sprawdza wszystkie zainstalowane aplikacje, aby określić, które z nich poradzą sobie z tego rodzaju intencjami ( intencja z działaniem ACTION_SEND i zawierająca hasło „text/plain” ). Jeśli jest tylko jedna aplikacja, która może obsłużyć tę czynność, otwiera się ona natychmiast i otrzymuje odpowiednią intencję. Jeśli inne aplikacje nie są w stanie go obsłużyć, wychwytuje ActivityNotFoundException które występują. Jeśli kilka aktywności akceptuje intencję, wyświetla okno podobne do pokazanego na Rysunku 2, dzięki czemu użytkownik może wybrać aplikację.

Więcej informacji o uruchamianiu innych aplikacji znajdziesz w przewodniku przesyłanianie użytkownika do innej aplikacji.

Rysunek 2. Okno wyboru

Wymuszenie wyboru aplikacji

Gdy więcej niż 1 aplikacja reaguje na intencje pośrednie, użytkownik może wybrać aplikację, której chce używać, i ustawić ją jako domyślną dla użytkownika, działania. Możliwość wyboru wartości domyślnej jest przydatna przy wykonywaniu działania, Pewnie chce używać tej samej aplikacji za każdym razem, na przykład podczas otwierania strony internetowej (użytkownicy często preferuje tylko jedną przeglądarkę).

Jeśli jednak wiele aplikacji może odpowiedzieć na intencję, a użytkownik może chcieć użyć innej za każdym razem musisz wyświetlić okno wyboru. W oknie wyboru użytkownik musi wybrać aplikację, której ma użyć do wykonania danej czynności (nie może wybrać aplikacji domyślnej). Na przykład gdy aplikacja wykonuje polecenie „udostępnij” używając działania ACTION_SEND, użytkownicy mogą chcieć udostępnić treści za pomocą innej aplikacji w zależności od tego: zgodnie z obecną sytuacją, należy więc zawsze korzystać z okna wyboru, tak jak na rys. 2.

Aby wyświetlić selektor, utwórz pole Intent przy użyciu createChooser() i przekaż go do startActivity(), jak pokazano w przykładzie poniżej. W tym przykładzie wyświetla się okno z listą aplikacji, które odpowiadają na intencję przekazaną do metody createChooser() i wykorzystują podany tekst jako tytuł okna dialogowego.

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);
}

Wykrywanie niebezpiecznych uruchomień intencji

Aplikacja może uruchomić intencje nawigacji między komponentami w niej, lub wykonać działanie w imieniu innej aplikacji. Aby zwiększyć bezpieczeństwo platformy, Android 12 (poziom interfejsu API 31) i nowsze oferują funkcję debugowania, która ostrzega przed jeśli aplikacja wykonuje niebezpieczne uruchomienie intencji. Aplikacja może na przykład wykonanie niebezpiecznego uruchomienia intencji zagnieżdżonej, która jest przekazywana jako dodatkowy w innej intencji.

Jeśli aplikacja wykona obie te czynności, system wykryje uruchomienie intencji i naruszenie zasad StrictMode następuje:

  1. Aplikacja oddziela zagnieżdżoną intencję od dodatkowych elementów intencji.
  2. Aplikacja natychmiast uruchamia aplikację komponentza pomocą tej zagnieżdżonej intencji, np. przekazanie intencji startActivity(), startService(), lub bindService()

Aby dowiedzieć się więcej o tym, jak wykryć taką sytuację i wprowadzić zmiany w aplikacji, przeczytaj post na blogu o zagnieżdżaniu na Androidzie Intencje w formacie Medium.

Sprawdzanie uruchamiania niebezpiecznych intencji

Aby sprawdzić, czy w aplikacji nie pojawiły się niebezpieczne intencje, wywołaj detectUnsafeIntentLaunch() podczas konfigurowania VmPolicy, jak pokazano poniżej. Jeśli aplikacja wykryje naruszenie zasad trybu ścisłego, możesz zatrzymać jej działanie, aby chronić potencjalnie poufne informacje.

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());
}

Korzystaj z intencji bardziej odpowiedzialnie

Aby zminimalizować ryzyko niebezpiecznego uruchomienia intencji i naruszenia zasad StrictMode: przestrzegaj tych sprawdzonych metod.

Skopiuj tylko najważniejsze dodatki w intencjach i wykonaj niezbędne czyszczenie i weryfikację. Aplikacja może skopiować dodatkowe informacje z jednej intencji do innej, która służy do uruchamiania nowego komponentu. Dzieje się tak, gdy Twoja aplikacja wywołuje putExtras(Intent) lub putExtras(Bundle). Jeśli aplikacja wykonuje jedną z tych operacji, skopiuj tylko dodatki, które którego oczekuje komponent odbierający. Jeśli inny zamiar (który otrzymuje kopię) uruchamia komponent, który nie został wyeksportowany, przed skopiowaniem dodatkowych informacji do zamiaru, który uruchamia komponent, należy je wyczyścić i sprawdzić.

Nie eksportuj niepotrzebnie komponentów aplikacji. Jeśli na przykład zamierza uruchomić komponent aplikacji przy użyciu wewnętrznej zagnieżdżonej intencji, ustaw ten android:exported komponentu do false.

Użyj PendingIntent zamiast intencja zagnieżdżona. Dzięki temu, gdy inna aplikacja ulepszy PendingIntent swoich danych, zawierający Intent, inna aplikacja może uruchomić PendingIntent za pomocą tożsamości aplikacji. Ta konfiguracja umożliwia bezpieczne uruchomienie drugiej aplikacji z dowolnym komponentem, w tym komponentem niewyeksportowanym.

Diagram na ilustracji 2 pokazuje, w jaki sposób system przekazuje kontrolę z klienta (klienta). do innej aplikacji (usługi) i z powrotem do aplikacji:

  1. Twoja aplikacja tworzy intencję, która wywołuje aktywność w innej aplikacji. W ramach tej intencji dodajesz obiekt PendingIntent jako dodatkowy. Ta intencja oczekująca wywołuje komponent w aplikacji; nie jest eksportowany.
  2. Po otrzymaniu intencji aplikacji druga aplikacja wyodrębnia umieszczony w niej zagnieżdżony PendingIntent obiekt.
  3. Druga aplikacja wywołuje metodę send() w obiekcie PendingIntent.
  4. Po przekazaniu elementu sterującego do aplikacji system wywołuje oczekujące na podstawie kontekstu aplikacji.

Rysunek 2. Schemat komunikacji między aplikacjami podczas korzystania z zagnieżdżonego oczekującego elementu intencji.

Odbieranie intencji ogólnej

Aby reklamować intencje niejawne, które może docierać do aplikacji, zadeklaruj co najmniej 1 filtr intencji każdego komponentu aplikacji za pomocą tagu <intent-filter> w pliku manifestu. Każdy filtr intencji określa typ akceptowanych intencji na podstawie działania intencji danych i kategorii. System dostarcza niejawną intencję do komponentu aplikacji tylko wtedy, gdy intencja może przejść przez jeden z Twoich filtrów intencji.

Uwaga: intencja jawna jest zawsze dostarczana do miejsca docelowego. niezależnie od wszelkich intencji zadeklarowanych przez komponent.

Komponent aplikacji powinien zadeklarować osobne filtry dla każdego unikalnego zadania, które może wykonać. Na przykład jedna aktywność w aplikacji galeria obrazów może mieć dwa filtry: jeden aby wyświetlić obraz, a drugi do jego edycji. Gdy aktywność się rozpocznie, sprawdza Intent i na podstawie tych informacji decyduje, jak ma się zachować w elemencie Intent (np. aby wyświetlić elementy sterujące edytora).

Każdy filtr intencji jest zdefiniowany przez element <intent-filter> w pliku manifestu aplikacji, zagnieżdżony w odpowiednim komponencie aplikacji (np. w elemencie <activity>).

W każdym komponencie aplikacji, który zawiera element <intent-filter>, jawnie ustaw wartość dla android:exported Ten atrybut wskazuje, czy element aplikacji jest dostępny dla innych aplikacji. W niektórych takich jak działania, których filtry intencji zawierają LAUNCHER kategorii, warto ustawić ten atrybut na true. W przeciwnym razie bezpieczniej jest ustawić ten atrybut na false.

Ostrzeżenie: jeśli aktywność, usługa lub komunikat Odbiorca w Twojej aplikacji używa filtrów intencji i nie ustawia bezpośrednio wartości w systemie android:exported nie można zainstalować aplikacji na urządzeniu, które ma system Android 12 lub nowszy,

W narzędziu <intent-filter> możesz określić typ akceptowanych intencji tych 3 elementów:

<action>
W atrybucie name deklaruje przyjęte działanie intencji. Wartość musi być literałem wartości ciągu działania, a nie stałą klasy.
<data>
Deklaruje typ akceptowanych danych za pomocą co najmniej jednego atrybutu określającego różne aspekty identyfikatora URI danych (scheme, host, port, path) i typ MIME.
<category>
W atrybucie name deklaruje zaakceptowaną kategorię intencji. Wartość musi być literałem wartości ciągu działania, a nie stałą klasy.

Uwaga: aby otrzymywać intencje pośrednie, musi zawierać CATEGORY_DEFAULT kategoria w filtrze intencji. Metody startActivity() i startActivityForResult() traktuje wszystkie intencje tak, jakby zadeklarowali kategorię CATEGORY_DEFAULT. Jeśli nie zadeklarujesz tej kategorii w filtrze intencji, żadne intencje niejawne nie będą kierować Twojej aktywności.

Oto deklaracja dotycząca aktywności z filtrem intencji, który otrzyma intencja ACTION_SEND, gdy typem danych jest tekst:

<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>

Możesz utworzyć filtr, który zawiera więcej niż 1 występ <action>, <data> lub <category>. Jeśli to zrobisz, musisz mieć pewność, że komponent obsługuje wszystkie kombinacji tych elementów filtra.

Gdy chcesz obsługiwać różne rodzaje intencji, ale tylko w konkretnych kombinacjach działania, danych i typu kategorii, musisz utworzyć kilka filtrów intencji.

Intencję niejawną testuje się za pomocą filtra, porównując intencję z każdym trzech elementów. Aby intencja mogła zostać dostarczona do komponentu, musi przejść wszystkie 3 testy. Jeśli nie uda się dopasować nawet jednego z nich, system Android nie udostępni intencji . Składnik może jednak mieć wiele filtrów intencji, więc intencja, która nie przejdzie przez jeden z nich, może zostać przepuszczona przez inny. Więcej informacji o tym, jak system rozpoznaje intencje, znajdziesz w sekcji poniżej. o rozwiązaniach intencji.

Uwaga: użycie filtra intencji nie jest bezpiecznym sposobem zapobiegania uruchamianiu innych aplikacji swoje komponenty. Filtry intencji ograniczają komponentowi, aby mógł reagować tylko określonych rodzajów niejawnych intencji, inna aplikacja może potencjalnie uruchomić komponent aplikacji. za pomocą intencji, jeśli to deweloper określa nazwy komponentów. Jeśli ważne jest, aby tylko Twoja aplikacja mogła uruchamiać jeden z komponentów, nie deklaruj filtrów intencji w pliku manifestu. Zamiast tego skonfiguruj parametr Atrybut exported do "false" dla tego komponentu.

Aby uniknąć przypadkowego uruchomienia innej aplikacji, Service, zawsze używaj jednoznacznej intencji, aby uruchomić własną usługę.

Uwaga: W przypadku wszystkich działań musisz zadeklarować filtry intencji w pliku manifestu. Filtry dla odbiorników transmisji mogą być jednak rejestrowane dynamicznie przez wywołanie funkcji registerReceiver(). Potem możesz wyrejestrować odbiorcę w unregisterReceiver(). Dzięki temu aplikacja może odbierać określone transmisje tylko przez określony czas, gdy jest uruchomiona.

Przykładowe filtry

Oto przykład, który pokazuje niektóre zachowania filtra intencji z pliku manifestu aplikacji do udostępniania treści społecznościowych:

<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>

Pierwsza aktywność (MainActivity) to główny punkt wejścia aplikacji, otwiera się, gdy użytkownik po raz pierwszy uruchomi aplikację z ikoną programu uruchamiającego:

  • Działanie ACTION_MAIN wskazuje, że jest to główny punkt wejścia i nie oczekuje żadnych danych intencji.
  • Kategoria CATEGORY_LAUNCHER wskazuje, że ikona tej aktywności powinna znajdować się w Menu z aplikacjami systemu. Jeśli element <activity> nie wskaże ikony z oznaczeniem icon, system użyje ikony z <application> .

Muszą one być ze sobą połączone, by aktywność była widoczna w Menu z aplikacjami.

Druga aktywność (ShareActivity) ma ułatwić udostępnianie tekstu i multimediów treści. Użytkownicy mogą przejść do tej czynności z poziomu MainActivity, ale mogą też otworzyć ShareActivity bezpośrednio z innej aplikacji, która wysyła niejawne działanie pasujące do jednego z 2 filtrów intencji.

Uwaga: typ MIME application/vnd.google.panorama360+jpg to specjalny typ danych, który określa zdjęć panoramicznych, które można przetworzyć na Google API panorama.

Dopasuj intencje do innych aplikacji filtry intencji

Jeśli inna aplikacja jest kierowana na Androida 13 (poziom interfejsu API 33) lub nowszego, może obsłużyć do intencji aplikacji tylko wtedy, gdy intencja pasuje do działań i kategorii <intent-filter> w tej drugiej aplikacji. Jeśli system nie znajdzie odpowiednik, rzuca ActivityNotFoundException Aplikacja wysyłająca musi obsłużyć tę sytuację.

Podobnie, jeśli zaktualizujesz aplikację tak, aby była kierowana na Androida 13. wszystkie intencje pochodzące z aplikacji zewnętrznych są przekazywane eksportowany komponent aplikacji tylko wtedy, gdy intencja pasuje do działań kategorii deklarowanego przez aplikację elementu <intent-filter>. Takie zachowanie występuje niezależnie od docelowej wersji pakietu SDK aplikacji wysyłającej.

W tych przypadkach dopasowywanie intencji nie jest egzekwowane:

  • Intencje dostarczane do komponentów, które nie deklarują żadnych filtrów intencji.
  • Intencje pochodzące z tej samej aplikacji.
  • intencje pochodzące z systemu, czyli intencji wysyłanych z systemu „system UID” (uid=1000). Aplikacje systemowe to system_server oraz aplikacje, które ustawiają wartość android:sharedUserId na android.uid.system.
  • Intencje pochodzące z poziomu roota.

Dowiedz się więcej o dopasowywaniu intencji.

Używasz intencji oczekującej

Obiekt PendingIntent to otoka wokół obiektu Intent. Główny cel obiektu PendingIntent jest zezwolenie na wyświetlanie zagranicznym wniosku aby używać zawartego w nim elementu Intent w taki sposób, jakby został on wykonany z Twojego do własnego procesu aplikacji.

Główne przypadki użycia intencji oczekującej to:

Tak jak każdy obiekt Intent jest przeznaczony do obsługi typ komponentu aplikacji (Activity, Service lub BroadcastReceiver), więc także PendingIntent musi być stworzonych w ten sam sposób. Gdy używasz intencji oczekującej, aplikacja nie wykonaj intencję za pomocą wywołania takiego jak startActivity(). Zamiast tego podczas tworzenia komponentu PendingIntent, wywołując odpowiednią metodę twórcy:

O ile aplikacja nie otrzymuje oczekujących intencji z innych aplikacji, powyższe metody tworzenia PendingIntent są prawdopodobnie jedynymi PendingIntent metod, których kiedykolwiek będziesz potrzebować.

Każda metoda przyjmuje bieżącą aplikację Context, Intent, którą chcesz opakować, oraz co najmniej 1 flagę, która określa sposób użycia intencji (np. czy można jej użyć więcej niż raz).

Więcej informacji o używaniu oczekujących intencji znajdziesz w dokumentacji dotyczącej poszczególnych przypadków użycia, na przykład w przewodnikach po interfejsach API powiadomieńwidżetów aplikacji.

Określ mutowalność

Jeśli Twoja aplikacja jest kierowana na Androida 12 lub nowszego, musisz podać zmienność każdego obiektu PendingIntent tworzonego przez aplikację. Zadeklarowanie, że dany obiekt PendingIntent jest zmienny, użyj funkcji PendingIntent.FLAG_MUTABLE. lub PendingIntent.FLAG_IMMUTABLE flaga.

Jeśli aplikacja próbuje utworzyć obiekt PendingIntent bez ustawienia flagi zmienności system zwraca IllegalArgumentException oraz w Logcat pojawi się następujący komunikat:

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.

Gdy tylko jest to możliwe, twórz stałe intencje oczekujące

W większości przypadków aplikacja powinna tworzyć stałe obiekty PendingIntent, jak w poniższym fragmencie kodu. Jeśli obiekt PendingIntent jest stały, to inne aplikacje nie mogą modyfikować intencji, aby dostosować wynik wywołania funkcji intencji.

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);

Jednak w niektórych przypadkach użycia wymagają zmiennych obiektów PendingIntent:

  • Obsługa odpowiedzi bezpośrednich w powiadomienia. bezpośrednia odpowiedź wymaga zmiany danych klipu w obiekcie PendingIntent powiązanego z odpowiedzią. Zazwyczaj żądanie tej zmiany wymaga FILL_IN_CLIP_DATA jako flagę dla fillIn(). .
  • Powiązanie powiadomień ze platformą Android Auto przy użyciu instancji CarAppExtender
  • Umieszczanie rozmów w dymkach przy użyciu instancji z PendingIntent. Zmienny obiekt PendingIntent umożliwia stosowanie zmian przez system odpowiednie flagi, takie jak FLAG_ACTIVITY_MULTIPLE_TASK. oraz FLAG_ACTIVITY_NEW_DOCUMENT
  • Wysyłanie prośby o informacje o lokalizacji urządzenia przez telefon requestLocationUpdates() lub podobnych interfejsów API. Zmienny obiekt PendingIntent umożliwia systemowi dodawanie dodatkowych intencji, które reprezentują zdarzenia cyklu życia lokalizacji. Do tych zdarzeń należą: zmiana lokalizacji i dostępność usługodawcy.
  • Planuję alarmy za pomocą AlarmManager. Zmienny obiekt PendingIntent umożliwia systemowi dodawanie funkcji EXTRA_ALARM_COUNT. intencja użytkownika. Ten dodatkowy element pokazuje, ile razy powtarzający się alarm zostało wywołane. Dzięki temu intencja może dokładnie powiadomić w aplikacji określa, czy powtarzający się alarm uruchomił się wielokrotnie, np. kiedy urządzenie było uśpione.

Jeśli Twoja aplikacja tworzy zmienny obiekt PendingIntent, zdecydowanie zalecamy to za pomocą intencji jawnej i uzupełnić pole ComponentName Dzięki temu za każdym razem, inna aplikacja wywołuje PendingIntent i przekazuje kontrolę z powrotem do aplikacji, zawsze uruchamia się ten sam komponent aplikacji.

Używaj bezpośrednich intencji w ramach intencji oczekujących

Aby lepiej zdefiniować, jak inne aplikacje mogą korzystać z oczekujących intencji, zawsze otoczenie intencji oczekującej od intencji jawnej. Aby zastosować tę sprawdzoną metodę, wykonaj te czynności:

  1. Sprawdź, czy działanie, pakiet i pola komponentu podstawowej intencji są ustawione.
  2. Użyj domeny FLAG_IMMUTABLE, dodano w Androidzie 6.0 (poziom interfejsu API 23) w celu utworzenia intencji oczekujących. Ta flaga uniemożliwia wypełnianie aplikacji, które otrzymują: PendingIntent nieuzupełnione właściwości. Jeśli minSdkVersion w Twojej aplikacji to 22 lub mniej, możesz zapewnić bezpieczeństwo i zgodność razem przy użyciu tego kodu:

    if (Build.VERSION.SDK_INT >= 23) {
      // Create a PendingIntent using FLAG_IMMUTABLE.
    } else {
      // Existing code that creates a PendingIntent.
    }

Rozwiązanie intencji

Gdy system otrzymuje ukrytą intencję rozpoczęcia działania, wyszukuje najlepsze działanie dla intencji, porównując je z filtrami intencji na podstawie 3 aspektów:

  • Akcja.
  • dane (identyfikator URI i typ danych).
  • Category [Kategoria]:

W sekcjach poniżej opisujemy, jak intencje są dopasowywane do odpowiednich komponentów zgodnie z deklaracją filtra intencji w pliku manifestu aplikacji.

Test działania

Aby określić zaakceptowane działania intencji, filtr intencji może zadeklarować zero lub więcej. <action> zgodnie z tym przykładem:

<intent-filter>
    <action android:name="android.intent.action.EDIT" />
    <action android:name="android.intent.action.VIEW" />
    ...
</intent-filter>

Aby przejść ten filtr, działanie określone w polu Intent musi pasować do jednego z działań wymienionych w filtrze.

Jeśli filtr nie wyświetla żadnych działań, nie będzie żadnych wyników dla więc wszystkie intencje kończą się niepowodzeniem. Jeśli jednak Intentnie określa działania, test się powiedzie, o ile filtr zawiera co najmniej 1 działanie.

Testowanie kategorii

Aby można było określić akceptowane kategorie intencji, filtr intencji może zadeklarować zero lub więcej. <category> zgodnie z tym przykładem:

<intent-filter>
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    ...
</intent-filter>

Aby można było zaliczyć test kategorii, każda kategoria w: Intent musi pasować do kategorii w filtrze. Odwrotność nie jest konieczna – filtr intencji może zadeklarować więcej kategorii niż określono w Intent i Intent nadal ma podania. Dlatego intencja bez kategorii zawsze przechodzi ten test, niezależnie od tego, jakie kategorie są zadeklarowane w filtrze.

Uwaga: Android automatycznie stosuje kategorię CATEGORY_DEFAULT do wszystkich intencji niejawnych przekazywanych do startActivity() i startActivityForResult(). Jeśli chcesz, aby aktywność otrzymywała intencje niejawne, musi ona uwzględnij kategorię dla elementu "android.intent.category.DEFAULT" w filtrach intencji, jak w poprzednim przykładzie z <intent-filter>.

Test danych

Aby określić dane o zaakceptowanych intencjach, filtr intencji może zadeklarować zero lub więcej <data> zgodnie z tym przykładem:

<intent-filter>
    <data android:mimeType="video/mpeg" android:scheme="http" ... />
    <data android:mimeType="audio/mpeg" android:scheme="http" ... />
    ...
</intent-filter>

Co <data> może określać strukturę identyfikatora URI oraz typ danych (typ multimediów MIME). Każda część identyfikatora URI jest osobnym atrybutem: scheme, host, port i path:

<scheme>://<host>:<port>/<path>

Przykład poniżej pokazuje możliwe wartości tych atrybutów:

content://com.example.project:200/folder/subfolder/etc

W tym identyfikatorze URI schemat to content, host to com.example.project, port to 200, a ścieżka to folder/subfolder/etc.

Każdy z tych atrybutów jest opcjonalny w elemencie <data>. ale istnieją zależności liniowe:

  • Jeśli schemat nie jest określony, host jest ignorowany.
  • Jeśli nie podasz hosta, port będzie ignorowany.
  • Jeśli nie określono zarówno schematu, jak i hosta, ścieżka jest ignorowana.

Gdy identyfikator URI w intencji jest porównywany ze specyfikacją identyfikatora URI w filtrze, jest porównywany tylko z częściami identyfikatora URI zawartymi w filtrze. Na przykład:

  • Jeśli filtr określa tylko schemat, pasują do niego wszystkie identyfikatory URI z tym schematem użyj filtra.
  • Jeśli filtr określa schemat i urząd, ale nie ścieżkę, wszystkie identyfikatory URI o tym samym schemacie i właściwości przechodzą filtr niezależnie od ich ścieżek.
  • Jeśli filtr określa schemat, urząd i ścieżkę, tylko identyfikatory URI z tym samym schematem, autorytet i ścieżka przez filtr.

Uwaga: specyfikacja ścieżki może zawierać symbol wieloznaczny gwiazdka (*), aby wymagać tylko częściowego dopasowania nazwy ścieżki.

Test danych porównuje identyfikator URI i typ MIME w intencji z identyfikatorem URI i typ MIME określony w filtrze. Reguły są następujące:

  1. Intencja, która nie zawiera ani identyfikatora URI, ani typu MIME, przechodzi test tylko wtedy, gdy filtr nie określa żadnych identyfikatorów URI ani typów MIME.
  2. Intencje zawierające identyfikator URI, ale nietyp MIME (ani jawny, ani niewynikający z identyfikatora URI) przechodzą test tylko wtedy, gdy identyfikator URI jest zgodny z formatem identyfikatora URI filtra, a filtr nie określa typu MIME.
  3. Intencje zawierające typ MIME, ale nie URI, przechodzą test tylko wtedy, gdy filtr zawiera ten sam typ MIME i nie określa formatu URI.
  4. Intencje zawierające zarówno identyfikator URI, jak i typ MIME (wyrażony w prosty sposób lub możliwy do wywnioskowania z identyfikatora URI) przechodzą test typu MIME tylko wtedy, gdy ten typ jest zgodny z typem wymienionym w filtrze. Przekazuje część URI testu albo jeśli jego identyfikator URI pasuje do identyfikatora URI w filtrze lub ma content: lub identyfikator URI file:, a filtr nie określa identyfikatora URI. Innymi słowy, przyjmuje się, że komponent obsługuje dane content: i file:, jeśli jego filtr pokazuje tylko typ MIME.

Uwaga: jeśli intencja określa identyfikator URI lub typ MIME, test danych kończy się niepowodzeniem, jeśli <intent-filter> nie zawiera żadnych elementów <data>.

Ostatnia reguła, reguła (d), odzwierciedla oczekiwanie. że komponenty mogą pobierać dane lokalne z pliku lub dostawcy treści. Dlatego filtry mogą uwzględniać tylko typ danych i nie muszą nadaj schematom content: i file:. Ten przykład pokazuje typowy przypadek, w którym element <data> informuje Androida, że komponent może pobierać dane obrazu z treści dostawcy i wyświetl go:

<intent-filter>
    <data android:mimeType="image/*" />
    ...
</intent-filter>

Filtry, które określają typ danych, ale nie URI, są prawdopodobnie najczęstsze, ponieważ większość dostępnych danych jest dostarczana przez dostawców treści.

Inną typową konfiguracją jest filtr ze schematem i typem danych. Dla: przykład: <data> taki jak ten informuje Androida, komponent może pobierać dane wideo z sieci w celu wykonania działania:

<intent-filter>
    <data android:scheme="http" android:mimeType="video/*" />
    ...
</intent-filter>

Dopasowywanie intencji

Intencje są dopasowywane do filtrów intencji nie tylko w celu wykrycia celu do aktywacji, ale też aby dowiedzieć się więcej o zestawie komponentów. Na przykład aplikacja Home wypełnia Menu z aplikacjami znajdując wszystkie działania z filtrami intencji, które określają ACTION_MAIN działanie i Kategoria CATEGORY_LAUNCHER. Dopasowanie jest udane tylko wtedy, gdy działania i kategorie w intencji odpowiadają danym intencji. zgodnie z opisem w dokumentacji funkcji IntentFilter zajęcia.

Aplikacja może korzystać z dopasowywania intencji w sposób podobny do działania aplikacji Home. Obiekt PackageManager zawiera zestaw metod query...(), które zwracają wszystkie komponenty, które mogą odpowiadać na dany zamiar, oraz podobną serię metod resolve...(), które określają najlepszy komponent do odpowiedzi na zamiar. Przykład: queryIntentActivities() zwraca listę wszystkich działań, które mogą wykonać intencja przekazana jako argument, a queryIntentServices() zwraca podobną listę usług. Żadna z metod nie aktywuje komponentów. po prostu podają te, mogą zareagować. Istnieje podobna metoda, queryBroadcastReceivers() dla odbiorników.