Android8.0适配方案
準(zhǔn)備工作
?
將我們項(xiàng)目中的targetSdkVersion改為 26(8.0) 或者 27(8.1)
1運(yùn)行時(shí)權(quán)限
?
首先引用官方的原文。
https://developer.android.google.cn/about/versions/oreo/android-8.0-changes#rmp
?
在 Android 8.0 之前,如果應(yīng)用在運(yùn)行時(shí)請(qǐng)求權(quán)限并且被授予該權(quán)限,系統(tǒng)會(huì)錯(cuò)誤地將屬于同一權(quán)限組并且在清單中注冊(cè)的其他權(quán)限也一起授予應(yīng)用。?
對(duì)于針對(duì) Android 8.0 的應(yīng)用,此行為已被糾正。系統(tǒng)只會(huì)授予應(yīng)用明確請(qǐng)求的權(quán)限。然而,一旦用戶為應(yīng)用授予某個(gè)權(quán)限,則所有后續(xù)對(duì)該權(quán)限組中權(quán)限的請(qǐng)求都將被自動(dòng)批準(zhǔn)。?
例如,假設(shè)某個(gè)應(yīng)用在其清單中列出?READ_EXTERNAL_STORAGE?和?WRITE_EXTERNAL_STORAGE。應(yīng)用請(qǐng)求?READ_EXTERNAL_STORAGE,并且用戶授予了該權(quán)限。如果該應(yīng)用針對(duì)的是 API 級(jí)別 24 或更低級(jí)別,系統(tǒng)還會(huì)同時(shí)授予?WRITE_EXTERNAL_STORAGE,因?yàn)樵摍?quán)限也屬于同一?STORAGE?權(quán)限組并且也在清單中注冊(cè)過(guò)。如果該應(yīng)用針對(duì)的是 Android 8.0,則系統(tǒng)此時(shí)僅會(huì)授予?READ_EXTERNAL_STORAGE;不過(guò),如果該應(yīng)用后來(lái)又請(qǐng)求?WRITE_EXTERNAL_STORAGE,則系統(tǒng)會(huì)立即授予該權(quán)限,而不會(huì)提示用戶。
?
所謂權(quán)限組如下:?
?
?
所以總結(jié)下來(lái),如果你之前是用什么權(quán)限就去申請(qǐng)什么權(quán)限,那么恭喜你,這個(gè)變化不會(huì)影響到你。
?
如果你只申請(qǐng)了權(quán)限組中的某些權(quán)限,卻用了同組的其他權(quán)限,那么你就需要去適配一下了。
?
那么怎么適配呢,如果你去檢查之前每個(gè)申請(qǐng)權(quán)限的地方,未免太過(guò)麻煩。那么你可以根據(jù)你項(xiàng)目中的Manifest文件中需要的權(quán)限與權(quán)限組去對(duì)比,整理出你需要申請(qǐng)的各個(gè)權(quán)限組。比如你需要android.permission.CALL_PHONE(打電話)與android.permission.READ_PHONE_STATE(讀取手機(jī)狀態(tài)) 這兩個(gè)權(quán)限。那么你就整理出了類似下面的類。
?
public?class?PermissionGroup?{//Phone權(quán)限public?static?String[]?PHONE?=?new?String[]?{Manifest.permission.READ_PHONE_STATE,?Manifest.permission.CALL_PHONE};... }?
到時(shí)在申請(qǐng)權(quán)限時(shí)就可以直接獲取它,一次將它們都申請(qǐng)了。這樣就防止了遺漏某個(gè)權(quán)限,導(dǎo)致的異常。
?
2通知適配
ps:也可以參考https://mp.weixin.qq.com/s/Ez-G_9hzUCOjU8rRnsW8SA
其實(shí)8.0在通知這里變化還挺多的,比如通知渠道、通知標(biāo)志、通知超時(shí)、背景顏色的等,詳細(xì)的說(shuō)明可以去看官方的Android 8.0 功能和 API。
?
雖然變化很多,但是國(guó)內(nèi)的機(jī)子貌似支持的不多。。。我在小米的文檔中了解到,Android 已將通知渠道的邏輯納入 Android Compatibility Definition Document (CDD) 中,意味著所有 Android 廠商都必須支持。所以我們可以放心的去適配。
?
?
通知渠道:Android 8.0 引入了通知渠道,其允許您為要顯示的每種通知類型創(chuàng)建用戶可自定義的渠道。用戶界面將通知渠道稱之為通知類別。
?
我個(gè)人很喜歡這個(gè)新特性。也就是說(shuō),我們可以將我們給用戶的通知進(jìn)行分類,我用高德地圖app來(lái)舉例,從左到右分別是小米(MIUI10)、華為(EMUI 8.1.0)、一加(氫OS 5.1):
?
?
?
可以看到高德地圖分的很細(xì)致,分為四個(gè)組共13個(gè)類別(華為貌似對(duì)組不生效)。這樣有個(gè)好處,我們可以控制我們想收到的通知,比如我不喜歡運(yùn)營(yíng)活動(dòng)通知,那我就可以把它關(guān)閉。
?
這樣避免大量的不必要通知,否則使得用戶覺(jué)得煩,一棒子打死。直接關(guān)閉你的允許通知。當(dāng)然了,大量app都還沒(méi)有適配,適配的也都分的不是很細(xì)致,比如下圖的QQ。(沒(méi)有對(duì)比就沒(méi)有傷害)
?
?
?
當(dāng)然更重要的問(wèn)題是,如果不去適配,可能通知都不會(huì)彈出來(lái)。那么適配的方法如下:
?
private?void?createNotificationChannel()?{if?(Build.VERSION.SDK_INT?>=?Build.VERSION_CODES.O)?{NotificationManager?notificationManager?=?(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);//分組(可選)//groupId要唯一String?groupId?=?"group_001";NotificationChannelGroup?group?=?new?NotificationChannelGroup(groupId,?"廣告");//創(chuàng)建groupnotificationManager.createNotificationChannelGroup(group);//channelId要唯一String?channelId?=?"channel_001";NotificationChannel?adChannel?=?new?NotificationChannel(channelId,"推廣信息",?NotificationManager.IMPORTANCE_DEFAULT);//補(bǔ)充channel的含義(可選)adChannel.setDescription("推廣信息");//將渠道添加進(jìn)組(先創(chuàng)建組才能添加)adChannel.setGroup(groupId);//創(chuàng)建channelnotificationManager.createNotificationChannel(adChannel);//創(chuàng)建通知時(shí),標(biāo)記你的渠道idNotification?notification?=?new?Notification.Builder(MainActivity.this,?channelId).setSmallIcon(R.mipmap.ic_launcher).setLargeIcon(BitmapFactory.decodeResource(getResources(),?R.mipmap.ic_launcher)).setContentTitle("一條新通知").setContentText("這是一條測(cè)試消息").setAutoCancel(true).build();notificationManager.notify(1,?notification);} }?
效果如下:?
?
華為手機(jī)當(dāng)只有一個(gè)渠道時(shí),不會(huì)顯示,會(huì)當(dāng)做默認(rèn)通知處理,除非一個(gè)以上。
?
注意:當(dāng)Channel已經(jīng)存在時(shí),后面的createNotificationChannel方法僅能更新其name/description,以及對(duì)importance進(jìn)行降級(jí),其余配置均無(wú)法更新。所以如果有必要的修改只能創(chuàng)建新的渠道,刪除舊渠道。
?
刪除渠道代碼如下:
?
private?void?deleteNotificationChannel(String?channelId){if?(Build.VERSION.SDK_INT?>=?Build.VERSION_CODES.O)?{NotificationManager?mNotificationManager?=?(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);mNotificationManager.deleteNotificationChannel(channelId);}}?
?
3懸浮窗適配
?
使用?SYSTEM_ALERT_WINDOW?權(quán)限的應(yīng)用無(wú)法再使用以下窗口類型來(lái)在其他應(yīng)用和系統(tǒng)窗口上方顯示提醒窗口:
?
-
TYPE_PHONE
-
TYPE_PRIORITY_PHONE
-
TYPE_SYSTEM_ALERT
-
TYPE_SYSTEM_OVERLAY
-
TYPE_SYSTEM_ERROR
?
相反,應(yīng)用必須使用名為?TYPE_APPLICATION_OVERLAY?的新窗口類型。
也就是說(shuō)需要在之前的基礎(chǔ)上判斷一下:
?
if?(Build.VERSION.SDK_INT?>=?Build.VERSION_CODES.O)?{mWindowParams.type?=?WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY }else?{mWindowParams.type?=?WindowManager.LayoutParams.TYPE_SYSTEM_ALERT }?
當(dāng)然記得需要有權(quán)限
?
<uses-permission?android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <uses-permission?android:name="android.permission.SYSTEM_OVERLAY_WINDOW"?/>?
再進(jìn)行判斷.
?
4安裝APK
?
Android 8.0去除了“允許未知來(lái)源”選項(xiàng),所以如果我們的App有安裝App的功能(檢查更新之類的),那么會(huì)無(wú)法正常安裝。
?
首先在AndroidManifest文件中添加安裝未知來(lái)源應(yīng)用的權(quán)限:
?
<uses-permission?android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>?
這樣系統(tǒng)會(huì)自動(dòng)詢問(wèn)用戶完成授權(quán)。當(dāng)然你也可以先使用?canRequestPackageInstalls()查詢是否有此權(quán)限,如果沒(méi)有的話使用Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES這個(gè)action將用戶引導(dǎo)至安裝未知應(yīng)用權(quán)限界面去授權(quán)。
?
private?static?final?int?REQUEST_CODE_UNKNOWN_APP?=?100;private?void?installAPK(){if?(Build.VERSION.SDK_INT?>=?Build.VERSION_CODES.O)?{boolean?hasInstallPermission?=?getPackageManager().canRequestPackageInstalls();if?(hasInstallPermission)?{//安裝應(yīng)用}?else?{//跳轉(zhuǎn)至“安裝未知應(yīng)用”權(quán)限界面,引導(dǎo)用戶開(kāi)啟權(quán)限Uri?selfPackageUri?=?Uri.parse("package:"?+?this.getPackageName());Intent?intent?=?new?Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,?selfPackageUri);startActivityForResult(intent,?REQUEST_CODE_UNKNOWN_APP);}}else?{//安裝應(yīng)用}}//接收“安裝未知應(yīng)用”權(quán)限的開(kāi)啟結(jié)果 @Override protected?void?onActivityResult(int?requestCode,?int?resultCode,?Intent?data)?{super.onActivityResult(requestCode,?resultCode,?data);if?(requestCode?==?REQUEST_CODE_UNKNOWN_APP)?{installAPK();} }?
對(duì)于權(quán)限組、懸浮窗還有安裝未知來(lái)源應(yīng)用的權(quán)限適配,我們也可以使用AndPermission。這樣更加便捷。
https://github.com/yanzhenjie/AndPermission
?
5集合的處理
?
現(xiàn)在,AbstractCollection.removeAll(null)?和?AbstractCollection.retainAll(null)始終引發(fā)?NullPointerException;之前,當(dāng)集合為空時(shí)不會(huì)引發(fā)?NullPointerException。所以我們需要做判空處理。
?
6后臺(tái)執(zhí)行限制
?
https://developer.android.google.cn/about/versions/oreo/background
?
應(yīng)用在兩個(gè)方面受到限制:
?
后臺(tái)服務(wù)限制:處于空閑狀態(tài)時(shí),應(yīng)用可以使用的后臺(tái)服務(wù)存在限制。 這些限制不適用于前臺(tái)服務(wù),因?yàn)榍芭_(tái)服務(wù)更容易引起用戶注意。
?
廣播限制:除了有限的例外情況,應(yīng)用無(wú)法使用清單注冊(cè)隱式廣播。 它們?nèi)匀豢梢栽谶\(yùn)行時(shí)注冊(cè)這些廣播,并且可以使用清單注冊(cè)專門針對(duì)它們的顯式廣播。
?
在大多數(shù)情況下,應(yīng)用都可以使用?JobScheduler?克服這些限制。 這種方式讓應(yīng)用安排為在未活躍運(yùn)行時(shí)執(zhí)行工作,不過(guò)仍能夠使系統(tǒng)可以在不影響用戶體驗(yàn)的情況下安排這些作業(yè)。
?
關(guān)于的用法可以參考官方例子:android-JobScheduler
https://github.com/googlesamples/android-JobScheduler
?
當(dāng)然還有后臺(tái)位置的限制需要去注意。
https://developer.android.google.cn/about/versions/oreo/background-location-limits
?
7圖標(biāo)適配
郭神的博客:https://mp.weixin.qq.com/s/WxgHJ1stBjokPi6lTUd1Mg
?
8安卓6.0-9.0的適配
https://mp.weixin.qq.com/s/K9eIN0veW96sjXoczHms5w
安卓11的文件部分適配
https://mp.weixin.qq.com/s/bEHTMAn9LB8SAUyf8WyF6A
安卓11完整適配
https://mp.weixin.qq.com/s/vwbnZPAFKg1rMYUkHxpirQ
參考
?
MIUI 10 通知類別 / Channel 適配
https://dev.mi.com/console/doc/detail?pId=1303
Create and Manage Notification Channels
https://developer.android.google.cn/training/notify-user/channels
Presentation of Notifications
https://source.android.google.cn/compatibility/8.0/android-8.0-cdd#3_8_user_interface_compatibility
Android 實(shí)現(xiàn)應(yīng)用更新適配 Android O
https://blog.csdn.net/mq2856992713/article/details/79688587
?
原文鏈接:https://mp.weixin.qq.com/s/MhWurQy9oOf9OuDsdBLU-w
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的Android8.0适配方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android7.0适配方案
- 下一篇: 图解八大排序算法