Android 12 Beta 版
本文主要摘取字Google官方文檔關于 Android 12 Beta 版相關修改和變更介紹,手動整理,如有錯誤,歡迎指正
@[TOC](Android 12 Beta 版 )
行為變更:所有應用
Android 12 平臺包含一些行為變更,這些變更可能會影響您的應用。以下行為變更將影響在 Android 12 上運行的所有應用,無論采用哪種 targetSdkVersion 都不例外。您應該測試您的應用,然后根據(jù)需要進行修改,以適當?shù)刂С诌@些變更。
用戶體驗
滾動效果
滾動事件的行為在 Android 12 中發(fā)生了變化
在搭載 Android 12 及更高版本的設備上,滾動事件的視覺行為發(fā)生了變化。
在 Android 11 及更低版本中,滾動事件會使視覺元素發(fā)光。在 Android 12 及更高版本中,發(fā)生拖動事件時,視覺元素會拉伸和反彈;發(fā)生快速滑動事件時,它們會快速滑動和反彈:


新的滾動行為會影響拖動和快速滑動動畫。
該行為會應用于使用 EdgeEffect 的所有應用,并且適用于以下類中的所有內(nèi)容:
- RecyclerView
- ListView
- ScrollView
- NestedScrollView
- HorizontalScrollView
- ViewPager
- ViewPager2
視覺效果對垂直滾動和水平滾動都適用。由于它默認應用于未停用滾動的所有應用,因此可以為用戶提供更一致的界面體驗。
最佳做法
為了確保新的滾動體驗與您的應用完美搭配,請遵循以下最佳做法:
- 適當調(diào)整滾動容器的大小,使其子視圖能夠容納在邊界內(nèi)。
- 增加滾動拉伸時,對 EdgeEffect.onPull(deltaDistance, displacement) 中的 deltaDistance 使用正值;減少拉伸時,使用負值。
- 向下滾動時捕捉動畫。
拉伸 EdgeEffect 的用法
EdgeEffect
添加了兩個用于實現(xiàn)拉伸滾動效果的 API。
float getDistance()
float onPullDistance(float deltaDistance, float displacement)
為了利用拉伸滾動提供最佳用戶體驗,請執(zhí)行以下操作:
- 當用戶在釋放動畫過程中釋放并輕觸內(nèi)容時,將輕觸注冊為“捕捉”。用戶停止動畫并再次開始操控拉伸。
- 當用戶沿拉伸的相反方向移動手指時,釋放拉伸,直到其完全消失,然后開始滾動。
- 當用戶在拉伸過程中快速滑動時,快速滑動 EdgeEffect 以增強拉伸效果。
捕捉動畫
當用戶捕捉活動的拉伸動畫時,EdgeEffect.isFinished() 會返回 false。這表示拉伸應由輕觸動作操控。在大多數(shù)容器中,這在 onInterceptTouchEvent() 中檢測:
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
...
when (action and MotionEvent.ACTION_MASK) {
MotionEvent.ACTION_DOWN ->
...
isBeingDragged = !edgeEffectBottom.isFinished() ||
!edgeEffectTop.isFinished()
...
}
return isBeingDragged
}
在前面的示例中,當 mIsBeingDragged 為 true 時,onInterceptTouchEvent() 返回 true,因此這對于在子級有機會消耗事件之前消耗事件已經(jīng)足夠了。
釋放滾動效果
務必在滾動之前釋放拉伸效果,以防止將拉伸應用于滾動內(nèi)容:
override fun onTouchEvent(ev: MotionEvent): Boolean {
val activePointerIndex = ev.actionIndex
when (ev.getActionMasked()) {
MotionEvent.ACTION_MOVE ->
val x = ev.getX(activePointerIndex)
val y = ev.getY(activePointerIndex)
var deltaY = y - mLastMotionY
val pullDistance = deltaY / height
val displacement = x / width
if (deltaY < 0f && mEdgeEffectTop.distance > 0f) {
deltaY -= height * mEdgeEffectTop
.onPullDistance(pullDistance, displacement);
}
if (deltaY > 0f && mEdgeEffectBottom.distance > 0f) {
deltaY += height * mEdgeEffectBottom
.onPullDistance(-pullDistance, 1 - displacement);
}
...
}
拖動時,在將觸摸事件傳遞給嵌套滾動或拖動滾動內(nèi)容之前,必須消耗 EdgeEffect 的拉取距離。在前面的代碼示例中,當正在顯示邊緣效果且可以通過動作將其釋放時,getDistance() 會返回一個正值。當觸摸事件釋放拉伸時,它首先由 EdgeEffect 消耗,這樣就可以在顯示其他效果(如嵌套滾動)之前完全釋放。您可以使用 getDistance() 了解釋放當前效果所需的拉取距離。
onPullDistance() 與 onPull() 的不同之處在于返回所傳遞增量的已消耗量。onPull() 以前允許發(fā)光效果的總距離為負值。在 Android 12 及更高版本中,如果在 getDistance() 為 0 時向 onPull() 或 onPullDistance() 傳遞負的 deltaDistance 值,則拉伸不會發(fā)生任何變化。
停用
可以在 XML 布局文件中或以編程方式停用滾動:
<!-- Via markup -->
<ScrollView
...
android:overScrollMode="never"
...
或者,在代碼中設置:
<!-- Programmatically-->
...
recyclerview.overScrollMode = View.OVER_SCROLL_NEVER
...
行為變更:以 Android 12 為目標平臺的應用
與早期版本一樣,Android 12 包含一些行為變更,這些變更可能會影響您的應用。以下行為變更僅影響以 Android 12 或更高版本為目標平臺的應用。如果您的應用以 Android 12 為目標平臺,您應該修改自己的應用以適當?shù)刂С诌@些行為(如果適用)。
用戶體驗
畫中畫行為改進
Android 12 針對畫中畫 (PiP) 模式引入了行為改進。
自定義通知
Android 12 更改了完全自定義通知的外觀和行為。以前,自定義通知能夠使用整個通知區(qū)域并提供自己的布局和樣式。由此產(chǎn)生的反模式可能會令用戶困惑,或在不同設備上引發(fā)布局兼容性問題。
對于以 Android 12 為目標平臺的應用,包含自定義內(nèi)容視圖的通知將不再使用完整通知區(qū)域;相反,系統(tǒng)會應用標準模板。此模板可確保自定義通知在所有狀態(tài)下都與其他通知相同,例如,在收起狀態(tài)下的通知圖標和展開功能,以及在展開狀態(tài)下的通知圖標、應用名稱和收起功能。此行為與 Notification.DecoratedCustomViewStyle 的行為幾乎完全相同。
通過這種方式,Android 12 通過為用戶提供可看到且熟悉的通知展開功能,使所有通知保持外觀一致且易于瀏覽。
下圖顯示了標準模板中的自定義通知:

以下示例展示了在收起狀態(tài)和展開狀態(tài)下呈現(xiàn)的自定義通知:


Android 12 中的變更會影響某些定義 Notification.Style 的自定義子類的應用,或使用 Notification.Builder 的方法 setCustomContentView(RemoteViews)、setCustomBigContentView(RemoteViews) 和 setCustomHeadsUpContentView(RemoteViews) 的應用。
如果你的應用使用的是完全自定義的通知,最好盡快使用新模板進行測試
- 啟用自定義通知變更:
- 將應用的 targetSdkVersion 變更為 S 以啟用新行為。
- 重新編譯。
- 在搭載 Android 12 的設備或模擬器上安裝您的應用。
- 測試所有使用自定義視圖的通知,確保這些通知在通知欄中看起來符合預期。在測試時,請考慮以下注意事項并進行必要的調(diào)整:
- 自定義視圖的尺寸已更改。一般來說,提供給自定義通知的高度比之前小。在收起狀態(tài)下,自定義內(nèi)容的最大高度已從 106dp 減少到 48dp。此外,水平空間也減小了。
- 對于以 Android 12 為目標平臺的應用,所有通知都是可展開的。通常,這意味著,如果您使用的是 setCustomContentView,則還需要使用 setBigCustomContentView,以確保收起狀態(tài)和展開狀態(tài)保持一致。
- 為了確?!案油ㄖ睜顟B(tài)看起來符合您的預期,請勿忘記將通知渠道的重要性提升至“高”(在屏幕中彈出)。
Android App Links 驗證的變更
對于以 Android 12 為目標平臺的應用,系統(tǒng)對 Android App Links 的驗證方式進行了一些更改。這些變更可以提升應用鏈接體驗的可靠性,并且能夠增強應用開發(fā)者和最終用戶的控制能力。
如果以 Android 12 為目標平臺并且依靠 Android App Links 驗證在您的應用中打開網(wǎng)頁鏈接,請更新 Android App Links 聲明,以支持更改后的驗證流程。您也可以手動調(diào)用網(wǎng)域驗證來測試聲明的可靠性。
隱私設置
大致位置
使用以 Android 12 為目標平臺的應用時,用戶可以請求應用只能訪問大致位置信息。
<table> <tr> <td bgcolor= #DBE4FF><font color=#01579B size =3 face ="黑體" > 注意:如果您的應用請求 ACCESS_COARSE_LOCATION 但未請求 ACCESS_FINE_LOCATION,則此變更不會影響您的應用。</font></td></tr></table>
如果您的應用以 Android 12 為目標平臺并且請求 ACCESS_FINE_LOCATION 運行時權限,則您還必須請求 ACCESS_COARSE_LOCATION 權限。您必須在單個運行時請求中包含這兩項權限。
當您的應用同時請求 ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION 時,系統(tǒng)權限對話框?qū)橛脩籼峁┮韵滦逻x項,如圖 1 所示:
- 確切:提供 ACCESS_FINE_LOCATION 權限提供的位置精確度。
- 大致:提供 ACCESS_COARSE_LOCATION 權限提供的位置精確度。
Android 12 基于最近平臺對位置權限模型所做的變更,包括后臺位置信息權限和單次授權。當應用以 Android 12 為目標平臺時,用戶可以請求應用僅檢索大致位置信息,即使應用請求 ACCESS_FINE_LOCATION 運行時權限也是如此。
如果您的應用請求 ACCESS_COARSE_LOCATION 但未請求 ACCESS_FINE_LOCATION,則本頁介紹的變更不會帶來任何影響。
圖 1 顯示了您的應用以 Android 12 為目標平臺且僅請求 ACCESS_COARSE_LOCATION 時顯示的面向用戶的對話框。
為了更好地尊重用戶隱私,建議您僅請求 ACCESS_COARSE_LOCATION。即使您只能訪問大致位置信息,也可以滿足大多數(shù)用例的要求。
如果您的應用以 Android 12 為目標平臺并且您請求 ACCESS_FINE_LOCATION 權限,則還必須請求 ACCESS_COARSE_LOCATION 權限。您必須在單個運行時請求中包含這兩項權限。如果您嘗試僅請求 ACCESS_FINE_LOCATION,則系統(tǒng)會忽略該請求,并在 Logcat 中記錄以下錯誤消息:
ACCESS_FINE_LOCATION must be requested with ACCESS_COARSE_LOCATION。
用戶在大致位置與確切位置之間進行選擇
當您的應用同時請求 ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION 時,系統(tǒng)權限對話框?qū)橛脩籼峁┮韵滦逻x項:
- 確切:提供 ACCESS_FINE_LOCATION 權限提供的位置信息精確度。
- 大致:提供 ACCESS_COARSE_LOCATION 權限提供的位置信息精確度。
圖 2 顯示該對話框包含這兩個新選項的視覺提示,以幫助用戶做出選擇。用戶確定位置信息精確度后,他們可以點按三個按鈕中的一個來選擇權限授予的時長。這些按鈕與搭載 Android 11(API 級別 30)的設備上的位置權限對話框中顯示的按鈕相同。
在 Android 12 中,用戶可以轉(zhuǎn)到系統(tǒng)設置,以設置任何應用的首選位置信息精確度,而不管該應用的目標 SDK 版本是什么。即使您的應用安裝在搭載 Android 11 或更低版本的設備上,然后升級到 Android 12,也是如此。如果用戶從權限對話框或在系統(tǒng)設置中將應用的位置信息訪問權限從確切位置降級到大致位置,則系統(tǒng)會重啟應用的進程。因此,遵循有關請求運行時權限的最佳做法特別重要。
用戶的選擇會影響權限授予
下表顯示了系統(tǒng)根據(jù)用戶在運行時權限對話框中選擇的選項向您的應用授予的權限:
| 確切 | 大致 | |
|---|---|---|
| 僅在使用該應用時允許 | ACCESS_FINE_LOCATION 和ACCESS_COARSE_LOCATION | ACCESS_COARSE_LOCATION |
| 僅限這一次 | ACCESS_FINE_LOCATION 和ACCESS_COARSE_LOCATION | ACCESS_COARSE_LOCATION |
| 拒絕 | 無位置權限 | 無位置權限 |
如需確定系統(tǒng)已向您的應用授予的權限,請查看權限請求的返回值。您可以在類似于下面的代碼中使用 Jetpack 庫,也可以使用平臺庫,在這種情況下,您自行管理權限請求代碼。
val locationPermissionRequest = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
when {
permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false) -> {
// Precise location access granted.
}
permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false) -> {
// Only approximate location access granted.
} else -> {
// No location access granted.
}
}
}
// ...
// Before you perform the actual permission request, check whether your app
// already has the permissions, and whether your app needs to show a permission
// rationale dialog. For more details, see Request permissions.
locationPermissionRequest.launch(arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION))
用戶的選擇還會影響后臺位置信息
如果系統(tǒng)向您的應用授予 ACCESS_BACKGROUND_LOCATION 權限,則用戶在位置權限對話框中的選擇也適用于后臺位置信息。
例如,如果用戶向您的應用授予 ACCESS_BACKGROUND_LOCATION 權限,但僅授予在前臺訪問大致位置信息的權限,則您的應用在后臺也只有大致位置信息的訪問權限。
升級到確切位置
如果您的應用當前依賴于使用 ACCESS_FINE_LOCATION 權限訪問確切位置,則大致位置可能會影響您的應用。
在讓用戶將應用的訪問權限升級到確切位置之前,請考慮應用的用例是否確實需要這一級別的精確度。如果您的應用需要通過藍牙或 Wi-Fi 將某個設備與附近的設備配對,請考慮使用配套設備配對或新的藍牙權限,而不是請求 ACCESS_FINE_LOCATION 權限。
如需請求用戶將應用的位置信息訪問權限從大致位置升級到確切位置,請執(zhí)行以下操作:
- 說明權限請求的原因
- 再次同時請求 ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION 權限。由于用戶已允許系統(tǒng)向您的應用授予大致位置信息訪問權限,因此這次系統(tǒng)對話框有所不同,如圖 3 和圖 4 所示:
測試您的應用如何處理大致位置信息
如需評估您是否需要更新您的應用以支持用戶可配置的位置信息精確度,請完成本部分中所述的測試。
處理對話框中的大致位置信息請求
對于用戶要求在新對話框中讓您的應用具有大致位置信息訪問權限的請求,如需檢查您的應用如何處理此類請求,請執(zhí)行以下操作:
- 同時請求 ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION。
- 在顯示的對話框中(圖 2),選擇頂部附近的大致,以及底部附近的僅在使用該應用時允許或僅限這一次。
- 檢查應用的用例是否仍按預期工作,即使您的應用只有大致位置信息訪問權限也是如此。
處理系統(tǒng)設置中的大致位置信息降級
對于用戶要求在系統(tǒng)設置中將您的應用的位置信息訪問權限從確切位置更改為大致位置的請求,如需檢查您的應用如何處理此類請求,請執(zhí)行以下操作:
- 同時請求 ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION。
- 在顯示的對話框中(圖 2),選擇頂部附近的確切,以及底部附近的僅在使用該應用時允許或僅限這一次。
- 轉(zhuǎn)到系統(tǒng)設置中應用的權限屏幕。
- 在位置權限屏幕上,關閉使用確切位置。圖 5 中顯示了此選項。
與任何權限降級一樣,系統(tǒng)會重啟應用的進程。 - 檢查應用的用例是否仍按預期工作,即使您的應用只有大致位置信息訪問權限也是如此。
處理系統(tǒng)設置中的確切位置升級
對于用戶要求在系統(tǒng)設置中將您的應用的位置信息訪問權限從大致位置更改為確切位置的請求,如需檢查您的應用如何處理此類請求,請執(zhí)行以下操作:
- 同時請求 ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION。
- 在顯示的對話框中(圖 2),選擇頂部附近的大致,以及底部附近的僅在使用該應用時允許或僅限這一次。
- 轉(zhuǎn)到系統(tǒng)設置中應用的權限屏幕。
- 在位置權限屏幕上,開啟使用確切位置,如圖 5 所示。
由于此權限更改是升級,因此系統(tǒng)不會重啟您的應用。 - 檢查您的應用是否可以在其基于位置信息的用例中接收更準確的位置數(shù)據(jù)。
應用休眠
Android 12 在 Android 11(API 級別 30)中引入的自動重置權限行為的基礎上進行了擴展。如果您的應用以 Android 12 為目標平臺并且用戶有幾個月未與您的應用互動,則系統(tǒng)會自動重置授予的所有權限并將您的應用置于休眠狀態(tài)。
<table> <tr> <td bgcolor= #DBE4FF><font color=#AA00FF face ="黑體" > 注意:如果您的應用是實現(xiàn) DeviceAdminService 或者在設備所有者或個人資料所有者操作模式下運行的設備政策控制器,則系統(tǒng)絕不會將您的應用置于休眠狀態(tài)。</font></td></tr></table>
處于休眠狀態(tài)的應用具有以下特征:
- 系統(tǒng)會針對存儲空間而非性能進行優(yōu)化。應用緩存中的任何文件都會被移除。
- 應用無法從后臺運行作業(yè)或提醒。
- 應用無法接收推送通知,包括通過 Firebase Cloud Messaging 發(fā)送的高優(yōu)先級消息。
當用戶下次與應用互動時,應用會退出休眠狀態(tài),并且可以再次創(chuàng)建作業(yè)、提醒和通知。不過,您需要重新調(diào)度在應用進入休眠狀態(tài)之前調(diào)度的所有作業(yè)、提醒和通知。此工作流與用戶從系統(tǒng)設置中手動強行停止應用時的工作流類似。為了更輕松地支持此工作流,請使用 WorkManager。您還可以在 ACTION_BOOT_COMPLETED 廣播接收器中添加重新調(diào)度邏輯,系統(tǒng)會在您的應用離開休眠狀態(tài)時以及設備啟動后調(diào)用它。
請求用戶停用休眠
如果您預計應用中的某個用例會受休眠的影響,您可以向用戶發(fā)送請求,讓其準許應用免于休眠和自動重置權限。如果用戶希望應用主要在后臺運行,即使用戶不與應用互動,應用也能正常工作,例如,當應用執(zhí)行以下一項或多項操作時,這種豁免很有用:
- 通過定期報告家庭成員的位置來保障家庭安全。
- 在設備與應用的服務器之間同步數(shù)據(jù)。
- 與智能設備(如電視)通信。
- 與配套設備(如手表)配對。
如需請求豁免,請調(diào)用包含 Intent.ACTION_APPLICATION_DETAILS_SETTINGS intent 操作的 intent。在顯示的屏幕中,用戶可以關閉名為撤消權限并釋放空間的選項。
<table> <tr> <td bgcolor= #DBE4FF><font color=#01579B size =3 face ="黑體" > 注意:在調(diào)用 intent 之前,不妨考慮向用戶顯示一個指導界面,以便用戶了解為什么您的應用將他們引導至系統(tǒng)設置。</font></td></tr></table>
測試休眠行為
如需將應用置于休眠狀態(tài)以進行測試,請執(zhí)行以下操作:
- 在設備上啟用該行為:
adb shell device_config put app_hibernation app_hibernation_enabled true
- 更改應用的狀態(tài),使其進入休眠狀態(tài)。包含 --global 標志的命令會強制應用進入“完全休眠”狀態(tài),以模擬系統(tǒng)已為多用戶設備上的所有用戶將應用置于休眠狀態(tài)的情況。
adb shell cmd app_hibernation set-state PACKAGE-NAME true && \
adb shell cmd app_hibernation set-state --global PACKAGE-NAME true
移動傳感器有采樣率限制
為了保護有關用戶的潛在敏感信息,如果您的應用以 Android 12 為目標平臺,則系統(tǒng)會對來自某些移動傳感器和位置傳感器的數(shù)據(jù)的刷新率施加限制。這些數(shù)據(jù)包括由設備的加速度計、陀螺儀和地磁場傳感器記錄的值。
刷新率限制取決于您訪問傳感器數(shù)據(jù)的方式:
- 如果您調(diào)用 registerListener() 方法,則傳感器采樣率限制為 200 Hz。對于 registerListener() 方法的所有過載變體都是如此。
- 如果您使用 SensorDirectChannel 類,則傳感器采樣率限制為 RATE_NORMAL,通常約為 50 Hz。
如果您的應用以 Android 12 為目標平臺并且需要以較高的采樣率收集移動傳感器數(shù)據(jù),則您必須聲明 HIGH_SAMPLING_RATE_SENSORS 權限。否則,如果您的應用嘗試在未聲明此權限的情況下以較高的采樣率收集移動傳感器數(shù)據(jù),就會發(fā)生 SecurityException。
<table> <tr> <td bgcolor= #DBE4FF><font color=#01579B size =3 face ="黑體" > 注意:如果用戶使用 Android 12 中的新設備切換開關關閉麥克風訪問權限,則移動傳感器和位置傳感器會有采樣率限制。無論您是否聲明 HIGH_SAMPLING_RATE_SENSORS 權限,此采樣率限制都會生效。</font></td></tr></table>
數(shù)據(jù)訪問審核
在 Android 11(API 級別 30)中引入的數(shù)據(jù)訪問審核 API 可讓您根據(jù)應用的用例創(chuàng)建歸因標記。這些標記可讓您更輕松地確定應用的哪一部分執(zhí)行特定類型的數(shù)據(jù)訪問。
如果您的應用以 Android 12 為目標平臺,您必須使用以下代碼段中所示的格式在應用的清單文件中聲明這些歸因標記。如果您的應用以 Android 12 為目標平臺并且您嘗試使用未在應用的清單文件中聲明的某個歸因標記,則系統(tǒng)會為您創(chuàng)建一個 null 標記并在 Logcat 中記錄一條消息。
<manifest ...>
<!-- The value of "android:tag" must be a literal string, and the
value of "android:label" must be a resource. The value of
"android:label" should be user-readable. -->
<attribution android:tag="sharePhotos"
android:label="@string/share_photos_attribution_label" />
...
</manifest>
WebView 中的現(xiàn)代 SameSite Cookie
Android 的 WebView 組件基于為 Google 的 Chrome 瀏覽器提供支持的開源項目 Chromium。在過去一年中,Chromium 變更了對第三方 Cookie 的處理方式,目的是為了更好地保護用戶的安全和隱私,并賦予用戶更高的透明度和控制權。這些變更已面向很多 Chrome 用戶發(fā)布,從 Android 12 開始,這些變更將應用于 WebView 中。
Cookie 的 SameSite 屬性決定了它是可以與任何請求一起發(fā)送,還是只能與同站點請求一起發(fā)送。Android 12 中的 WebView 基礎版本(版本 89.0.4385.0)包含以下隱私保護方面的變更,旨在改善對第三方 Cookie 的默認處理方式,并幫助防止意外跨站點共享:
- 沒有 SameSite 屬性的 Cookie 被視為 SameSite=Lax。
- 帶有 SameSite=None 的 Cookie 還必須指定 Secure 屬性,這意味著它們需要安全的上下文,并應通過 HTTPS 發(fā)送。
- 站點的 HTTP 版本和 HTTPS 版本之間的鏈接現(xiàn)在被視為跨站點請求,因此除非將 Cookie 正確標記為 SameSite=None; Secure,否則 Cookie 不會被發(fā)送。
對于開發(fā)者而言,一般指導意見是識別關鍵用戶流中的跨站點 Cookie 依賴項,并確保在需要時使用適當?shù)闹碉@式設置 SameSite 屬性。您必須顯式指定允許在不同網(wǎng)站上運行的 Cookie,或適用于從 HTTP 切換到 HTTPS 進行同站點導航的 Cookie。
ADB 備份限制
為了幫助保護私有應用數(shù)據(jù),Android 12 更改了 adb backup 命令的默認行為。對于以 Android 12 為目標平臺的應用,當用戶運行 adb backup 命令時,從設備導出的其他任何系統(tǒng)數(shù)據(jù)都不包含應用數(shù)據(jù)。
如果您的測試或開發(fā)工作流程依賴于使用 adb backup 的應用數(shù)據(jù),現(xiàn)在您可以選擇通過在應用的清單文件中將 android:debuggable 設置為 true 來導出應用數(shù)據(jù)。
<table> <tr> <td bgcolor=#FEEFE3><font color=#D26B4A size =3 face ="黑體" > 注意:為了幫助保護應用數(shù)據(jù),請務必在發(fā)布應用前將 android:debuggable 設置為 false。</font></td></tr></table>
安全
更安全的組件導出
如果您的應用以 Android 12 為目標平臺,且包含使用 intent 過濾器的 activity、服務或廣播接收器,您必須為這些應用組件顯式聲明 android:exported 屬性。
<table> <tr> <td bgcolor=#FCE8E6><font color=#E35251 size =3 face ="黑體" > 警告:如果 activity、服務或廣播接收器使用 intent 過濾器,并且未顯式聲明 android:exported 的值,則您的應用將無法在搭載 Android 12 的設備上進行安裝。</font></td></tr></table>
以下代碼段顯示了一個服務示例,該服務包含 intent 過濾器并針對 Android 12 進行了正確配置:
<service android:name="com.example.app.backgroundService"
android:exported="false">
<intent-filter>
<action android:name="com.example.app.START_BACKGROUND" />
</intent-filter>
</service>
Android Studio 中的消息
如果您的應用包含使用 intent 過濾器的 activity、服務或廣播接收器但未聲明 android:exported,系統(tǒng)會顯示以下警告消息,具體取決于您使用的 Android Studio 版本:
Android Studio 2020.3.1 Canary 11 或更高版本
系統(tǒng)會顯示以下消息:
- 清單文件中會顯示以下 lint 警告:
When using intent filters, please specify android:exported as well
- 當您嘗試編譯應用時,系統(tǒng)會顯示以下 build 錯誤消息:
to specify an explicit value for android:exported when the corresponding \
component has an intent filter defined.```
**較低的 Android Studio 版本**
如果您嘗試安裝應用,Logcat 會顯示以下錯誤消息
```bash
Installation did not succeed.
The application could not be installed: INSTALL_FAILED_VERIFICATION_FAILURE
List of apks:
[0] '.../build/outputs/apk/debug/app-debug.apk'
Installation failed due to: 'null'
待處理 intent 可變性
如果您的應用以 Android 12 為目標平臺,您必須為您的應用創(chuàng)建的每個 PendingIntent 對象指定可變性。這項額外的要求可提高應用的安全性。
如需聲明特定 PendingIntent 對象是否可變,請分別使用 PendingIntent.FLAG_MUTABLE 或 PendingIntent.FLAG_IMMUTABLE 標志。如果您的應用嘗試在不設置任一可變性標志的情況下創(chuàng)建 PendingIntent 對象,系統(tǒng)會拋出 IllegalArgumentException,并在 Logcat 中顯示以下消息:
PACKAGE_NAME: Targeting S+ (version 10000 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.
盡可能創(chuàng)建不可變的待處理 intent
在大多數(shù)情況下,您的應用應創(chuàng)建不可變的 PendingIntent 對象,如以下代碼段所示。如果 PendingIntent 對象不可變,則應用無法修改 intent 來調(diào)整調(diào)用 intent 的結(jié)果。
val pendingIntent = PendingIntent.getActivity(applicationContext,
REQUEST_CODE, intent,
/* flags */ PendingIntent.FLAG_IMMUTABLE)
然而,某些應用需要創(chuàng)建可變的 PendingIntent 對象:
- 通知中的直接回復操作需要變更與回復關聯(lián)的 PendingIntent 對象中的剪輯數(shù)據(jù)。通常,您可以通過將 FILL_IN_CLIP_DATA 作為標志傳遞給 fillIn() 的方法請求此變更。
- 如果您的應用使用 PendingIntent 將對話放在氣泡中,則 intent 應該可變,以便系統(tǒng)可以應用正確的標志,例如 FLAG_ACTIVITY_MULTIPLE_TASK 和 FLAG_ACTIVITY_NEW_DOCUMENT。
如果您的應用創(chuàng)建了可變的 PendingIntent 對象,強烈建議您使用顯式 intent 并填寫 ComponentName。如此一來,每當其他應用調(diào)用 PendingIntent 并將控制權傳回您的應用時,您的應用中的同一組件總是會啟動。
測試待處理的 intent 可變性變更
如需確定您的應用是否缺少可變性聲明,請在 Android Studio 中查找以下 lint 警告:
Warning: Missing PendingIntent mutability flag [UnspecifiedImmutableFlag]
在開發(fā)者預覽版計劃期間,您可以通過關閉 PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED 應用兼容性標志來停用此系統(tǒng)行為以進行測試。
不安全的 intent 啟動
為了提高平臺安全性,Android 12 提供了一種調(diào)試功能,如果您的應用以不安全的方式啟動 intent,此功能便會發(fā)出警告。例如,您的應用可能會以不安全的方式啟動從 URI 重新創(chuàng)建的 intent,或者以不安全的方式啟動下一部分定義的嵌套 intent。
嵌套 intent 簡介
嵌套 intent 是在其他 intent 中作為 extra 傳遞的 intent。如果您的應用執(zhí)行以下兩項操作,就會發(fā)生 StrictMode 違規(guī)行為。
- 您的應用從已傳遞的 intent 的 extra 中解封嵌套 intent。
- 您的應用立即使用該嵌套 intent 啟動應用組件,例如將 intent 傳遞給 startActivity()、startService() 或 bindService()。
配置應用以檢測不安全的 intent 啟動
如需檢查您的應用中是否有不安全的 intent 啟動,請在配置 VmPolicy 時調(diào)用 detectUnsafeIntentLaunch(),如以下代碼段所示。如果您的應用檢測到 StrictMode 違規(guī)行為,您可能需要停止應用的執(zhí)行以保護潛在的敏感信息。
<table> <tr> <td bgcolor= #DBE4FF><font color=#01579B size =3 face ="黑體" >注意:如果您的應用以 Android 12 為目標平臺,并在其 VmPolicy 定義中使用 detectAll() 方法,系統(tǒng)將自動調(diào)用 detectUnsafeIntentLaunch() 方法。</font></td></tr></table>
fun onCreate() {
StrictMode.setVmPolicy(VmPolicy.Builder()
// Other StrictMode checks that you've previously added.
// ...
.detectUnsafeIntentLaunch()
.penaltyLog()
// Consider also adding penaltyDeath()
.build())
}
更負責地使用 intent
您的應用可能會啟動 intent,以便在應用內(nèi)的各個組件之間導航,或代表其他應用執(zhí)行操作。為了在這兩種情況下最大限度地降低出現(xiàn) StrictMode 違規(guī)行為的可能性,請執(zhí)行以下操作:
- 僅復制 intent 中的必要 extra,并執(zhí)行任何必要的清理和驗證。您的應用可能會將 extra 從一個 intent 復制到用于啟動新組件的另一個 intent。當您的應用調(diào)用 putExtras(Intent) 或 putExtras(Bundle) 時,就會發(fā)生這種情況。如果您的應用執(zhí)行這些操作其中之一,請僅復制接收組件所期望的 extra。如果另一個 intent(它接收副本)啟動一個未導出的組件,請先清理和驗證 extra,然后再將其復制到啟動該組件的 intent。
- 嵌套 intent 的內(nèi)部啟動:確保這些組件不會被導出。
Log()
// Consider also adding penaltyDeath()
.build())
}
更負責地使用 intent
您的應用可能會啟動 intent,以便在應用內(nèi)的各個組件之間導航,或代表其他應用執(zhí)行操作。為了在這兩種情況下最大限度地降低出現(xiàn) StrictMode 違規(guī)行為的可能性,請執(zhí)行以下操作:
- 僅復制 intent 中的必要 extra,并執(zhí)行任何必要的清理和驗證。您的應用可能會將 extra 從一個 intent 復制到用于啟動新組件的另一個 intent。當您的應用調(diào)用 putExtras(Intent) 或 putExtras(Bundle) 時,就會發(fā)生這種情況。如果您的應用執(zhí)行這些操作其中之一,請僅復制接收組件所期望的 extra。如果另一個 intent(它接收副本)啟動一個未導出的組件,請先清理和驗證 extra,然后再將其復制到啟動該組件的 intent。
- 嵌套 intent 的內(nèi)部啟動:確保這些組件不會被導出。
- 嵌套 intent 的跨應用啟動:使用 PendingIntent 代替嵌套 intent。如此一來,當 PendingIntent 從包含它的 Intent 中解封時,應用組件可以使用調(diào)用進程的身份啟動 PendingIntent。該配置允許提供程序應用向調(diào)用應用的任何組件(包括未導出的組件)發(fā)送回調(diào)。
性能
前臺服務啟動限制
以 Android 12 為目標平臺的應用再也無法在后臺運行時啟動前臺服務,但一些特殊情況除外。如果應用嘗試在后臺運行時啟動前臺服務,則會引發(fā)異常(少數(shù)特殊情況除外)。當您的應用在后臺運行時,請考慮使用 WorkManager 來計劃和啟動工作。
精確的鬧鐘權限
為了鼓勵應用節(jié)省系統(tǒng)資源,Android 12 要求為以 Android 12 為目標平臺且設置精確的鬧鐘的應用配置“鬧鐘和提醒”特殊應用訪問權限。
如需獲取這種特殊應用訪問權限,請在清單中請求 SCHEDULE_EXACT_ALARM 權限。
精確的鬧鐘只能用于面向用戶的功能,如可接受的用例部分中所述的某種情況。
用戶和系統(tǒng)均可撤消“鬧鐘和提醒”特殊應用訪問權限。為您的應用撤消“鬧鐘和提醒”特殊應用訪問權限后,您的應用會停止,并且將來的所有精確的鬧鐘都會取消。
向您的應用授予“鬧鐘和提醒”特殊應用訪問權限后,系統(tǒng)會向其發(fā)送 ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED 廣播。您的應用應實現(xiàn)廣播接收器,以便執(zhí)行以下操作:
- 確認您的應用仍具有特殊應用訪問權限。為此,請調(diào)用 canScheduleExactAlarms()。
- 根據(jù)應用的當前狀態(tài),重新調(diào)度它所需的任何精確的鬧鐘。此邏輯應與您的應用接收 ACTION_BOOT_COMPLETED 廣播時所執(zhí)行的操作類似。
如果您的應用嘗試使用設置精確的鬧鐘的 API 但未被授予特殊應用訪問權限,會發(fā)生 SecurityException。
<table> <tr> <td bgcolor=#FEEFE3><font color=#D26B4A size =3 face ="黑體" > 注意:當系統(tǒng)觸發(fā)應用設置的精確的鬧鐘時,設備會消耗大量的資源(如電池續(xù)航時間),特別是在它必須離開低電耗模式才能觸發(fā)鬧鐘時。此外,系統(tǒng)無法輕松地對這些請求進行批處理,以便更高效地使用資源。</font></td></tr></table>
考慮一下應用的用例是否確實需要精確的鬧鐘,如可接受的用例部分中所述的某種情況。如需執(zhí)行時間更長的工作或需要接入網(wǎng)絡的工作,請使用 WorkManager 或 JobScheduler。如需在設備處于低電耗模式的同時執(zhí)行工作,請使用 setAndAllowWhileIdle() 創(chuàng)建不精確的鬧鐘,并從該鬧鐘啟動作業(yè)。
精確的鬧鐘和不精確的鬧鐘
您的應用在調(diào)用如下方法時設置精確的鬧鐘:
相比之下,您在調(diào)用如下方法時設置不精確的鬧鐘:
此權限的可接受用例
只有在應用中面向用戶的功能需要精確計時的操作時,例如在以下情況下,應用才應使用精確的鬧鐘,并聲明關聯(lián)的權限和廣播接收器:
- 您的應用是鬧鐘應用或計時器應用。
- 您的應用可讓用戶調(diào)度精確計時的操作,如任務和事件的通知。
Android 12 認為精確的鬧鐘是對時間敏感的緊急中斷。因此,精確的鬧鐘不受新的前臺服務啟動限制的影響。
讓用戶授予應用訪問權限
如有必要,您可以將用戶引導至系統(tǒng)設置中的鬧鐘和提醒屏幕,如圖 2 所示。為此,請完成以下步驟:
- 在應用的界面中,向用戶解釋為什么您的應用需要調(diào)度精確的鬧鐘。
- 調(diào)用包含 ACTION_REQUEST_SCHEDULE_EXACT_ALARM intent 操作的 intent。
啟用行為變更
如需啟用行為變更以進行測試,請執(zhí)行以下某項操作:
- 在開發(fā)者選項設置屏幕中,選擇應用兼容性變更。在顯示的屏幕上,點按應用的名稱,然后開啟 REQUIRE_EXACT_ALARM_PERMISSION。
- 在開發(fā)機器上的終端窗口中,運行以下命令:
adb shell am compat enable REQUIRE_EXACT_ALARM_PERMISSION PACKAGE_NAME
通知 trampoline 限制
當用戶與通知互動時,某些應用會啟動一個應用組件來響應通知點按操作,該應用組件最終會啟動用戶最終看到并與之互動的 activity。此應用組件被稱為通知 trampoline。
為了改進應用性能和用戶體驗,以 Android 12 為目標平臺的應用無法從用作通知 trampoline 的服務或廣播接收器中啟動 activity。換言之,當用戶點按通知或通知中的操作按鈕時,您的應用無法在服務或廣播接收器內(nèi)調(diào)用 startActivity()。
當您的應用嘗試從充當通知 trampoline 的服務或廣播接收器啟動 activity 時,系統(tǒng)會阻止該 activity 啟動,并在 Logcat 中顯示以下消息:
Indirect notification activity start (trampoline) from PACKAGE_NAME, \
this should be avoided for performance reasons.
識別哪些應用組件充當通知 trampoline
測試您的應用時,點按通知后,您可以識別哪個服務或廣播接收器在您的應用中充當通知 trampoline。為此,請查看以下終端命令的輸出:
adb shell dumpsys activity service \
com.android.systemui/.dump.SystemUIAuxiliaryDumpService
輸出的某一部分包含文本“NotifInteractionLog”。此部分包含識別因點按通知而啟動的組件所需的信息。
更新應用
如果您的應用從充當通知 trampoline 的服務或廣播接收器啟動 activity,請完成以下遷移步驟:
- 創(chuàng)建一個與用戶點按通知后看到的 activity 關聯(lián)的 PendingIntent 對象。
- 在構建通知的過程中,使用您在上一步中創(chuàng)建的 PendingIntent 對象。
如需識別 activity 的來源,例如為了執(zhí)行日志記錄,請在發(fā)布通知時使用 extra。對于集中式日志記錄,請使用 ActivityLifecycleCallbacks 或 Jetpack 生命周期觀察器。
切換行為
在開發(fā)者預覽版計劃期間測試您的應用時,您可以使用 NOTIFICATION_TRAMPOLINE_BLOCK 應用兼容性標志啟用和停用此限制。
備份和恢復
對于在 Android 12 上運行且以其為目標平臺的應用,備份和恢復的工作方式發(fā)生了變化。Android 備份和恢復有兩種形式:
- 云端備份:用戶數(shù)據(jù)存儲在用戶的 Google 云端硬盤中,以便之后可以在相應設備或新設備上恢復。
- 設備到設備 (D2D) 傳輸:用戶數(shù)據(jù)直接從用戶的舊設備發(fā)送到其新設備,如通過使用數(shù)據(jù)線。
如需詳細了解如何備份和恢復數(shù)據(jù),請參閱通過自動備份功能備份用戶數(shù)據(jù)和使用 Android Backup Service 備份鍵值對。
D2D 傳輸功能變更
對于在 Android 12 及更高版本上運行且以其為目標平臺的應用:
指定 android:allowBackup="false" 會禁止備份到 Google 云端硬盤,但不會停用應用的 D2D 傳輸這種方式。
使用 XML 配置機制指定包含和排除規(guī)則不再影響 D2D 傳輸,不過仍影響 Google 云端硬盤備份。如需指定 D2D 傳輸?shù)囊?guī)則,您必須使用下一部分中所述的新配置。
新的包含和排除格式
在 Android 12 及更高版本上運行且以其為目標平臺的應用對 XML 配置使用不同的格式。這種格式要求您分別為云端備份和 D2D 傳輸指定包含和排除規(guī)則,從而明確區(qū)分 Google 云端硬盤備份和 D2D 傳輸。
(可選)您還可以使用它來指定備份的規(guī)則,在這種情況下,系統(tǒng)會忽略舊配置。
<table> <tr> <td bgcolor= #DBE4FF><font color=#01579B size =3 face ="黑體" >注意:如果您使用新配置格式,您的應用將使用新行為,即使您尚未以 Android 12 為目標平臺也是如此。</font></td></tr></table>
XML 格式變更
下面是 Android 11 及更低版本中用于備份和恢復配置的格式:
<full-backup-content>
<include domain=["file" | "database" | "sharedpref" | "external" |
"root"] path="string"
requireFlags=["clientSideEncryption" | "deviceToDeviceTransfer"] />
<exclude domain=["file" | "database" | "sharedpref" | "external" |
"root"] path="string" />
</full-backup-content>
下面以粗體顯示了格式的變更。
<data-extraction-rules>
<cloud-backup [disableIfNoEncryptionCapabilities="true|false"]>
...
<include domain=["file" | "database" | "sharedpref" | "external" |
"root"] path="string"/>
...
<exclude domain=["file" | "database" | "sharedpref" | "external" |
"root"] path="string"/>
...
</cloud-backup>
<device-transfer>
...
<include domain=["file" | "database" | "sharedpref" | "external" |
"root"] path="string"/>
...
<exclude domain=["file" | "database" | "sharedpref" | "external" |
"root"] path="string"/>
...
</device-transfer>
</data-extraction-rules>
配置的每一部分(<cloud-backup> 和 <device-transfer>)包含僅適用于該特定傳輸類型的規(guī)則。例如,這樣可讓您從 Google 云端硬盤備份中排除某個文件或目錄,同時仍在 D2D 傳輸過程中傳輸該文件或目錄。如果您的文件太大而無法備份到云端,但可以在設備之間毫無問題地傳輸,這可能會很有用。
如果您沒有為某種特定的備份模式指定規(guī)則(例如,如果缺少 <device-transfer> 部分),則系統(tǒng)會為除 no-backup 和 cache 目錄之外的所有內(nèi)容完全啟用該模式,如備份的文件中所述。
您的應用可以在 <cloud-backup> 部分中設置 disableIfNoEncryptionCapabilities 標志,以確保只有在可以加密時(例如,當用戶具有鎖定屏幕時)備份操作才會發(fā)生。如果用戶的設備無法支持加密,設置此約束條件可阻止將備份內(nèi)容發(fā)送到云端,但由于不會將 D2D 傳輸內(nèi)容發(fā)送到服務器,因此即使在不支持加密的設備上,D2D 傳輸也會繼續(xù)執(zhí)行。
應用的清單標志
通過在清單文件中使用 android:dataExtractionRules 屬性,將您的應用指向新的 XML 配置。當您指向新的 XML 配置時,系統(tǒng)會忽略指向舊配置的 android:fullBackupContent 屬性。以下代碼示例展示了新的清單文件條目:
<application
...
<!-- The below attribute is ignored. -->
android:fullBackupContent="old_config.xml"
<!-- You can point to your new configuration using the new
dataExtractionRules attribute . -->
android:dataExtractionRules="new_config.xml"
...>
</application>
連接性
并發(fā)點對點 + 互聯(lián)網(wǎng)連接
從 Android 12 開始,支持并發(fā)點對點和互聯(lián)網(wǎng)連接的設備可以保持與對等設備和互聯(lián)網(wǎng)提供的主要網(wǎng)絡的并發(fā) Wi-Fi 連接,從而使用戶體驗更加順暢。系統(tǒng)會自動為以 API 級別 31 及更高級別為目標的所有應用啟用此功能。以較低 API 級別為目標的應用仍會體驗舊行為,即在連接到對等設備之前會斷開主要 Wi-Fi 網(wǎng)絡。
兼容性
WifiManager.getConnectionInfo() 只能返回一個網(wǎng)絡的 WifiInfo。因此,該 API 的行為在 Android 12 中從以下幾個方面發(fā)生了變化:
- 如果只有一個 Wi-Fi 網(wǎng)絡可用,則返回其 WifiInfo。
- 如果有多個 Wi-Fi 網(wǎng)絡可用,并且發(fā)起調(diào)用的應用觸發(fā)了點對點連接,則返回與對等設備對應的 WifiInfo。
- 如果有多個 Wi-Fi 網(wǎng)絡可用,并且發(fā)起調(diào)用的應用未觸發(fā)點對點連接,則返回互聯(lián)網(wǎng)提供的主要連接的 WifiInfo。
為了在支持雙并發(fā) Wi-Fi 網(wǎng)絡的設備上提供更好的用戶體驗,我們建議所有應用(特別是觸發(fā)點對點連接的應用)脫離調(diào)用 WifiManager.getConnectionInfo(),而改用 NetworkCallback.onCapabilitiesChanged(),以獲取與用于注冊 NetworkCallback 的 NetworkRequest 匹配的所有 WifiInfo 對象。從 Android 12 開始,棄用了 getConnectionInfo()。
以下代碼示例展示了如何在 NetworkCallback 中獲取 WifiInfo:
val networkCallback = object : ConnectivityManager.NetworkCallback() {
...
override fun onCapabilitiesChanged(
network : Network,
networkCapabilities : NetworkCapabilities) {
val transportInfo = networkCapabilities.getTransportInfo()
if (transportInfo !is WifiInfo) return
val wifiInfo : WifiInfo = transportInfo
...
}
}
為 NFC 付款啟用屏幕關閉
在以 Android 12 及更高版本為目標平臺的應用中,您可以通過將 requireDeviceScreenOn 設置為 false,在設備屏幕未打開的情況下啟用 NFC 付款。
供應商庫
供應商提供的原生共享庫
如果應用以 Android 12 或更高版本為目標平臺,默認情況下無法訪問由芯片供應商或設備制造商提供的非 NDK 原生共享庫。只有在使用 <uses-native-library> 標記明確請求時,才能訪問這些庫。
如果應用以 Android 11 或更低版本為目標平臺,則無需使用 <uses-native-library> 標記。在這種情況下,任何原生共享庫均可訪問,而不管它是否為 NDK 庫。
更新后的非 SDK 限制
Android 12 包含更新后的受限制非 SDK 接口列表(基于與 Android 開發(fā)者之間的協(xié)作以及最新的內(nèi)部測試)。在限制使用非 SDK 接口之前,我們會盡可能確保有可用的公開替代方案。
如果您的應用并非以 Android 12 為目標平臺,其中一些變更可能不會立即對您產(chǎn)生影響。然而,雖然您目前仍可以使用一些非 SDK 接口(具體取決于應用的目標 API 級別),但只要您使用任何非 SDK 方法或字段,終歸存在導致應用出問題的顯著風險。
如果您不確定自己的應用是否使用了非 SDK 接口,則可以測試您的應用來進行確認。如果您的應用依賴于非 SDK 接口,您應該開始計劃遷移到 SDK 替代方案。然而,我們知道某些應用具有使用非 SDK 接口的有效用例。如果您無法為應用中的某項功能找到使用非 SDK 接口的替代方案,應請求新的公共 API。
廢棄
隨著每個版本的發(fā)布,特定的 Android API 可能會過時或需要進行重構,以提供更好的開發(fā)者體驗或支持新的平臺功能。在這些情況下,Android 將正式廢棄過時的 API,并引導開發(fā)者改用新的 API。
廢棄意味著我們已結(jié)束對這些 API 的正式支持,但它們將繼續(xù)可供開發(fā)者使用。本頁重點介紹此 Android 版本中廢棄的一些 API。如需查看廢棄的其他 API,請參閱 API 差異報告。
RenderScript
從 Android 12 開始,廢棄了 RenderScript API。它們將繼續(xù)正常運行,但我們預計設備和組件制造商會逐漸停止提供硬件加速支持。為充分利用 GPU 加速功能,我們建議停止使用 RenderScript。
Android 播放列表
廢棄了 Android 播放列表。不再維護該 API,但為了兼容性而保留了當前的功能。
我們建議以 m3u 文件的形式讀取和保存播放列表。
廢棄了 Display API
Android 設備有許多不同的外形規(guī)格,如大屏設備、平板電腦和可折疊設備。為了針對每種設備適當?shù)爻尸F(xiàn)內(nèi)容,您的應用需要確定屏幕或顯示屏尺寸。隨著時間的推移,Android 提供了不同的 API 來檢索此信息。在 Android 11 中,我們引入了 WindowMetrics API 并廢棄了以下方法:
在 Android 12 中,我們繼續(xù)建議使用 WindowMetrics,并且正在逐步廢棄以下方法:
應用應使用 WindowMetrics API 查詢其窗口的邊界,或使用 Configuration.densityDpi 查詢當前的密度。
請注意,Jetpack WindowManager 庫包含一個 WindowMetrics 類,該類支持 Android 4.0.1(API 級別 14)及更高版本。
示例
下面是一些關于如何使用 WindowMetrics 的示例。
首先,確保您的應用可使其 activity 完全可調(diào)整大小。
activity 應依賴于來自 activity 上下文的 WindowMetrics 來執(zhí)行任何與界面相關的工作,特別是 WindowManager.getCurrentWindowMetrics()。
如果您的應用創(chuàng)建了 MediaProjection,則必須正確地調(diào)整邊界的大小,因為投影會捕捉顯示內(nèi)容。如果應用完全可調(diào)整大小,則 activity 上下文會返回正確的邊界。
WindowMetrics projectionMetrics = activityContext
.getSystemService(WindowManager.class).getMaximumWindowMetrics();
如果應用并非完全可調(diào)整大小,則必須從 WindowContext 實例查詢邊界,并使用 WindowManager.getMaximumWindowMetrics() 檢索應用可用的最大顯示區(qū)域的 WindowMetrics。
Context windowContext = mContext.createWindowContext(mContext.getDisplay(),
TYPE_APPLICATION, null /* options */);
WindowMetrics projectionMetrics = windowContext.getWindowManager()
.getMaximumWindowMetrics();
<table> <tr> <td bgcolor= #DBE4FF><font color=#01579B size =3 face ="黑體" >注意:使用 MediaProjection 的任何庫也應遵循此建議,并查詢應用窗口的相應 WindowMetrics。</font></td></tr></table>