Android 11 中的軟件包可見性
在 Android 10 及之前的版本中,應(yīng)用可以通過 queryIntentActivities() 這樣的方法獲取到設(shè)備中所有已安裝的應(yīng)用列表。在大多數(shù)情況下,這種訪問權(quán)限遠超出了應(yīng)用實際所需要的權(quán)限范圍。隨著我們不斷加強對隱私保護的關(guān)注,我們將在 Android 11 上引入一些新的變化,從而改變應(yīng)用查詢用戶已安裝應(yīng)用并與之交互的方式。為了達到這一目的,我們?yōu)樘囟ㄔO(shè)備上所安裝的應(yīng)用列表帶來了更好的訪問控制。
為了更好地 "問責(zé)" 訪問已安裝應(yīng)用的行為,默認情況下,以 Android 11 為目標平臺 (目標 API level 為 30) 的應(yīng)用默認將只能檢測到部分過濾后的已安裝應(yīng)用。如果想獲取更多別的已安裝應(yīng)用列表信息,則需要在應(yīng)用內(nèi)的 Android manifest 中添加 元素,從而拓寬訪問范圍。
在大部分常見場景下,包括任何以 startActivity() 啟動的 intents,您不需要做任何改動。而其他場景,比如從您應(yīng)用的界面中直接打開某個特定的第三方應(yīng)用,則需要開發(fā)者們顯式地聲明應(yīng)用的包名或者 intent filter 簽名,如下所示:
- ...
- 大部分常見場景
- https://developer.android.google.cn/preview/privacy/package-visibility#use-cases-not-affected
- 其他場景
- https://developer.android.google.cn/preview/privacy/package-visibility-use-cases
- intent filter 簽名
- https://developer.android.google.cn/preview/privacy/package-visibility#intent-signature
如果您使用 Custom Tab 來打開 URL 鏈接,您也許會調(diào)用 resolveActivity() 和 queryIntentActivities() 來啟動一個非瀏覽器應(yīng)用 (前提是您安裝了處理該 URL 的應(yīng)用)。在 Android 11 中,則有更好的辦法來對此進行處理: 使用 intent 的 FLAG_ACTIVITY_REQUIRE_NON_BROWSER 標記,而不是去查詢其他的應(yīng)用。如果在您使用此標記調(diào)用 startActivity() 時啟動了瀏覽器,則會拋出一個 ActivityNotFoundException 異常,此時您的應(yīng)用可以對此異常進行處理,轉(zhuǎn)而使用 Custom Tab 來打開 URL 鏈接。
- try {
- val intent = Intent(ACTION_VIEW, Uri.parse(url)).apply {
- // 非瀏覽器應(yīng)用會直接處理該 URL(默認情況下)
- // 用戶也可以在消除歧義對話框中選擇非瀏覽器應(yīng)用
- addCategory(CATEGORY_BROWSABLE)
- flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER
- }
- startActivity(intent)
- } catch (e: ActivityNotFoundException) {
- // 只能使用瀏覽器應(yīng)用,或者默認使用瀏覽器處理該 intent。
- }
- Custom Tab
- https://developers.google.cn/web/android/custom-tabs
- 更好的辦法
- https://developer.android.google.cn/preview/privacy/package-visibility-use-cases#avoid-a-disambiguation-dialog
- FLAG_ACTIVITY_REQUIRE_NON_BROWSER
- https://developer.android.google.cn/preview/privacy/package-visibility#web-intent-non-browser-app
在極少數(shù)情況下,您的應(yīng)用可能需要查詢設(shè)備上所有已安裝的應(yīng)用或與之進行交互,不管這些應(yīng)用包含哪些組件。為了允許您的應(yīng)用看到其他所有已安裝應(yīng)用,Android 11 引入了 QUERY_ALL_PACKAGES 權(quán)限。在即將發(fā)布的政策更新中,Google Play 會為需要 QUERY_ALL_PACKAGES 權(quán)限的應(yīng)用提供相關(guān)指南。 您可以將 API Level 設(shè)為 30,并使用 Android Studio 3.2 以上和最新發(fā)布的相應(yīng) Android Gradle 插件,即可在應(yīng)用中添加 元素。您可以在開發(fā)者文檔 — Android 11 中的軟件包可見性中找到更多有關(guān)軟件包可用性的使用信息和用例。
- QUERY_ALL_PACKAGEShttps://developer.android.google.cn/preview/privacy/package-visibility#all-apps
- 開發(fā)者文檔 — Android 11 中的軟件包可見性https://developer.android.google.cn/preview/privacy/package-visibility
Android Studio 和 Gradle 對該功能的支持
如果您使用的 Android Gradle 插件版本是 4.1 和以上版本的話,就可以正常使用新的 元素,因為舊版本的 Gradle 插件并不兼容此元素。如果您使用了 ,或者是依賴了支持 Android 11 的庫或 SDK,則可能會引起 manifest 沖突從而出現(xiàn)合并 manifest 的錯誤。例如,在構(gòu)建應(yīng)用時,在 Build Output Window 中可能會看到以下錯誤:
- Android resource linking failed
- /Users/sample/AndroidStudioProjects/MyApp/app/build/intermediates/merged_manifests/debug/AndroidManifest.xml:18: error: unexpected element <queries> found in <manifest>
在 Build Output Window 中可能還會出現(xiàn)這樣一條錯誤信息,引導(dǎo)您去查看 Manifest 合并日志 (Manifest merger logs):
- Manifest merger failed with multiple errors, see logs
展開 Merged Manifest 視圖后,會出現(xiàn)一條附加的報錯信息:
- Error: Missing 'package' key attribute on element package
Merged Manifest 視圖
- https://developer.android.google.cn/studio/build/manifest-merge#inspect_the_merged_manifest_and_find_conflicts
修復(fù) Android Gradle 插件的問題
解決以上錯誤的最好辦法就是將 Android Gradle 插件升級到 4.1 Beta 版本。 但是,并不是所有開發(fā)者都能夠使用最新的版本,一些項目中可能會依賴老版本的 Gradle 或者代碼庫,而它們與 4.1 版本的 Android Gradle 插件有兼容性問題。 因此,近期我們?yōu)?Android Gradle 插件發(fā)布了一個小版本 (dot releases) 的升級,以便兼容<queries> 元素:
- Android Gradle 插件升級到 4.1 Beta 版本https://developer.android.google.cn/studio/releases/gradle-plugin#updating-plugin
- 小版本 (dot releases) 的升級https://developer.android.google.cn/studio/releases/gradle-plugin#4-0-0
舉個例子,如果您正在使用 4.0.0 版本的 Android Gradle 插件,就可以在項目級別的 build.gradle 文件中將相關(guān)依賴升級到上圖中對應(yīng)的版本。
- buildscript {
- repositories {
- google()
- jcenter()
- }
- dependencies {
- // classpath 'com.android.tools.build:gradle:4.0.0'
- classpath 'com.android.tools.build:gradle:4.0.1'
- }
- }