意圖和意圖篩選器

Intent 是可用來要求動作的訊息物件 從其他應用程式元件擷取物件 雖然意圖可透過多種方式促進元件之間的通訊,但有三種基本用途:

  • 啟動活動

    Activity 代表應用程式中的單一畫面。您可以將 Intent 傳遞至 startActivity(),藉此啟動 Activity 的新例項。Intent 描述了啟動並攜帶任何必要資料的活動。

    如果您想在活動完成後收到結果, 呼叫 startActivityForResult()。您的活動會在活動的 onActivityResult() 回呼中,以個別的 Intent 物件形式接收結果。詳情請參閱「活動」指南。

  • 啟動服務

    Service 是會在背景執行作業的元件 不必使用使用者介面在 Android 5.0 (API 級別 21) 以上版本中,您可以啟動服務 只在 JobScheduler。如要進一步瞭解 JobScheduler,請參閱其 API-reference documentation

    如果是 Android 5.0 (API 級別 21) 以下版本,您可以使用 Service 類別的方法啟動服務。您可以啟動服務 執行一次性作業 (例如下載檔案) 方法是傳遞 IntentstartService()Intent 描述服務以啟動並傳送任何必要資料。

    如果這項服務是以用戶端伺服器介面設計而成,您即可繫結至該服務 將 Intent 傳遞至 bindService(),藉此從另一個元件中取出。詳情請參閱服務指南。

  • 放送廣播

    廣播是指任何應用程式都能接收的訊息。這套系統提供多項 廣播訊息,例如系統啟動或裝置開始充電時。 您可以將 Intent 傳遞至 sendBroadcast()sendOrderedBroadcast(),藉此向其他應用程式傳送廣播。

本頁面其餘部分將說明意圖的運作方式及使用方法。 如需相關資訊,請參閱「與其他應用程式互動」和「共用內容」。

意圖類型

意圖有兩種類型:

  • 明確意圖:指定完整的 ComponentName,指定應用程式滿足意圖的元件。您通常會使用明確意圖,在自己的應用程式中啟動元件,因為您知道要啟動的活動或服務的類別名稱。適用對象 舉例來說,您可能會為了回應使用者動作,或在應用程式內啟動新活動 可在背景下載檔案的服務。
  • 「隱式意圖」不會指特定元件,而是宣告一般動作 執行,可讓其他應用程式的元件處理舉例來說,如果您想在地圖上向使用者顯示某個位置,可以使用隱含意圖要求其他可用的應用程式在地圖上顯示指定位置。

圖 1 說明啟動活動時如何使用意圖。當 Intent 物件明確命名特定活動元件時,系統會立即啟動該元件。

圖 1. 隱含意圖如何透過系統傳送,以啟動其他活動:[1] 活動 A 會建立含有動作說明的 Intent,並將其傳遞至 startActivity()[2] Android 系統會在所有應用程式中搜尋與意圖相符的意圖篩選器。找到相符項目後,[3]系統會透過呼叫 onCreate() 方法並傳遞 Intent,啟動相符的活動 (活動 B)。

使用隱含意圖時,Android 系統會尋找適當的元件來啟動 ,比較意圖內容與其他應用程式資訊清單檔案中宣告的意圖篩選器 裝置。如果意圖符合意圖篩選器,系統會啟動該元件並提交要求 Intent 物件。如果有多個意圖篩選器相容,系統會顯示對話方塊,讓使用者選擇要使用的應用程式。

意圖篩選器是應用程式資訊清單檔案中的運算式, 會指定元件的意圖類型 。例如,為活動宣告意圖篩選器後 您可讓其他應用程式直接以某種特定意圖啟動您的活動。 同樣地,如果您「不」為活動宣告任何意圖篩選器,系統就會啟動 只用於明確意圖

注意:為確保應用程式安全,請務必在啟動 Service 時使用明確意圖,且不要為服務宣告意圖篩選器。使用隱含意圖啟動服務 可能會產生安全性危害,因為您無法確定哪個服務會回應意圖 導致使用者看不到哪個服務啟動了。從 Android 5.0 (API 級別 21) 開始,系統 若呼叫 bindService(),就會擲回例外狀況 針對隱含意圖

建立意圖

Intent 物件會攜帶 Android 系統用於判斷要啟動哪個元件 (例如應接收意圖的確切元件名稱或元件類別) 的資訊,以及收件者元件用於正確執行動作的資訊 (例如要採取的動作和要採取的資料)。

Intent 中包含的主要資訊如下:

元件名稱
要啟動的元件名稱。

這項資訊為選用項目,但卻是讓意圖「明確」的關鍵資訊,意即意圖應只傳送至由元件名稱定義的應用程式元件。如果沒有元件名稱,意圖會是「隱含」, 系統會根據其他意圖資訊,判斷哪個元件應接收意圖 (例如下述動作、資料和類別)。如果您需要在應用程式中啟動特定元件,請指定元件名稱。

注意:啟動 Service 時, 請務必指定元件名稱。否則,您無法確定哪個服務會回應意圖,而使用者也無法查看哪個服務會啟動。

Intent 的這個欄位是 ComponentName 物件,您可以使用目標元件的完整類別名稱指定該物件,包括應用程式的套件名稱,例如 com.example.ExampleActivity。您可以使用 setComponent()setClass()setClassName()Intent 建構函式設定元件名稱。

動態
指定要執行的一般動作 (例如 viewpick) 的字串。

在廣播意圖的情況下,這是發生且正在回報的動作。動作主要會決定其餘意圖的結構 (尤其是 資料和額外項目內含的資訊。

您可以指定自己的動作,供應用程式內的意圖使用 (或供其他應用程式用於叫用應用程式中的元件),但通常會指定由 Intent 類別或其他架構類別定義的動作常數。以下是啟動活動的常見動作:

ACTION_VIEW
當您擁有一些資訊,且該意圖使用 startActivity() 時,請在意圖中使用此動作 可以向使用者顯示活動,例如要在圖片庫應用程式查看的相片,或是允許 在地圖應用程式中查看。
ACTION_SEND
也稱為「共用」意圖,如果您有足夠的資料可供使用者運用,應該在搭配 startActivity() 的意圖中使用此意圖。 透過其他應用程式分享,例如電子郵件應用程式或社群媒體分享應用程式。

如要進一步瞭解定義一般動作的常數,請參閱 Intent 類別參考資料。其他動作的定義如下 安裝在 Android 架構中的其他位置,例如使用 Settings 執行動作 在系統「設定」應用程式中開啟特定畫面。

您可以使用 setAction()Intent 建構函式為意圖指定動作。

如果您定義自己的動作,請務必將應用程式的套件名稱做為前置字元,如以下範例所示:

KotlinJava
const val ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL"
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
資料
參照要執行的資料和/或該資料的 MIME 類型的 URI (Uri 物件)。提供的資料類型通常會取決於意圖的動作。適用對象 舉例來說,如果動作是 ACTION_EDIT,資料就應包含 要編輯的文件 URI。

建立意圖時,除了 URI 之外,通常也需要指定資料類型 (其 MIME 類型)。舉例來說,能夠顯示圖片的活動可能無法顯示 播放音訊檔案,不過 URI 格式可能很類似。 指定資料的 MIME 類型有助於 Android 系統找出接收意圖的最佳元件。不過,MIME 類型有時可以從 URI 推斷,尤其是當資料為 content: URI 時。content: URI 表示資料位於裝置上 並由不同叢集 ContentProvider,系統會允許系統顯示資料 MIME 類型。

如要只設定資料 URI,請呼叫 setData()。如果只要設定 MIME 類型,請呼叫 setType()。如有需要, 可以使用 setDataAndType() 明確設定這兩項功能。

注意:如果您想同時設定 URI 和 MIME 類型,請不要呼叫 setData()setType(),因為這兩者會將對方的值設為無效。一律使用 setDataAndType() 來設定兩者 URI 和 MIME 類型。

類別
字串,其中包含應處理意圖的元件類型相關的其他資訊。類別說明的數量不限 但是大多數意圖都不需要類別 以下是一些常見的類別:
CATEGORY_BROWSABLE
網路瀏覽器可自行啟動目標活動來顯示資料 透過連結 (例如圖片或電子郵件) 參照。
CATEGORY_LAUNCHER
活動是工作的初始活動,並列於系統的應用程式啟動器中。

如需完整的類別清單,請參閱 Intent 類別說明。

您可以使用 addCategory() 指定類別。

上述屬性 (元件名稱、動作、資料和類別) 代表 定義意圖的特徵透過讀取這些屬性,Android 系統就能解析應啟動哪個應用程式元件。然而,意圖可以是 不影響其他資料 如何解析為應用程式元件意圖也可以提供下列資訊:

額外內容
鍵/值組合,可提供完成所要求動作所需的額外資訊。就像某些動作會使用特定類型的資料 URI 一樣,某些動作也會使用特定的額外項目。

您可以透過各種 putExtra() 方法新增額外資料。 每一個都接受兩個參數:鍵名和值 您也可以建立包含所有額外資料的 Bundle 物件,然後使用 putExtras()Intent 中插入 Bundle

例如,建立意圖以內含 ACTION_SEND 可讓您將 to 收件者指定為 EXTRA_EMAIL 鍵,然後將主旨指定為 EXTRA_SUBJECT 鍵。

Intent 類別會為標準化資料類型指定許多 EXTRA_* 常數。如果您需要宣告自己的額外鍵 (針對應用程式收到的意圖),請務必加入應用程式的套件名稱做為前置字元,如以下範例所示:

KotlinJava
const val EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS"
static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";

注意:請勿使用 Parcelable 或 傳送預期中的意圖時,系統會處理 Serializable 的資料 即可接收其他應用程式的通知。如果是應用程式 嘗試存取 Bundle 物件中的資料,但不會嘗試存取 可存取 Parceled 或序列化類別,則會引發 RuntimeException

標記
旗標是在 Intent 類別中定義,該類別的功能是 意圖。標記可指示 Android 系統如何啟動活動 (例如活動應屬於哪個工作),以及如何在啟動後處理活動 (例如活動是否屬於近期活動清單)。

詳情請參閱 setFlags() 方法。

明確意圖範例

明確意圖,是用來啟動特定應用程式元件的應用程式,例如 應用程式中的特定活動或服務。如要建立明確意圖,請定義 Intent 物件的元件名稱— 以及選用其他意圖屬性

舉例來說,如果您在應用程式中建構名為 DownloadService 的服務,用於從網路下載檔案,您可以使用以下程式碼啟動服務:

KotlinJava
// 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)
// 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) 建構函式會為應用程式 Context 和元件提供 Class 物件。因此 此意圖會明確啟動應用程式中的 DownloadService 類別。

如要進一步瞭解如何建構及啟動服務,請參閱「服務」指南。

隱含意圖範例

隱含意圖會指定一項動作,能在裝置上叫用任何應用程式 來執行動作如果應用程式無法執行 但其他應用程式或許會讓您選擇想用的應用程式。

舉例來說,如果您有要讓使用者與其他人分享的內容,請使用 ACTION_SEND 動作建立意圖,並新增指定要分享的內容的額外項目。當您使用該意圖呼叫 startActivity() 時,使用者可以選擇要用來分享內容的應用程式。

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

呼叫 startActivity() 時,系統會檢查所有已安裝的應用程式,判斷哪些應用程式可處理這類意圖 (含有 ACTION_SEND 動作且攜帶「text/plain」資料的意圖)。如果只有一個應用程式可處理這個程式碼,該應用程式會立即開啟,並給予 意圖。如果沒有其他應用程式能夠處理,則您的應用程式可擷取 ActivityNotFoundException 。如果有多個活動接受意圖,系統會 會顯示對話方塊 (如圖 2 所示),因此使用者可以挑選要使用的應用程式。

指南也提供如何啟動其他應用程式的詳細資訊 關於將使用者引導至 其他應用程式

圖 2. 選擇工具對話方塊。

強制使用應用程式選擇工具

如果有多個應用程式會回應隱含意圖,使用者可以選擇要使用的應用程式,並將該應用程式設為動作的預設選擇。當使用者每次執行動作時,可能都會想使用同一款應用程式,例如開啟網頁 (使用者通常只會使用一個網路瀏覽器),這時就能透過選取預設值來解決問題。

不過,如果多個應用程式可以回應意圖,則使用者可能會想使用不同的 應用程式,都應明確顯示選擇器對話方塊。選擇工具對話方塊會要求使用者選取該動作使用的應用程式 (使用者無法選取動作的預設應用程式)。舉例來說,如果應用程式會執行「分享」若是 ACTION_SEND 動作,則使用者可能會想根據不同條件使用其他應用程式共用內容 建議您一律使用選擇器對話方塊,如圖 2 所示。

如要顯示選擇工具,請使用 createChooser() 建立 Intent,並傳送至 startActivity(),如以下範例所示。本範例顯示的對話方塊含有應用程式清單,這些應用程式會回應傳遞至 createChooser() 方法的意圖,並使用提供的文字做為 對話方塊標題。

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

偵測不安全的意圖啟動

應用程式可能會啟動意圖,以在應用程式內的各個元件之間瀏覽, 或代表其他應用程式執行動作為了提昇平台安全性 Android 12 (API 級別 31) 以上版本提供偵錯功能,用於發出警告 應用程式會執行不安全的意圖啟動作業。舉例來說,您的應用程式 執行不安全的巢狀意圖 (也就是傳遞的意圖) 時 做為另一個意圖中的額外項目

如果應用程式同時執行下列這兩項動作,系統偵測到不安全 意圖啟動,以及 StrictMode 違規 發生:

  1. 應用程式將巢狀意圖從已傳遞意圖的額外項目中拆解出來。
  2. 應用程式立即使用該巢狀意圖啟動應用程式元件,例如將意圖傳遞至 startActivity()startService()bindService()

如要進一步瞭解如何找出這種情況並修改應用程式, 閱讀有關 Android 巢狀結構的網誌文章 意圖 在 Medium 上

檢查是否有不安全的意圖啟動作業

如要檢查應用程式中是否有安全性不佳的意圖啟動,請在設定 VmPolicy 時呼叫 detectUnsafeIntentLaunch(),如以下程式碼片段所示。如果 應用程式偵測到 StrictMode 違規事件,建議你停止執行應用程式 保護潛在機密資訊

KotlinJava
fun onCreate() {
    StrictMode.setVmPolicy(VmPolicy.Builder()
        // Other StrictMode checks that you've previously added.
        // ...
        .detectUnsafeIntentLaunch()
        .penaltyLog()
        // Consider also adding penaltyDeath()
        .build())
}
protected void onCreate() {
    StrictMode.setVmPolicy(new VmPolicy.Builder()
        // Other StrictMode checks that you've previously added.
        // ...
        .detectUnsafeIntentLaunch()
        .penaltyLog()
        // Consider also adding penaltyDeath()
        .build());
}

以更負責任的態度使用意圖

如要盡可能減少不安全意圖啟動和 StrictMode 違規的機會,請遵循下列最佳做法。

只複製意圖中必要的額外項目,並執行任何必要的清理和驗證作業。應用程式可能會將額外功能從一個意圖複製到 用於啟動新元件的其他意圖這種情況會發生在 應用程式呼叫 putExtras(Intent)putExtras(Bundle)。 如果您的應用程式會執行其中一項作業,請僅複製 接收相應的元件如果其他意圖 (接收副本) 啟動未匯出的元件,請先清理及驗證額外項目,再將這些項目複製到啟動元件的意圖。

不要在不需要的情況下匯出應用程式元件。舉例來說,如果您想使用內部巢狀意圖啟動應用程式元件,請將該元件的 android:exported 屬性設為 false

使用 PendingIntent,而不是 巢狀結構意圖。這樣一來,當其他應用程式解析所含 IntentPendingIntent 時,該應用程式就能使用您應用程式的身分啟動 PendingIntent。這項設定可讓其他應用程式在您的應用程式中安全地啟動任何元件,包括未匯出的元件。

圖 2 中的圖表顯示系統如何將控制權從您的 (用戶端) 應用程式傳遞至其他 (服務) 應用程式,然後再傳回您的應用程式:

  1. 您的應用程式會建立意圖,以便在其他應用程式中叫用活動。在該意圖中,您會將 PendingIntent 物件新增為額外項目。這個待處理意圖會在應用程式中叫用元件,但該元件並未匯出。
  2. 收到應用程式意圖後,其他應用程式會擷取巢狀 PendingIntent 物件。
  3. 另一個應用程式對 PendingIntent 物件叫用 send() 方法。
  4. 將控制權移回應用程式後,系統會叫用待處理 修改應用程式意圖的意圖

圖 2.使用巢狀待處理結構時,應用程式內通訊的圖表 意圖。

接收隱含意圖

如要宣傳應用程式可接收的隱含意圖,請在資訊清單檔案中,為每個應用程式元件宣告一或多個意圖篩選器,並使用 <intent-filter> 元素。每個意圖篩選器都會根據意圖的動作指定所接受的意圖類型。 資料和類別只有在意圖可通過其中一個意圖篩選器時,系統才會將隱含意圖傳送至應用程式元件。

注意:無論元件宣告的任何意圖篩選器為何,一律會將明確意圖傳送至目標。

應用程式元件應為每項獨特的工作宣告個別篩選器。舉例來說,相片庫應用程式中的一個活動可能有兩個篩選器:一個用於檢視圖片,另一個用於編輯圖片。活動啟動時,會檢查 Intent,並根據 Intent 中的資訊決定如何運作 (例如是否顯示編輯器控制項)。

每個意圖篩選器都由應用程式資訊清單檔案中的 <intent-filter> 元素定義,並嵌入對應的應用程式元件 (例如 <activity> 元素)。

在每個包含 <intent-filter> 元素的應用程式元件中, 明確設定一個 android:exported。 此屬性指出其他應用程式是否可存取應用程式元件。在某些情況下,例如活動的意圖篩選器包含 LAUNCHER 類別時,將這個屬性設為 true 會很有幫助。否則 建議您將這項屬性設為 false

警告:如果活動、服務或廣播訊息 應用程式中的接收器使用意圖篩選器,且並未明確設定該值 如果是 android:exported,您無法在以下裝置上安裝應用程式: 搭載 Android 12 以上版本。

<intent-filter> 中, 您可以使用一或多個方式,指定要接受的意圖類型 以上三個要素:

<action>
name 屬性中宣告接受的意圖動作。值必須是動作的文字常值,而非類別常數。
<data>
使用一或多個指定各種屬性的屬性,宣告可接受的資料類型 資料 URI 方面 (schemehostport path) 和 MIME 類型。
<category>
name 屬性中宣告可接受的意圖類別。值必須是動作的字面字串值,而非類別常數。

注意:如要接收隱含意圖,您必須 必須包含 CATEGORY_DEFAULT 類別。startActivity()startActivityForResult() 方法會將所有意圖視為宣告 CATEGORY_DEFAULT 類別。如果您未在意圖篩選器中宣告這個類別,系統就不會將任何隱含意圖解析為 您的活動。

舉例來說,以下活動宣告內含意圖篩選器接收 ACTION_SEND 意圖 (資料類型為文字):

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

您可以建立包含多個 <action><data><category> 例項的篩選器。如果這樣做,您就必須確定該元件能夠處理任何及所有 這些篩選器元素的組合

如果您想處理多種意圖,但只在特定動作、資料和類別類型組合中處理,就需要建立多個意圖篩選器。

系統會比較意圖與三個元素,藉此測試意圖是否符合篩選器。意圖必須通過所有三項測試,才能傳送至元件。如果應用程式連一個都無法比對,Android 系統就不會將意圖傳遞給 元件。然而,由於一個元件可能包含多個意圖篩選器, 未通過元件的任一篩選器,就有可能通過其他篩選器篩選。 如要進一步瞭解系統如何解析意圖,請參閱下文的「意圖解析」一節。

注意: 使用意圖篩選器並非防止其他應用程式啟動的安全方法 您的元件雖然意圖篩選器會限制元件只回應特定類型的隱含意圖,但如果開發人員決定元件名稱,其他應用程式可能會使用明確意圖啟動您的應用程式元件。如果「只有您自己的應用程式」能夠啟動其中一個元件, 未在資訊清單中宣告意圖篩選器。請改為將該元件的 exported 屬性設為 "false"

同樣地,為了避免不慎 執行其他應用程式的 Service,一律使用明確意圖來啟動您自己的服務。

注意: 對於所有活動,您必須在資訊清單檔案中宣告意圖篩選器。 不過,您可以透過呼叫,以動態方式登錄廣播接收器的篩選器 registerReceiver()。接著,您可以使用 unregisterReceiver() 取消註冊接收器。這樣一來,應用程式就能在執行期間的特定時間內,只收聽特定廣播。

篩選器示例

為了示範部分意圖篩選器行為,以下是社交分享應用程式資訊清單檔案的範例:

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

第一個活動 MainActivity 是應用程式的主要進入點,也就是使用者最初透過啟動器圖示啟動應用程式時開啟的活動:

  • ACTION_MAIN 動作表示這是主要進入點,且不預期任何意圖資料。
  • CATEGORY_LAUNCHER 類別表示此活動的圖示應放置在系統的應用程式啟動器中。如果 <activity> 元素未使用 icon 指定圖示,系統會使用 <application> 元素中的圖示。

這兩者必須配對,活動才能顯示在應用程式啟動器中。

第二項活動 (ShareActivity) 是用於分享文字和媒體 內容。雖然使用者可能會從「MainActivity」前往該活動, 使用者也可以在發出隱含要求的其他應用程式中,直接輸入 ShareActivity 符合其中一個意圖篩選器的意圖

注意:MIME 類型 application/vnd.google.panorama360+jpg 是特殊資料類型,用於指定 或全景的相片,你可以透過 Google 全景 API

將意圖與其他應用程式進行比對意圖篩選器

如果其他應用程式指定 Android 13 (API 級別 33) 以上版本,則只有在您的意圖與該應用程式中 <intent-filter> 元素的動作和類別相符時,該應用程式才能處理您的應用程式意圖。如果系統找不到相符項目,就會擲回 ActivityNotFoundException。傳送端應用程式必須處理 。

同樣地,如果您將應用程式更新為指定 Android 13 版本, 來自外部應用程式的所有意圖都會傳送至 前提是該意圖與動作和 應用程式所宣告的 <intent-filter> 元素類別。無論傳送應用程式的目標 SDK 版本為何,都會發生這種行為。

在下列情況下,系統不會強制執行意圖比對:

  • 在未宣告任何意圖篩選器的元件放送的意圖。
  • 來自同一應用程式內的意圖。
  • 來自系統的意圖;也就是從 「系統 UID」(uid=1000)。系統應用程式包括system_server,以及 android:sharedUserIdandroid.uid.system
  • 源自根的意圖。

進一步瞭解意圖比對

使用待處理意圖

PendingIntent 物件是 Intent 物件的包裝函式。PendingIntent 的主要用途是授予外部應用程式權限,讓該應用程式使用內含的 Intent,就好像是從應用程式本身的程序執行一樣。

待處理意圖的主要用途包括:

  • 透過通知,宣告當使用者執行動作時將執行的意圖 (Android 系統的 NotificationManager 會執行 Intent)。
  • 宣告使用者透過 App Widget 執行動作時要執行的意圖 (主畫面應用程式會執行 Intent)。
  • 宣告要在指定的未來時間執行的意圖 (Android 系統的 AlarmManager 會執行 Intent)。

就像每個 Intent 物件的設計都是由特定的 應用程式元件的類型 (ActivityService 或 是 BroadcastReceiver),因此也必須是 PendingIntent 都具有相同考量使用待處理意圖時,應用程式 透過 startActivity() 等呼叫執行意圖。相反地,您必須在建立 PendingIntent,方法是呼叫相應的創作者方法:

除非應用程式從其他應用程式接收待處理意圖,否則: 建立 PendingIntent 的方法可能只有 所需的 PendingIntent 方法。

每個方法都會採用目前的應用程式 Context、您要包裝的 Intent,以及一或多個旗標,用於指定意圖的使用方式 (例如意圖是否可重複使用)。

如要進一步瞭解如何使用待處理意圖,請參閱各個用途的說明文件,例如 通知應用程式小工具 API 指南。

指定可變動性

如果您的應用程式指定 Android 12 以上版本,您就必須指定 應用程式所建立的每個 PendingIntent 物件的可變動性。如要宣告特定 PendingIntent 物件是否可變動,請分別使用 PendingIntent.FLAG_MUTABLEPendingIntent.FLAG_IMMUTABLE 標記。

如果應用程式嘗試建立 PendingIntent 物件,但未設定任何可變動性標記,系統會擲回 IllegalArgumentException,並在 Logcat 中顯示以下訊息:

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.

盡可能建立不可變動的待處理意圖

在大多數情況下,應用程式應建立不可變動的 PendingIntent 物件,如 如以下程式碼片段所示。如果 PendingIntent 物件不可變更,其他應用程式就無法修改意圖,以調整叫用意圖的結果。

KotlinJava
val pendingIntent = PendingIntent.getActivity(applicationContext,
        REQUEST_CODE, intent,
        /* flags */ PendingIntent.FLAG_IMMUTABLE)
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
        REQUEST_CODE, intent,
        /* flags */ PendingIntent.FLAG_IMMUTABLE);

不過,某些用途需要使用可變動的 PendingIntent 物件:

  • 支援通知中的直接回覆動作。直接回覆功能需要變更與回覆相關聯的 PendingIntent 物件中的短片資料。通常,您可以將 FILL_IN_CLIP_DATA 做為標記傳遞至 fillIn() 方法,藉此要求此變更。
  • 使用 CarAppExtender 例項,將通知與 Android Auto 架構建立關聯。
  • 使用 PendingIntent 的例項,將對話放入對話框中。可變動的 PendingIntent 物件可讓系統 正確標記,例如 FLAG_ACTIVITY_MULTIPLE_TASKFLAG_ACTIVITY_NEW_DOCUMENT
  • 撥打電話,要求取得裝置位置資訊 requestLocationUpdates() 或類似的 API可變動的 PendingIntent 物件可讓系統 代表位置生命週期事件的意圖額外項目。這類事件包括 並有供應商提供服務。
  • 使用「AlarmManager」設定鬧鐘時間。 可變動的 PendingIntent 物件可讓系統 EXTRA_ALARM_COUNT 意圖額外項目這個額外項目代表重複鬧鐘觸發的次數。加入這些額外項目後,意圖便能準確通知 應用程式偵測是否多次觸發週期性鬧鐘,例如 裝置休眠時。

如果應用程式會建立可變動的 PendingIntent 物件,則強烈建議您 使用明確意圖,並在 ComponentName。這樣一來,只要其他應用程式叫用 PendingIntent 並將控制權傳回您的應用程式,應用程式中就會一律啟動相同的元件。

在待處理意圖中使用明確意圖

如要進一步定義其他應用程式如何使用應用程式的待處理意圖,請務必在明確意圖中包裝待處理意圖。如要遵循這項最佳做法,請執行下列操作:

  1. 檢查基本意圖的動作、套件和元件欄位 是否有設定。
  2. 請使用 Android 6.0 (API 級別 23) 新增的 FLAG_IMMUTABLE,建立待處理意圖。這個標記可防止收到 PendingIntent 的應用程式填入未填寫的屬性。如果應用程式的 minSdkVersion 22 或更低的級別,可以同時提供安全性和相容性 使用下列程式碼:

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

意圖解析

當系統收到隱含意圖來啟動活動時,會搜尋 將意圖與意圖篩選器進行比較,根據三個層面來判定意圖最出色的活動:

  • 開拍
  • 資料 (包括 URI 和資料類型)。
  • 類別。

以下各節說明如何根據應用程式資訊清單檔案中的意圖篩選器宣告,將意圖與適當的元件配對。

動作測試

如要指定可接受的意圖動作,意圖篩選器可以宣告 0 個以上 <action> 元素,如以下範例所示:

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

如要通過這個篩選器,請在 Intent 中指定的動作 必須符合篩選器所列的其中一項動作。

如果篩選器未列出任何動作,意圖就沒有任何項目可比對,因此所有意圖都會失敗。不過,如果 Intent 未指定動作,只要篩選器包含至少一個動作,就會通過測試。

類別測試

如要指定可接受的意圖類別,意圖篩選器可以宣告 0 個以上 <category> 元素,如以下範例所示:

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

為了傳遞類別測試,Intent 中的每個類別 必須符合篩選器中的類別。不需要反向操作,意圖篩選器可能會 宣告的類別數量超過 IntentIntent 未通過。因此,沒有類別的意圖 無論篩選器中宣告的類別為何,一律會通過這項測試。

注意:Android 會自動將 CATEGORY_DEFAULT 類別套用至傳遞至 startActivity()startActivityForResult() 的所有隱含意圖。如要讓活動接收隱含意圖, 在意圖篩選器中加入 "android.intent.category.DEFAULT" 的類別,如 與上一個 <intent-filter> 範例所示

資料測試

如要指定可接受的意圖資料,意圖篩選器可以宣告 0 個以上 <data> 元素,如以下範例所示:

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

<data> 元素可以指定 URI 結構和資料類型 (MIME 媒體類型)。 URI 的各個部分 屬性:schemehostport、 和 path

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

以下範例列出這些屬性的可能值:

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

在這個 URI 中,配置為 content,主機為 com.example.project。 通訊埠為 200,路徑為 folder/subfolder/etc

這些屬性在 <data> 元素中皆為選用屬性, 但具有線性依附元件:

  • 如未指定配置,系統會忽略主機。
  • 如未指定主機,系統會忽略通訊埠。
  • 如果未指定架構和主機,系統會忽略路徑。

將意圖中的 URI 與篩選器中的 URI 規格進行比較時, 只會與篩選器中的 URI 部分進行比較例如:

  • 如果篩選器僅指定配置,則所有具有該配置的 URI 篩選器。
  • 如果篩選器指定配置和權限,但未指定路徑,則所有具有相同配置和權限的 URI 都會通過篩選器,無論其路徑為何。
  • 如果篩選器指定配置、權威機構和路徑,只有具有相同配置、權威機構和路徑的 URI 才能通過篩選器。

注意:路徑規格 包含萬用字元星號 (*),只要求部分路徑名稱相符。

資料測試會將意圖中的 URI 和 MIME 類型,與篩選器中指定的 URI 和 MIME 類型進行比較。規則如下:

  1. 未包含 URI 和 MIME 類型的意圖會傳遞 只在篩選器未指定任何 URI 或 MIME 類型時執行測試。
  2. 包含 URI 但沒有 MIME 類型的意圖 (無法從 URI) 只有在 URI 符合篩選器 URI 格式時,才會通過測試 而且篩選器同樣不會指定 MIME 類型。
  3. 如果篩選器列出相同的 MIME 類型,且未指定 URI 格式,則含有 MIME 類型但不含 URI 的意圖才能通過測試。
  4. 意圖同時包含 URI 和 MIME 類型 (不論是明確的或可從 URI 推斷的),只有在該類型與篩選器中列出的類型相符時,才能通過測試的 MIME 類型部分。如果 URI 與篩選器中的 URI 相符,或是 URI 為 content:file:,而篩選器未指定 URI,則會通過測試的 URI 部分。也就是 並假設元件支援 content:file: 資料 (如有) 篩選器「只會」列出 MIME 類型。

注意:如果意圖指定了 URI 或 MIME 類型,資料測試會 如果 <intent-filter> 中沒有 <data> 元素,就會失敗。

最後一項規則 (d) 反映了期望 該元件可從檔案或內容供應器取得本機資料。 因此,他們的篩選器可以列出資料類型,不需要明確指定 命名 content:file: 配置。 以下範例顯示 <data> 元素的一般情況 告知 Android 該元件可以從內容取得圖片資料 並顯示:

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

會套用的篩選器 指定資料類型,但不是 URI 最常見,因為 數據則是由內容供應者支付

另一個常見的設定是具有配置和資料類型的篩選器。適用對象 例如 <data> 這類元素會通知 Android 元件可以從網路擷取影片資料,才能執行動作:

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

意圖比對

不僅會將意圖與意圖篩選器比對,還能與意圖篩選器比對, 啟動 元件,也可探索一組相關資訊 元件舉例來說,Home 應用程式會找出所有含有意圖篩選器的活動,這些意圖篩選器會指定 ACTION_MAIN 動作和 CATEGORY_LAUNCHER 類別,然後將這些活動填入應用程式啟動器。如同 IntentFilter 類別的說明文件所述,只有在意圖中的動作和類別與篩選器相符時,才能成功比對。

應用程式可以使用意圖比對功能,類似於 Google Home 應用程式。PackageManager 有一組 query...() 方法,這些方法會傳回所有可接受特定意圖的元件 一系列類似的 resolve...() 方法, 回應意圖舉例來說,queryIntentActivities() 會傳回可執行以引數傳遞的意圖的所有活動清單,而 queryIntentServices() 會傳回類似的服務清單。這兩種方法都不會啟用元件,只會列出可回應的元件。廣播接收器也有類似的方法 queryBroadcastReceivers()