Android6.0-9.0版本适配攻略

众所周知,Android版本更新飞快,各个版本都有一些新的特性增加,这就出现了许多坑,导致了开发者要不断进行适配,下面我就来谈谈从Android6.0到Android9.0主流特性的适配过程。

Anrdoid 6.0

1.动态权限

Android 6.0最大的更改就是动态权限申请,详细的说明请查看我的另一篇博客:Android开发之Android6.0权限管理

2.弃用HttpClient

Android6.0以后,AndroidSDK已经不再使用Apache Http的相关api,如果你的项目需要使用HttpClient,需要在app的build.gradle文件添加如下配置:

defaultConfig {
        useLibrary 'org.apache.http.legacy'
}

注:Android 9.0之后已经完全移除了对Apache HTTP 客户端的支持,即时你配置了上面的也不起作用,详情请看下面Android9.0的适配。

Android 7.0

Android7.0在6.0的基础上对权限这一块更加严格地控制,主要体现有:

1.应用间共享文件

如果你的应用想要通过Intent访问本地文件(夹),那么在Android7.0或许会报这个错android.os.FileUriExposedException。

这是因为,7.0禁止了应用间文件的直接访问,具体解决方案请看:安卓7.0报错android.os.FileUriExposedException

2.App新签名方案V2

Android 7.0 引入一项新的应用签名方案 APK Signature Scheme v2,它能提供更快的应用安装时间和更多针对未授权 APK 文件更改的保护。在默认情况下,Android Studio 2.2 以上和Gradle 2.2 以上会使用 APK Signature Scheme v2 和传统签名方案来签署您的应用。

在应用打包时,必须勾选上两个

1)只勾选v1签名就是传统方案签署,但是在7.0上不会使用V2安全的验证方式。
2)只勾选V2签名7.0以下会显示未安装,7.0上则会使用了V2安全的验证方式。
3)同时勾选V1和V2则所有版本都没问题。

3.SharedPreferences问题

//Context.MODE_WORLD_READABLE:7.0以后不推荐使用这个,已经过时,这个也属于应用间共享文件的范畴,修改成MODE_PRIVATE
SharedPreferences sp = context.getSharedPreferences("key", Context.MODE_WORLD_READABLE);

MODE_WORLD_READABLE在安卓7.0后的api不再推荐使用,如果需要共享应用间配置,推荐使用ContentProvider或者Broadcast。

Android 8.0

1.新增权限

PHONE权限组新增两个权限:

android.permission.ANSWER_PHONE_CALLS:允许您的应用通过编程方式接听呼入电话。要在您的应用中处理呼入电话,您可以使用 acceptRingingCall() 方法。

android.permission.READ_PHONE_NUMBERS:允许您的应用读取设备中存储的电话号码。

安装未知来源应用的权限:

android.permission.REQUEST_INSTALL_PACKAGES:允许安装未知来源的应用

这样系统会自动询问用户完成授权。当然你也可以先使用 canRequestPackageInstalls()查询是否有此权限,如果没有的话使用Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES这个action将用户引导至安装未知应用权限界面去授权。

 private void installAPK(String apkPath){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            boolean hasPermission = getPackageManager().canRequestPackageInstalls();
            if (hasPermission) {
                //安装应用
                install(apkPath);
            } else {
                //跳转至“允许安装未知应用”权限界面,引导用户开启权限
                Uri packageUri = Uri.parse("package:" + this.getPackageName());
                Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageUri);
                startActivityForResult(intent, 101);
            }
        }else {
            //安装应用
            install(apkPath);
        }
    }
    
    private void install(String apkPath){
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_VIEW);
        Uri uri = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            uri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", new File(apkPath));
        } else {
            uri = Uri.fromFile(new File(apkPath));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        intent.setDataAndType(uri, "application/vnd.android.package-archive");
    }

2.Notification的变更

Notification这个东西是我觉得变化的最频繁的,一个版本一个api,十分坑爹。

Android 8.0 新增了NotificationChannel来区别不同渠道的通知。

下面是代码示例:

   /**
     * 使用一个ID来标识不同渠道,在手机中可以禁止接收来自某个渠道的通知
     */
    public static final String CHANNEL_ID = "test";

    private void showNotify(int progress) {
         NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //先创建一个新渠道:渠道ID,渠道名称,渠道重要性
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "channel_name", NotificationManager.IMPORTANCE_LOW);
            channel.enableVibration(false); //对于持续性的通知,有些手机会不断地震动和发出提示音,建议禁用
            channel.enableLights(false); //禁止灯光闪烁提示
            channel.setSound(null, null);
            manager.createNotificationChannel(channel);
        }

        NotificationCompat.Builder notifyBuilder = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//8.0之后,使用渠道,必须使用已经存在的渠道ID
            notifyBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
        } else {
            notifyBuilder = new NotificationCompat.Builder(this);
        }
        notifyBuilder.setSound(null); //禁用提示音,对于持续性的通知,有些手机会不断地震动和发出提示音,建议禁用
        notifyBuilder.setSmallIcon(getResources().getIdentifier("ic_launcher", "mipmap", getPackageName()));
        notifyBuilder.setPriority(NotificationCompat.PRIORITY_HIGH); //优先级
        notifyBuilder.setVisibility(Notification.VISIBILITY_PUBLIC);
        notifyBuilder.setShowWhen(true);
        notifyBuilder.setOnlyAlertOnce(true);//只提示一次
        notifyBuilder.setContentTitle("下载中...");
        notifyBuilder.setAutoCancel(false);
        notifyBuilder.setOngoing(true);
        notifyBuilder.setProgress(100, progress, false);

        Intent intent =new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 100, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        notifyBuilder.setContentIntent(pendingIntent);

        Notification notification = notifyBuilder.build();
        notification.priority = Notification.PRIORITY_HIGH;
        manager.notify(100, notification);
    }

3. 静态广播无法正常接收

Android 8.0 引入了新的广播接收器限制,导致需要移除所有为隐式广播 Intent 注册的广播接收器,使用动态广播代替静态广播。

4.Caused by: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation

 Android 8.0 非全屏透明页面不允许设置方向(后面8.1系统谷歌就去掉了这个限制)

解决方案:

(1)android:windowIsTranslucent设置为false

(2)如果还是想用的话,就去掉清单文件中Activity中的android:screenOrientation这个配置项,

Android 9.0

1.CLEARTEXT communication to life.115.com not permitted by network security policy

Android P 限制了明文流量的网络请求(普通的http请求),非加密的流量请求都会被系统禁止掉。

解决方案:在资源文件新建xml目录,新建文件network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

AndroidManifest配置:

<application
        android:networkSecurityConfig="@xml/network_security_config">
        <uses-library
            android:name="org.apache.http.legacy"
            android:required="false" /><!-- Android P添加对ApacheHttp的支持 -->
</application>

不过还是建议后台的接口都使用https来传递数据会更安全。

针对Android9.0之后的更多适配可看:AndroidP适配指南(必看)

好了,以上就是我遇到过的Android适配的问题,加上一些大神的经验,肯定还不算完整,以后遇到了再补充。

猜你喜欢

转载自blog.csdn.net/gs12software/article/details/84936019