Android从target19升级至target26

背景:因为谷歌要求上架到google play上面的应用targetSdkVersion必须为26以上,国内各大应用渠道也纷纷出台这个要求。而之前目前使用的版本为19,所以进行了一系列的升级变动,本文主要记录升级过程中的一些变动。

运行时权限申请

Android6.0引入了新的权限机制,将系统权限区分为正常权限和危险权限。开发者在使用到危险权限相关的功能时,不仅需要在Manifest文件中配置,还需要在代码中动态获取权限,如果没有确认获取到权限而直接执行相应所需权限的代码,将导致App崩溃。
危险权限:

android.permission.READ_CALENDAR
android.permission.WRITE_CALENDAR
android.permission.CAMERA
android.permission.READ_CONTACTS
android.permission.WRITE_CONTACTS
android.permission.GET_ACCOUNTS
android.permission.ACCESS_FINE_LOCATION
android.permission.ACCESS_COARSE_LOCATION
android.permission.RECORD_AUDIO
android.permission.READ_PHONE_STATE
android.permission.READ_PHONE_NUMBERS
android.permission.CALL_PHONE
android.permission.ANSWER_PHONE_CALLS
android.permission.READ_CALL_LOG
android.permission.WRITE_CALL_LOG
android.permission.ADD_VOICEMAIL
android.permission.USE_SIP
android.permission.PROCESS_OUTGOING_CALLS
android.permission.BODY_SENSORS
android.permission.SEND_SMS
android.permission.RECEIVE_SMS
android.permission.READ_SMS
android.permission.RECEIVE_WAP_PUSH
android.permission.RECEIVE_MMS
android.permission.READ_EXTERNAL_STORAGE
android.permission.WRITE_EXTERNAL_STORAGE
android.permission.SYSTEM_ALERT_WINDOW

我司SDK主要应用到了READ_PHONE_STATE 和 READ_EXTERNAL_STORAGE 这个两个权限,所以在初始化的过程中需要首先判断应用是否授予这两个权限。(申请的时机可以是启动的时候就一次性向用户申请,也可以需要用到的时候才申请,但是必须要注意的是,如果不是强制不授权就退出的话,那么在应用到权限的时候一定要先判断是否拥有该权限)

context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED

通过checkSelfPermission来判断是否授权,如果没有,那就需要向用户申请,接口如下:

ActivityCompat.requestPermissions(this, permissions, 1212);

其中参数permissions是String[]类型,可以同时申请多个权限,系统会弹出对话框依次询问是否授权。授权结束之后会通过onRequestPermissionsResult进行回调,在这个回调中判断是否授权成功。

  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
      super.onRequestPermissionsResult(requestCode, permissions, grantResults);
      if (requestCode == 1212) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
	          if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
	                 if (!shouldShowRequestPermissionRationale(permissions[0])) {
	                      //  引导用户跳转设置界面
	                 } else
	                      finish();
	                 }
              } else {
                Toast.makeText(this, "权限获取成功", Toast.LENGTH_SHORT).show();
              }
           }
      }
   }

在申请权限的页面,如果用户勾选了不在提示而且点击拒绝,那么再次申请的话就会不会弹出申请的弹窗而直接回调失败,那么这时候就只有去设置界面手动开启权限了。
这里建议的解决方案是首次申请权限被拒绝之后,不管用户是否勾选了不在提示,都应该弹出对话框向用户解释申请权限的必要性已经不会造成额外的风险。来引导用户授权,避免多次弹出导致用户勾选不再提示。
通过shouldShowRequestPermissionRationale接口判断用户是否勾选了不再提示选项。如果返回false。则只有引导用户跳转到设置界面去手动开启。

Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, 123);

FileProvider

在Android7.0上面禁止在应用外部公开 file:// URI,如果一项包含文件URI的intent离开应用,则应用出现故障,并出现 FileUriExposedException 异常。
此时需要用到的是FileProvider,我们在应用中会使用更新功能,下载一个新版本的APK之后通知系统安装,需要将下载apk的文件路径携带过去。
Manifest中的配置


    

在res目录下面创建provider_file.xml文件,其中external-path对应文件的位置。



    

安装APK

Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
String type = "application/vnd.android.package-archive";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
	Uri uri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", file);
	intent.setDataAndType(uri, type);
	intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
	intent.setDataAndType(Uri.fromFile(file), type);
}
context.startActivity(intent);

FileProvider冲突时候处理
试想一下,如果应用接入了很多SDK,里面都有FileProvider的配置,这时候在Manifest里面就会有多个FileProvider的配置,然而里面指向的xml文件又不一致,这肯定是不行的。
如果产品是一个SDK需要给别的应用接入,这时候可以自己写一个XXFileProvider类来继承FileProvider即可,避免和别人的冲突。

你可能感兴趣的:(Android,移动开发)