安卓资源收集安卓兼容性Android适配

Android适配全面总结(二)----版本适配

2017-11-15  本文已影响755人  AWeiLoveAndroid

版权声明:本文为博主原创文章(部分引用他人博文,已加上引用说明),未经博主允许不得转载。https://www.jianshu.com/p/49fa8ebc0105

转载请标明出处:
https://www.jianshu.com/p/49fa8ebc0105
本文出自 AWeiLoveAndroid的博客


上一篇文章讲了 屏幕适配 http://www.jianshu.com/p/7aa34434ad4d
这一篇文章讲一下 版本适配 https://www.jianshu.com/p/49fa8ebc0105
下一篇文章讲一下 ROM适配 https://www.jianshu.com/p/f9c67a4b908e

在我们的开发中,会对不同安卓版本做适配,比如我之前做过的项目中最低兼容到4.4,最高兼容是最新的系统7.1,由于不同版本的系统中部分API版本也不同,我就要对这些API做特殊处理。新的平台有一些API不能使用旧的API,旧的平台也使用不了新的API。所以这就要考验我们开发人员的能力了。我这里简单给出几点我开发中使用过的一些方式,仅供参考:

一、同一个api在不同版本都存在,只是api的一些接口方法有变更。

这种情况是最好处理的,只要对版本号做判断,对应的系统版本用相应的api方法就好了。为了好维护,建议做一个简单的封装。

举例说明如下:

比如Notification在不同版本的兼容,举例如下:

首先打开谷歌官方文档,看看文档里面的一些说明:

Notification官方文档

1.Notification这个类是added in API level 1,一直都有,只是具体某些方法有变更。继续往下看。

2.这个类有个说明,意思是Notification.Builder是新增的一个内部类,用它创建通知更方便。接着往下看。

A class that represents how a persistent notification is to
be presented to the user using the NotificationManager.

The Notification.Builder has been added to make it easier
to construct Notifications.

3.Public constructors公共的构造方法,其中有3个参数的这个在api 11过时,它被Notification.Builder替代了。

Notification(int icon, CharSequence tickerText, long when)

This constructor was deprecated in API level 11. 
Use Notification.Builder instead.

4.常量

5.字段Fields


二、Android6.0的动态权限介绍

因为Android6.0(API23)开始需要动态申请权限,需要手动申请的权限有8组(短信、电话、联系人、存储、位置、麦克风、日历、相机),共24个,如下所示:

所属权限组 权限
短信 SEND_SMS
短信 RECEIVE_SMS
短信 READ_SMS
短信 RECEIVE_WAP_PUSH
短信 RECEIVE_MMS
电话 READ_PHONE_STATE
电话 CALL_PHONE
电话 READ_CALL_LOG
电话 WRITE_CALL_LOG
电话 ADD_VOICEMAIL
电话 USE_SIP
电话 PROCESS_OUTGOING_CALLS
联系人 READ_CONTACTS
联系人 WRITE_CONTACTS
联系人 GET_ACCOUNTS
存储 READ_EXTERNAL_STORAGE
存储 WRITE_EXTERNAL_STORAGE
位置 ACCESS_FINE_LOCATION
位置 ACCESS_COARSE_LOCATION
麦克风 RECORD_AUDIO
日历 READ_CALENDAR
日历 WRITE_CALENDAR
相机 CAMERA
传感器 BODY_SENSORS

注意:如果应用程序请求在AndroidManifest中列出的危险权限,并且应用程序已经在同一权限组中具有另一个危险权限,系统会立即授予权限,而不会与用户进行任何交互。
例如,如果一个应用程序先前已经请求并被授予READ_CONTACTS权限,然后它请求WRITE_CONTACTS(同属于联系人一组),系统会立即授予该权限,不会再弹出权限授予询问的对话框。


三、Android6.0如何申请动态权限

开发中经常会遇到拍照的权限申请,这里就讲一下如何动态设置拍照权限:

//别忘记在清单文件也加上CAMERA权限
//<uses-permission android:name="android.permission.CAMERA" />

// 定义识别码
public static final int CAMERA_OK = 1;

//动态申请拍照权限
if (Build.VERSION.SDK_INT>22){
   if (ContextCompat.checkSelfPermission(this,Manifest.permission.CAMERA)
        != PackageManager.PERMISSION_GRANTED){
           //先判断有没有权限 ,没有就在这里进行权限的申请
           requestPermissions(new String[]{Manifest.permission.CAMERA}, CAMERA_OK);       
    }else {
            //说明已经获取到摄像头权限了,可以去选择照片或者拍照了。
            toSelectPhotoOrOpenCamera();
    }
}else {
      //这个说明系统版本在6.0之下,不需要动态获取权限,直接去选择照片或者拍照。
      toSelectPhotoOrOpenCamera();
}

//在Activity中重写权限获取方法:

/**
* 权限操作结果处理
*/
@Override
public void onRequestPermissionsResult(int requestCode,
                       String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case CAMERA_OK: 
            if (grantResults.length > 0 && grantResults[0]
                         == PackageManager.PERMISSION_GRANTED) {
                 //用户已授权
                toSelectPhotoOrOpenCamera();
            } else {
                //用户拒绝权限
                ToastUtils.show(this, 
                    "缺少相机权限,暂时无法提供扫描功能,请尝试在设置中打开相机权限!", 
                    Toast.LENGTH_LONG);
            }
            break;
        }
    }
}

四、Android7.0对文件权限进一步升级,提出了新的类FileProvider来获取文件。所以适配的时候一定要注意这一点api的变化。

FileProviderContentProvider的子类,把原来文件共享的 file://uri 换成了 content://uri 。一个Uri允许你获取临时权限去读写文件,当使用含有Uri的Intent,可以使用Intent.setFlags来添加临时权限。

下面来看看调用系统相机拍摄照片有如何变化,大致步骤如下所示

(一)在manifest中添加Provider

<manifest>
    ...
    <application>
        ...
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.lzw.demo.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            ...
        </provider>
        ...
    </application>
</manifest>

(二)配置你要获取的文件所在的文件夹 --> 创建一个xml文件,比如file_demo.xml,文件内容如下:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="my_images" path="images/"/>
    ...
</paths>

路径说明:

<files-path name="name" path="path/" />   
   <!--等同于Context.getFilesDir()下面的path文件夹的所有文件--> 

<cache-path name="name" path="path/" />  
   <!--等同于Context.getCacheDir()下面的path文件夹--> 

<external-path name="name" path="path/" /> 
   <!--等同于Environment.getExternalStorageDirectory()下面的path文件夹--> 

<external-files-path name="name" path="path/" /> 
   <!--等同于 Context#getExternalFilesDir(String)下面子文件path文件夹--> 

<external-cache-path name="name" path="path/" /> 
   <!--相当于 Context.getExternalCacheDir()下边的path文件夹--> 

(三)添加路径信息到provier

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.lzw.demo.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_demo" />
</provider>

(四)现在可以去拍照了。(由于Android6.0开始要动态申请权限,所以别忘了,这里就不写了,主要讲FileProvider的使用)

//适配7.0的fileprovider,imgfile是图片文件路径
public void TakePhotoAdaption(File imgFile){
    Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    //适配android7.0 手机拍照取uri的处理
    if(Build.VERSION.SDK_INT<24){
        //7.0如果用会Uri.fromFile(XXX)会闪退,所以这里要特别做一个判断。
        //imgfile是图片文件路径
        uri = Uri.fromFile(imgFile);
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
    }else{
        //7.0+使用FileProvider.getUriForFile这个api
        uri=FileProvider.getUriForFile(DemoActivity.this,
                "com.lzw.demo.fileprovider",imgFile);
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        //添加这一句表示对目标应用临时授权该Uri所代表的文件
        cameraIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION );
    }
    startActivityForResult(cameraIntent, FLAG_CHOOSE_CAMERA);
}

想看到拍照、选择照片、裁剪等完整流程的描述,可以参考这篇博客 解决安卓7.0拍照,相册选择崩溃的问题(包括压缩图片在内)


五、关于Android7.0相机闪退以及相册获取不到图片问题


六、Android 8.0适配报错:Only fullscreen opaque activities can request orientation解决方案:

出现的原因:绝大多数都是因为我们为了提高用户体验,手动取消App启动白屏或者黑屏的时候,将Splash界面设为了透明,然后这个时候又设置了方向为垂直,从而导致了这个问题。

解决方案:

这个坑来自于博客: https://www.jianshu.com/p/d0d907754603


七、Android8.0版本更新相关api适配

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            NotificationChannel mChannel = new NotificationChannel("channel_01",
                    "消息推送", NotificationManager.IMPORTANCE_DEFAULT);
            manager.createNotificationChannel(mChannel);
        }
Context context = DJApplication.getInstance();
        Notification.Builder builder = new Notification.Builder(context);
        builder.setTicker("开始下载");
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setLargeIcon(BitmapFactory.decodeResource(DJApplication.getInstance().getResources(), 
            R.mipmap.ic_launcher));
        builder.setAutoCancel(true);
        PendingIntent pIntent = PendingIntent.getActivity(context, 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentTitle("下载中");
        builder.setContentIntent(pIntent);
        builder.setContentText(text);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder.setChannelId("channel_01");//设置有效的通知渠道 ID,这个ID要和之前创建时候的Channel_ID相同
        }
        manager.notify(1,  builder.build());

在 Android 8.0 中,安装未知应用权限提高了安装未知来源应用时的安全性。此权限与其他运行时权限一样,会与应用绑定,在安装时进行提示,确保用户授予使用安装来源的权限后,此权限才会提示用户安装应用。在运行 Android 8.0 或更高版本的设备上使用此权限时,恶意下载程序将无法骗取用户安装未获得预先授权的应用,所以我们需要加入安装apk文件的权限。

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

这个坑来自微信公众号“代码集中营”。


上一篇下一篇

猜你喜欢

热点阅读