整个8.0适配,设计的部分包括6部分(我项目中的,其他的适配感觉并不会影响项目的运行)
1)运行时权限
2)通知Notifaction适配
3)未知来源apk安装适配
4)后台执行限制(后台服务)
5)悬浮框适配
6)集合的处理 (AbstractCollection使用限制)
一:运行时权限
android6.0的运行时权限,当一个权限被允许后,该权限同一组中的权限也都会默认被允许,8.0修复了该bug。每一个权限都要去单一申请。
二:通知Notifaction适配
8.0安卓新增了 “通知渠道“ 的概念,所有的通知必须增加通知渠道,否则会导致crash。适配起来也是非常的简单,只要我们创建一个渠道对象,然后将对象以参数的方式传入即可。白话:创建 Notification.Builder 对象的传参增加了渠道id。
8.0以下创建通知的方式:
mBuilder = new Notification.Builder(MainApplicaton.getInstance());
8.0以上创建通知的方式分三步:
第一步:创建渠道对象
NotificationChannel channel = new NotificationChannel(“01”, “消息”, NotificationManager.IMPORTANCE_HIGH);
channel.canBypassDnd();//是否绕过请勿打扰模式
channel.enableLights(true);//闪光灯
channel.setLockscreenVisibility(VISIBILITY_PUBLIC);//锁屏显示通知
channel.setLightColor(android.graphics.Color.RED);//闪关灯的灯光颜色
channel.canShowBadge();//桌面launcher的消息角标
channel.getGroup();//获取通知取到组
channel.setBypassDnd(true);//设置可绕过勿扰模式
channel.shouldShowLights();//是否会有灯光
第二步:添加渠道
mNotificationManager = (NotificationManager) mGContext.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.createNotificationChannel(channel);
第三步:创建通知
mBuilder = new Notification.Builder(mGContext, “01”); //此处的01很重要
完整的代码如下:
private NotificationUtil() {
mGContext = MainApplicaton.getInstance();
mNotificationManager = (NotificationManager) mGContext.getSystemService(Context.NOTIFICATION_SERVICE);
}
/**
* 初始化notifacation 包括适配8.0增加channel
*/
private void initNotification() {
if (Build.VERSION.SDK_INT >= 26) {
NotificationChannel channel = new NotificationChannel(“01”, “消息”, NotificationManager.IMPORTANCE_HIGH);
channel.canBypassDnd();//是否绕过请勿打扰模式
channel.enableLights(true);//闪光灯
channel.setLockscreenVisibility(VISIBILITY_PUBLIC);//锁屏显示通知
channel.setLightColor(android.graphics.Color.RED);//闪关灯的灯光颜色
channel.canShowBadge();//桌面launcher的消息角标
channel.getGroup();//获取通知取到组
channel.setBypassDnd(true);//设置可绕过勿扰模式
channel.shouldShowLights();//是否会有灯光
mNotificationManager.createNotificationChannel(channel);
mBuilder = new Notification.Builder(mGContext, "01");
} else {
mBuilder = new Notification.Builder(MainApplicaton.getInstance());
}
}
三:未知来源apk安装适配
8.0后安装一个未知的apk的时候,需求进行判断,如果是未知来源的需要申请权限。
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
boolean haveInstallPermission = context.getPackageManager().canRequestPackageInstalls();
//没有未知来源的安装权限需要引导用户进入到设置页面
if (!haveInstallPermission) {
Toast.makeText(context, "安装应用需要打开未知来源权限,请去设置中开启权限", Toast.LENGTH_LONG).show();
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
context.startActivityForResult(intent, 0);
} else {
installApk(context, localUri); //安装apk
}
} else {
installApk(context, localUri); //安装apk
}
。。。。
//安装apk
private void installApk(Activity context, @Nullable String apkPath) {
if (TextUtils.isEmpty(apkPath) || context == null) {
return;
}
File file = new File(apkPath);
Intent intent = new Intent(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
} else {
//Android7.0之后获取uri要用contentProvider
Uri apkUri = FileProvider.getUriForFile(context, context.getPackageName(), file);
//Granting Temporary Permissions to a URI
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
四:后台执行限制(后台服务+隐式广播)
隐式广播:应用无法使用清单注册隐式广播,但可以在运行的时候进行显示广播的注册。
后台服务:当应用处于空闲时,几分钟后在后台启动service,会导致crash。解决办法是将后台服务该为前台服务。
**
* Created by malei on 2019/1/22.
* 该类适配service8.0的启动方式
*/
public class BaseService extends Service {
public static final String CHANNEL_ID_STRING = "guagua001";
public static final String CHANNEL_NAME = "guazi";
//适配8.0 启动service 8.0后应用进入后台,5分钟左右不可以在启动后台服务
public static void startService(Context context, Intent intent) {
if (context == null || intent == null) {
return;
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
context.startService(intent);
}
}
@Override
public void onCreate() {
super.onCreate();
adapter8();
}
//适配8.0service
private void adapter8() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_STRING, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(mChannel);
Notification notification = new Notification.Builder(getApplicationContext(), CHANNEL_ID_STRING).build();
startForeground(1, notification);
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
这样当我们需要使用service的时候,可以直接基础该BaseService父类。
同时也可以,在大多数情况下,应用都可以使用 JobScheduler
克服这些限制。