本文件說明與其他應用程式互動的幾個常見用途。本節會說明如何在有限的套件瀏覽權限中完成應用程式功能,如果應用程式指定目標為 Android 11 (API 級別 30) 或以上版本,則必須列入考量。
如果應用程式指定 Android 11 或以上的版本,並要使用意圖在其他應用程式中啟動活動,最直接的做法是叫用意圖並處理 ActivityNotFoundException
例外狀況,如果沒有可用的應用程式則適用。
如果應用程式的部分功能需要知道是否成功呼叫 startActivity()
(例如顯示 UI),請將元素新增至 <queries>
應用程式的資訊清單。一般來說,這是 <intent>
元素。
開啟網址
本節說明在指定 Android 11 或以上版本的應用程式中開啟網址的各種方法。
在瀏覽器或其他應用程式中開啟網址
如要開啟網址,請使用包含 ACTION_VIEW
的意圖動作,詳情請參閱「載入 web 網址」指南。在使用這個意圖叫用 startActivity()
後,將發生下列其中一種情況:
- 網址隨即在網路瀏覽器中開啟。
- 網址隨即會在支援該網址的應用程式中開啟,做為深層連結。
- 畫面上隨即會顯示消歧對話方塊,讓使用者選擇要用哪個應用程式開啟網址。
裝置上沒有安裝任何可開啟網址的應用程式時,會產生
ActivityNotFoundException
的問題 (此為異常現象)。如果應用程式出現
ActivityNotFoundException
,建議應用程式擷取並處理相關問題。
由於 startActivity()
方法不需要套件瀏覽權限來啟動其他應用程式的活動,因此您不需要在應用程式資訊清單中加入 <queries>
元素,也無須變更現有的 <queries>
元素。隱性和明確的意圖都以開啟網址為依據。
檢查是否有瀏覽器可以使用
在某些情況下,您的應用程式可能會確認裝置上至少有一個瀏覽器可正常運作,或是指定某個瀏覽器為預設瀏覽器,然後再嘗試開啟網址。在這種情況下,請在資訊清單的 <queries>
元素中加入下列 <intent>
元素:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="https" /> </intent>
當您呼叫 queryIntentActivities()
並將網路意圖以引數傳送時,在某些情況下傳回清單會含有可用的瀏覽器應用程式資訊。如果使用者將網址預設為在非瀏覽器應用程式中開啟,則清單就不會包含瀏覽器應用程式。
在自訂分頁中開啟網址
自訂分頁可讓應用程式自訂瀏覽器的外觀與風格。您可以在自訂分頁中開啟網址,無須在應用程式資訊清單中新增或變更 <queries>
元素。
不過,建議您用檢查裝置瀏覽器是否支援自訂分頁,或使用 CustomTabsClient.getPackageName()
選擇特定瀏覽器以透過自訂分頁啟動。在這種情況下,請在資訊清單的 <queries>
元素中加入下列 <intent>
元素:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.support.customtabs.action.CustomTabsService" /> </intent>
由非瀏覽器的應用程式處理網址
即使您的應用程式可使用自訂分頁開啟網址,但仍建議您盡可能讓非瀏覽器應用程式開啟網址。如要在應用程式中提供這項功能,請使用設定 FLAG_ACTIVITY_REQUIRE_NON_BROWSER
的意圖來呼叫 startActivity()
。如果系統擲回 ActivityNotFoundException
,應用程式就可以在自訂分頁中開啟網址。
如果意圖包含此旗標,當發生下列任一情況時,會對 startActivity()
的呼叫會造成 ActivityNotFoundException
擲回:
- 呼叫將直接啟動瀏覽器應用程式。
- 唯一的選項是瀏覽器應用程式時,該呼叫會顯示消歧對話方塊。
下列程式碼片段說明如何更新邏輯以使用 FLAG_ACTIVITY_REQUIRE_NON_BROWSER
意圖旗標:
Kotlin
try { val intent = Intent(ACTION_VIEW, Uri.parse(url)).apply { // The URL should either launch directly in a non-browser app (if it's // the default) or in the disambiguation dialog. addCategory(CATEGORY_BROWSABLE) flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER } startActivity(intent) } catch (e: ActivityNotFoundException) { // Only browser apps are available, or a browser is the default. // So you can open the URL directly in your app, for example in a // Custom Tab. openInCustomTabs(url) }
Java
try { Intent intent = new Intent(ACTION_VIEW, Uri.parse(url)); // The URL should either launch directly in a non-browser app (if it's the // default) or in the disambiguation dialog. intent.addCategory(CATEGORY_BROWSABLE); intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REQUIRE_NON_BROWSER); startActivity(intent); } catch (ActivityNotFoundException e) { // Only browser apps are available, or a browser is the default. // So you can open the URL directly in your app, for example in a // Custom Tab. openInCustomTabs(url); }
避免消歧對話方塊
為避免使用者開啟網址時,但仍顯示消歧對話方塊,所以最好先處理網址,因此您可以先設定 FLAG_ACTIVITY_REQUIRE_DEFAULT
的意圖。
如果意圖中包含這個標記,則呼叫會出現消歧對話框給使用者,因為呼叫 startActivity()
會觸發 ActivityNotFoundException
。
如果意圖同時包含這個標記和 FLAG_ACTIVITY_REQUIRE_NON_BROWSER
,要呼叫 startActivity()
觸發 ActivityNotFoundException
,而發生在下列任一情況時,系統會觸發這個事件:
- 呼叫將直接啟動瀏覽器應用程式。
- 此呼叫會顯示消歧對話方塊。
下列程式碼片段顯示如何搭配使用 FLAG_ACTIVITY_REQUIRE_NON_BROWSER
和 FLAG_ACTIVITY_REQUIRE_DEFAULT
:
Kotlin
val url = URL_TO_LOAD try { // For this intent to be invoked, the system must directly launch a // non-browser app. val intent = Intent(ACTION_VIEW, Uri.parse(url)).apply { addCategory(CATEGORY_BROWSABLE) flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER or FLAG_ACTIVITY_REQUIRE_DEFAULT } startActivity(intent) } catch (e: ActivityNotFoundException) { // This code executes in one of the following cases: // 1. Only browser apps can handle the intent. // 2. The user has set a browser app as the default app. // 3. The user hasn't set any app as the default for handling this URL. openInCustomTabs(url) }
Java
String url = URL_TO_LOAD; try { // For this intent to be invoked, the system must directly launch a // non-browser app. Intent intent = new Intent(ACTION_VIEW, Uri.parse(url)); intent.addCategory(CATEGORY_BROWSABLE); intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REQUIRE_NON_BROWSER | FLAG_ACTIVITY_REQUIRE_DEFAULT); startActivity(intent); } catch (ActivityNotFoundException e) { // This code executes in one of the following cases: // 1. Only browser apps can handle the intent. // 2. The user has set a browser app as the default app. // 3. The user hasn't set any app as the default for handling this URL. openInCustomTabs(url); }
開啟檔案
假如您的應用程式會處理檔案或附件 (例如檢查裝置能否開啟指定檔案),那麼最簡單的步驟就是嘗試啟動可處理檔案的活動。如要這麼做,請使用包含 ACTION_VIEW
意圖動作的意圖,以及代表特定檔案的 URI。如果裝置上沒有可用應用程式,應用程式可擷取 ActivityNotFoundException
。在例外狀況處理邏輯中,您可以顯示錯誤,或嘗試自行處理檔案。
如果應用程式必須事先知道其他應用程式是否可以開啟指定檔案,請將下列程式碼片段裡的 <intent>
元素加入資訊清單的 <queries>
元素中。如果已知編譯時間,請加入檔案類型。
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.VIEW" /> <!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". --> <data android:mimeType="application/pdf" /> </intent>
接著,您可以透過意圖呼叫 resolveActivity()
來確認應用程式是否可用。
授予 URI 存取權
注意事項:如果應用程式指定目標為 Android 11 (API 級別 30) 或以上版本,且向所有應用程式提出建議,則無論應用程式的目標 SDK 版本為何,您都必須宣告本節所述的 URI 存取權限,以及是否匯出其內容供應者。
如果應用程式指定 Android 11 或以上版本,才能存取內容 URI,則應用程式的意圖必須宣告URI 存取權限透過設定下列一或兩項意圖旗標:FLAG_GRANT_READ_URI_PERMISSION
和FLAG_GRANT_WRITE_URI_PERMISSION
。
在 Android 11 或以上版本中,URI 存取權限會為具備意圖的應用程式提供下列功能:
- 讀取或寫入 URI 代表的內容資料 (視指定的 URI 權限而定)。
- 查看含有與 URI 授權相符的內容供應者的應用程式。因為內容供應者的應用程式與傳送意圖的應用程式有可能不同。
下列程式碼片段顯示如何新增 URI 權限意圖旗標,以便指定 Android 11 或以上版本的其他應用程式查看 URI 內容資料:
Kotlin
val shareIntent = Intent(Intent.ACTION_VIEW).apply { flags = Intent.FLAG_GRANT_READ_URI_PERMISSION data = CONTENT_URI_TO_SHARE_WITH_OTHER_APP }
Java
Intent shareIntent = new Intent(Intent.ACTION_VIEW); shareIntent.setFlags(FLAG_GRANT_READ_URI_PERMISSION); shareIntent.setData(CONTENT_URI_TO_SHARE_WITH_OTHER_APP);
連線至服務
如果應用程式需要與未自動顯示的服務互動,您可以在 <queries>
元素中宣告適當的意圖動作。以下各節將提供使用常用存取服務的範例。
連線至文字轉語音引擎
如果您的應用程式與文字轉語音 (TTS) 引擎互動,請在資訊清單的 <queries>
元素中加入下列 <intent>
元素:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.TTS_SERVICE" /> </intent>
連線至語音辨識服務
如果應用程式與語音辨識服務互動,請在資訊清單的 <queries>
元素中加入下列 <intent>
元素:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.speech.RecognitionService" /> </intent>
連線至媒體瀏覽器服務
如果您的應用程式是用戶端媒體瀏覽器應用程式,請在資訊清單的 <queries>
元素中加入以下 <intent>
元素:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.media.browse.MediaBrowserService" /> </intent>
提供自訂功能
如果應用程式需要執行可自訂動作,或根據使用者與其他應用程式的互動顯示可自訂的資訊,您可以使用意圖篩選器簽名來作為資訊清單中的 <queries>
元素代表該自訂行為。下列各節將針對幾種常見情況提供更詳盡的指南。
簡訊應用程式查詢
如果應用程式需要瞭解安裝在裝置上的簡訊應用程式,例如要檢查哪個應用程式是裝置的預設簡訊處理常式,請將下列 <intent>
元素加入資訊清單中的 <queries>
元素:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.SENDTO"/> <data android:scheme="smsto" android:host="*" /> </intent>
建立自訂共用試算表
請盡可能使用系統提供的分享表。您也可以在資訊清單的 <queries>
元素中加入下列 <intent>
元素:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.SEND" /> <!-- Replace with the MIME type that your app works with, if needed. --> <data android:mimeType="image/jpeg" /> </intent>
在應用程式邏輯裡,建構 Sharesheet 的程序 (例如呼叫 queryIntentActivities()
) 會保持先與 Android 11 之前的 Android 版本不變。
顯示選取自訂文字的動作
當使用者在應用程式中選取文字時,文字選取工具列會顯示一組可對所選文字執行的作業。如果這個工具列應該顯示在其他應用程式的自訂動作,請在資訊清單的 <queries>
元素中加入下列 <intent>
元素:
<!-- Place inside the <queries> element. --> <intent> <action android:name="android.intent.action.PROCESS_TEXT" /> <data android:mimeType="text/plain" /> </intent>
顯示聯絡人的自訂資料列
應用程式可以在聯絡人提供者中新增自訂資料列。要讓「聯絡人」應用程式顯示這項自訂資料,必須能夠執行下列操作:
- 讀取其他應用程式中的
contacts.xml
檔案。 - 載入與自訂 MIME 類型對應的圖示。
如果您的應用程式是聯絡人應用程式,請將下列 <intent>
元素加入資訊清單的 <queries>
元素中:
<!-- Place inside the <queries> element. --> <!-- Lets the app read the contacts.xml file from other apps. --> <intent> <action android:name="android.accounts.AccountAuthenticator" /> </intent> <!-- Lets the app load an icon corresponding to the custom MIME type. --> <intent> <action android:name="android.intent.action.VIEW" /> <data android:scheme="content" android:host="com.android.contacts" android:mimeType="vnd.android.cursor.item/*" /> </intent>