將使用者傳送至其他應用程式

在 Android 裡,其中一項最重要的功能是應用程式會根據希望執行的「動作」,將使用者傳送至其他應用程式。舉例來說,如果您想要在地圖上顯示商家地址,您並不需要在您的應用程式中建立地圖。不過,您倒是可以使用 Intent 來提出要求來查看地址。接下來,Android 系統會啟動一個應用程式,以在地圖上顯示地址。

如第一個類別「打造第一個應用程式」一文所述,您必須使用意圖在自己的應用程式中切換活動。通常 您可以使用「明確意圖」進行定義,該類別會定義要啟動元件的確切類別名稱。然而,如果您希望單獨的應用程式執行某個動作 (例如「查看地圖」),則必須使用「隱含意圖」

本課程將說明如何針對特定動作建立隱含意圖,以及如何啟動在其他應用程式執行該動作。另請參閱嵌入的影片,瞭解隱含意圖納入執行確認其重要性。

建構隱含意圖

隱式意圖並不會依宣告元件的類別名稱去啟動,而是宣告要執行的動作。動作會指定您要執行的操作,例如「檢視」、「編輯」、「傳送」或「取得」

將意圖動作與資料建立關聯

意圖通常也包含與動作相關的資料,例如您要查看的地址或是要傳送的電子郵件。視您要建立的意圖而定,資料可能為 Uri、其中一種資料類型,或意圖完全不需要資料。

如果資料是 Uri,您可以透過簡單的 Intent() 建構函式去定義動作和資料。

舉例來說,以下是如何使用 Uri 資料建立一個撥打指定電話號碼的意圖:

Kotlin

val callIntent: Intent = Uri.parse("tel:5551234").let { number ->
    Intent(Intent.ACTION_DIAL, number)
}

Java

Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);

當應用程式用 startActivity() 來呼叫這個意圖之後,「電話」應用程式就會撥打給定的電話號碼。

還有幾個其他意圖及其動作和 Uri 資料配對:

查看地圖

Kotlin

// Map point based on address
val mapIntent: Intent = Uri.parse(
        "geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"
).let { location ->
    // Or map point based on latitude/longitude
    // val location: Uri = Uri.parse("geo:37.422219,-122.08364?z=14") // z param is zoom level
    Intent(Intent.ACTION_VIEW, location)
}

Java

// Map point based on address
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
// Or map point based on latitude/longitude
// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

查看網頁

Kotlin

val webIntent: Intent = Uri.parse("https://www.android.com").let { webpage ->
    Intent(Intent.ACTION_VIEW, webpage)
}

Java

Uri webpage = Uri.parse("https://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);

在意圖中新增額外資料

其他類型的隱含意圖會要求提供不同資料類型的「額外」資料 (例如字串)。您可以使用多種 putExtra() 方法新增一或多個額外資料。

根據預設,系統會根據意圖的 Uri 資料,決定意圖所需的適當 MIME 類型。如果您沒有在意圖中加入 Uri,通常應使用 setType() 來指定與意圖相關的資料類型。設定 MIME 類型還能進一步指定哪些種類的活動應接收意圖。

以下列出其他的意圖,用新增額外資料以指定所需動作:

傳送含有附件的電子郵件

Kotlin

Intent(Intent.ACTION_SEND).apply {
    // The intent does not have a URI, so declare the "text/plain" MIME type
    type = "text/plain"
    putExtra(Intent.EXTRA_EMAIL, arrayOf("jan@example.com")) // recipients
    putExtra(Intent.EXTRA_SUBJECT, "Email subject")
    putExtra(Intent.EXTRA_TEXT, "Email message text")
    putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"))
    // You can also attach multiple items by passing an ArrayList of Uris
}

Java

Intent emailIntent = new Intent(Intent.ACTION_SEND);
// The intent does not have a URI, so declare the "text/plain" MIME type
emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jan@example.com"}); // recipients
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text");
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"));
// You can also attach multiple items by passing an ArrayList of Uris

建立日曆活動

注意:只有 API 等級 14 或以上的版本可支援日曆活動的意圖。

Kotlin

// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM.
Intent(Intent.ACTION_INSERT, Events.CONTENT_URI).apply {
    val beginTime: Calendar = Calendar.getInstance().apply {
        set(2021, 0, 23, 7, 30)
    }
    val endTime = Calendar.getInstance().apply {
        set(2021, 0, 23, 10, 30)
    }
    putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.timeInMillis)
    putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.timeInMillis)
    putExtra(Events.TITLE, "Ninja class")
    putExtra(Events.EVENT_LOCATION, "Secret dojo")
}

Java

// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM.
Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
Calendar beginTime = Calendar.getInstance();
beginTime.set(2021, 0, 23, 7, 30);
Calendar endTime = Calendar.getInstance();
endTime.set(2021, 0, 23, 10, 30);
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis());
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis());
calendarIntent.putExtra(Events.TITLE, "Ninja class");
calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");

注意:請盡可能具體說明 Intent 很重要。舉例來說,如要使用 ACTION_VIEW 意圖顯示映像檔,請指定 image/* MIME 類型。這樣可以防止應用程式被意圖啟動後,「查看」其他資料的類型(例如地圖)。

以意圖啟動活動

建立 Intent 並設定額外資訊後,請呼叫 startActivity() 並將其傳送至系統:

Kotlin

startActivity(intent)

Java

startActivity(intent);

處理應用程式無法接收意圖的情況

雖然許多裝置上已安裝的其他應用程式 (例如手機、電子郵件或日曆) 都能順利處理這些意圖,但應用程式必須準備好,能在沒有任何活動可處理意圖的情況也能處理。當您呼叫意圖時,請準備好擷取 ActivityNotFoundException;如果沒有其他可處理應用程式意圖的活動,就會發生此情況:

Kotlin

try {
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

try {
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

瞭解例外狀況後,請決定應用程式接下來應採取的行動。後續步驟取決於您試圖叫用的意圖的特性。舉例來說,如果您知道可以處理意圖的特定應用程式,請提供使用者下載應用程式的連結。進一步瞭解如何連結到 Google Play 中您的產品

消歧對話方塊

如果系統識別出有多項活動可處理意圖,就會顯示對話方塊 (有時稱為「消歧對話方塊」) 讓使用者選擇要使用的應用程式 (如圖 1 所示)如果只有一個活動處理意圖,系統會立即啟動該活動。

面板附近會顯示螢幕按鈕。這個面板列出可處理意圖的不同應用程式。

圖 1. 有多個應用程式能夠處理同個意圖時,系統顯示的選取對話方塊範例。

完整範例

以下完整範例說明如何建立意圖查看地圖,並確認有應用程式可處理該意圖,然後啟動應用程式:

Kotlin

// Build the intent.
val location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California")
val mapIntent = Intent(Intent.ACTION_VIEW, location)

// Try to invoke the intent.
try {
    startActivity(mapIntent)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

// Build the intent.
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

// Try to invoke the intent.
try {
    startActivity(mapIntent);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

顯示應用程式選擇工具

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

請注意,當您執行活動時,會將 Intent 傳遞至 startActivity(),且有多個應用程式會回應意圖,使用者即可在對話方塊底部的核取方塊裡,依預設選取要使用的應用程式(請見圖 1)。舉例來說,當使用者執行常用的動作時,例如開啟網頁(可能是使用者只使用一個瀏覽器)或拍照(使用者可能偏好某部攝影機)時,這項動作就非常實用。

不過,如果要執行的動作可由多個應用程式處理,且使用者可能偏好每次都使用不同的應用程式 (例如「共用」動作,使用者可能會有多款應用程式可用來共用項目),您就應該明確顯示選擇工具對話方塊,如圖 2 所示。選擇工具對話方塊會強制使用者,每次選取該動作使用的應用程式(使用者無法選取動作的預設應用程式)。

如要顯示選擇工具,請使用 createChooser() 建立 Intent 並傳送至 startActivity()。例如:

Kotlin

val intent = Intent(Intent.ACTION_SEND)

// Create intent to show chooser
val chooser = Intent.createChooser(intent, /* title */ null)

// Try to invoke the intent.
try {
    startActivity(chooser)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

Intent intent = new Intent(Intent.ACTION_SEND);

// Create intent to show chooser
Intent chooser = Intent.createChooser(intent, /* title */ null);

// Try to invoke the intent.
try {
    startActivity(chooser);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

這會顯示應用程式清單的對話方塊,而這些應用程式會回應傳送至 createChooser() 方法的意圖。如果動作不是 ACTION_SEND ACTION_SEND_MULTIPLE,則可能提供 title 參數。