前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android适配全面总结(二)----版本适配

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

作者头像
AWeiLoveAndroid
发布2018-09-03 16:39:38
2.3K0
发布2018-09-03 16:39:38
举报

版权声明:本文为博主原创文章(部分引用他人博文,已加上引用说明),未经博主允许不得转载。https://cloud.tencent.com/developer/article/1326610

转载请标明出处:

https://cloud.tencent.com/developer/article/1326610

本文出自 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是新增的一个内部类,用它创建通知更方便。接着往下看。

代码语言:javascript
复制
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替代了。

代码语言:javascript
复制
Notification(int icon, CharSequence tickerText, long when)

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

4.常量

  • EXTRA_LARGE_ICON This constant was deprecated in API level 26. Use getLargeIcon(), which supports a wider variety of icon sources.(在API级别26中已弃用。使用getLargeIcon(),它支持更多种图标源。)
  • EXTRA_SMALL_ICON This constant was deprecated in API level 26. Use getSmallIcon(), which supports a wider variety of icon sources.(在API级别26中已弃用。使用getSmallIcon(),它支持更多种图标源。)
  • FLAG_HIGH_PRIORITY This constant was deprecated in API level 16. Use priority with a positive value.(在api16被弃用,请使用正数priority值替代)
  • FLAG_SHOW_LIGHTS This constant was deprecated in API level 26. use shouldShowLights().(在API级别26中已弃用。请使用 shouldShowLights() 替代)
  • PRIORITY_DEFAULT This constant was deprecated in API level 26. use IMPORTANCE_DEFAULT instead.(在API级别26中已弃用。请使用 IMPORTANCE_DEFAULT 替代)
  • PRIORITY_HIGH This constant was deprecated in API level 26. use IMPORTANCE_HIGH instead.(在API级别26中已弃用。请使用 IMPORTANCE_HIGH 替代)
  • PRIORITY_LOW This constant was deprecated in API level 26. use IMPORTANCE_LOW instead.(在API级别26中已弃用。请使用 IMPORTANCE_LOW 替代)
  • PRIORITY_MAX This constant was deprecated in API level 26. use IMPORTANCE_HIGH instead.(在API级别26中已弃用。请使用 IMPORTANCE_HIGH 替代)
  • PRIORITY_MIN This constant was deprecated in API level 26. use IMPORTANCE_MIN instead.(在API级别26中已弃用。请使用 IMPORTANCE_MIN 替代)
  • STREAM_DEFAULT This constant was deprecated in API level 21. Use getAudioAttributes() instead.(在API级别21中已弃用。请使用 getAudioAttributes() 替代)

5.字段Fields

  • audioAttributes 在api 26弃用. 使用 getAudioAttributes() 替代.
  • audioStreamType 在api 21弃用. 使用 audioAttributes 替代.
  • defaults 此字段在API 26弃用。使用getSound()shouldShowLights()shouldVibrate()
  • icon 此字段已在API级别26中弃用。使用setSmallIcon(Icon)替代。
  • largeIcon This field was deprecated in API level 23. Use `setLargeIcon(Icon) instead.
  • ledARGB This field was deprecated in API level 26. use `shouldShowLights().
  • ledOffMS This field was deprecated in API level 26. use `shouldShowLights().
  • ledOnMS This field was deprecated in API level 26. use shouldShowLights().
  • priority This field was deprecated in API level 26. use getImportance() instead.
  • sound This field was deprecated in API level 26. use getSound() instead.
  • vibrate This field was deprecated in API level 26. use getVibrationPattern().

二、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如何申请动态权限

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

代码语言:javascript
复制
//别忘记在清单文件也加上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

代码语言:javascript
复制
<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,文件内容如下:

代码语言:javascript
复制
<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

代码语言:javascript
复制
<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的使用)

代码语言:javascript
复制
//适配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界面设为了透明,然后这个时候又设置了方向为垂直,从而导致了这个问题。 解决方案:

  • 1.找到你设置透明的Activity,然后在他的theme中将android:windowIsTranslucent改为false <item name="android:windowIsTranslucent">false</item>
  • 2.再加入下面这行代码就搞定了。 <item name="android:windowDisablePreview">true</item>

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


七、Android8.0版本更新相关api适配
  • 创建通知渠道
代码语言:javascript
复制
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);
        }
  • 创建Notification
代码语言:javascript
复制
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());
  • 安装apk权限

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

代码语言:javascript
复制
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.11.15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 上一篇文章讲了 屏幕适配 http://www.jianshu.com/p/7aa34434ad4d
  • 这一篇文章讲一下 版本适配 https://www.jianshu.com/p/49fa8ebc0105
  • 下一篇文章讲一下 ROM适配 https://www.jianshu.com/p/f9c67a4b908e
  • 一、同一个api在不同版本都存在,只是api的一些接口方法有变更。
  • 二、Android6.0的动态权限介绍
  • 三、Android6.0如何申请动态权限
  • 四、Android7.0对文件权限进一步升级,提出了新的类FileProvider来获取文件。所以适配的时候一定要注意这一点api的变化。
  • 五、关于Android7.0相机闪退以及相册获取不到图片问题
  • 六、Android 8.0适配报错:Only fullscreen opaque activities can request orientation解决方案:
  • 七、Android8.0版本更新相关api适配
相关产品与服务
短信
腾讯云短信(Short Message Service,SMS)可为广大企业级用户提供稳定可靠,安全合规的短信触达服务。用户可快速接入,调用 API / SDK 或者通过控制台即可发送,支持发送验证码、通知类短信和营销短信。国内验证短信秒级触达,99%到达率;国际/港澳台短信覆盖全球200+国家/地区,全球多服务站点,稳定可靠。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档