Intent
to obiekt wiadomości, którego możesz użyć do żądania wykonania działania przez inny komponent aplikacji.
Chociaż intencje ułatwiają komunikację między komponentami na kilka sposobów, istnieją 3 podstawowe przypadki użycia:
- Rozpoczynanie aktywności
Obiekt
Activity
reprezentuje pojedynczy ekran w aplikacji. Możesz uruchomić nową instancjęActivity
, przekazując obiektIntent
dostartActivity()
. ElementIntent
opisuje aktywność do uruchomienia i zawiera wszystkie niezbędne dane.Jeśli chcesz otrzymać wynik po zakończeniu aktywności, zadzwoń pod numer
startActivityForResult()
. Twoja aktywność otrzyma wynik jako osobny obiektIntent
w wywołaniu zwrotnymonActivityResult()
. Więcej informacji znajdziesz w przewodniku Aktywności. - Uruchamianie usługi
Service
to komponent, który wykonuje operacje w tle bez interfejsu użytkownika. W Androidzie 5.0 (poziom interfejsu API 21) i nowszych możesz uruchomić usługę za pomocąJobScheduler
. Więcej informacji na ten temat (JobScheduler
) znajdziesz tutaj:API-reference documentation
.W wersjach starszych niż Android 5.0 (poziom interfejsu API 21) możesz uruchomić usługę, używając metod klasy
Service
. Możesz uruchomić usługę, aby wykonać jednorazową operację (np. pobrać plik), przekazującIntent
dostartService()
.Intent
opisuje usługę, która ma zostać uruchomiona, i zawiera wszystkie 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 funkcjibindService()
. Więcej informacji znajdziesz w przewodniku Usługi. - Wysyłanie transmisji
Wiadomość rozgłaszana to wiadomość, którą może otrzymać dowolna aplikacja. System wysyła różne transmisje dotyczące zdarzeń systemowych, np. uruchamiania systemu lub ładowania urządzenia. Możesz przesyłać transmisję do innych aplikacji, przekazując wartość
Intent
dosendBroadcast()
lubsendOrderedBroadcast()
.
W dalszej części tej strony wyjaśniamy, jak działają intencje i jak z nich korzystać. Informacje pokrewne znajdziesz w sekcjach Korzystanie z innych aplikacji i Udostępnianie treści.
Typy intencji
Istnieją 2 rodzaje intencji:
- Jasne intencje określają, który komponent której aplikacji ma spełnić intencję, przez podanie pełnego
ComponentName
. Zwykle do uruchomienia komponentu we własnej aplikacji zwykle używasz wyraźnej intencji, ponieważ znasz nazwę klasy działania lub usługi, którą chcesz uruchomić. Możesz na przykład uruchomić nową aktywność w aplikacji w odpowiedzi na działanie użytkownika lub uruchomić usługę, aby pobrać plik w tle. - Intencje ogólne nie określają nazwy konkretnego komponentu, tylko deklarują ogólne działanie do wykonania, które umożliwia komponentowi z innej aplikacji jego obsługę. Jeśli na przykład chcesz wyświetlić użytkownikowi lokalizację na mapie, możesz użyć domyślnego zamiaru, aby poprosić inną aplikację o wyświetlenie określonej lokalizacji na mapie.
Rysunek 1 pokazuje, w jaki sposób intencja jest wykorzystywana podczas rozpoczynania działania. Jeśli obiekt Intent
wyraźnie podaje nazwę konkretnego komponentu aktywności, system natychmiast uruchamia ten komponent.
Gdy używasz intencji domyślnej, system Android znajduje odpowiedni komponent do uruchomienia, porównując zawartość intencji z filtrami intencji zadeklarowanymi w pliku manifestu innych aplikacji na urządzeniu. Jeśli intencja pasuje do filtra intencji, system uruchamia komponent i przekazuje mu obiekt Intent
. Jeśli kilka filtrów intencji jest zgodnych, system wyświetli okno dialogowe, aby użytkownik mógł wybrać aplikację, której ma użyć.
Filtr intencji to wyrażenie w pliku manifestu aplikacji, które określa typy intencji, które komponent chce otrzymywać. Na przykład zadeklarowanie filtra intencji dla danej aktywności umożliwia innym aplikacjom bezpośrednie rozpoczęcie aktywności z określonym zamiarem. Podobnie, jeśli nie zadeklarujesz żadnych filtrów intencji dla aktywności, może ona zostać uruchomiona tylko z wyraźną intencją.
Uwaga: aby mieć pewność, że aplikacja jest bezpieczna, uruchamiając Service
, zawsze używaj jednoznacznej intencji. Nie deklaruj filtrów intencji dla swoich 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ć).
Główne informacje zawarte w pliku Intent
:
- Nazwa komponentu
- Nazwa komponentu do uruchomienia.
Jest to element opcjonalny, ale kluczowa informacja, która sprawia, że chęć jest wyraźna, co oznacza, że chęć powinna być dostarczana tylko do komponentu aplikacji zdefiniowanego przez nazwę komponentu. Bez nazwy komponentu intencja jest domyślna, a system decyduje, który komponent powinien ją otrzymać na podstawie innych informacji o intencji (takich jak działanie, dane i kategoria, opisane poniżej). Jeśli chcesz uruchomić w aplikacji określony komponent, podaj jego nazwę.
Uwaga: podczas uruchamiania
Service
zawsze podawaj 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 obiektemComponentName
, który możesz określić, używając pełnej i jednoznacznej nazwy klasy komponentu docelowego z nazwą pakietu aplikacji, np.com.example.ExampleActivity
. Nazwa komponentu może być ustawiana za pomocą funkcjisetComponent()
,setClass()
,setClassName()
lub konstruktoraIntent
. - Działanie
- Ciąg znaków określający ogólne działanie do wykonania (np. wyświetl lub wybierz).
W przypadku intencji transmisji jest to działanie, które miało miejsce i jest raportowane. Działanie to w dużej mierze określa strukturę reszty intencji, a zwłaszcza informacji zawartych w danych i materiałach dodatkowych.
Możesz określić własne działania na potrzeby intencji w aplikacji (lub do wykorzystania przez inne aplikacje 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 typowych czynności, które można wykonać, rozpoczynając aktywność:ACTION_VIEW
- Używaj tego działania w intencji z
startActivity()
, gdy masz informacje, które aktywność może wyświetlić użytkownikowi, np. zdjęcie do wyświetlenia w aplikacji galerii lub adres do wyświetlenia w aplikacji map. ACTION_SEND
- Zwany też zamierzaniem udostępniania. Należy go używać w zamierzaniu
startActivity()
, gdy masz dane, które użytkownik może udostępnić za pomocą innej aplikacji, np. aplikacji pocztowej 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. wSettings
w przypadku działań, które otwierają określone ekrany w aplikacji Ustawienia systemu.Działanie związane z intencją możesz określić za pomocą funkcji
setAction()
lub konstruktoraIntent
.Jeśli definiujesz własne działania, pamiętaj, aby w prefiksie umieścić nazwę 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
) odwołujący się do danych, na których ma zostać wykonana operacja, lub typ MIME tych danych. Typ danych jest zwykle określany przez działanie związane z zamiarem. Jeśli na przykład działaniem jestACTION_EDIT
, dane powinny zawierać identyfikator URI dokumentu do edycji.Podczas tworzenia zamiaru często trzeba 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 mogła odtwarzać pliku audio, mimo że formaty URI mogą być podobne. Określenie typu MIME danych pomaga systemowi Android znajdować najlepszy komponent do odbioru intencji. Czasami typ MIME można jednak określić na podstawie identyfikatora URI, zwłaszcza gdy dane są identyfikatorem URI
content:
. Identyfikator URIcontent:
wskazuje, że dane znajdują się na urządzeniu i są kontrolowane przez interfejsContentProvider
, dzięki czemu typ MIME danych jest widoczny dla systemu.Aby ustawić tylko identyfikator URI danych, wywołaj funkcję
setData()
. Aby ustawić tylko typ MIME, wywołaj funkcjęsetType()
. W razie potrzeby możesz ustawić obie te wartości bezpośrednio za pomocą funkcjisetDataAndType()
.Uwaga: jeśli chcesz ustawić zarówno URI, jak i typ MIME, nie wywołuj funkcji
setData()
anisetType()
, ponieważ każda z nich anuluje wartość drugiej. Do ustawiania typu URI i MIME zawsze używaj właściwościsetDataAndType()
. - 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 typowych kategorii:
CATEGORY_BROWSABLE
- Aktywność docelowa może być uruchamiana przez przeglądarkę internetową w celu wyświetlenia danych, do których odwołuje się link, np. obraz lub wiadomość e-mail.
CATEGORY_LAUNCHER
- Aktywność jest początkową aktywnością zadania i jest wymieniona w Menu z aplikacjami systemu.
Pełną listę kategorii znajdziesz w opisie zajęć
Intent
.Kategorię możesz określić za pomocą tagu
addCategory()
.
Wymienione powyżej właściwości (nazwa komponentu, działanie, dane i kategoria) stanowią cechy definiujące intencję. Dzięki odczytaniu tych właściwości system Android może określić, który komponent aplikacji ma uruchomić. Może ona jednak zawierać dodatkowe informacje, które nie wpływają na sposób jej przekształcania w element aplikacji. Intencja może też zawierać te informacje:
- Dodatki
- Pary klucz-wartość zawierające dodatkowe informacje wymagane do wykonania żą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ć obiektBundle
ze wszystkimi dodatkowymi danymi, a następnie wstawićBundle
wIntent
za pomocąputExtras()
.Jeśli na przykład tworzysz intencję wysłania e-maila za pomocą
ACTION_SEND
, możesz określić adresata to za pomocą kluczaEXTRA_EMAIL
, a temat – za pomocą kluczaEXTRA_SUBJECT
.Klasa
Intent
definiuje wiele stałychEXTRA_*
dla ujednoliconych typów danych. Jeśli musisz zadeklarować dodatkowe klucze (dla intencji, które otrzymuje Twoja aplikacja), pamiętaj, aby dołączyć nazwę pakietu aplikacji jako prefiks, 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 danych
Parcelable
aniSerializable
podczas wysyłania intencji, która według Ciebie powinna otrzymać inna aplikacja. Jeśli aplikacja próbuje uzyskać dostęp do danych w obiekcieBundle
, ale nie ma dostępu do pakietowanej lub serializowanej klasy, system zgłasza błądRuntimeException
. - Flagi
- Flagi są zdefiniowane w klasie
Intent
, które działają jako metadane intencji. Flagi mogą przekazywać systemowi Android instrukcje dotyczące uruchamiania aktywności (np. do którego zadania powinna należeć dana aktywność) oraz sposobu postępowania z aktywność po jej uruchomieniu (np. czy powinna być umieszczona na liście ostatnich aktywności).Więcej informacji znajdziesz w metodzie
setFlags()
.
Przykładowa intencja bezpośrednia
Wyraźna intencja to intencja, której używasz do uruchamiania określonego komponentu aplikacji, np. określonej aktywności lub usługi w aplikacji. Aby utworzyć wyraźną intencję, zdefiniuj nazwę komponentu dla obiektu Intent
. Pozostałe właściwości intencji są opcjonalne.
Jeśli np. w aplikacji utworzysz usługę o nazwie DownloadService
, która ma pobierać pliki z internetu, możesz ją uruchomić za pomocą tego kodu:
Kotlin
// Executed in an Activity, so 'this' is theContext
// 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 theContext
// 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);
Konstruktor Intent(Context, Class)
dostarcza aplikacji Context
, a komponentowi obiekt Class
. W związku z tym ten zamiar wyraźnie uruchamia klasę DownloadService
w aplikacji.
Więcej informacji o tworzeniu i uruchamianiu usługi znajdziesz w przewodniku Usługi.
Przykład intencji ogólnej
Intencja ogólna określa działanie, które może wywołać dowolną aplikację na urządzeniu, która może wykonać to działanie. Użycie niejawnej intencji jest przydatne, gdy Twoja aplikacja nie może wykonać danej czynności, ale inne aplikacje prawdopodobnie mogą, a Ty chcesz, aby użytkownik wybrał, której aplikacji użyć.
Jeśli na przykład masz treści, które użytkownik ma udostępnić innym osobom, utwórz intencję z działaniem ACTION_SEND
i dodaj dodatkowe informacje 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. }
Gdy wywołana zostanie metoda startActivity()
, system sprawdza wszystkie zainstalowane aplikacje, aby określić, które z nich mogą obsłużyć ten rodzaj zamiaru (zamiar z działaniem ACTION_SEND
i danymi w formacie „text/plain”). Jeśli jest tylko jedna aplikacja, która może obsłużyć tę czynność, otwiera się ona natychmiast i otrzymuje intencję. Jeśli inne aplikacje nie są w stanie go obsłużyć, może wychwytywać błąd ActivityNotFoundException
. Jeśli wiele działań akceptuje ten zamiar, system wyświetla okno podobne do tego na rysunku 2, aby użytkownik mógł wybrać aplikację.
Więcej informacji o uruchamianiu innych aplikacji znajdziesz w przewodniku przesyłania użytkownika do innej aplikacji.
Wymuszenie wyboru aplikacji
Jeśli istnieje więcej niż 1 aplikacja, która reaguje na Twoją domyślną intencję, użytkownik może wybrać aplikację, której ma używać domyślnie. Możliwość wyboru wartości domyślnych jest przydatna przy wykonywaniu działania, którego użytkownik prawdopodobnie chce używać za każdym razem, np. przy otwieraniu strony internetowej (użytkownicy często preferują tylko jedną przeglądarkę).
Jeśli jednak na daną intencję może odpowiadać kilka aplikacji i użytkownik może chcieć za każdym razem korzystać z innej, wyświetl 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). Jeśli na przykład Twoja aplikacja wykonuje działanie „udostępnianie” za pomocą działania ACTION_SEND
, użytkownicy mogą chcieć udostępnić plik za pomocą innej aplikacji w zależności od bieżącej sytuacji. Z tego powodu zawsze używaj okna wyboru, jak pokazano na rysunku 2.
Aby wyświetlić selektor, utwórz obiekt Intent
za pomocą funkcji createChooser()
i przenieś go do funkcji startActivity()
, jak pokazano w tym przykładzie.
Ten przykład wyświetla okno z listą aplikacji, które odpowiadają intencji przekazanej metodzie createChooser()
, i używa dostarczonego tekstu jako tytułu okna.
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 uruchamiać intencje nawigacji między komponentami wewnątrz aplikacji lub wykonywania działania w imieniu innej aplikacji. Aby poprawić bezpieczeństwo platformy, Android 12 (poziom interfejsu API 31) i nowsze wersje udostępniają funkcję debugowania, która ostrzega o przypadku niebezpiecznych uruchomień intencji. Aplikacja może na przykład wykonać niebezpieczne uruchomienie zagnieżdżonego zamiaru, czyli zamiaru przekazanego jako dodatkowy w ramach innego zamiaru.
Jeśli aplikacja wykonuje oba te działania, system wykryje niebezpieczne uruchomienie intencjonalnego wywołania i wystąpi naruszenie Trybu rygorystycznego:
- Aplikacja rozpakowuje zagnieżdżoną intencję z elementów dodatkowych dostarczonej intencji.
- Aplikacja natychmiast uruchamia komponent aplikacji, używając tej zagnieżdżonej intencji, na przykład przekazując ją do
startActivity()
,startService()
lubbindService()
.
Więcej informacji o tym, jak zidentyfikować tę sytuację i wprowadzić zmiany w aplikacji, znajdziesz w poście na blogu na temat intencji związanych z Androidem Nesting w Medium.
Sprawdzanie uruchamiania niebezpiecznych intencji
Aby sprawdzić, czy w aplikacji nie są uruchamiane niebezpieczne intencje, podczas konfigurowania VmPolicy
wywołaj funkcję detectUnsafeIntentLaunch()
, jak pokazano w tym fragmencie kodu. Jeśli aplikacja wykryje naruszenie zasad StrictMode, możesz zatrzymać wykonywanie aplikacji, aby chronić informacje potencjalnie poufne.
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 uruchomienia niebezpiecznej intencji i naruszenia zasad trybu ścisłego, stosuj te sprawdzone metody.
Skopiuj tylko najważniejsze dodatki w intencjach i wykonaj niezbędne czyszczenie i weryfikację. Aplikacja może skopiować dodatki z jednej intencji do innej intencji, która służy do uruchamiania nowego komponentu. Dzieje się tak, gdy Twoja aplikacja wywołuje putExtras(Intent)
lub putExtras(Bundle)
.
Jeśli Twoja aplikacja wykonuje jedną z tych operacji, skopiuj tylko dodatkowe elementy, których 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 komponentów aplikacji bez potrzeby. Jeśli na przykład chcesz uruchomić komponent aplikacji za pomocą wewnętrznej intencji zagnieżdżonej, ustaw atrybut android:exported
tego komponentu na false
.
Zamiast zagnieżdżonego zamiaru używaj PendingIntent
. Dzięki temu, gdy inna aplikacja odbierze pakiet PendingIntent
, który zawiera Intent
, druga aplikacja może uruchomić PendingIntent
, korzystając z tożsamości Twojej aplikacji. Dzięki tej konfiguracji druga aplikacja może bezpiecznie uruchomić w Twojej aplikacji dowolny komponent, w tym komponent niewyeksportowany.
Schemat na rysunku 2 pokazuje, jak system przekazuje kontrolę z Twojej aplikacji (klienta) do innej aplikacji (usługi) i z powrotem do Twojej aplikacji:
- 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 on eksportowany. - Po otrzymaniu intencji Twojej aplikacji inna aplikacja wyodrębnia zagnieżdżony obiekt
PendingIntent
. - Inna aplikacja wywołuje metodę
send()
w obiekciePendingIntent
. - Po przekazaniu sterowania aplikacji system wywołuje oczekującą intencję przy użyciu kontekstu aplikacji.
Rysunek 2. Schemat komunikacji między aplikacjami podczas korzystania z zagnieżdżonego oczekującego inten.
Odbieranie intencji ogólnej
Aby określić, które ukryte intencje może otrzymywać Twoja aplikacja, zadeklaruj co najmniej 1 filtr intencji dla każdego z jej komponentów za pomocą elementu <intent-filter>
w pliku manifestu.
Każdy filtr intencji określa typy intencji, które akceptuje, na podstawie działania, danych i kategorii intencji. System dostarcza domyślną intencję do komponentu aplikacji tylko wtedy, gdy intencja może przejść przez jeden z filtrów intencji.
Uwaga: intencja jawna jest zawsze dostarczana do miejsca docelowego, niezależnie od filtrów intencji zadeklarowanych przez komponent.
Składnik aplikacji powinien deklarować osobne filtry dla każdego niepowtarzalnego zadania, które może wykonać.
Na przykład jedna aktywność w aplikacji z galeria zdjęć może mieć 2 filtry: jeden do wyświetlania obrazu i drugi do jego edytowania. Po rozpoczęciu działania sprawdza Intent
i na podstawie informacji w Intent
określa, jak ma się zachować (np. wyświetlić elementy sterujące edytora).
Każdy filtr intencji jest definiowany przez element <intent-filter>
w pliku manifestu aplikacji umieszczony w odpowiednim komponencie aplikacji (takim jak element <activity>
).
W każdym komponencie aplikacji, który zawiera element <intent-filter>
, wyraźnie określ wartość atrybutu android:exported
.
Ten atrybut wskazuje, czy komponent aplikacji jest dostępny dla innych aplikacji. W niektórych sytuacjach, takich jak działania, których filtry intencji zawierają kategorię LAUNCHER
, warto ustawić w tym atrybucie wartość true
. W przeciwnym razie bezpieczniej jest ustawić ten atrybut na false
.
Ostrzeżenie: jeśli aktywność, usługa lub odbiornik w aplikacji używa filtrów intencji i nie ma jawnie ustawionej wartości dla android:exported
, aplikacja nie może zostać zainstalowana na urządzeniu z Androidem 12 lub nowszym.
W elementach <intent-filter>
możesz określić typy intencji do zaakceptowania, używając co najmniej jednego z tych trzech elementów:
<action>
- Określa w atrybutach
name
zaakceptowane działanie intencyjne. Wartość musi być dosłowną wartością ciągu znaków działania, a nie stałą klasy. <data>
- Określa typ akceptowanych danych za pomocą co najmniej jednego atrybutu, który określa różne aspekty identyfikatora URI danych (
scheme
,host
,port
,path
) i typ MIME. <category>
- Określa kategorię intencji zaakceptowaną w atrybucie
name
. Wartość musi być literacką wartością ciągu znaków działania, a nie stałą klasy.Uwaga: aby otrzymywać niejawne intencje, musisz uwzględnić kategorię
CATEGORY_DEFAULT
w filtrze intencji. MetodystartActivity()
istartActivityForResult()
traktują wszystkie intencje tak, jakby były zadeklarowane w kategoriiCATEGORY_DEFAULT
. Jeśli nie zadeklarujesz tej kategorii w filtrze intencji, żadne niejawne intencje nie będą się wiązać z Twoją aktywnością.
Na przykład oto deklaracja aktywności z filtrem intencji odbierającym intencję ACTION_SEND
, gdy typ danych to 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ż 1 wystąpienie <action>
, <data>
lub <category>
.
Jeśli tak, musisz mieć pewność, że komponent może obsłużyć wszystkie kombinacje tych elementów filtra.
Jeśli chcesz obsługiwać wiele rodzajów intencji, ale tylko w określonych kombinacjach działań, danych i typów kategorii, musisz utworzyć kilka filtrów intencji.
Ukryta intencja jest testowana za pomocą filtra przez porównanie intencji z każdym z tych 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 przekaże intencji do danego komponentu. Komponent może jednak mieć wiele filtrów intencji, więc intencja, która nie przejdzie przez żaden z filtrów komponentu, może przedostać się przez inny filtr. Więcej informacji o tym, jak system rozpoznaje intencje, znajdziesz w sekcji dotyczącej rozwiązywania intencji poniżej.
Uwaga: użycie filtra intencji nie jest bezpiecznym sposobem na uniemożliwienie uruchamiania Twoich komponentów przez inne aplikacje. Chociaż filtry intencji ograniczają działanie komponentu tylko do określonych rodzajów domniemanych intencji, inna aplikacja może uruchomić komponent Twojej aplikacji, używając do tego wyraźnej intencji, jeśli deweloper określił nazwy komponentów.
Jeśli zależy Ci na tym, aby tylko Twoja aplikacja mogła uruchamiać jeden ze swoich komponentów, nie deklaruj w manifeście żadnych filtrów intencji. Zamiast tego ustaw atrybut exported
na "false"
dla tego komponentu.
Aby uniknąć przypadkowego uruchomienia Service
innej aplikacji, zawsze używaj wyraźnego zamiaru do uruchamiania własnej usługi.
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()
. Następnie możesz wyrejestrować odbiornik w usłudze unregisterReceiver()
. Dzięki temu aplikacja może nasłuchiwać określonych transmisji tylko przez określony czas, gdy aplikacja jest uruchomiona.
Przykładowe filtry
Aby zademonstrować niektóre zachowania filtra intencji, podajemy przykład pliku manifestu aplikacji do udostępniania treści w mediach 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, czyli działanie, które rozpoczyna 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 że nie są wymagane żadne dane o intencji. - Kategoria
CATEGORY_LAUNCHER
wskazuje, że ikona aktywności powinna być umieszczona w programie uruchamiającym aplikacje systemu. Jeśli element<activity>
nie określa ikony za pomocą atrybutuicon
, system używa ikony z elementu<application>
.
Aby aktywność była widoczna w Menu z aplikacjami, te 2 elementy muszą być sparowane.
Druga aktywność, ShareActivity
, ma ułatwiać udostępnianie tekstu i multimediów. Użytkownicy mogą rozpoczynać to działanie, przechodząc do niego z poziomu MainActivity
, ale mogą też wpisać ShareActivity
bezpośrednio z innej aplikacji, która wywołuje intencję ogólną 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ęcia panoramiczne. Możesz je obsługiwać za pomocą interfejsów API Google Panorama.
dopasowywać intencje do filtrów intencji innych aplikacji;
Jeśli inna aplikacja jest kierowana na Androida 13 (poziom interfejsu API 33) lub nowszego, może obsłużyć intencję Twojej aplikacji tylko wtedy, gdy Twoja intencja pasuje do działań i kategorii elementu <intent-filter>
w tej innej aplikacji. Jeśli system nie znajdzie dopasowania, rzuci błąd ActivityNotFoundException
.
Aplikacja wysyłająca musi obsłużyć tę sytuację.
Jeśli zaktualizujesz aplikację, aby była kierowana na Androida 13 lub nowszego, wszystkie intencje pochodzące z aplikacji zewnętrznych są dostarczane do wyeksportowanego komponentu aplikacji tylko wtedy, gdy intencje te pasują do działań i kategorii elementu <intent-filter>
zadeklarowanego przez aplikację. Takie zachowanie występuje niezależnie od docelowej wersji pakietu SDK aplikacji wysyłającej.
W tych sytuacjach dopasowywanie intencji nie jest wymuszane:
- 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 intencje wysyłane z identyfikatora „system UID” (uid=1000). Aplikacje systemowe to
system_server
oraz aplikacje, które ustawiają wartośćandroid:sharedUserId
naandroid.uid.system
. - Intencje pochodzące z roota.
Dowiedz się więcej o dopasowywaniu intencji.
Używasz intencji oczekującej
Obiekt PendingIntent
jest opakowaniem obiektu Intent
. Głównym celem PendingIntent
jest udzielenie aplikacji zewnętrznej uprawnień do używania zawartego w niej Intent
tak, jakby była ona wykonywana w ramach procesu aplikacji.
Główne przypadki użycia oczekującego zamiaru to:
- Deklaracja intencji, która ma zostać wykonana, gdy użytkownik wykona działanie związane z Twoim powiadomieniem (
NotificationManager
w systemie Android wykonujeIntent
). - Deklarowanie intencji do wykonania, gdy użytkownik wykona działanie za pomocą widżetu aplikacji (aplikacja na ekranie głównym wykonuje działanie
Intent
). - Oświadczenie o intencji do wykonania w określonym czasie w przyszłości (
AlarmManager
systemu Androida wykonujeIntent
).
Podobnie jak każdy obiekt Intent
jest przeznaczony do obsługi przez określony typ komponentu aplikacji (Activity
, Service
lub BroadcastReceiver
), tak samo obiekt PendingIntent
musi być tworzony z uwzględnieniem tych samych kryteriów. Gdy używasz oczekującego zamiaru, aplikacja nie wykonuje go za pomocą wywołania takiego jak startActivity()
. Zamiast tego musisz zadeklarować odpowiedni typ komponentu podczas tworzenia elementu PendingIntent
, wywołując odpowiednią metodę kreatora:
PendingIntent.getActivity()
dlaIntent
, który uruchamiaActivity
.PendingIntent.getService()
dlaIntent
, który rozpoczynaService
.PendingIntent.getBroadcast()
dlaIntent
, który rozpoczynaBroadcastReceiver
.
Jeśli aplikacja nie otrzymuje oczekujących intencji z innych aplikacji, PendingIntent
metody PendingIntent
są prawdopodobnie jedynymi metodami, których 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ń i widżetów aplikacji.
Określ mutowalność
Jeśli aplikacja jest kierowana na Androida 12 lub nowszego, musisz określić zmienność każdego obiektu PendingIntent
tworzonego przez aplikację. Aby zadeklarować, że dany obiekt PendingIntent
jest zmienny, użyj odpowiednio flagi PendingIntent.FLAG_MUTABLE
lub PendingIntent.FLAG_IMMUTABLE
.
Jeśli aplikacja próbuje utworzyć obiekt PendingIntent
bez ustawienia żadnej flagi zmienności, system zgłasza błąd IllegalArgumentException
, a w Logcat pojawia się ten 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 pokazano w tym fragmencie kodu. Jeśli obiekt PendingIntent
jest niezmienny, inne aplikacje nie mogą modyfikować intencji w celu dostosowania wyniku wywołania 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);
W niektórych przypadkach wymagane są jednak obiekty PendingIntent
, które można zmieniać:
- Obsługa działań bezpośrednich w powiadomieniach. Odpowiedź bezpośrednia wymaga zmiany danych klipu w obiekcie PendingIntent powiązanym z odpowiedzią. Zwykle prośba o wprowadzenie tej zmiany jest przekazywana jako parametr
FILL_IN_CLIP_DATA
do metodyfillIn()
. - Powiązanie powiadomień z ramami Androida Auto za pomocą instancji
CarAppExtender
. - umieszczanie rozmów w dymkach za pomocą instancji
PendingIntent
. Zmienny obiektPendingIntent
pozwala systemowi stosować odpowiednie flagi, takie jakFLAG_ACTIVITY_MULTIPLE_TASK
iFLAG_ACTIVITY_NEW_DOCUMENT
. - Żądanie informacji o lokalizacji urządzenia przez wywołanie
requestLocationUpdates()
lub podobne interfejsy API. Zmienny obiektPendingIntent
umożliwia systemowi dodawanie dodatkowych informacji o intencji, które reprezentują zdarzenia cyklu życia lokalizacji. Te zdarzenia obejmują zmianę lokalizacji i usługodawcy. - ustawianie alarmów za pomocą
AlarmManager
. Zmienny obiektPendingIntent
pozwala systemowi dodać dodatkowy elementEXTRA_ALARM_COUNT
intencji. Ten element reprezentuje liczbę powtórzeń alarmu. Dzięki temu intencja może dokładnie poinformować aplikację, czy powtarzający się alarm był włączany wielokrotnie, na przykład wtedy, gdy urządzenie było w stanie uśpienia.
Jeśli Twoja aplikacja tworzy zmienny obiekt PendingIntent
, zdecydowanie zalecamy użycie wyraźnego zamiaru i wypełnienie pola ComponentName
. Dzięki temu za każdym razem, gdy inna aplikacja wywoła PendingIntent
i przekaże kontrolę Twojej aplikacji, zawsze uruchamia się ten sam komponent w Twojej aplikacji.
Używanie intencji bezpośrednich w intencjach oczekujących
Aby lepiej określić, jak inne aplikacje mogą korzystać z oczekujących intencji Twojej aplikacji, zawsze otaczaj oczekującą intencję dokładną intencją. Aby zastosować tę sprawdzoną metodę, wykonaj te czynności:
- Sprawdź, czy działanie, pakiet i pola komponentu podstawowej intencji są ustawione.
-
Aby utworzyć oczekujące intencje, użyj
FLAG_IMMUTABLE
, dodanego w Androidzie 6.0 (poziom interfejsu API 23). Ten parametr uniemożliwia aplikacjom, które otrzymują intencjęPendingIntent
, wypełnianie brakujących właściwości. JeśliminSdkVersion
Twojej aplikacji jest22
lub mniejszy, możesz zapewnić bezpieczeństwo i zgodność, używając tego kodu:if (Build.VERSION.SDK_INT >= 23) { // Create a PendingIntent using FLAG_IMMUTABLE. } else { // Existing code that creates a PendingIntent. }
Rozwiązywanie intencji
Gdy system otrzyma domyślną intencję rozpoczęcia aktywności, wyszuka najlepszą aktywność dla tej intencji, porównując ją z filtrami intencji pod 3 względami:
- Działanie.
- Dane (zarówno identyfikator URI, jak 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 elementów <action>
, jak w tym przykładzie:
<intent-filter> <action android:name="android.intent.action.EDIT" /> <action android:name="android.intent.action.VIEW" /> ... </intent-filter>
Aby ten filtr zadziałał, działanie określone w parametrze Intent
musi być zgodne z jednym z działań wymienionych w filtrze.
Jeśli filtr nie zawiera żadnych działań, nie ma żadnej intencji, która mogłaby zostać dopasowana, więc wszystkie intencje kończą się niepowodzeniem. Jeśli jednak Intent
nie określa działania, test się powiedzie, o ile filtr zawiera co najmniej 1 działanie.
Testowanie kategorii
Aby określić akceptowane kategorie intencji, filtr intencji może zawierać 0 lub więcej elementów <category>
, jak w tym przykładzie:
<intent-filter> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> ... </intent-filter>
Aby intencja przeszła test kategorii, każda kategoria w Intent
musi być zgodna z kategorią w filtrze. Odwrotność nie jest konieczna – filtr intencji może zadeklarować więcej kategorii niż określono w zasadzie Intent
, a Intent
i tak spełnia warunki. Dlatego intencja bez kategorii zawsze kończy ten test niezależnie od tego, jakie kategorie są zadeklarowane w filtrze.
Uwaga: Android automatycznie stosuje kategorię CATEGORY_DEFAULT
do wszystkich domyślnych intencji przekazywanych do startActivity()
i startActivityForResult()
.
Jeśli chcesz, aby aktywność otrzymywała intencje niejawne, musi ona zawierać kategorię obiektu "android.intent.category.DEFAULT"
w filtrach intencji, jak pokazano w poprzednim przykładzie (<intent-filter>
).
Test danych
Aby określić dane zaakceptowanych intencji, filtr intencji może zadeklarować zero lub więcej elementów <data>
, jak w tym przykładzie:
<intent-filter> <data android:mimeType="video/mpeg" android:scheme="http" ... /> <data android:mimeType="audio/mpeg" android:scheme="http" ... /> ... </intent-filter>
Każdy element <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 nie określisz schematu, host zostanie zignorowany.
- Jeśli nie podasz hosta, port będzie ignorowany.
- Jeśli nie określisz ani schematu, ani hosta, ścieżka zostanie zignorowana.
Podczas porównywania identyfikatora URI w intencji ze specyfikacją identyfikatora URI w filtrze porównywane są tylko te części identyfikatora URI, które są uwzględnione w filtrze. Na przykład:
- Jeśli filtr określa tylko schemat, wszystkie adresy URI z tym schematem pasują do filtra.
- Jeśli filtr określa schemat i urzędnik, ale nie ścieżkę, pomijają go wszystkie identyfikatory URI o tym samym schemacie i uprawnieniu, niezależnie od ścieżki.
- Jeśli filtr określa schemat, autorytet i ścieżkę, tylko URI z tymi samymi wartościami przechodzą przez filtr.
Uwaga: specyfikacja ścieżki może zawierać symbol wieloznaczny (*). Pozwala to wymagać tylko częściowego dopasowania nazwy ścieżki.
Test danych porównuje identyfikator URI i typ MIME w intencji z identyfikatorem URI i typem MIME określonym w filtrze. Oto zasady:
- 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.
- 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.
- Intencja, która zawiera typ MIME, ale nie identyfikator URI, zalicza test tylko wtedy, gdy filtr zawiera ten sam typ MIME i nie określa formatu identyfikatora URI.
- 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. Przechodzi część testu dotyczącą identyfikatora URI, jeśli jego identyfikator URI pasuje do identyfikatora URI w filtrze lub jeśli ma identyfikator URI
content:
lubfile:
, a filtr nie określa identyfikatora URI. Inaczej mówiąc, zakłada się, że komponent obsługuje danecontent:
ifile:
, jeśli jego filtr wyświetla tylko typ MIME.
Uwaga: jeśli intencja określa typ URI lub MIME, test danych zakończy się niepowodzeniem, jeśli w elementach <intent-filter>
nie ma elementów <data>
.
Ostatnia reguła (d) odzwierciedla oczekiwanie, że komponenty mogą pobierać dane lokalne z pliku lub dostawcy treści.
Dlatego ich filtry mogą zawierać tylko typ danych i nie muszą wyraźnie wymieniać schematów content:
ani file:
.
Ten przykład pokazuje typowy przypadek, w którym element <data>
informuje Androida, że komponent może pobierać dane obrazu od dostawcy treści i je wyświetlać:
<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. Na przykład element <data>
, taki jak ten, informuje Androida, że komponent może pobierać dane wideo z sieci, aby wykonać działanie:
<intent-filter> <data android:scheme="http" android:mimeType="video/*" /> ... </intent-filter>
Dopasowywanie intencji
Intencje są dopasowywane do filtrów intencji nie tylko po to, aby wykryć docelowy komponent do aktywacji, ale też po to, aby dowiedzieć się czegoś o zbiorze komponentów na urządzeniu. Na przykład aplikacja Home wypełnia Menu z aplikacjami, znajdując wszystkie działania z filtrami intencji, które określają działanie ACTION_MAIN
i kategorię CATEGORY_LAUNCHER
.
Dopasowanie następuje tylko wtedy, gdy działania i kategorie w intencji pasują do filtra, zgodnie z opisem w dokumentacji klasy IntentFilter
.
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. Na przykład funkcja queryIntentActivities()
zwraca listę wszystkich działań, które mogą wykonać intencję przekazaną jako argument, a queryIntentServices()
zwraca podobną listę usług.
Żadna z tych metod nie aktywuje komponentów, tylko wyświetla te, które mogą odpowiadać. W przypadku odbiorników jest podobna metoda,queryBroadcastReceivers()
.