android 7.0 适配
来源:互联网 发布:ubuntu 卸载自带jdk 编辑:程序博客网 时间:2024/05/16 11:55
项目运行两个礼拜了,相机也在7.0以下运行的完美,突然早上同事拿他的7.0手机给我说 这是一个大bug.我一看调用相机直接崩溃。报的错误如下图:
接着我以为是我的文件路径错误,找了老半天没发现问题,仔细想想不太可能了。于是乎,开始求助各大网友了。
解决方案:
1、(推荐)7.0之后你的app就算有权限,给出一个URI之后手机也认为你没有权限。
不用修改原有代码,在Application的oncreate方法中:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build());}
2、在调用相机的时候添加7.0系统的判断,
/*获取当前系统的android版本号*/int currentapiVersion = android.os.Build.VERSION.SDK_INT;Log.e("currentapiVersion","currentapiVersion====>"+currentapiVersion);if (currentapiVersion<24){ intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(pathFile)); startActivityForResult(intent, TAKE_PICTURE);}else { ContentValues contentValues = new ContentValues(1); contentValues.put(MediaStore.Images.Media.DATA, pathFile.getAbsolutePath()); Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(intent, TAKE_PICTURE);}
推荐使用第一种。
参考:https://developer.Android.com/reference/android/support/v4/content/FileProvider.html
这个异常只会在Android 7.0 + 出现,当app使用file:// url 共享给其他app时, 会抛出这个异常。
因为在android 6.0 + 权限需要 在运行时候检查, 其他app 可能没有读写文件的权限, 所以google在7.0的时候加上了这个限制。
官方推荐使用 FileProvider 解决这个问题。
下面我们来看看具体实现步骤。
在manifest.xml文件添加provider,相机,读写文件权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.CAMERA"/><application> ... <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.example.android.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"></meta-data> </provider> ...</application>心得:exported:要求必须为false,为true则会报安全异常。grantUriPermissions:true,表示授予 URI 临时访问权限。
注意 android:authorities 里面的值,在后面使用的getUriForFile(Context, String, File) 中, 第二个参数就是这个里面的值。
作者:起个牛逼的昵称
链接:http://www.jianshu.com/p/eaf122537740
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
编写file_paths.xml
<?xml version="1.0" encoding="utf-8"?><paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="my_images" path="images/"/></paths>
<files-path name="name" path="path" /> //相当 Context.getFilesDir() + path, name是分享url的一部分<cache-path name="name" path="path" /> //getCacheDir()<external-path name="name" path="path" /> //Environment.getExternalStorageDirectory()<external-files-path name="name" path="path" />//getExternalFilesDir(String) Context.getExternalFilesDir(null)<external-cache-path name="name" path="path" /> //Context.getExternalCacheDir()如果有权限,则直接打开系统相机:
/** * 打开系统相机 */private void openCamera() { File file = new FileStorage().createIconFile(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { imageUri = FileProvider.getUriForFile(MainActivity.this, "com.bugull.cameratakedemo.fileprovider", file);//通过FileProvider创建一个content类型的Uri } else { imageUri = Uri.fromFile(file); } Intent intent = new Intent(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 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, REQUEST_CAPTURE);}这里指定保存图片路径的时候,我们做了一个判断,如果运行设备的版本低于7.0,则调用Uri.fromFile(),可以获取到图片的本地真实路径。否则,就调用FileProvider.getUriForFile(),获取一个封装过的uri对象,这是因为从安卓7.0开始,直接使用本地真实路径被认为是不安全的,会抛出FileUriExposedExCeption异常,而FileProvider则是一种特殊的内容提供其,它使用了和内容提供器类似的机制来对数据进行保护,可以选择性地将封装过的Uri共享给外部,从而提高了应用的安全性。
上面我们提到了内容提供器,作为安卓四大组件之一,肯定是要在xml中进行注册的:
对于面向 Android 7.0以上API的应用,Android框架执行的StrictMode
API(严苛模式) 政策禁止在应用向外部公开file://
URI。如果一项包含文件 URI 的 intent 离开你的应用,则应用出现故障,并出现FileUriExposedException
异常。在Android 7.0以上API要在应用间共享文件,需要发送一项content://
URI,并授予 URI 临时访问的权限,进行此授权的最简单方式是使用FileProvider
类。下面以安装Apk为例,具体步骤如下:一:清单文件中设置FileProvider<!--exported:要求必须为false,为true则会报安全异常。--><!--grantUriPermissions:true,表示授予 URI 临时访问权限--><!--authorities 组件标识,按照江湖规矩,都以包名开头${APPLICATION_ID}.fileprovider,避免和其它应用发生冲突,当然也可以自己随便写--><provider android:name="android.support.v4.content.FileProvider" android:authorities="com.winterrunner.vandroid70_install_bug.fileprovider" android:grantUriPermissions="true" android:exported="false"> <!--元数据--> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /></provider>TIPS:注意上面的布局,一般情况下,这样布局即可。但是,如果应用中引用的jar或者module也使用了name=“android.support.v4.content.FileProvider”,这样问题就来了,运行时我们发现会报错,multiple error,怎么办???原因:一个应用只能有一个FileProvider解决办法:有两个解决办法-------方法一:就是覆盖jar或者module的provider,然后把file_paths的内容复制到自己写的file_paths里面一份,有的甚至还要去改动源码,个人感受繁琐的很。具体实现,请自行百度。-------方法二:出现这个错误的根本就是不能出现两个相同名字的类,我们自己换个名字不就行了,继承FileProvider即可步骤:1.写个类MyFileProvider继承FileProvider,okpackage com.winterrunner.vandroid70_install_bug;import android.support.v4.content.FileProvider;/** * Created by L.K.X on 2017/5/9. */public class MyFileProvider extends FileProvider{}2.清单文件修改为:<!--exported:要求必须为false,为true则会报安全异常。--><!--grantUriPermissions:true,表示授予 URI 临时访问权限--><!--authorities 组件标识,按照江湖规矩,都以包名开头${APPLICATION_ID}.fileprovider,避免和其它应用发生冲突,当然也可以自己随便写--><provider android:name=".MyFileProvider" android:authorities="com.winterrunner.vandroid70_install_bug.fileprovider" android:grantUriPermissions="true" android:exported="false"> <!--元数据--> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /></provider>二:res建立xml包,创建file_paths.xml文件<?xml version="1.0" encoding="utf-8"?><resources xmlns:android="http://schemas.android.com/apk/res/android"> <paths> <external-path name="download" path="." /> </paths></resources>三:调用,注意判断Android版本if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //参数1 上下文, 参数2 Provider主机地址 和配置文件中保持一致 参数3 共享的文件 Uri apkUri = FileProvider.getUriForFile(context, "com.winterrunner.vandroid70_install_bug.fileprovider", uriFile); Intent intent = new Intent(Intent.ACTION_VIEW); // 由于没有在Activity环境下启动Activity,设置下面的标签 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //添加这一句表示对目标应用临时授权该Uri所代表的文件 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setDataAndType(apkUri, "application/vnd.android.package-archive"); context.startActivity(intent);}else { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(uriFile), "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent);}阅读全文0 0
- Android安装apk文件,适配Android 7.0
- android Bugly升级SDK适配Android 7.0
- Android 7.0适配
- android 7.0 适配
- android 7.0 拍照 适配
- android 7.0适配
- android N(7.0)适配
- android 安装apk适配7.0
- PopupWindow 适配 Android 7.0 、7.1
- android app 更新下载安装 适配android 7.0
- android适配
- Android 适配
- android适配
- Android适配
- android适配
- android适配
- android 适配
- Android适配
- Lucene学习笔记(一)
- 代理模式
- django模型的用法
- 一天写多少行代码才算是好程序员?
- 如何用Xshell快速连接远程电脑
- android 7.0 适配
- 深度解析tomcat核心配置文件server.xml
- 调用支付宝接口原理
- dll类型的项目debug中没有lib文件
- 栈的反转
- linux open函数
- 【算法】求二叉搜索树的第K个结点
- 数据结构实验之查找四:二分查找
- 做了4个微信小程序后,我总结了一个快速开发流程
原创粉丝点击热门IT博客热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 ug设计多少钱一个月 广东ug网 模具论坛 ug设计培训 ug模具 ug设计 ug教程电子书下载 ug制图初学入门 ug制图 ug爱好者手机版 ug怎么下载 ugnx ug用什么显卡好 ug下载 ug培训班 ug是什么 ug学习教程 ug自学网 ug软件下载 ug入门教程 ug 爱好者 ug网论坛 ug好学吗 ug图纸 学ug要多久 ug模具设计 ug网站 ug版本 ug论坛爱好者 ug数控编程 自学ug编程 学ug有前途吗 ug编程好学吗 ug绘图练习 ug飞机模型 ug分模步骤 ug逆向工程 ug制图教程 ug曲面建模 ug旋转实体 ug入门到精通