Android 7.0 行為變更

除了新功能外,Android 7.0 包括各種系統和 API 行為變更。這份文件 重點列出您必須瞭解並納入考量的幾項重要異動 。

如果您先前曾發布 Android 應用程式,請注意, 可能會受到這些異動影響

電池與記憶體

為提升電池續航力,Android 7.0 包含系統行為變更 以及降低 RAM 用量這些變更可能會影響應用程式存取 系統資源,以及您的應用程式透過 特定隱含意圖

打盹

在 Android 6.0 (API 級別 23) 中推出,打盹功能可透過 在使用者將裝置未插電時延後處理 CPU 和網路活動 並關閉螢幕Android 7.0 進一步 套用部分 CPU 和網路限制來強化打盹功能 螢幕關閉時 例如手機在使用者口袋中移動時。

插圖:打盹功能如何在第一層
  系統活動限制,以便延長電池續航力

圖 1. 插圖:打盹功能如何在第一層 系統活動限制,以便延長電池續航力。

裝置使用電池供電,且螢幕關閉時 時,裝置會進入「打盹」模式並套用第一部分的限制: 會關閉應用程式網路存取權,並延後工作和同步處理作業。如果裝置 進入打盹模式後一段時間,系統將採用 其他的打盹限制功能 (PowerManager.WakeLock) AlarmManager 個鬧鐘、GPS 和 Wi-Fi 掃描。無論如何 無論是否套用部分或所有打盹限制,系統都會喚醒 裝置短暫進行維護,期間允許應用程式 網路存取,並能執行任何延遲的工作/同步處理。

插圖:打盹如何套用第二層
  裝置閒置一段時間後的系統活動限制

圖 2. 插圖:打盹如何套用第二層 裝置閒置一段時間後的系統活動限制。

請注意,啟用裝置的螢幕或接上電源會結束「打盹」模式, 移除這些處理限制其他行為 需要先採用 Android 6.0 (API 級別 23) 中導入的 Doze 版本,如 針對打盹和應用程式待命進行最佳化。建議您 遵循這些建議 (如使用 Firebase 雲端通訊 (FCM)) 收發訊息,並開始規劃更新時程,配合 其他打盹行為。

Svelte 專案:背景最佳化

Android 7.0 移除了三個隱含廣播訊息,以便最佳化這兩者 記憶體用量與耗電量這項變更是必要的,因為隱含 廣播訊息經常啟動已註冊聆聽音訊的應用程式 背景工作。移除這類廣播訊息會對裝置造成很大的助益 效能和使用者體驗

行動裝置的連線速度頻繁,例如移動時 。目前,應用程式可以監控以下項目的變化: 針對隱式 CONNECTIVITY_ACTION 廣播訊息註冊接收器 資訊清單。由於許多應用程式都註冊以便接收這則廣播訊息,因此單一 網路開關可能會導致它們全部喚醒並在時間處理廣播。 一次。

同樣地,在舊版 Android 中,應用程式可以註冊接收來自其他應用程式的隱含 ACTION_NEW_PICTUREACTION_NEW_VIDEO 廣播訊息,例如 攝影機:當使用者透過相機應用程式拍照時,會喚醒這些應用程式 處理廣播。

為減輕這些問題的影響,Android 7.0 會套用下列功能 最佳化:

如果應用程式使用上述任一意圖,您應移除依附元件 以便您正確指定 Android 7.0 裝置。 Android 架構提供數種解決方案,可降低 這些隱式廣播訊息舉例來說,JobScheduler API 提供強大的排程機制 在任何指定條件下執行網路作業,例如連線至 而非計量付費網路您甚至可以使用 JobScheduler 來回應內容供應器的變更。

進一步瞭解 Android 7.0 (API 級別) 的背景最佳化功能 24) 以及如何調整應用程式,請參閱背景 最佳化

權限變更

Android 7.0 包含對應用程式造成影響的權限變更。

檔案系統權限變更

為提升私人檔案的安全性, 指定 Android 7.0 以上版本的應用程式將限制存取權 (0700)。 這項設定可避免私人檔案的中繼資料外洩 (例如檔案大小) 或是存在這項權限變更造成多項副作用:

在應用程式之間共用檔案

針對指定 Android 7.0 為目標版本的應用程式,Android 架構會強制執行 StrictMode API 政策禁止公開 file:// URI 應用程式以外的功能如果包含檔案 URI 的意圖離開應用程式,應用程式就會失敗 為 FileUriExposedException 例外狀況

如要在應用程式之間分享檔案,請傳送 content:// URI 並授予 URI 的臨時存取權。如要授予這項權限,最簡單的做法是 方法是使用 FileProvider 類別。如要進一步瞭解 允許存取 請參閱「共用檔案」。

無障礙功能再進化

Android 7.0 包含多項變更,以提高應用程式的可用性 專為低視能或身心障礙使用者打造的平台這些調整應該 您通常不需要在應用程式中變更程式碼,但建議您查看 這些功能,並透過應用程式進行測試,評估可能對使用者造成的影響 無須專人管理

螢幕縮放

Android 7.0 可讓使用者設定「顯示大小」,以放大畫面 或縮小畫面上所有元素,進而改善裝置的無障礙功能 或適合低視能的使用者使用者無法將畫面縮放至超過最小的螢幕 寬度 sw320dp 是 Nexus 4 的寬度,常見中型手機。

螢幕顯示執行 Android 7.0 系統映像檔的裝置未放大的顯示大小
螢幕畫面顯示對搭載 Android 7.0 系統映像檔的裝置增加顯示大小的效果

圖 3. 右側畫面顯示 為執行 Android 7.0 系統映像檔的裝置增加顯示大小

當裝置密度有所變更時,系統會通知正在運作的應用程式, 方法如下:

  • 如果應用程式指定的 API 級別為 23 以下,系統會自動終止 所有背景程序也就是說,如果使用者改用 開啟「設定」畫面, 「Display size」 (顯示大小) 設定,系統會終止應用程式在 才適合在記憶體不足的情況下使用如果應用程式有前景 因此,系統會通知那些設定變更的程序 如處理 執行階段變更,就像裝置螢幕方向改變時一樣。
  • 如果應用程式指定 Android 7.0,所有程序 (前景和背景) 會收到設定變更通知 如處理 執行階段變更

大多數應用程式無須進行任何變更即可支援這項功能,方法是 都遵循 Android 最佳做法需要檢查的具體事項:

  • 在螢幕寬度為 sw320dp 的裝置上測試應用程式 確保成效良好
  • 裝置設定變更時,請更新所有與密度相關的格式 快取資訊,例如快取的點陣圖或 更是如此當應用程式從暫停狀態恢復運作時,檢查設定變更 時間。

    注意:如要快取設定相依資料,則 建議您加入相關的中繼資料,例如 資料的大小或像素密度儲存這項中繼資料 決定是否要在設定完成之後重新整理快取資料 變更。

  • 避免以像素單位指定尺寸,因為這類維度無法 螢幕密度請改為指定與密度無關的維度 像素 (dp) 單位。

設定精靈中的視覺輔助設定

Android 7.0 版在歡迎畫面中提供視覺設定,方便使用者 在新裝置上調整下列無障礙設定: 放大手勢字型大小螢幕大小TalkBack。這項異動 可更清楚查看不同螢幕設定相關錯誤。目的地: 評估此功能的影響 您應該使用下列項目來測試應用程式 已啟用設定。你可以前往「設定」>「設定」 無障礙功能

連結至平台程式庫的 NDK 應用程式

從 Android 7.0 開始,系統會禁止應用程式進行動態連結 使用非 NDK 程式庫,這可能會導致應用程式異常終止。這項變更 促使所有平台更新都能提供一致的應用程式體驗 和不同裝置就算您的程式碼 私人程式庫中可能存在第三方靜態資料庫 藉此達到這個目標因此,所有開發人員都應檢查 確保應用程式不會在搭載 Android 7.0 的裝置上當機。如果應用程式使用 原生程式碼,建議您只使用公開 NDK API

應用程式存取私人平台的方式有三種 API:

  • 您的應用程式會直接存取私人平台程式庫。建議您更新 來加入自己的程式庫副本,或使用公開 NDK API
  • 應用程式使用了會存取私人平台的第三方程式庫 程式庫即使您確定應用程式不會存取私人程式庫 但您還是應該針對這個情境測試應用程式。
  • 應用程式參照的程式庫並未包含在其 APK 中。適用對象 舉例來說,如果您嘗試使用自己的 OpenSSL 副本, 您忘記將這個 APK 與應用程式的 APK 整合。應用程式可能會在版本上正常執行 包含 libcrypto.so 的 Android 平台。不過應用程式 在不含此程式庫的較新 Android 版本中可能會當機 (例如 Android 6.0 以上版本)。如要修正這個問題,請務必將 增加非 NDK 程式庫。

應用程式不應使用 NDK 未包含的原生資料庫,因為 可能在不同 Android 版本之間變更或移除。 例如從 OpenSSL 改用 BoringSSL 就是一種變更。另外, 因為平台程式庫沒有相容性需求 不同裝置提供的 相容性。

為減少這項限制目前可能造成的影響 已釋出的應用程式,也就是一組具顯著用途的程式庫,例如 libandroid_runtime.solibcutils.solibcrypto.solibssl.so—暫時 可在 Android 7.0 (API 級別 24) 上存取,適用於目標 API 級別 23 或 較低如果應用程式載入上述任一程式庫,Logcat 會產生警告 並在目標裝置上顯示浮動式訊息,通知你。如果有 警告,您必須更新應用程式,加入專屬訊息副本 或只使用公開 NDK API。日後推出的 Android 版本 平台可能會限制使用私人程式庫 應用程式停止運作。

所有應用程式都會呼叫 。結果在於 System.loadLibrarydlopen(3)都會傳回 NULL,這可能導致應用程式異常終止。建議您查看 應用程式的程式碼,移除使用私人平台 API 並徹底測試應用程式 使用搭載 Android 7.0 (API 級別 24) 的裝置或模擬器。如果您是 如果不確定應用程式是否使用私人程式庫,您可以查看 logcat 來找出執行階段錯誤。

下表說明您應看到 監控應用程式的使用方式 等級 (android:targetSdkVersion)。

程式庫 目標 API 級別 透過動態連結器存取執行階段 Android 7.0 (API 級別 24) 行為 未來 Android 平台行為
NDK 公開 不限 無障礙 可正常運作 可正常運作
私人 (可暫時存取的私人程式庫) 23 以下 暫時開放存取 可正常運作,但收到 Logcat 警告。 執行階段錯誤
私人 (可暫時存取的私人程式庫) 24 以上版本 受限制 執行階段錯誤 執行階段錯誤
私人 (其他) 不限 受限制 執行階段錯誤 執行階段錯誤

檢查應用程式是否使用私人程式庫

為了協助您找出載入私人程式庫的問題,Logcat 可能會產生 警告或執行階段錯誤舉例來說,如果應用程式指定 API 級別 23 或 並嘗試在搭載 Android 7.0、 您可能會看到類似下列內容的警告:

03-21 17:07:51.502 31234 31234 W linker  : library "libandroid_runtime.so"
("/system/lib/libandroid_runtime.so") needed or dlopened by
"/data/app/com.popular-app.android-2/lib/arm/libapplib.so" is not accessible
for the namespace "classloader-namespace" - the access is temporarily granted
as a workaround for http://b/26394120

這些 logcat 警告會指出哪個程式庫正在嘗試存取 Private Platform API,但不會讓應用程式停止運作。如果應用程式 目標 API 級別為 24 以上,但 logcat 會產生下列結果: 執行階段錯誤,您的應用程式可能會當機:

java.lang.UnsatisfiedLinkError: dlopen failed: library "libcutils.so"
("/system/lib/libcutils.so") needed or dlopened by
"/system/lib/libnativeloader.so" is not accessible for the namespace
"classloader-namespace"
  at java.lang.Runtime.loadLibrary0(Runtime.java:977)
  at java.lang.System.loadLibrary(System.java:1602)

如果應用程式使用第三方程式庫,可能也會看到這些 Logcat 輸出內容 以動態方式連結至私人平台 API讀取工具中的 readelf 工具 Android 7.0DK 可讓您產生所有動態連結共用的清單 執行下列指令,以找出指定 .so 檔案的程式庫:

aarch64-linux-android-readelf -dW libMyLibrary.so

更新應用程式

您可以採取下列步驟來修正這類錯誤,並 確保應用程式不會在日後平台更新時異常終止:

  • 如果應用程式使用私人平台程式庫,請更新應用程式,加入私人平台程式庫 自己的程式庫副本,或使用公開 NDK API
  • 如果您的應用程式使用的第三方程式庫會存取私人符號,請與 更新程式庫。
  • 請務必將所有非 NDK 程式庫與 APK 一併封裝。
  • 使用標準 JNI 函式而非 getJavaVM 並 「libandroid_runtime.so」的getJNIEnv
    AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h>
    AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
    JavaVM::AttachCurrentThread from <jni.h>.
    
  • 使用 __system_property_get 取代私人 property_get 符號,來自 libcutils.so。方法是使用 __system_property_get 其中包括:
    #include <sys/system_properties.h>
    

    注意:系統屬性的可用性和內容為 未經過 CTS 測試更好的方法是避免使用 資源

  • 使用 libcrypto.so 的本機版本 SSL_ctrl 符號。舉例來說,您應將 libcyrpto.a 您的 .so 檔案,或加入 BoringSSL/OpenSSL 的 libcrypto.so 動態連結版本,並封裝在您的 APK 中。

Android for Work

Android 7.0 針對指定 Android for Work 的應用程式包含其變更,包括 變更憑證安裝、密碼重設、次要使用者 管理、管理及存取裝置 ID如果您正在建構適用於 針對 Android for Work 環境,建議您檢查這些異動並修改 據此調整應用程式

  • 您必須先安裝委派憑證安裝程式,DPC 才能設定 基礎架構針對指定 Android 7.0 (API 級別 24) 的設定檔和裝置擁有者應用程式, 您應該先安裝委派憑證安裝程式,再安裝裝置政策 控制器 (DPC) 呼叫 DevicePolicyManager.setCertInstallerPackage()。如果安裝程式 如未安裝,則系統會擲回 IllegalArgumentException
  • 裝置管理員的重設密碼限制現在會套用到設定檔 擁有者。裝置管理員無法再使用 DevicePolicyManager.resetPassword()即可清除密碼或變更 也可以查看已經設定的廣告裝置管理員仍可設定密碼,但只有 裝置沒有密碼、PIN 碼或解鎖圖案時。
  • 即使受限制限制,裝置和設定檔擁有者仍可管理帳戶 設定。裝置擁有者和設定檔擁有者可以呼叫 Account Management API 即使設有 DISALLOW_MODIFY_ACCOUNTS 使用者限制也一樣。
  • 裝置擁有者可以更輕鬆地管理次要使用者。當裝置處於 在裝置擁有者模式下執行,有 DISALLOW_ADD_USER 項限制 。這樣做可以避免使用者建立非受管的次要執行個體 使用者。此外,CreateUser()createAndInitializeUser() 方法已淘汰;新的 DevicePolicyManager.createAndManageUser() 方法會取代替代內容。
  • 裝置擁有者可以存取裝置 ID。裝置擁有者可以存取 裝置的 Wi-Fi MAC 位址,使用 DevicePolicyManager.getWifiMacAddress()。如果從未使用 Wi-Fi 此方法會傳回 null 的值。
  • 工作模式設定可控管工作應用程式的存取權,工作模式關閉時, 系統啟動器會將工作應用程式顯示為灰色,指出這類應用程式無法使用。啟用中 工作模式會恢復正常行為。
  • 安裝含有用戶端憑證鏈結和 「設定」使用者介面中對應的私密金鑰,亦即 鏈結已不再安裝至信任憑證儲存空間。這麼做 不影響應用程式嘗試擷取用戶端時,KeyChain.getCertificateChain() 的結果 憑證鏈結。如有需要,應安裝 CA 憑證 透過「設定」使用者介面個別加入信任憑證儲存空間,並使用 採用 .crt 或 .cer 副檔名的 DER 編碼格式。
  • 從 Android 7.0 開始,系統會管理指紋註冊和儲存空間作業 (每位使用者)。如果個人資料擁有者的裝置政策用戶端 (DPC) 指定 API 級別 在搭載 Android 7.0 (API 級別 24) 的裝置上,使用者為 23 (或更舊版本) 仍可在裝置上設定指紋,但工作應用程式無法 存取裝置指紋。當 DPC 指定 API 級別 24 以上版本時,使用者可以設定 你可以前往「設定」設定 > 專為工作資料夾設計的指紋 安全性 >工作資料夾安全性
  • 新的加密狀態:ENCRYPTION_STATUS_ACTIVE_PER_USER DevicePolicyManager.getStorageEncryptionStatus() 會傳回,到 表示加密功能已啟用,且加密金鑰與 內容。DPC 指定 API 級別 24 以上時,才會傳回新狀態。 如果應用程式指定舊版 API 級別,ENCRYPTION_STATUS_ACTIVE
  • 在 Android 7.0 中,數種通常會影響 如果裝置未連接工作資料夾, 獨立作業挑戰系統不會影響整個裝置 方法,僅適用於工作資料夾。(這類方法的完整清單為 DevicePolicyManager.getParentProfileInstance()說明文件中)。例如: DevicePolicyManager.lockNow() 只會鎖定工作資料夾,而非 鎖定整部裝置。在這些方法中,您可以取得 呼叫該程式的 DevicePolicyManager;你可以透過以下方式取得這個家長: 正在呼叫 DevicePolicyManager.getParentProfileInstance()。舉例來說,假設您呼叫 父項執行個體的 lockNow() 方法時,就會鎖定整個裝置。

註解保留

Android 7.0 修正了忽略註解瀏覽權限的錯誤。 這個問題可讓執行階段存取不應發生的註解 。這些註解包括:

  • VISIBILITY_BUILD:僅在建構時間顯示。
  • VISIBILITY_SYSTEM:適合在執行階段顯示,但只有 緊密整合

如果您的應用程式仰賴此行為,請在必須在符合要求條件的註解中加入保留政策 使用這些內容只要使用 @Retention(RetentionPolicy.RUNTIME) 即可。

TLS/SSL 預設設定變更

Android 7.0 預設對預設 TLS/SSL 設定做出了以下變更 用於 HTTPS 和其他 TLS/SSL 流量的應用程式:

  • RC4 加密套件現已停用。
  • 現已啟用 CHACHA20-POLY1305 加密套件。

預設停用 RC4 可能會導致 HTTPS 或 TLS/SSL 故障 就能在伺服器不交涉現代加密套件時 調度資源 建議的修正方式是改善伺服器設定,提高 以及更現代化的加密套件和通訊協定理想情況下,TLSv1.2 和 AES-GCM 應啟用,且應啟用正向密碼加密套件 (ECDHE)

或者,您也可以修改應用程式,使用自訂的 SSLSocketFactory 與伺服器通訊。 工廠必須設計為SSLSocket 包含伺服器需要的部分加密套件的執行個體 除了預設加密套件之外,還啟用了 加密功能

注意:這些變更與 WebView 無關。

鎖定 Android 7.0 的應用程式

這些行為變更僅適用於指定的應用程式 Android 7.0 (API 級別 24) 以上版本。針對 Android 7.0 平台編譯的應用程式 或將 targetSdkVersion 設為 Android 7.0 以上版本,必須修改 確保應用程式能妥善支援這些行為 (如適用)。

序列化變更

Android 7.0 (API 級別 24) 修正了計算預設時的錯誤 serialVersionUID 的值,因為與規格不符。

實作 Serializable 的類別 且未指定明確的 serialVersionUID 欄位 預設 serialVersionUID 會因變更而出現例外狀況 在嘗試將已復原的 序列化到較舊版本,或是由指定較舊版本的應用程式序列化 版本。錯誤訊息應如下所示:

local class incompatible: stream classdesc serialVersionUID = 1234, local class serialVersionUID = 4567

如要修正這些問題,必須在以下位置加入 serialVersionUID 欄位: 錯誤訊息中值為 stream classdesc serialVersionUID 的受影響類別,例如1234 英寸 本例中。這項異動符合所有 編寫序列化程式碼,且適用於所有 Android 版本。

修正的特定錯誤與具有靜態資料的存在 初始化方法,例如 <clinit>。根據 會指定是否在 類別將影響該類別計算的預設 serialVersionUID。 修正錯誤前,系統還會檢查父類別 靜態初始化器。

具體來說,這項異動不會影響目標 API 級別 23 或 表示類別包含 serialVersionUID 欄位或類別 含有靜態初始化器方法的 BERT 模型

其他重要事項

  • 在 Android 7.0 上執行應用程式,但指定較低的 API 級別時 如果使用者變更顯示大小,就會終止應用程式程序。應用程式 才能妥善處理這種情況否則當機 使用者從「近期」還原檔案時

    您應測試應用程式,確保 不會發生這類行為 同一個當機事件 透過 DDMS 手動關閉應用程式

    系統不會自動指定指定 Android 7.0 (API 級別 24) 以上版本的應用程式 導致作業失敗但他們可能仍然不太會 設定變更。

  • Android 7.0 中的應用程式應能妥善處理設定變更。 且不應在後續啟動時異常終止你可以驗證應用程式行為 變更字型大小 (設定 > 顯示 >字型大小),然後還原 顯示在「近期」專區中
  • 由於舊版 Android 發生錯誤,系統並未標記寫入行為 至於主執行緒的 TCP 通訊端,則屬於嚴格模式違規情形。Android 7.0 修正了這項錯誤。 表現出此行為的應用程式現在會擲回 android.os.NetworkOnMainThreadException。 一般來說,在主執行緒上執行網路作業是不好的想法,因為這些作業 通常延遲時間很長,會導致 ANR 和卡頓。
  • Debug.startMethodTracing() 方法系列現在預設為 會將輸出內容儲存在共用儲存空間的套件專屬目錄中。 而不是頂層 的備份。這表示應用程式不再需要要求 WRITE_EXTERNAL_STORAGE 權限,就能使用這些 API。
  • 許多平台 API 現已開始檢查傳送的大型酬載 用於 Binder交易,而 系統現在會對 TransactionTooLargeExceptions (例如 RuntimeExceptions),而不是無訊息記錄或隱藏。一 最常見的例子是 Activity.onSaveInstanceState(), 這會導致 ActivityThread.StopInfo 擲回 RuntimeException (如果應用程式指定 Android 7.0 版本為目標)。
  • 如果應用程式將 Runnable 工作發布至 View,且 View 未附加至視窗,系統 使用 ViewRunnable 工作排入佇列; 「Runnable」工作只會在 已附加 View 移至視窗此行為修正了下列錯誤:
    • 如果某個應用程式是從預期以外的執行緒發布至 View 視窗的 UI 執行緒,因此 Runnable 可能會在錯誤的執行緒上執行。
    • Runnable 工作是否透過其他執行緒發布 迴圈執行緒,應用程式可能會公開 Runnable 工作。
  • 如果應用程式搭載 Android 7.0 且 DELETE_PACKAGES 權限嘗試刪除套件,但已安裝該套件的其他應用程式 系統需要使用者確認在此情況下,應用程式應預期 STATUS_PENDING_USER_ACTION 做為叫用狀態 PackageInstaller.uninstall()
  • 名為 Crypto 的 JCA 供應商已淘汰,因為 演算法 SHA1PRNG 的加密強度不足。無法再使用應用程式 SHA1PRNG 向 (不安全) 衍生金鑰,因為此供應商已 廣告。詳情請參閱網誌。 貼文安全性「Crypto」已在 Android 中淘汰 N