Android 8.0适配指南

一、为什么要适配

从 2018 年 8 月 1 日起,所有向 Google Play 首次提交的新应用都必须针对 Android 8.0 (API 等级 26) 开发; 2018 年 11 月 1 日起,所有 Google Play 的现有应用更新同样必须针对 Android 8.0。
国内情况:为保障华为用户的使用体验,华为应用市场已在7月份启动Android P版本应用适配检测工作,针对未做适配的应用开发者陆续进行邮件通知。请您对应用适配这一环节加以重视,并于2018年10月底前完成Android P版本适配工作并自检通过。针对未适配或在Android P版本体验欠佳的应用,华为应用市场将在Android P版本机型上采取下架、不推荐更新或屏蔽策略,可能会对您的推广、用户口碑及品牌产生影响。
每次 Android 版本的更新都会新增一大波优化功能。新版本会让我们的 Android 设备更流畅,更省电,隐私性更好。可以提高用户体验。因此适配对于我们的应用有很大的好处。

二、适配流程

1、通知栏

从 Android 8.0(API 级别 26)开始,所有通知都必须分到一个渠道,否则通知将不会显示。通过将通知分类到渠道,用户可以停用应用的特定通知渠道(而不是停用所有通知),还可以控制某个渠道的视觉和听觉选项,针对不同渠道配置不同的视觉和听觉选项,所有这些操作都在 Android 系统设置中完成。

1)、通知的重要性

Android 使用通知的重要性来决定该通知应在多大程度上(视觉和听觉上)打扰用户。通知的重要性越高,通知的打扰级别就越高。
Android 8.0(API 级别 26)及更高版本上,通知的重要性由通知目标发布渠道的 importance 决定。用户可以在系统设置中更改通知渠道的重要性。在 Android 7.1(API 级别 25)及更低版本上,各通知的重要性由通知的 priority 决定
可能的重要性级别如下:
紧急:发出声音并以浮动通知的形式显示。
高:发出声音。
中:不发出声音。
低:不发出声音,也不在状态栏中显示。
下图方框中就是通知渠道。
通知在这里插入图片描述
下面就是“新消息通知”渠道的设置界面:
在这里插入图片描述

2)、设置通知渠道

fun createNoticeChannel(context: Context, id: String, name: String, desc: String, importance: Int) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val notificationChannel = NotificationChannel(id, name, importance)
        notificationChannel.description = desc
        val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        manager.createNotificationChannel(notificationChannel)
    }
}

显示通知代码如下:

fun showNotification(context: Context
                     , id: Int
                     , channelId: String
                     , title: String = ""
                     , content: String = ""
                     , intent: PendingIntent? = null) {
    val notification = NotificationCompat.Builder(context, channelId)
            .setSmallIcon(R.drawable.ic_launcher_background) // setSmallIcon必须设置,否则不能显示
            .setContentTitle(title)
            .setContentText(content)
            .setAutoCancel(true) // 点击通知栏后通知栏信息会消失
            .setDefaults(NotificationCompat.DEFAULT_SOUND) // 设置通知栏提醒方式。支持声音、震动、呼吸道提醒
            .setOngoing(false) // 设置通知左右滑动删除,false表示可以删除,true表示不能删除
            .setContentIntent(intent)
            .build()

    val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    manager.notify(id, notification)
}

注意:通知渠道创建一次后下次不创建也可以显示通知,包括退出应用后重新进入显示通知。但是卸载应用重新安装,如果没有设置通知渠道就不能显示通知。

2、后台执行限制

如果针对 Android 8.0 的应用尝试在不允许其创建后台服务的情况下使用 startService() 函数,则该函数将引发一个 IllegalStateException。
我们无法得知系统如何判断是否允许应用创建后台服务,所以我们目前只能简单 try-catch startService(),保证应用不会 crash,示例代码:

Intent intent = new Intent(getApplicationContext(),Service.class);
ServiceUtils.safeStartService(mApplication, intent);

public static void safeStartService(Context context, Intent intent) {
    try { 
        context.startService(intent);
    } catch (Throwable th) {
        DebugLog.i("service", "start service: " + intent.getComponent() + "error: " + th);
        ExceptionUtils.printExceptionTrace(th);
    }
}

3、允许安装未知来源应用

8.0 的应用需要在 AndroidManifest.xml 中声明 REQUEST_INSTALL_PACKAGES 权限,否则将无法进行应用内升级。

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

安装apk时需要检查是否打开“允许未知应用安装”,没有打开的话需要跳转到打开界面。代码如下:

// android8.0需要打开“允许未知应用安装”,如果没有打开跳转到设置界面
val haveInstallPermission = getPackageManager().canRequestPackageInstalls()
if (!haveInstallPermission) {
    //权限没有打开则提示用户去手动打开val
    val packageURI = Uri.parse("package:" + getPackageName())
    val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI)
    startActivityForResult(intent, 1)
} else {
    startActivity(intent)
}

然后在onActivityResult中判断打开“允许未知应用安装”的话就开始安装,代码如下:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (resultCode == RESULT_OK && requestCode == 1) {
        startActivity(intent)
    }
}

4、8.0透明主题Activity崩溃

8.0设置透明主题:

<style name="TranslucentCrashTestTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:windowIsTranslucent">true</item>
</style>

为Activity设置透明主题并设置方向。

<activity android:name=".TranslucentCrashTestActivity"
    android:theme="@style/TranslucentCrashTestTheme"
    android:screenOrientation="portrait"/>

然后targetSdkVersion设置27,然后运行在26的手机上就会崩溃,日志如下:
在这里插入图片描述
其他情况不会崩溃,这时Android系统的一个bug。

5、隐式广播限制

1)、广播注册方式

静态注册:也称为清单注册,就是在AndroidManifest.xml中注册的广播。此类广播接收器在应用尚未启动的时候就可以接收到相应广播。
动态注册:也称为运行时注册,也就是在Service或者Activity组件中,通过Context.registerReceiver()注册广播接收器。此类广播接收器是在应用已启动后,通过代码进行注册。registerReceiver传入一个实例化的BroadcastReceiver和IntentFilter。

2)、广播分类

显式广播(Explicit Broadcast):发送的Intent是显示Intent的广播。通过指定Intent组件名称来实现的,它一般用在知道目标组件名称的前提下,去调用以下方法。意图明确,指定了要激活的组件是哪个组件,一般是在相同的应用程序内部实现的。

Intent.setComponent()
Intent.setClassName()
Intent.setClass()
new Intent(A.this,B.class)

隐式广播(Implicit Broadcast):通过Intent Filter来实现的,它一般用在没有明确指出目标组件名称的前提下。Android系统会根据隐式意图中**设置的动作(action)、类别(category)、数据(URI和数据类型)**找到最合适的组件来处理这个意图。一般是用于在不同应用程序之间。

3)、8.0隐式广播的限制

由于 Android 8.0 引入了新的广播接收器限制,因此您应该移除所有为隐式广播 Intent 注册的广播接收器。将它们留在原位并不会在构建时或运行时令应用失效,但当应用运行在 Android 8.0 上时它们不起任何作用
我们自己定义的广播隐式调用不能接收,显式Intent可以接收。或者动态注册,然后隐式调用可以接收。
如果要接收系统广播只能动态注册。

4)、为什么限制隐式广播

在Manifest里面注册的系统广播接收器会被缓存在系统中,即使当App关闭之后,如果有相应的广播发出,应用程序仍然会被唤醒。比如有20个App在Manifest里面注册了ACTION_BOOT_COMPLETED的广播接收器监听设备启动,那么当设备启动时,就会有20个应用程序被唤醒并作出相应的动作。而动态注册的广播则跟随组件的生命周期而消存。因此在Manifest里面注册广播接收器的App越多,设备的性能就越容易受到影响,限制隐式广播主要是为了优化系统性能

5)、例外的隐式广播

这些广播在8.0隐式注册也可以接收。详细见官网:https://developer.android.com/guide/components/broadcast-exceptions

6、权限

在 Android 8.0 之前,如果应用在运行时请求权限并且被授予该权限,系统会错误地将属于同一权限组并且在清单中注册的其他权限也一起授予应用。
对于针对 Android 8.0 的应用,此行为已被纠正。系统只会授予应用明确请求的权限。然而,一旦用户为应用授予某个权限,则所有后续对该权限组中权限的请求都将被自动批准。
例如,假设某个应用在其清单中列出 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE。应用请求 READ_EXTERNAL_STORAGE,并且用户授予了该权限。如果该应用针对的是 API 级别 24 或更低级别,系统还会同时授予 WRITE_EXTERNAL_STORAGE,因为该权限也属于同一 STORAGE 权限组并且也在清单中注册过。如果该应用针对的是 Android 8.0,则系统此时仅会授予 READ_EXTERNAL_STORAGE;不过,如果该应用后来又请求 WRITE_EXTERNAL_STORAGE,则系统会立即授予该权限,而不会提示用户
因此即使同一权限组,每个权限也需要单独申请。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值