行為變更:指定 Android 12 的應用程式

和先前版本一樣,Android 12 也包含可能會影響應用程式的行為變更。以下行為變更僅適用於指定 Android 12 以上版本的應用程式。如果您的應用程式指定 Android 12 版本,建議您視情況修改應用程式,以支援這些行為。

此外,請務必查看影響所有在 Android 12 中執行的應用程式的行為變更清單。

使用者體驗

自訂通知

Android 12 會變更完全自訂通知的外觀和行為。之前,自訂通知可以使用整個通知區域,並提供自己的版面配置和樣式。這會導致反面模式,讓使用者感到困惑,或導致不同裝置上的版面配置相容性問題。

針對以 Android 12 為目標版本的應用程式,具有自訂內容檢視畫面的通知將不再使用整個通知區域;系統會改為套用標準範本。這個範本可確保自訂通知在所有狀態下採用與其他通知相同的裝飾,例如通知的圖示和展開功能 (處於收合狀態),以及通知的圖示、應用程式名稱和收合預設用途 (在展開狀態中)。這個行為與 Notification.DecoratedCustomViewStyle 的行為幾乎相同。

如此一來,Android 12 會將所有通知視覺化,而且一目瞭然,方便使用者輕鬆查看通知。

下圖顯示標準範本的自訂通知:

以下範例說明自訂通知在收合和展開狀態時的顯示方式:

Android 12 的變更會影響定義 Notification.Style 自訂子類別的應用程式,或定義使用 Notification.Builder 方法 setCustomContentView(RemoteViews)setCustomBigContentView(RemoteViews)setCustomHeadsUpContentView(RemoteViews) 的應用程式。

如果您的應用程式使用的是完全自訂的通知,建議您盡快使用新範本進行測試。

  1. 啟用自訂通知變更:

    1. 將應用程式的 targetSdkVersion 變更為 S,啟用新行為。
    2. 重新編譯。
    3. 在搭載 Android 12 的裝置或模擬器上安裝應用程式。
  2. 測試所有使用自訂檢視畫面的通知,確保這些通知的外觀與預期相符。測試時,請將下列考量納入考量,並做出必要的調整:

    • 自訂檢視畫面的維度已變更。一般來說,自訂通知所承受的高度不如以往。在收合狀態下,自訂內容的高度上限已從 106 dp 降至 48 dp。此外,水平空間較少。

    • 針對指定 Android 12 為目標版本的應用程式,所有通知皆可展開。一般而言,這意味著,如果您使用 setCustomContentView,也會希望使用 setBigCustomContentView,確保收合和展開的狀態保持一致。

    • 為確保「看路提醒」狀態能正常顯示,別忘了將通知管道的重要性提高為「高」(畫面上彈出)。

針對指定 Android 12 或以上版本的應用程式,系統會對 Android 應用程式連結的驗證方式做出幾項變更。這些變更可改善應用程式連結體驗的可靠性,並進一步掌控應用程式開發人員和使用者。

如果您仰賴 Android 應用程式連結驗證功能開啟應用程式中的網頁連結,在新增意圖篩選器以執行 Android 應用程式連結驗證時,請檢查使用的格式是否正確。特別是,請確認這些意圖篩選器包含 BROWSABLE 類別,並支援 https 配置。

您也可以手動驗證應用程式連結,測試宣告的可靠性。

改善子母畫面行為

Android 12 針對子母畫面 (PiP) 模式推出了行為改善,並針對手勢瀏覽和元素導向導覽作業,改善轉場動畫效果的建議外觀。

詳情請參閱「子母畫面改善項目」。

吐司重新設計

在 Android 12 中,我們重新設計了 toast 檢視畫面。浮動式訊息現在限制為兩行文字,並在文字旁顯示應用程式圖示。

圖中的 Android 裝置顯示彈出的浮動式訊息,而訊息內的應用程式圖示旁顯示「正在傳送郵件」

詳情請參閱「浮動式訊息總覽」。

安全性和隱私權

概略位置

在搭載 Android 12 以上版本的裝置上,使用者可以要求應用程式的概略位置精確度

WebView 中的新型 SameSite Cookie

Android 的 WebView 元件是以 Chromium 為基礎,Chromium 是支援 Google Chrome 瀏覽器的開放原始碼專案。Chromium 對第三方 Cookie 處理方式進行了調整,以提升安全性和隱私性,並讓使用者更清楚瞭解相關資訊。自 Android 12 起,如果應用程式指定 Android 12 (API 級別 31) 以上版本,這些變更也會納入 WebView 中。

Cookie 的 SameSite 屬性可控制這個值可隨任何要求傳送,還是只能透過相同網站要求傳送。下列隱私權保護變更可以改善第三方 Cookie 的預設處理方式,並協助防範非預期的跨網站分享行為:

  • 系統會將沒有 SameSite 屬性的 Cookie 視為 SameSite=Lax
  • 具有 SameSite=None 的 Cookie 也必須指定 Secure 屬性,這代表這些 Cookie 需要安全的環境,並且應透過 HTTPS 傳送。
  • 網站的 HTTP 和 HTTPS 版本之間的連結現在會視為跨網站要求,因此除非 Cookie 已適當標示為 SameSite=None; Secure,否則系統不會傳送 Cookie。

對開發人員來說,一般而言,原則是找出重要使用者流程中的跨網站 Cookie 依附元件,並確保已視需要為 SameSite 屬性明確設定適當的值。您必須明確指定哪些 Cookie 能夠在從 HTTP 遷移至 HTTPS 的網站或跨網站導覽中運作。

如需網頁程式開發人員想瞭解這些變更的完整指南,請參閱「SameSite Cookie 說明」和「Schemeful SameSite」。

在應用程式中測試 SameSite 行為

如果您的應用程式使用 WebView,或者您管理的網站/服務使用 Cookie,建議您在 Android 12 WebView 上測試流程。如果發現問題,您可能需要更新 Cookie 以支援新的 SameSite 行為。

請留意登入和嵌入內容發生的問題、登入流程、購買和其他驗證流程,也就是使用者先從不安全的網頁開始進入安全網頁。

如要使用 WebView 測試應用程式,則必須完成下列任一步驟,為要測試的應用程式啟用新的 SameSite 行為:

如要進一步瞭解如何在 Android 裝置上對 WebView 進行遠端偵錯,請參閱「開始使用 Android 裝置的遠端偵錯功能」。

其他資源

如要進一步瞭解 SameSite 新行為以及如何推出 Chrome 和 WebView,請參閱 Chromium SameSite 更新頁面。如果您在 WebView 或 Chromium 中發現錯誤,可以透過公開的 Chromium Issue Tracker 回報。

動作感應器設有頻率限制

為保護使用者的潛在機密資訊,如果應用程式指定 Android 12 以上版本,系統會限制特定動作感應器和位置感應器提供的資料刷新率。

進一步瞭解感應器頻率限制

應用程式休眠

Android 12 則是以 Android 11 (API 級別 30) 推出的自動重設權限行為為基礎。如果應用程式以 Android 12 為目標版本,且使用者已連續數月未與應用程式互動,系統會自動重設任何授予的權限,並將應用程式設為「休眠」狀態。

詳情請參閱應用程式休眠指南。

資料存取稽核中的歸因宣告

Android 11 (API 級別 30) 中推出的資料存取稽核 API 可讓您根據應用程式的用途建立歸因標記。這些標記可讓您更輕鬆地判斷應用程式的哪些部分會執行特定類型的資料存取權。

如果應用程式指定 Android 12 以上版本,您必須在應用程式的資訊清單檔案中宣告這些歸因標記

ADB 備份限制

為保護私人應用程式資料,Android 12 會變更 adb backup 指令的預設行為。對於指定 Android 12 (API 級別 31) 以上版本的應用程式,當使用者執行 adb backup 指令時,從裝置匯出的任何其他系統資料都不會涵蓋應用程式資料。

如果您的測試或開發工作流程仰賴使用 adb backup 的應用程式資料,您現在可選擇在應用程式資訊清單檔案中將 android:debuggable 設為 true,選擇匯出應用程式的資料。

更安全的元件匯出功能

如果應用程式指定 Android 12 以上版本,且包含使用意圖篩選器活動服務廣播接收器,您必須為這些應用程式元件明確宣告 android:exported 屬性。

如果應用程式元件包含 LAUNCHER 類別,請將 android:exported 設為 true。在大多數情況下,請將 android:exported 設為 false

以下程式碼片段為包含意圖篩選器的服務範例,該篩選器的 android:exported 屬性設為 false

<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 中的訊息

如果應用程式包含使用意圖篩選器的活動、服務或廣播接收器,但並未宣告 android:exported,系統會根據您使用的 Android Studio 版本顯示以下警告訊息:

Android Studio 2020.3.1 Canary 11 或以上版本

系統會顯示以下訊息:

  1. 資訊清單檔案中會顯示下列 Lint 警告:

    When using intent filters, please specify android:exported as well
    
  2. 嘗試編譯應用程式時,系統會顯示以下建構錯誤訊息:

    Manifest merger failed : Apps targeting Android 12 and higher are required \
    to specify an explicit value for android:exported when the corresponding \
    component has an intent filter defined.
    
舊版 Android Studio

如果您嘗試安裝應用程式,Logcat 會顯示下列錯誤訊息:

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'

待處理意圖的可變動性

如果應用程式以 Android 12 為目標版本,則必須為應用程式所建立的每個 PendingIntent 物件指定可變動性。這項額外規定有助於提高應用程式的安全性。

測試待處理的意圖可變動性變更

如要判斷應用程式是否缺少可變動性宣告,請在 Android Studio 中尋找以下 Lint 警告

Warning: Missing PendingIntent mutability flag [UnspecifiedImmutableFlag]

啟動不安全的意圖

為了提高平台安全性,Android 12 以上版本提供偵錯功能,可偵測不安全的意圖啟動情形。當系統偵測到這類不安全的啟動行為時,就會發生 StrictMode 違規事項。

效能

前景服務啟動限制

指定 Android 12 以上版本為目標的應用程式無法在背景執行時啟動前景服務,但少數特殊情況除外。如果應用程式嘗試在背景執行時啟動前景服務,就會發生例外狀況 (少數特殊情況除外)。

在應用程式於背景執行的情況下,建議您使用 WorkManager 安排及啟動加急作業。如要完成使用者要求且具時效性的動作,請在精確鬧鐘中啟動前景服務。

精確鬧鐘權限

為鼓勵應用程式節省系統資源,如果應用程式指定 Android 12 以上版本且設定精確鬧鐘,就必須在系統設定中的「特殊應用程式存取權」畫面中找到「鬧鐘與提醒」功能的存取權。

如要取得這個特殊的應用程式存取權,請在資訊清單中要求 SCHEDULE_EXACT_ALARM 權限。

精確鬧鐘只能用於面向使用者的功能。進一步瞭解設定精確鬧鐘的使用限制

停用行為變更功能

準備讓應用程式指定 Android 12 時,可以基於測試目的,在可進行偵錯的建構變化版本中暫時停用行為變更。如要解除安裝,請完成下列其中一項工作:

  • 在「開發人員選項」設定畫面中,選取「應用程式相容性變更」。在隨即顯示的畫面中,輕觸應用程式名稱,然後關閉 REQUIRE_EXACT_ALARM_PERMISSION
  • 在開發機器的終端機視窗中執行下列指令:

    adb shell am compat disable REQUIRE_EXACT_ALARM_PERMISSION PACKAGE_NAME
    

通知彈跳床限制

當使用者與通知互動時,有些應用程式會啟動應用程式元件,以回應輕觸通知的動作,該元件最終會啟動使用者最終查看並互動的活動。這個應用程式元件稱為「通知彈跳床」

為提升應用程式效能和使用者體驗,如果應用程式指定 Android 12 以上版本,則無法透過做為通知彈跳床的服務廣播接收器啟動活動。換句話說,使用者輕觸特定通知或通知中的動作按鈕後,應用程式就無法在服務或廣播接收器內呼叫 startActivity()

當應用程式嘗試從具有通知彈跳床的服務或廣播接收器啟動活動時,系統會阻止活動啟動,且 Logcat 中會顯示以下訊息:

Indirect notification activity start (trampoline) from PACKAGE_NAME, \
this should be avoided for performance reasons.

找出做為通知彈跳床的應用程式元件

測試應用程式時,輕觸通知後,您可以識別在應用程式中做為通知彈跳床的服務或廣播接收器。如要這麼做,請查看下列終端機指令的輸出內容:

adb shell dumpsys activity service \
  com.android.systemui/.dump.SystemUIAuxiliaryDumpService

輸出結果中有部分包含「NotifInteractionLog」這段文字。本節包含必要資訊,用於辨識輕觸通知後啟動的元件。

更新應用程式

如果應用程式是透過做為通知彈跳床的服務或廣播接收器啟動活動,請完成下列遷移步驟:

  1. 建立 PendingIntent 物件,請將其與使用者輕觸通知後看見的活動建立關聯。
  2. 使用在建構通知時在上一個步驟中建立的 PendingIntent 物件。

如要識別活動的來源,請在發布通知時使用額外項目,以便執行記錄功能。如要集中管理,請使用 ActivityLifecycleCallbacksJetpack 生命週期觀察器

切換行為

測試應用程式的可偵錯版本時,您可以使用 NOTIFICATION_TRAMPOLINE_BLOCK 應用程式相容性標記啟用及停用這項限制。

備份與還原

在以 Android 12 (API 級別 31) 為目標版本中執行的應用程式,備份和還原功能的運作方式有所變更。Android 備份與還原功能有兩種形式:

  • 雲端備份:使用者資料會儲存在使用者的 Google 雲端硬碟中,以便日後在該裝置或新裝置上還原。
  • 裝置對裝置 (D2D) 傳輸:使用者資料直接從舊裝置傳送到使用者新裝置,例如使用傳輸線。

如要進一步瞭解如何備份及還原資料,請參閱「使用自動備份功能備份使用者資料」和「使用 Android Backup Service 備份鍵/值組合」。

D2D 傳輸功能異動

如果是在搭載 Android 12 以上版本執行且指定 Android 12 以上版本為目標的應用程式:

  • 使用 XML 設定機制指定 include 和排除規則並不會影響 D2D 傳輸,但仍會影響雲端型備份與還原 (例如 Google 雲端硬碟備份) 的資料。如要指定 D2D 移轉作業的規則,您必須使用下一節所述的新設定。

  • 在某些裝置製造商的裝置上,指定 android:allowBackup="false" 會停用將資料備份至 Google 雲端硬碟的功能,但不會停用應用程式的 D2D 傳輸。

新增納入和排除格式

在 Android 12 以上版本執行且指定 Android 12 以上版本執行的應用程式會使用其他格式進行 XML 設定。這種格式會要求您分別針對雲端備份和 D2D 傳輸指定納入及排除規則,藉此明確區分 Google 雲端硬碟備份和 D2D 傳輸。

或者,您也可以使用這個項目指定備份規則。在這種情況下,搭載 Android 12 以上版本的裝置會忽略先前的設定。搭載 Android 11 以下版本的裝置仍需採用較舊的設定。

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>

詳情請參閱使用自動備份功能備份使用者資料指南中的對應章節

應用程式資訊清單標記

在資訊清單檔案中使用 android:dataExtractionRules 屬性,將應用程式指向新的 XML 設定。指向新的 XML 設定時,搭載 Android 12 以上版本的裝置會忽略指向舊設定的 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>

連線能力

藍牙權限

Android 12 導入了 BLUETOOTH_SCANBLUETOOTH_ADVERTISEBLUETOOTH_CONNECT 權限。這些權限可讓以 Android 12 為目標版本的應用程式更容易與藍牙裝置互動,尤其是不需要存取裝置位置資訊的應用程式。

如要讓裝置做好指定 Android 12 或以上版本的準備,請更新應用程式的邏輯。請勿宣告舊版藍牙權限組合,而應宣告更新型藍牙權限

同時點對點 + 網際網路連線

針對指定 Android 12 (API 級別 31) 以上版本的應用程式,支援同時點對點和網際網路連線的裝置可以同時與對等互連裝置和提供網際網路提供的主要網路的 Wi-Fi 連線,讓使用者體驗更加流暢。指定 Android 11 (API 級別 30) 以下版本的應用程式仍會發生舊版行為,也就是主要 Wi-Fi 網路在連線至對等裝置前會中斷連線。

相容性

WifiManager.getConnectionInfo() 只能針對單一網路傳回 WifiInfo。因此,在 Android 12 以上版本中,API 的行為已變更如下:

  • 如果只有一個 Wi-Fi 網路,系統會傳回其 WifiInfo
  • 如果可以使用多個 Wi-Fi 網路,且呼叫的應用程式觸發了點對點連線,系統會傳回與對等裝置對應的 WifiInfo
  • 如果可以使用多個 Wi-Fi 網路,且呼叫應用程式並未觸發點對點連線,系統會傳回提供主要網際網路連線的主要連線 WifiInfo

如要在支援雙並行 Wi-Fi 網路的裝置上提供更優質的使用者體驗,建議您從呼叫 WifiManager.getConnectionInfo() 遷移所有應用程式 (特別是會觸發點對點連線的應用程式),然後改用 NetworkCallback.onCapabilitiesChanged(),取得用於註冊 NetworkCallback 的所有 WifiInfo 物件。NetworkRequestgetConnectionInfo() 已於 Android 12 淘汰。

以下程式碼範例說明如何在 NetworkCallback 中取得 WifiInfo

Kotlin

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
    ...
  }
}

Java

final NetworkCallback networkCallback = new NetworkCallback() {
  ...
  @Override
  public void onCapabilitiesChanged(
         Network network,
         NetworkCapabilities networkCapabilities) {
    final TransportInfo transportInfo = networkCapabilities.getTransportInfo();
    if (!(transportInfo instanceof WifiInfo)) return;
    final WifiInfo wifiInfo = (WifiInfo) transportInfo;
    ...
  }
  ...
};

mDNSResponseer 原生 API

當應用程式可使用 mDNSResponseer 原生 API 與 mDNSResponder Daemon 互動,Android 12 會有所變更。以前,當應用程式在網路上註冊服務並呼叫 getSystemService() 方法時,即使應用程式尚未呼叫任何 NsdManager 方法,系統的 NSD 服務也會啟動 mDNSResponder Daemon。接著 Daemon 會將裝置訂閱所有節點的多點傳送群組,讓系統更頻繁地喚醒裝置,並增加用電量。為盡量減少電池用量,現在在 Android 12 以上版本中,系統只會在需要用於 NSD 事件時啟動 mDNSResponder Daemon,並在之後停止執行該 Daemon。

由於這項變更會影響 mDNSResponseer Daemon 何時可用,因此如果應用程式假設 mDNSResponseer Daemon 會在呼叫 getSystemService() 方法後啟動,系統可能會傳送表示 mDNSResponder Daemon 無法使用的訊息。如果應用程式使用 NsdManager 且未使用 mDNSResponder 原生 API,則不會受到這項異動的影響。

供應商程式庫

供應商提供的原生共用程式庫

根據預設,如果應用程式指定 Android 12 (API 級別 31) 以上版本,則無法存取由晶片供應商或裝置製造商提供的非 NDK 原生共用程式庫。只有使用 <uses-native-library> 標記明確要求時,才能存取這些程式庫。

如果應用程式指定 Android 11 (API 級別 30) 以下版本,則不需要 <uses-native-library> 標記。在這種情況下,任何原生共享程式庫均可存取,無論其是否為 NDK 程式庫。

更新非 SDK 限制

基於與 Android 開發人員合作及最新的內部測試,Android 12 包含更新後的受限制非 SDK 介面清單。在限制非 SDK 介面之前,我們盡可能確保公開替代方案的可得性。

如果您的應用程式並不是以 Android 12 為目標版本,則此處所述的某些變更可能不會立即對您造成影響。不過,雖然您目前可以使用某些非 SDK 介面 (視應用程式的目標 API 級別而定),但使用任何非 SDK 方法或欄位時,都會面臨應用程式中斷的高風險。

如果不確定應用程式是否使用非 SDK 介面,可對應用程式進行測試以便確認。如果您的應用程式仰賴非 SDK 介面,則建議您開始規劃遷移至 SDK 替代方案。我們瞭解有些應用程式可使用非 SDK 介面運作。如果您除了為應用程式中的某個功能使用非 SDK 介面外,已別無他法,則應要求新的公用 API

如要進一步瞭解此 Android 版本中的變更,請參閱 Android 12 的非 SDK 介面限制更新內容。如要進一步瞭解非 SDK 介面的一般資訊,請參閱非 SDK 介面的限制