Android Pie(9.0) New Features
內(nèi)容:
- 劉海屏適配
- 通知功能的變更
- 隱私權(quán)變更
- 對(duì)使用非 SDK 接口的限制 和 適配策略
- 非Activity-Context啟動(dòng)Activity
- Apache HTTP 客戶端棄用,影響采用非標(biāo)準(zhǔn) ClassLoader 的應(yīng)用
- 前臺(tái)服務(wù)
API 變更
Display Cutout Support
Android 9 支持最新的全面屏叫倍,其中包含為攝像頭和揚(yáng)聲器預(yù)留空間的屏幕缺口偷卧。 通過(guò) DisplayCutout
類可確定非功能區(qū)域的位置和形狀,這些區(qū)域不應(yīng)顯示內(nèi)容吆倦。 要確定這些屏幕缺口區(qū)域是否存在及其位置听诸,使用 getDisplayCutout()
函數(shù)。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
View decorView = getWindow().getDecorView();
WindowInsets rootWindowInsets = decorView.getRootWindowInsets();
if (rootWindowInsets != null) {
DisplayCutout cutout = rootWindowInsets.getDisplayCutout();
List<Rect> boundingRects = cutout.getBoundingRects();
if (boundingRects != null && boundingRects.size() > 0) {
String msg;
for (Rect rect : boundingRects) {
msg = s+"left-" + rect.left;
Log.d(TAG, msg);
}
}
}
}
用新的窗口布局屬性 layoutInDisplayCutoutMode 為設(shè)備屏幕缺口周圍的內(nèi)容進(jìn)行布局蚕泽。 可以將此屬性設(shè)為下列值之一:
LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
The window is allowed to extend into the DisplayCutout area, only if the DisplayCutout is fully contained within a system bar. Otherwise, the window is laid out such that it does not overlap with the DisplayCutout area.
LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
The window is always allowed to extend into the DisplayCutout areas on the short edges of the screen. The window will never extend into a DisplayCutout area on the long edges of the screen.屏幕短邊有cutout晌梨,會(huì)延伸過(guò)去桥嗤;若cutout在長(zhǎng)邊,一定不會(huì)延伸過(guò)去仔蝌。
In this mode, the window extends under cutouts on the short edge of the display in both portrait and landscape, regardless of whether the window is hiding the system bars
On the other hand, should the cutout be on the long edge of the display, a letterbox will be applied such that the window does not extend into the cutout on either long edge在長(zhǎng)邊有cutout的情況泛领,會(huì)排出在外。
LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
The window is never allowed to overlap with the DisplayCutout area.
This should be used with windows that transiently set View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION to avoid a relayout of the window when the respective flag is set or cleared.
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
getWindow().setAttributes(lp);
Channel settings, broadcasts, and Do Not Disturb
Android 8.0 引入了通知渠道敛惊,允許您為要顯示的每種通知類型創(chuàng)建可由用戶自定義的渠道渊鞋。 Android 9 通過(guò)下列變更簡(jiǎn)化通知渠道設(shè)置:
屏蔽渠道組:現(xiàn)在,用戶可以針對(duì)某個(gè)應(yīng)用在通知設(shè)置中屏蔽整個(gè)渠道組瞧挤。 您可以使用
isBlocked()
函數(shù)確定何時(shí)屏蔽一個(gè)渠道組锡宋,從而不會(huì)向該組中的渠道發(fā)送任何通知。
此外特恬,您的應(yīng)用可以使用全新的getNotificationChannelGroup()
函數(shù)查詢當(dāng)前渠道組設(shè)置执俩。全新的廣播 Intent 類型:現(xiàn)在,當(dāng)通知渠道和渠道組的屏蔽狀態(tài)發(fā)生變更時(shí)鸵鸥,Android 系統(tǒng)將發(fā)送廣播 Intent奠滑。 擁有已屏蔽的渠道或渠道組的應(yīng)用可以偵聽(tīng)這些 Intent 并做出相應(yīng)的回應(yīng)丹皱。 有關(guān)這些 Intent 操作和 extra 的更多信息妒穴,請(qǐng)參閱 NotificationManager 參考中更新的常量列表。 有關(guān)響應(yīng)廣播 Intent 的信息摊崭,請(qǐng)參閱廣播讼油。
NotificationManager.Policy 有 3 種新的“請(qǐng)勿打擾”優(yōu)先級(jí)類別:
PRIORITY_CATEGORY_ALARMS
優(yōu)先處理警報(bào)。PRIORITY_CATEGORY_MEDIA
優(yōu)先處理媒體源的聲音呢簸,如媒體和語(yǔ)音導(dǎo)航矮台。PRIORITY_CATEGORY_SYSTEM
優(yōu)先處理系統(tǒng)聲音。NotificationManager.Policy 還有 7 種新的“請(qǐng)勿打擾”常量根时,可以用來(lái)抑制視覺(jué)中斷:
SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
防止通知啟動(dòng)全屏 Activity瘦赫。SUPPRESSED_EFFECT_LIGHTS
屏蔽通知燈赦肋。SUPPRESSED_EFFECT_PEEK
防止通知短暫進(jìn)入視圖(“滑出”)刃永。SUPPRESSED_EFFECT_STATUS_BAR
防止通知顯示在支持狀態(tài)欄的設(shè)備的狀態(tài)欄中。SUPPRESSED_EFFECT_BADGE
在支持標(biāo)志的設(shè)備上屏蔽標(biāo)志吩蔑。 如需了解詳細(xì)信息替裆,請(qǐng)參閱修改通知標(biāo)志校辩。SUPPRESSED_EFFECT_AMBIENT
在支持微光顯示的設(shè)備上屏蔽通知。SUPPRESSED_EFFECT_NOTIFICATION_LIST
防止通知顯示在支持列表視圖(如通知欄或鎖屏)的設(shè)備的列表視圖中辆童。
隱私權(quán)變更-現(xiàn)在收的原來(lái)越緊宜咒,安卓也越來(lái)越規(guī)范
為了增強(qiáng)用戶隱私,Android 9 引入了若干行為變更把鉴,如限制后臺(tái)應(yīng)用訪問(wèn)設(shè)備傳感器故黑、限制通過(guò) Wi-Fi 掃描檢索到的信息,以及與通話、手機(jī)狀態(tài)和 Wi-Fi 掃描相關(guān)的新權(quán)限規(guī)則和權(quán)限組倍阐。
無(wú)論采用哪一種目標(biāo) SDK 版本概疆,這些變更都會(huì)影響運(yùn)行于 Android 9 上的所有應(yīng)用。
后臺(tái)對(duì)傳感器的訪問(wèn)受限
Android 9 限制后臺(tái)應(yīng)用訪問(wèn)用戶輸入和傳感器數(shù)據(jù)的能力峰搪。 如果您的應(yīng)用在運(yùn)行 Android 9 設(shè)備的后臺(tái)運(yùn)行岔冀,系統(tǒng)將對(duì)您的應(yīng)用采取以下限制:
您的應(yīng)用不能訪問(wèn)麥克風(fēng)或攝像頭。
使用連續(xù)報(bào)告模式的傳感器(例如加速度計(jì)和陀螺儀)不會(huì)接收事件概耻。
使用變化或一次性報(bào)告模式的傳感器不會(huì)接收事件使套。
如果您的應(yīng)用需要在運(yùn)行 Android 9 的設(shè)備上檢測(cè)傳感器事件,請(qǐng)使用前臺(tái)服務(wù)鞠柄。
限制訪問(wèn)通話記錄
Android 9 引入 CALL_LOG 權(quán)限組
并將 READ_CALL_LOG
侦高、WRITE_CALL_LOG
和 PROCESS_OUTGOING_CALLS
權(quán)限移入該組。 在之前的 Android 版本中厌杜,這些權(quán)限位于 PHONE 權(quán)限組奉呛。
如果應(yīng)用需要訪問(wèn)通話記錄或者需要處理去電,則您必須向 CALL_LOG
權(quán)限組明確請(qǐng)求這些權(quán)限夯尽。 否則會(huì)發(fā)生 <mark>SecurityException
</mark>瞧壮。
限制訪問(wèn)電話號(hào)碼
在未首先獲得 READ_CALL_LOG 權(quán)限
的情況下,除了應(yīng)用的用例需要的其他權(quán)限之外匙握,運(yùn)行于 Android 9 上的應(yīng)用無(wú)法讀取電話號(hào)碼或手機(jī)狀態(tài)咆槽。
與來(lái)電和去電關(guān)聯(lián)的電話號(hào)碼可在手機(jī)狀態(tài)廣播(比如來(lái)電和去電的手機(jī)狀態(tài)廣播)中看到,并可通過(guò) PhoneStateListener 類
訪問(wèn)圈纺。 但是秦忿,如果沒(méi)有 READ_CALL_LOG 權(quán)限
,則 PHONE_STATE_CHANGED 廣播和 PhoneStateListener <mark>提供的電話號(hào)碼字段為空</mark>蛾娶。
要從手機(jī)狀態(tài)中讀取電話號(hào)碼灯谣,請(qǐng)根據(jù)您的用例更新應(yīng)用以請(qǐng)求必要的權(quán)限:
- 要通過(guò) PHONE_STATE Intent 操作讀取電話號(hào)碼,同時(shí)需要
READ_CALL_LOG 權(quán)限
和READ_PHONE_STATE 權(quán)限
蛔琅。 - 要從 onCallStateChanged() 中讀取電話號(hào)碼胎许,只需要
READ_CALL_LOG 權(quán)限
。 不需要READ_PHONE_STATE 權(quán)限
揍愁。
電話信息現(xiàn)在依賴設(shè)備位置設(shè)置
如果用戶在運(yùn)行 Android 9 的設(shè)備上<mark>停用設(shè)備定位</mark>呐萨,則以下函數(shù)不提供結(jié)果:
- TelephonyManager.getAllCellInfo()
- TelephonyManager.listen()
- TelephonyManager.getCellLocation()
- TelephonyManager.getNeighboringCellInfo()
Build.SERIAL 始終設(shè)置為 "UNKNOWN" 以保護(hù)用戶的隱私。
如果您的應(yīng)用需要訪問(wèn)設(shè)備的硬件序列號(hào)莽囤,您應(yīng)改為請(qǐng)求 READ_PHONE_STATE
權(quán)限谬擦,然后調(diào)用 getSerial()。
多進(jìn)程 webview 信息訪問(wèn)限制
在 Android P 中為了提升系統(tǒng)的安全性朽缎,用戶無(wú)法在多進(jìn)程的 webview 中共享數(shù)據(jù)目錄惨远,該目錄下存儲(chǔ)的是一些 cookies谜悟、Http 緩存和其他一些永久、臨時(shí)的緩存北秽。當(dāng)下不少應(yīng)用會(huì)把 webview 放在另一個(gè)進(jìn)程中打開(kāi)以避免內(nèi)存泄漏葡幸,但是他們 cookies 的設(shè)置往往還是在主進(jìn)程中,所以開(kāi)發(fā)者需要仔細(xì)排查自己的應(yīng)用是否有這么使用贺氓,webview 相關(guān)運(yùn)行是否正常等蔚叨。
對(duì)使用非 SDK 接口的限制
為幫助確保應(yīng)用穩(wěn)定性和兼容性,此平臺(tái)對(duì)某些非 SDK 函數(shù)和字段的使用進(jìn)行了限制辙培;無(wú)論您是直接訪問(wèn)這些函數(shù)和字段蔑水,還是通過(guò)反射或 JNI 訪問(wèn),這些限制均適用扬蕊。 在 Android 9 中搀别,您的應(yīng)用可以繼續(xù)訪問(wèn)這些受限的接口;<mark>該平臺(tái)通過(guò) toast
和日志
條目提醒您注意這些接口</mark>尾抑。 如果您的應(yīng)用顯示這樣的 toast歇父,則必須尋求受限接口之外的其他實(shí)現(xiàn)策略。 如果您認(rèn)為沒(méi)有可行的替代策略再愈,您可以提交錯(cuò)誤以請(qǐng)求重新考慮此限制榜苫。
SDK 接口的鏈接
對(duì)于非SDK 接口
- 淺灰名單:仍可以訪問(wèn)的非 SDK 函數(shù)/字段。
- 深灰名單:
對(duì)于目標(biāo) SDK 低于 API 級(jí)別 28 的應(yīng)用践磅,允許使用深灰名單接口单刁。
對(duì)于目標(biāo) SDK 為 API 28 或更高級(jí)別的應(yīng)用:行為與黑名單相同灸异。 - 黑名單:受限府适,無(wú)論目標(biāo) SDK 如何
平臺(tái)將提示接口并不存在。
例如肺樟,無(wú)論應(yīng)用何時(shí)嘗試使用接口檐春,<mark>平臺(tái)都會(huì)引發(fā)NoSuchMethodError
/NoSuchFieldException
,</mark>即使應(yīng)用想要了解某個(gè)特殊類別的字段/函數(shù)名單么伯,平臺(tái)也不會(huì)包含接口疟暖。
檢測(cè)是否使用了非SDK接口
- 工具veridex
- 下載工具,閱讀README.txt
- 打包一個(gè)應(yīng)用 APK田柔,建議使用 release 包俐巴,排除一些未使用到的單元測(cè)試類或者其他因素的影響,取消混淆硬爆,將 APK 放到工具目錄下欣舵;
- 執(zhí)行命令 ./appcompat.sh --dex-file=test.apk,在終端上會(huì)輸出三個(gè)名單每個(gè) API 的詳細(xì)調(diào)用處
非 SDK API 的處理
適配的原則是優(yōu)先黑名單和深灰名單缀磕,淺灰名單在官方未有替代 API 之前可以暫時(shí)不適配缘圈,在 Android P 上運(yùn)行也不會(huì)有任何問(wèn)題劣光。
- 向google申請(qǐng)
在之前 DP 版本時(shí)開(kāi)發(fā)者如果遇到了不得不使用的黑名單或者深灰名單 API,需要向 google 官方及時(shí)提出反饋 (反饋url)申請(qǐng)將其移動(dòng)到淺灰名單中糟把,但是目前正式版本已經(jīng)發(fā)布绢涡,未得知該申請(qǐng)通道是否仍有效。 - 針對(duì)第三方庫(kù)調(diào)用到了非 SDK API 接口遣疯,解決辦法當(dāng)然是直接查詢相關(guān)資料或者聯(lián)系庫(kù)提供方雄可,確認(rèn)是否有適配 Android P 新版本的 SDK。還有需要提到的一點(diǎn)缠犀,就算更換適配完成的第三方 SDK 后滞项,仍然可能會(huì)在同一地方掃描出非 SDK API 的調(diào)用,這是因?yàn)檫m配工程師只是在調(diào)用處加了一個(gè) try-catch 保護(hù)邏輯夭坪,雖然這樣也勉強(qiáng)叫做適配完成文判,但是還是強(qiáng)烈建議大家使用如下的適配方式:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// Android P or above
} else {
// below Android P
}
嚴(yán)格按照上面的適配方案,掃描工具就不會(huì)再掃描出此處的非 SDK API 調(diào)用室梅,我們也無(wú)需每次都去確認(rèn)所有非 SDK API 調(diào)用處都加了保護(hù)邏輯戏仓。
當(dāng)然如果第三方庫(kù)沒(méi)有適配也沒(méi)有近期適配的意向,目前有兩種方法:第一種是屏蔽入口亡鼠;第二種是反編譯 SDK赏殃,在關(guān)鍵地方加上適配代碼;
非Activity-Context啟動(dòng)Activity间涵,現(xiàn)在強(qiáng)制執(zhí)行 FLAG_ACTIVITY_NEW_TASK
要求
Apache HTTP 客戶端棄用仁热,影響采用非標(biāo)準(zhǔn) ClassLoader 的應(yīng)用
將 compileSdkVersion 升級(jí)到 28 之后,如果在項(xiàng)目中用到了 Apache HTTP client 的相關(guān)類勾哩,<mark>就會(huì)拋出找不到這些類的錯(cuò)誤</mark>抗蠢。這是因?yàn)楣俜揭呀?jīng)<mark>在 Android P 的啟動(dòng)類加載器中將其移除</mark>,如果仍然需要使用 Apache HTTP client.
- 在 Manifest 文件中加入:
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
- 或者也可以直接將 Apache HTTP client 的相關(guān)類打包進(jìn) APK 中思劳。
- 如果它們委托給
系統(tǒng) ClassLoader
迅矛,則應(yīng)用在 Android 9 或更高版本上將失敗并顯示 NoClassDefFoundError,因?yàn)?系統(tǒng) ClassLoader
不再識(shí)別這些類潜叛。 為防止將來(lái)出現(xiàn)類似問(wèn)題秽褒,一般情況下,應(yīng)用應(yīng)通過(guò)應(yīng)用 ClassLoader
加載類威兜,而不是直接訪問(wèn)系統(tǒng) ClassLoader
前臺(tái)服務(wù)
針對(duì) Android 9 或更高版本并使用前臺(tái)服務(wù)的應(yīng)用<mark>必須請(qǐng)求</mark> FOREGROUND_SERVICE 權(quán)限
销斟。 這是普通權(quán)限,因此椒舵,系統(tǒng)會(huì)自動(dòng)為請(qǐng)求權(quán)限的應(yīng)用授予此權(quán)限蚂踊。
如果針對(duì) Android 9 或更高版本的應(yīng)用嘗試創(chuàng)建一個(gè)前臺(tái)服務(wù)且未請(qǐng)求 FOREGROUND_SERVICE,則系統(tǒng)會(huì)引發(fā) SecurityException逮栅。
新開(kāi)了個(gè)個(gè)人公眾號(hào)悴势,求關(guān)注, 希望有懂運(yùn)營(yíng)的朋友給點(diǎn)建議