android8.0适配工作

整个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 克服这些限制。

 

 

 

 

 

你可能感兴趣的:(android)