我們正在 Android 平臺(tái)上進(jìn)行多項(xiàng)變更來(lái)增強(qiáng)用戶(hù)隱私和平臺(tái)安全性命迈,旨在為用戶(hù)提供更安全的體驗(yàn)制跟。以 Android 11 (API 級(jí)別 30) 或更高版本為目標(biāo)的應(yīng)用默認(rèn)將只能獲取 過(guò)濾后的已安裝應(yīng)用列表我注。如需訪問(wèn)過(guò)濾后列表以外的應(yīng)用,則需要在應(yīng)用內(nèi)的 Android manifest 中使用 <queries> 元素聲明需要與之交互的應(yīng)用指蚜。本文將介紹適應(yīng)此特性的最佳實(shí)踐献起。
查詢(xún)應(yīng)用并與之交互
您可以通過(guò)以下幾種方式查詢(xún)應(yīng)用并與之交互:
- 如果您知道想要查詢(xún)或與之交互的特定應(yīng)用集,請(qǐng)將其 軟件包 名稱(chēng)包含在 <queries> 元素內(nèi)的一組 <package> 元素中掌挚。
<manifest package="com.example.game">
<queries>
<package android:name="com.example.store" />
<package android:name="com.example.services" />
</queries>
...
</manifest>
- 如果您的應(yīng)用需要查詢(xún)或與一組具有特定用途的應(yīng)用交互雨席,但您可能不知道要添加的具體軟件包名稱(chēng),您可以將 intent 過(guò)濾器簽名 列在您的 <queries> 元素中吠式。然后陡厘,您的應(yīng)用便可發(fā)現(xiàn)具有匹配的 <intent-filter> 元素的應(yīng)用。
<manifest package="com.example.game">
<queries>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="image/jpeg" />
</intent>
</queries>
...
</manifest>
- 如果您需要查詢(xún) Content Provider特占,但不知道具體的軟件包名稱(chēng)糙置,則可以在 <provider> 元素中聲明該提供程序授權(quán)。
<manifest package="com.example.suite.enterprise">
<queries>
<provider android:authorities="com.example.settings.files" />
</queries>
...
</manifest>
我們建議通過(guò)僅查詢(xún)您需要與之交互的軟件包來(lái)盡可能減少數(shù)據(jù)是目。QUERY_ALL_PACKAGES 或同等廣泛的 <intent> 元素應(yīng)當(dāng)僅由需要此級(jí)別信息的應(yīng)用使用谤饭。我們新增的軟件包可見(jiàn)性政策為新推出的 QUERY_ALL_PACKAGES 權(quán)限引入了一個(gè)審批流程,用于控制對(duì)設(shè)備上已安裝應(yīng)用清單的訪問(wèn)懊纳。您可以 點(diǎn)擊這里 觀看視頻或閱讀更多 政策更新揉抵。
Activity 標(biāo)記
大多數(shù)常見(jiàn)用例都不需要您的應(yīng)用具有廣泛的軟件包可見(jiàn)性。對(duì)于許多場(chǎng)景嗤疯,您可以使用 startActivity()冤今,并在沒(méi)有應(yīng)用可以打開(kāi)此 intent 時(shí)捕獲異常。
try {
val intent = Intent(ACTION_VIEW, Uri.parse(url)).apply {
addCategory(CATEGORY_BROWSABLE)
}
startActivity(intent)
} catch (e:ActivityNotFoundException) {
Snackbar.make(it,"Activity Not Found",Snackbar.LENGTH_LONG).show()
}
盡管您可以啟動(dòng)沒(méi)有目標(biāo)可見(jiàn)性的任何 Activity茂缚,但由于它是一個(gè) 隱式 intent戏罢,您在啟動(dòng)之前無(wú)法查詢(xún)它的可用性屋谭,也無(wú)法了解將啟動(dòng)哪個(gè)特定的應(yīng)用。如果您在它不解析的情況下啟動(dòng)龟糕,將收到通知桐磁。為了解決這一問(wèn)題,您可以使用 intent 標(biāo)記讲岁。
使用標(biāo)記的常見(jiàn)示例是 自定義標(biāo)簽頁(yè)我擂,自定義標(biāo)簽頁(yè)讓?xiě)?yīng)用可以自定義瀏覽器的外觀。鏈接將在非瀏覽器應(yīng)用 (如果有) 中正確打開(kāi)催首,而標(biāo)記則可以在開(kāi)發(fā)者希望能夠自由選擇 "自定義標(biāo)簽頁(yè)" 瀏覽器的高級(jí)用例中提供幫助扶踊。
FLAG_ACTIVITY_REQUIRE_NON_BROWSER
只有 intent 解析為非瀏覽器結(jié)果時(shí),此標(biāo)記才會(huì)啟動(dòng)它郎任。如果此類(lèi)結(jié)果不存在秧耗,將拋出 ActivityNotFoundException,然后舶治,您的應(yīng)用可以在自定義標(biāo)簽頁(yè)中打開(kāi)該網(wǎng)址分井。
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
}
如果一個(gè) intent 包含此標(biāo)記,則在調(diào)用直接啟動(dòng)瀏覽器應(yīng)用或者向用戶(hù)顯示一個(gè)消歧對(duì)話框 (唯一選項(xiàng)是瀏覽器應(yīng)用) 時(shí)霉猛,調(diào)用 startActivity() 會(huì)導(dǎo)致拋出 ActivityNotFoundException尺锚。要詳細(xì)了解標(biāo)記,請(qǐng)參閱 基于用例配置軟件包可見(jiàn)性惜浅。
自定義共享表單
建議使用系統(tǒng)提供的共享表單代替自定義表單瘫辩。無(wú)需應(yīng)用可見(jiàn)性,您也可以自定義系統(tǒng)共享表單坛悉。請(qǐng)參閱 文檔 了解更多信息伐厌。
調(diào)試軟件包可見(jiàn)性
您可以輕松檢查 manifest,了解是否包括了所有 queries裸影。為此挣轨,請(qǐng)?jiān)L問(wèn) manifest 文件并選擇 Merged Manifest。
您也可以啟用軟件包過(guò)濾的日志消息轩猩,了解默認(rèn)可見(jiàn)性對(duì)您的應(yīng)用有何影響:
$ adb shell pm log-visibility --enable YOUR_PACKAGE_NAME
后續(xù)步驟
有關(guān)軟件包可見(jiàn)性的詳細(xì)信息卷扮,您可以參閱以下資源:
樂(lè)享編碼!