Android7.0 nougat适配

简介


Android7.0是Google2016年I/O大会推出来的代号:nougat—–牛轧糖,在给用户带来一些新的特性如:多窗口支持,随时随地低电耗模式,新增的表情符号,当然也给Android开发者带来不少的挑战!那么Android7.0有哪些行为变更呢?这里小木箱分享一些感想,让大家的app早一天跑在Android7.0上!


一.permission

Android 的版本越来越高,Android对隐私的保护力度也越来越大,Android6.0引入动态权限设置(RuntimePermission)–Android7.0”私有目录被限制访问”,如何让这些change让你的app不被cash,是每一位AndroidDeveloper的责任.


二.私有目录被限制

  • 私有权限文件权限不再发放给所有的application,如果私自打开MODE_WORLD_READABLEMODE_WORLD_WRITEABLE 将会触发SecurityException;

    这就意味你无法通过File这个API访问你的手机里面的数据了

  • 给其他应用传递file://URL类型的URi,触发FileUriExposedException

解决方案:使用FileProvider这个API解决这个问题

  • DownMannager不再按照文件名分享私有存储文件,AndroidN版本访问 COLUMN_LOCAL_FILENAME ,会触发SecurityException.

解决方案:使用ContentResolver.openFileDescriptor()这个API访问DownloadManager 里面的公开文件

三.应用间共享文件

Android7.0禁止你的API对外file://URL ,一些file://URL类型意图离开,会抛出FileUriExposedException 异常如调用:系统照相机或裁剪照片

解决方案:如果应用需要共享文件,可以发送content:// URI类型的Uri,并使用FileProvider进行授权

  • 使用FileProvider
    • 第一步:在清单文件注册Provider
  <provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.jph.takephoto.fileprovider"
    android:grantUriPermissions="true"
    android:exported="false">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

exported:要求必须为false,为true则会报SecurityException。grantUriPermissions:true,表示授予 URI 临时访问权限。

  • 第二步
    指定共享的目录:
    首先在res目录下创建一个xml目录下,然后创建一个file_paths的xml文件,该xml文件已经在清单文件里面引用了,内容如下:
  <?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <external-path path="" name="camera_photos" />
    </paths>
</resources>

其中path=”“有特殊意义的,代表全局根目录,如果path=”picture”代表更目录下的eg:/storage/emulated/0/pictures),那么超过这个范围是不可以的


  • 第三步:使用FileProvider

调用系统照相机为例
 File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists())file.getParentFile().mkdirs();
Uri imageUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", file);//通过FileProvider创建一个content类型的Uri
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
startActivityForResult(intent,1006);

可以看出7.0相比6.0动态添加权限而言,下面我们来看看6.0是怎样申请照相机授权的:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists())file.getParentFile().mkdirs();
Uri imageUri = Uri.fromFile(file);
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
startActivityForResult(intent,1006);
  • ①利用FileProvider创建content类型的uri
  • ②利用 intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);来对目标临时授权,Nougat需要做这样两个操作

    通过FileProvide的Uri的 getUriForFile(Context context, String authority, File file)静态方法,获取uri,该方法的authority是在清单文件中注册的provider的android:authorities=”com.jph.takephoto.fileprovider”

四.裁剪图片

在Android7.0之前,图片裁剪之前需要调用这一行代码:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists())file.getParentFile().mkdirs();
Uri outputUri = Uri.fromFile(file);
Uri imageUri=Uri.fromFile(new File("/storage/emulated/0/temp/1474960080319.jpg"));
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(imageUri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent,1008);

Android7.0 Nougat图片裁剪需要添加这一行代码,否则会出现
android.os.FileUriExposedException,两者的区别也是巧妙的使用了FileProvider辅助ApI取代File

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists())file.getParentFile().mkdirs();
Uri outputUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider",file);
Uri imageUri=FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", new File("/storage/emulated/0/temp/1474960080319.jpg");//通过FileProvider创建一个content类型的Uri
Intent intent = new Intent("com.android.camera.action.CROP");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(imageUri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent,1008);

五.电池和内存

Android 6.0的API23进入了 低一电耗模式,Android7.0对内存和电耗进入更大一步的升级,Android7.0在锁屏状态下限制Apliacation对CPU资源和网络的占用

  • 规则如下:
    1.充电状态,屏幕关闭,关闭应用程序对网络的访问

    2.手机进入低电模式一段时间:owerManager.WakeLock、AlarmManager 闹铃、GPS 和 Wi-Fi 扫描应用余下的低电耗模式限制

六.优化

  • Android7.0将收不到CONNECTIVITY_ACTION 的广播
  • Android7.0无法接收和发送ACTION_NEW_PICTUREACTION_NEW_VIDEO 类型的广播
以上借鉴于Google官方文档,欢迎吐槽,如有不妥之处,还请老司机多多指教.~~~

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值