Android 7.0 新特性(源自官方文檔)
Android 7.0(API 級別 24) 除了提供諸多新特性和功能外,還對系統(tǒng)和 API 行為做出了各種變更。本文重點(diǎn)介紹您應(yīng)該了解并在開發(fā)應(yīng)用時加以考慮的一些主要變更。
如果您之前發(fā)布過 Android 應(yīng)用,請注意您的應(yīng)用可能受到這些平臺變化的影響。
電池和內(nèi)存
Android 7.0 包括旨在延長設(shè)備電池壽命和減少 RAM 使用的系統(tǒng)行為變更。這些變更可能會影響您的應(yīng)用訪問系統(tǒng)資源,以及您的應(yīng)用通過特定隱式 intent 與其他應(yīng)用交互的方式。
低電耗模式
Android 6.0(API 級別 23)引入了低電耗模式,當(dāng)用戶設(shè)備未插接電源、處于靜止?fàn)顟B(tài)且屏幕關(guān)閉時,該模式會推遲 CPU 和網(wǎng)絡(luò)活動,從而延長電池壽命。而 Android 7.0 則通過在設(shè)備未插接電源且屏幕關(guān)閉狀態(tài)下、但不一定要處于靜止?fàn)顟B(tài)(例如用戶外出時把手持式設(shè)備裝在口袋里)時應(yīng)用部分 CPU 和網(wǎng)絡(luò)限制,進(jìn)一步增強(qiáng)了低電耗模式。
圖 1. 低電耗模式如何應(yīng)用第一級系統(tǒng)活動限制以延長電池壽命的圖示。
當(dāng)設(shè)備處于充電狀態(tài)且屏幕已關(guān)閉一定時間后,設(shè)備會進(jìn)入低電耗模式并應(yīng)用第一部分限制:關(guān)閉應(yīng)用網(wǎng)絡(luò)訪問、推遲作業(yè)和同步。如果進(jìn)入低電耗模式后設(shè)備處于靜止?fàn)顟B(tài)達(dá)到一定時間,系統(tǒng)則會對 PowerManager.WakeLock、AlarmManager 鬧鈴、GPS 和 WLAN 掃描應(yīng)用余下的低電耗模式限制。無論是應(yīng)用部分還是全部低電耗模式限制,系統(tǒng)都會喚醒設(shè)備以提供簡短的維護(hù)時間窗口,在此窗口期間,應(yīng)用程序可以訪問網(wǎng)絡(luò)并執(zhí)行任何被推遲的作業(yè)/同步。
圖 2. 低電耗模式如何在設(shè)備處于靜止?fàn)顟B(tài)達(dá)到一定時間后應(yīng)用第二級系統(tǒng)活動限制的圖示。
請注意,激活屏幕或插接設(shè)備電源時,系統(tǒng)將退出低電耗模式并移除這些處理限制。此項新增的行為不會影響有關(guān)使您的應(yīng)用適應(yīng) Android 6.0(API 級別 23)中所推出的舊版本低電耗模式的建議和最佳做法,如對低電耗模式和應(yīng)用待機(jī)模式進(jìn)行針對性優(yōu)化中所討論。您仍應(yīng)遵循這些建議(例如使用 Google 云消息傳遞 (GCM) 發(fā)送和接收消息)并開始安排更新計劃以適應(yīng)新增的低電耗模式行為。
Project Svelte:后臺優(yōu)化
Android 7.0 移除了三項隱式廣播,以幫助優(yōu)化內(nèi)存使用和電量消耗。此項變更很有必要,因為隱式廣播會在后臺頻繁啟動已注冊偵聽這些廣播的應(yīng)用。刪除這些廣播可以顯著提升設(shè)備性能和用戶體驗。
移動設(shè)備會經(jīng)歷頻繁的連接變更,例如在 WLAN 和移動數(shù)據(jù)之間切換時。目前,可以通過在應(yīng)用清單中注冊一個接收器來偵聽隱式 CONNECTIVITY_ACTION 廣播,讓應(yīng)用能夠監(jiān)控這些變更。由于很多應(yīng)用會注冊接收此廣播,因此單次網(wǎng)絡(luò)切換即會導(dǎo)致所有應(yīng)用被喚醒并同時處理此廣播。
同理,在之前版本的 Android 中,應(yīng)用可以注冊接收來自其他應(yīng)用(例如相機(jī))的隱式 ACTION_NEW_PICTURE 和 ACTION_NEW_VIDEO 廣播。當(dāng)用戶使用相機(jī)應(yīng)用拍攝照片時,這些應(yīng)用即會被喚醒以處理廣播。
為緩解這些問題,Android 7.0 應(yīng)用了以下優(yōu)化措施:
- 面向 Android 7.0 開發(fā)的應(yīng)用不會收到 CONNECTIVITY_ACTION 廣播,即使它們已有清單條目來請求接受這些事件的通知。在前臺運(yùn)行的應(yīng)用如果使用 BroadcastReceiver 請求接收通知,則仍可以在主線程中偵聽 CONNECTIVITY_CHANGE。
- 應(yīng)用無法發(fā)送或接收 ACTION_NEW_PICTURE 或 ACTION_NEW_VIDEO 廣播。此項優(yōu)化會影響所有應(yīng)用,而不僅僅是面向 Android 7.0 的應(yīng)用。
如果您的應(yīng)用使用任何 intent,您仍需要盡快移除它們的依賴關(guān)系,以正確適配 Android 7.0 設(shè)備。Android 框架提供多個解決方案來緩解對這些隱式廣播的需求。例如,JobScheduler API 提供了一個穩(wěn)健可靠的機(jī)制來安排滿足指定條件(例如連入無限流量網(wǎng)絡(luò))時所執(zhí)行的網(wǎng)絡(luò)操作。您甚至可以使用 JobScheduler 來適應(yīng)內(nèi)容提供程序變化。
如需了解有關(guān) Android N 中后臺優(yōu)化以及如何改寫應(yīng)用的詳細(xì)信息,請參閱后臺優(yōu)化。
權(quán)限更改
Android 7.0 做了一些權(quán)限更改,這些更改可能會影響您的應(yīng)用。
系統(tǒng)權(quán)限更改
為了提高私有文件的安全性,面向 Android 7.0 或更高版本的應(yīng)用私有目錄被限制訪問 (0700)。此設(shè)置可防止私有文件的元數(shù)據(jù)泄漏,如它們的大小或存在性。此權(quán)限更改有多重副作用:
私有文件的文件權(quán)限不應(yīng)再由所有者放寬,為使用 MODE_WORLD_READABLE 和/或 MODE_WORLD_WRITEABLE 而進(jìn)行的此類嘗試將觸發(fā) SecurityException。
注:迄今為止,這種限制尚不能完全執(zhí)行。應(yīng)用仍可能使用原生 API 或 File API 來修改它們的私有目錄權(quán)限。但是,我們強(qiáng)烈反對放寬私有目錄的權(quán)限。傳遞軟件包網(wǎng)域外的 file:// URI 可能給接收器留下無法訪問的路徑。因此,嘗試傳遞 file:// URI 會觸發(fā) FileUriExposedException。分享私有文件內(nèi)容的推薦方法是使用 FileProvider。
DownloadManager 不再按文件名分享私人存儲的文件。舊版應(yīng)用在訪問 COLUMN_LOCAL_FILENAME 時可能出現(xiàn)無法訪問的路徑。面向 Android 7.0 或更高版本的應(yīng)用在嘗試訪問 COLUMN_LOCAL_FILENAME 時會觸發(fā) SecurityException。通過使用 DownloadManager.Request.setDestinationInExternalFilesDir() 或 DownloadManager.Request.setDestinationInExternalPublicDir() 將下載位置設(shè)置為公共位置的舊版應(yīng)用仍可以訪問 COLUMN_LOCAL_FILENAME 中的路徑,但是我們強(qiáng)烈反對使用這種方法。對于由 DownloadManager 公開的文件,首選的訪問方式是使用ContentResolver.openFileDescriptor()。
在應(yīng)用間共享文件
對于面向 Android 7.0 的應(yīng)用,Android 框架執(zhí)行的 StrictMode API 政策禁止在您的應(yīng)用外部公開 file:// URI。如果一項包含文件 URI 的 intent 離開您的應(yīng)用,則應(yīng)用出現(xiàn)故障,并出現(xiàn) FileUriExposedException 異常。
要在應(yīng)用間共享文件,您應(yīng)發(fā)送一項 content:// URI,并授予 URI 臨時訪問權(quán)限。進(jìn)行此授權(quán)的最簡單方式是使用 FileProvider 類。如需了解有關(guān)權(quán)限和共享文件的詳細(xì)信息,請參閱共享文件。
無障礙改進(jìn)
為提高平臺對于視力不佳或視力受損用戶的易用性,Android 7.0 做出了一些更改。這些更改一般并不要求更改您的應(yīng)用代碼,不過您應(yīng)仔細(xì)檢查并使用您的應(yīng)用測試這些功能,以評估它們對用戶體驗的潛在影響。
屏幕縮放
Android 7.0 支持用戶設(shè)置顯示尺寸,以放大或縮小屏幕上的所有元素,從而提升設(shè)備對視力不佳用戶的可訪問性。用戶無法將屏幕縮放至低于最小屏幕寬度 sw320dp,該寬度是 Nexus 4 的寬度,也是常規(guī)中等大小手機(jī)的寬度。
圖 3. 右側(cè)屏幕顯示的是一臺運(yùn)行
Android 7.0 系統(tǒng)映像的設(shè)備增大顯示尺寸后的效果。
當(dāng)設(shè)備密度發(fā)生更改時,系統(tǒng)會以如下方式通知正在運(yùn)行的應(yīng)用:
如果是面向 API 級別 23 或更低版本系統(tǒng)的應(yīng)用,系統(tǒng)會自動終止其所有后臺進(jìn)程。這意味著如果用戶切換離開此類應(yīng)用,轉(zhuǎn)而打開 Settings 屏幕并更改 Display size 設(shè)置,則系統(tǒng)會像處理內(nèi)存不足的情況一樣終止該應(yīng)用。如果應(yīng)用具有任何前臺進(jìn)程,則系統(tǒng)會如處理運(yùn)行時更改中所述將配置變更通知給這些進(jìn)程,就像對待設(shè)備屏幕方向變更一樣。
如果是面向 Android 7.0 的應(yīng)用,則其所有進(jìn)程(前臺和后臺)都會收到有關(guān)配置變更的通知,如處理運(yùn)行時更改中所述。
大多數(shù)應(yīng)用并不需要進(jìn)行任何更改即可支持此功能,不過前提是這些應(yīng)用遵循 Android 最佳做法。具體要檢查的事項:在屏幕寬度為 sw320dp 的設(shè)備上測試您的應(yīng)用,并確保其充分運(yùn)行。
當(dāng)設(shè)備配置發(fā)生變更時,更新任何與密度相關(guān)的緩存信息,例如緩存位圖或從網(wǎng)絡(luò)加載的資源。當(dāng)應(yīng)用從暫停狀態(tài)恢復(fù)運(yùn)行時,檢查配置變更。
注:如果您要緩存與配置相關(guān)的數(shù)據(jù),則最好也包括相關(guān)元數(shù)據(jù),例如該數(shù)據(jù)對應(yīng)的屏幕尺寸或像素密度。保存這些元數(shù)據(jù)便于您在配置變更后決定是否需要刷新緩存數(shù)據(jù)。避免用像素單位指定尺寸,因為像素不會隨屏幕密度縮放。應(yīng)改為使用與密度無關(guān)像素 (dp) 單位指定尺寸。
設(shè)置向?qū)е械囊曈X設(shè)置
Android 7.0 在“Welcome”屏幕中加入了“Vision Settings”,用戶可以在新設(shè)備上設(shè)置以下無障礙功能設(shè)置:Magnification gesture、Font size、Display size 和話語提示。此項變更讓您可以更容易發(fā)現(xiàn)與不同屏幕設(shè)置有關(guān)的錯誤。要評估此功能的影響,您應(yīng)在啟用這些設(shè)置的狀態(tài)下測試應(yīng)用。您可以在 Settings > Accessibility 中找到這些設(shè)置。
NDK 應(yīng)用鏈接至平臺庫
從 Android 7.0 開始,系統(tǒng)將阻止應(yīng)用動態(tài)鏈接非公開 NDK 庫,這種庫可能會導(dǎo)致您的應(yīng)用崩潰。此行為變更旨在為跨平臺更新和不同設(shè)備提供統(tǒng)一的應(yīng)用體驗。即使您的代碼可能不會鏈接私有庫,但您的應(yīng)用中的第三方靜態(tài)庫可能會這么做。因此,所有開發(fā)者都應(yīng)進(jìn)行相應(yīng)檢查,確保他們的應(yīng)用不會在運(yùn)行 Android 7.0 的設(shè)備上崩潰。如果您的應(yīng)用使用原生代碼,則只能使用公開 NDK API。
您的應(yīng)用可通過以下三種方式嘗試訪問私有平臺 API:
- 您的應(yīng)用直接訪問私有平臺庫。您應(yīng)更新您的應(yīng)用以添加該應(yīng)用的庫副本,或使用公開 NDK API。
- 您的應(yīng)用使用一個可訪問私有平臺庫的第三方庫。即使您確定您的應(yīng)用不會直接訪問私有庫,您仍應(yīng)針對此情景測試您的應(yīng)用。
- 您的應(yīng)用引用一個其 APK 中未包含的庫。例如,如果您嘗試使用您自己的 OpenSSL 副本,但忘記將它與應(yīng)用的 APK 進(jìn)行捆綁,則可能會出現(xiàn)此情況。正常情況下,此應(yīng)用可在包含 libcrypto.so 的 Android 平臺版本上運(yùn)行。不過,此應(yīng)用在不包含此庫的新版 Android(例如,Android 6.0 和更高的版本)上會崩潰。為修復(fù)此問題,請確保您的 APK 捆綁您的所有非 NDK 庫。
應(yīng)用不應(yīng)使用 NDK 中未包含的原生庫,因為這些庫可能會發(fā)生更改或在不同 Android 版本之間的可用性不同。例如,從 OpenSSL 切換至 BoringSSL 即屬于此類更改。此外,由于不屬于 NDK 中的平臺庫沒有兼容性要求,因此不同的設(shè)備可能提供不同級別的兼容性。
為降低此限制可能對當(dāng)前發(fā)布的應(yīng)用的影響,面向 API 級別 23 或更低級別的應(yīng)用在 Android N 上可暫時訪問頗為常用的一組庫,例如 libandroid_runtime.so、libcutils.so、libcrypto.so 和 libssl.so。如果您的應(yīng)用加載其中某個庫,logcat 會生成一個警告,并在目標(biāo)設(shè)備上顯示一個 Toast 來通知您。如果您看到這些警告,您應(yīng)更新您的應(yīng)用以添加該應(yīng)用自己的庫副本,或僅使用公開 NDK API。將來發(fā)布的 Android 平臺可能會完全限制對私有庫的使用,并導(dǎo)致您的應(yīng)用崩潰。
所有應(yīng)用在調(diào)用既非公開又不可暫時訪問的 API 時都會生成一個運(yùn)行時錯誤。結(jié)果就是 System.loadLibrary 和 dlopen(3) 同時返回 NULL,并可能導(dǎo)致您的應(yīng)用崩潰。您應(yīng)檢查應(yīng)用代碼以移除對私有平臺 API 的使用,并使用預(yù)覽版設(shè)備或模擬器全面測試應(yīng)用。如果您不確定您的應(yīng)用是否使用私有庫,您可以檢查 logcat 以識別運(yùn)行時錯誤。
下表描述的是根據(jù)應(yīng)用使用的私有原生庫及其目標(biāo) API 級別 (android:targetSdkVersion),應(yīng)用預(yù)期顯示的行為。
檢查您的應(yīng)用是否使用私有庫
為幫助您識別加載私有庫的問題,logcat 可能會生成一個警告或運(yùn)行時錯誤。例如,如果您的應(yīng)用面向 API 級別 23 或更低級別,并在運(yùn)行 Android 7.0 的設(shè)備上嘗試訪問私有庫,您可能會看到一個類似于下面所示的警告:
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 警告通知您哪個庫正在嘗試訪問私有平臺 API,但不會導(dǎo)致您的應(yīng)用崩潰。但是,如果應(yīng)用面向 API 級別 24 或更高級別,logcat 會生成以下運(yùn)行時錯誤,您的應(yīng)用可能會崩潰:
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)
如果您的應(yīng)用使用動態(tài)鏈接到私有平臺 API 的第三方庫,您可能也會看到上述 logcat 輸出。利用 Android 7.0DK 中的 readelf 工具,您可以通過運(yùn)行以下命令生成給定 .so 文件的所有動態(tài)鏈接的共享庫列表:
aarch64-linux-android-readelf -dW libMyLibrary.so
更新您的應(yīng)用
通過下面的一些步驟,您可以修復(fù)上述類型的錯誤并確保您的應(yīng)用不會在將來的更新版平臺上崩潰:
- 如果您的應(yīng)用使用私有平臺庫,您應(yīng)更新它,以添加該應(yīng)用自己的庫副本或使用公開 NDK API。
- 如果您的應(yīng)用使用訪問私有符號的第三方庫,則聯(lián)系庫作者以更新庫。
- 請確保將您的所有非 NDK 庫與您的 APK 打包在一起。
- 使用標(biāo)準(zhǔn) JNI 函數(shù)而非來自 libandroid_runtime.so 的 getJavaVM 和 getJNIEnv:
AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h>
AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
JavaVM::AttachCurrentThread from <jni.h>.
- 使用 __system_property_get 而非來自 libcutils.so 的私有 property_get 符號。為此,請使用 __system_property_get 及以下 include 函數(shù):
#include <sys/system_properties.h>
注:系統(tǒng)屬性的可用性和內(nèi)容未通過 CTS 進(jìn)行測試。應(yīng)執(zhí)行進(jìn)一步修復(fù)以避免同時使用這些屬性。
- 使用來自 libcrypto.so 的 SSL_ctrl 符號的本地版本。例如,您應(yīng)在您的 .so 文件中靜態(tài)鏈接 libcyrpto.a,或從 BoringSSL/OpenSSL 添加一個動態(tài)鏈接的 libcrypto.so 版本,并將其打包到您的 APK 中。
Android for Work
Android 7.0 包含一些針對面向 Android for Work 的應(yīng)用的變更,包括對證書安裝、密碼重置、二級用戶管理、設(shè)備標(biāo)識符訪問權(quán)限的變更。如果您是要針對 Android for Work 環(huán)境開發(fā)應(yīng)用,則應(yīng)仔細(xì)檢查這些變更并相應(yīng)地修改您的應(yīng)用。
- 您必須先安裝授權(quán)證書安裝程序,然后 DPC 才能對其進(jìn)行設(shè)置。對于面向 N SDK 的配置文件和設(shè)備所有者應(yīng)用,您應(yīng)在設(shè)備規(guī)范控制器 (DPC) 調(diào)用 DevicePolicyManager.setCertInstallerPackage() 之前安裝授權(quán)證書安裝程序。如果尚未安裝此安裝程序,則系統(tǒng)會引發(fā) IllegalArgumentException。
- 針對設(shè)備管理員的重置密碼限制現(xiàn)在也適用于配置文件所有者。設(shè)備管理員無法再使用 DevicePolicyManager.resetPassword() 來清除或更改已經(jīng)設(shè)置的密碼。設(shè)備管理員仍可以設(shè)置密碼,但只能在設(shè)備沒有密碼、PIN 碼或圖案時這樣做。
- 即使設(shè)置了限制,設(shè)備所有者和配置文件所有者仍可以管理帳戶。而且,即使具有 DISALLOW_MODIFY_ACCOUNTS 用戶限制,設(shè)備所有者和配置文件所有者仍可調(diào)用 Account Management API。
- 設(shè)備所有者可以更輕松地管理二級用戶。當(dāng)設(shè)備在設(shè)備所有者模式下運(yùn)行時,系統(tǒng)將自動設(shè)置 DISALLOW_ADD_USER 限制。這樣可以防止用戶創(chuàng)建非托管二級用戶。此外,CreateUser() 和 createAndInitializeUser() 方法已棄用,取而代之的是 DevicePolicyManager.createAndManageUser() 方法。
- 設(shè)備所有者可以訪問設(shè)備標(biāo)識符。設(shè)備所有者可以使用 DevicePolicyManagewr.getWifiMacAddress() 訪問設(shè)備的 WLAN MAC 地址。如果設(shè)備上從未啟用 WLAN,則此方法將返回一個 null 值。
- 工作模式設(shè)置控制工作應(yīng)用訪問。當(dāng)工作模式關(guān)閉時,系統(tǒng)啟動器通過使工作應(yīng)用顯示為灰色來指示它們不可用。啟用工作模式會再次恢復(fù)正常行為。
- 從 Settings UI 安裝包含客戶端證書鏈和對應(yīng)的私鑰的 PKCS #12 文件時,系統(tǒng)不再將該證書鏈中的 CA 證書安裝到受信任的憑據(jù)存儲空間。當(dāng)應(yīng)用稍后嘗試檢索客戶端證書鏈時,這不會影響 KeyChain.getCertificateChain() 的結(jié)果。如果需要,使用 .crt 或 .cer 文件擴(kuò)展名的 DER 編碼格式通過 Settings UI 單獨(dú)將 CA 證書安裝到受信任的憑據(jù)存儲空間。
- 從 Android 7.0 開始,可針對每個用戶管理指紋登記和存儲空間。如果配置文件所有者的設(shè)備規(guī)范客戶端 (DPC) 面向 Android N 設(shè)備上的 Android N 之前的版本,則用戶仍可以在該設(shè)備上設(shè)置指紋,但工作應(yīng)用不能訪問設(shè)備指紋。當(dāng) DPC 面向 Android N 和更高版本時,用戶可以通過轉(zhuǎn)到 Settings > Security > Work profile security 專門為托管配置文件設(shè)置指紋。
- DevicePolicyManager.getStorageEncryptionStatus() 返回新的加密狀態(tài) ENCRYPTION_STATUS_ACTIVE_PER_USER,以表明加密處于活動狀態(tài),且加密密鑰與用戶關(guān)聯(lián)。僅當(dāng) DPC 面向 API 級別 24 和更高級別時才會返回新的狀態(tài)。對于面向更早的 API 級別的應(yīng)用,即使加密密鑰是用戶或配置文件特有的,系統(tǒng)也會返回 ENCRYPTION_STATUS_ACTIVE。
- 在 Android 7.0 中,如果設(shè)備通過單獨(dú)的工作挑戰(zhàn)安裝了托管配置文件,則原本通常會影響整個設(shè)備的多個方法將會改變其行為方式。這些方法將僅應(yīng)用于托管配置文件,而不是影響整個設(shè)備。(此類方法的完整列表位于 DevicePolicyManager.getParentProfileInstance() 文檔中。)例如,DevicePolicyManager.lockNow() 只鎖定托管配置文件,而不是鎖定整個設(shè)備。對于上述每個方法,您可以通過對 DevicePolicyManager 的父實例調(diào)用該方法來獲取以前的行為;您可以通過調(diào)用 DevicePolicyManager.getParentProfileInstance() 獲取此父項。例如,如果您調(diào)用父實例的 lockNow() 方法,則整個設(shè)備將被鎖定。
如需了解有關(guān) Android 7.0 中針對 Android for Work 所做變更的詳細(xì)信息,請參閱 Android for Work 更新。
注解保留
Android 7.0 修復(fù)了一個注解可見性被忽略的錯誤。這種問題會導(dǎo)致應(yīng)用可在運(yùn)行時訪問原本不允許訪問的注解。這些注解包括:
- VISIBILITY_BUILD:僅應(yīng)編譯時可見。
- VISIBILITY_SYSTEM:運(yùn)行時應(yīng)可見,但僅限底層系統(tǒng)。
如果您的應(yīng)用依賴這種行為,請為運(yùn)行時必須可用的注解添加保留政策。您可通過使用 @Retention(RetentionPolicy.RUNTIME) 來執(zhí)行此操作。
其他重要說明
如果一個應(yīng)用在 Android 7.0 上運(yùn)行,但卻是針對更低 API 級別開發(fā)的,那么在用戶更改顯示尺寸時,系統(tǒng)將終止此應(yīng)用進(jìn)程。應(yīng)用必須能夠妥善處理此情景。否則,當(dāng)用戶從最近使用記錄中恢復(fù)運(yùn)行應(yīng)用時,應(yīng)用將會出現(xiàn)崩潰現(xiàn)象。
您應(yīng)測試應(yīng)用以確保不會發(fā)生此行為。要進(jìn)行此測試,您可以通過 DDMS 手動終止應(yīng)用,以造成相同的崩潰現(xiàn)象。
在密度發(fā)生更改時,系統(tǒng)不會自動終止面向 N 及更高版本的應(yīng)用;不過,這些應(yīng)用仍可能對配置變更做出不良響應(yīng)。Android 7.0 上的應(yīng)用應(yīng)能夠妥善處理配置變更,并且在后續(xù)啟動時不會出現(xiàn)崩潰現(xiàn)象。您可以通過更改字體大小 (Setting >Display > Font size) 并隨后從最近使用記錄中恢復(fù)運(yùn)行應(yīng)用,來驗證應(yīng)用行為。
由于之前的 Android 版本中的一項錯誤,系統(tǒng)未能將對主線程上的一個 TCP 套接字的寫入操作舉報為違反嚴(yán)格模式。Android 7.0 修復(fù)了此錯誤。呈現(xiàn)出這種行為的應(yīng)用現(xiàn)在會引發(fā) android.os.NetworkOnMainThreadException。一般情況下,我們不建議在主線程上執(zhí)行網(wǎng)絡(luò)操作,因為這些操作通常會出現(xiàn)可能導(dǎo)致 ANR 和卡頓的高尾延遲。
Debug.startMethodTracing() 方法系列現(xiàn)在默認(rèn)在您的共享存儲空間上的軟件包特定目錄中存儲輸出,而非 SD 卡根目錄。這意味著應(yīng)用不再需要請求 WRITE_EXTERNAL_STORAGE 權(quán)限來使用這些 API 。
許多平臺 API 現(xiàn)在開始檢查在 Binder 事務(wù)間發(fā)送的大負(fù)載,系統(tǒng)現(xiàn)在會將 TransactionTooLargeExceptions 作為 RuntimeExceptions 再次引發(fā),而不再只是默默記錄或抑制它們。一個常見例子是在 Activity.onSaveInstanceState() 上存儲過多數(shù)據(jù),導(dǎo)致 ActivityThread.StopInfo 在您的應(yīng)用面向 Android 7.0 時引發(fā) RuntimeException。
-
如果應(yīng)用向 View 發(fā)布 Runnable 任務(wù),并且 View 未附加到窗口,系統(tǒng)會用 View 為 Runnable 任務(wù)排隊;在 View 附加到窗口之前,不會執(zhí)行 Runnable 任務(wù)。此行為會修復(fù)以下錯誤:
- 如果一項應(yīng)用是從并非預(yù)期窗口 UI 線程的其他線程發(fā)布到 View,則 Runnable 可能會因此運(yùn)行錯誤的線程。
如果 Runnable 任務(wù)是從并非環(huán)路線程的其他線程發(fā)布,則應(yīng)用可能會曝光 Runnable 任務(wù)。 - 如果 Android 7.0 上一項有 DELETE_PACKAGES 權(quán)限的應(yīng)用嘗試刪除一個軟件包,但另一項應(yīng)用已經(jīng)安裝了這個軟件包,則系統(tǒng)需要用戶進(jìn)行確認(rèn)。在這種情況下,應(yīng)用在調(diào)用 PackageInstaller.uninstall() 時預(yù)計的返回狀態(tài)應(yīng)為 STATUS_PENDING_USER_ACTION。
- 如果一項應(yīng)用是從并非預(yù)期窗口 UI 線程的其他線程發(fā)布到 View,則 Runnable 可能會因此運(yùn)行錯誤的線程。
名為 Crypto 的 JCA 提供程序已棄用,因為它僅有的 SHA1PRNG 算法為弱加密。應(yīng)用無法再使用 SHA1PRNG(不安全地)派生密鑰,因為不再提供此提供程序。如需了解詳細(xì)信息,請參閱博文 Android N 中已棄用“Crypto”安全提供程序。