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 około JobScheduler, zobacz jego 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 została zaprojektowana z wykorzystaniem interfejsu klient-serwer, możesz ją powiązać z innego komponentu, przekazując Intent do 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 ich używać. Powiązane informacje: Interakcje z innymi aplikacjami oraz Udostępnianie treści.

Typy intencji

Istnieją 2 typy intencji:

  • Intencje jawne określają, który komponent danej aplikacji spełni intencję, poprzez określenie pełnego parametru ComponentName. Za zwykle używają jednoznacznej intencji, aby uruchomić komponent masz własną aplikację, 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ą działanie ogólne. umożliwia jego obsługę komponentowi z innej aplikacji. 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. Intencja pośrednia dostarczone przez system, aby rozpocząć inne działanie: [1] Działanie 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życie intencji ogólnej do uruchomienia usługi zagraża bezpieczeństwu, ponieważ nie można mieć pewności, która usługa zareaguje na intencję, a użytkownik nie widzi, która usługa się uruchamia. Począwszy od Androida 5.0 (poziom interfejsu API 21) system zwróci wyjątek, jeśli wywołasz funkcję bindService() z intencją niejawną.

Budowanie zamiaru

Obiekt Intent zawiera informacje używane przez system Android w celu określenia, który komponent należy uruchomić (np. dokładna nazwa komponentu lub komponent). kategoria, która powinna otrzymać intencję), oraz informacje używane przez komponent odbiorcy na potrzeby prawidłowego wykonania czynności (np. działania i danych, na które należy podjąć działanie).

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 masz pewności, która usługa zareaguje na intencję, a użytkownik nie będzie mógł zobaczyć, 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 informacji znajdziesz w dokumentacji zajęć Intent. stałe, które definiują działania ogólne. Zdefiniowano inne działania w innym miejscu platformy Androida, na przykład w Settings w przypadku działań. które otwierają określone ekrany w systemowej aplikacji Ustawienia.

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.

Gdy tworzysz intencję, często ważne jest, aby oprócz identyfikatora URI określić typ danych (jego typ MIME). 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 identyfikator URI, jak i typ MIME, nie dzwoń do: setData() i setType(), bo każdy z nich anuluje wartość drugiego. Zawsze używaj setDataAndType() do ustawienia obydwu źródeł Identyfikator URI i typ MIME.

Kategoria
Ciąg tekstowy zawierający dodatkowe informacje o rodzaju komponentu który powinien obsługiwać intencję. Można użyć dowolnej liczby opisów kategorii, są umieszczane w intencji, 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 reklam.

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.

Możesz dodawać dodatkowe dane za pomocą różnych metod putExtra(), każdy z nich akceptuje 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 określa wiele stałych EXTRA_* dla ustandaryzowanych 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 opisie metody 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 Przewodnik po usługach.

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 z nich 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 dzwonisz startActivity() z tym zamiarem, użytkownik może wybierz aplikację, za pomocą której chcesz 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 istnieje tylko jedna aplikacja, która może ją obsłużyć, otwiera się od razu i otrzymuje intencji. 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 na temat wprowadzania innych aplikacji znajdziesz w przewodniku o wysyłaniu użytkownika do innej aplikacji.

Rysunek 2. Okno wyboru.

Wymuszanie 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 jest wybór aplikacji, która ma zostać wykonana w ramach danego działania (nie może on wybrać aplikacji domyślnej działanie). 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 jeśli aplikacja wykryje naruszenie zasad StrictMode, możesz zatrzymać wykonywanie aplikacji, ochrony potencjalnie poufnych informacji.

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 niezbędne dodatki i wykonuj odpowiednie działania dotyczące higieny i weryfikacji. Aplikacja może skopiować dodatki z jednej intencji do innej intencji, która służy do uruchamiania nowego komponentu. Dzieje się tak, gdy wywołania z aplikacji 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 inna intencja (która otrzymuje kopię) uruchamia komponent, który nie jest wyeksportowane, oczyszczone sprawdzić dodatki przed skopiowaniem ich do intencji, która uruchamia .

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. Aplikacja tworzy intencję, która wywołuje działanie w innej aplikacji. W ciągu dla tej intencji, dodaj obiekt PendingIntent jako dodatek. 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 definiowany przez element <intent-filter> w pliku manifestu aplikacji zagnieżdżonym w odpowiednim komponencie aplikacji (takim jak jako <activity> ).

W każdym komponencie aplikacji, który zawiera element <intent-filter>, jawnie ustaw wartość dla android:exported Ten atrybut wskazuje, czy komponent 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 obejmujący więcej niż jedno wystąpienie <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 . Komponent może jednak mieć wiele filtrów intencji, więc intencja, która takie działanie jeśli jeden z filtrów komponentu może nie przejść przez inny filtr. 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 odbiorników można jednak rejestrować dynamicznie przez wywołanie registerReceiver() Potem możesz wyrejestrować odbiorcę w unregisterReceiver(). Dzięki temu aplikacja będzie mogła aby nasłuchiwać określonych transmisji tylko przez określony czas, gdy aplikacja jest uruchomiony.

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 ta aktywność jest należy umieścić w systemowym Menu z aplikacjami. 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ą dołączyć do tej aktywności po przejściu do niej z MainActivity, mogą też wpisać ShareActivity bezpośrednio z innej aplikacji, która generuje niejawnie intencję pasującą 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ługiwać ten wyjątek.

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>. To zachowanie występuje niezależnie od wersji docelowej pakietu SDK aplikacji wysyłającej.

W tych przypadkach dopasowywanie intencji nie jest egzekwowane:

  • Intencje dostarczone 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). Do aplikacji systemowych należą system_server oraz aplikacje z ustawieniem android:sharedUserId do 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 pobiera bieżącą aplikację Context, Intent, które chcesz zapakować, oraz co najmniej 1 flagę określającą sposób jej użycia (np. czy intencja może być używana więcej niż raz).

Więcej informacji o korzystaniu z intencji oczekujących znajdziesz w dokumentacji poszczególnych odpowiednich przypadków użycia, takich jak Powiadomienia i przewodników po interfejsie API App Widgets.

Określ zmienność

Jeśli Twoja aplikacja jest kierowana na Androida 12 lub nowszego, musisz podać zmienność każdego obiektu PendingIntent tworzonego przez aplikację. Zadeklarowanie, że jeśli 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 skorzystać ze sprawdzonych metod, wykonaj te czynności:

  1. Sprawdź, czy działanie, pakiet i pola komponentu intencji podstawowej ustawienia.
  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 Intent nie określa działania, test przechodzi test, dopóki filtr zawiera co najmniej jedno działanie.

Test 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. Zamiar bez kategorii zawsze zalicza 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 stanowi osobny identyfikator atrybut: 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 zawierają symbol wieloznaczny (*), co 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, przekazuje testu tylko wtedy, gdy filtr nie określa żadnych identyfikatorów URI ani typów MIME.
  2. Intencja zawierająca identyfikator URI, ale bez typu MIME (ani jawna, ani niewywnioskowana na podstawie URI) przechodzi test tylko wtedy, gdy jego identyfikator URI pasuje do formatu URI filtra. a filtr także nie określa typu MIME.
  3. Intencja, która zawiera typ MIME, ale nie identyfikator URI, kończy test. tylko wtedy, gdy filtr zawiera ten sam typ MIME i nie określa formatu identyfikatora URI.
  4. intencja zawierająca zarówno identyfikator URI, jak i typ MIME (jawną lub możliwą do wywnioskowania na podstawie URI) przekazuje część testu dotyczącą typu MIME tylko wtedy, gdy typ pasuje do typu wymienionego 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 typu danych, ale nie identyfikatora URI, są najprawdopodobniej najczęstsze, są dostarczane 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 urządzenia. 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. PackageManager zawiera zbiór query...() Metody, które zwracają wszystkie komponenty, które mogą zaakceptować konkretną intencję podobnej serii resolve...() metod, które określają najlepszą w odpowiedzi na intencję. 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.