Android 7.0调用系统相机适配-bo

版权声明:本文为博主原创文章,未经博主允许不得转载。

目录(?)[+]

对于Android N以下,文件直接Uri.fromFile(file)就可以直接使用,Audroid N 即编译app的版本 compileSdkVersion 24时,此时会报出FileUriExposedException异常,解释如下:

对于面向AndroidN 的应用,Android框架执行的 StrictMode,API 禁止向您的应用外公开 file://URI。

如果一项包含文件 URI 的 Intent 离开您的应用,应用失败,并出现 FileUriExposedException异常。

若要在应用间共享文件,您应发送一项 content://URI,并授予 URI 临时访问权限。

进行此授权的最简单方式是使用 FileProvider类。

@Overridepublic voidonTakePhoto() {if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.N) {//7.0及其以后版本使用升级后的代码处理Intent takePictureIntent =newIntent(MediaStore.ACTION_IMAGE_CAPTURE);if(takePictureIntent.resolveActivity(getPackageManager()) !=null) {//判断是否有相机应用picName= DateUtil.format(newDate(),"yyyyMMddHHmmss") +".jpg";File imagePath =newFile(Files.photoPath,picName);Uri photoURI =getUriForFile(this,"xxx.xxx.xxx",imagePath);takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,photoURI);startActivityForResult(takePictureIntent,PHOTO_REQUEST_TAKEPHOTO);}    }else{//7.0之前还保持原来方案进行处理即可Intent cameraintent =newIntent(MediaStore.ACTION_IMAGE_CAPTURE);picName= DateUtil.format(newDate(),"yyyyMMddHHmmss") +".jpg";File f =newFile(Files.photoPath,picName);cameraintent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(f));PrefTool.setBooleanSave(this,Prefs.PRE_NOT_TO_BACKGROUD, true);startActivityForResult(cameraintent,PHOTO_REQUEST_TAKEPHOTO);}}

现在,需要配置FileProvider。在应用程序的清单,提供者添加到您的应用程序,authorities=”applicationId.fileprovider”,使用时

file-path

表示你应用内部存储区域的文件的子目录。这个子目录和getFilesDir()的返回值一样。external-path

表示你应用外部存储区域的文件的子目录。这个子目录和getExternalFilesDir()的返回值一样。cache-path

表示你应用内部存储区域的缓存子目录。这个子目录的根目录和getCacheDir()的返回值一样。(如果你修改了provider和paths中的值,需要把应用卸载重装或者开关机一下才能看到变化。)

@Overrideprotected voidonActivityResult(intrequestCode, intresultCode,Intent data) {super.onActivityResult(requestCode,resultCode,data);switch(requestCode) {casePHOTO_REQUEST_TAKEPHOTO:// 当选择拍照时调用if(resultCode ==RESULT_CANCELED) {return;}else if(resultCode !=RESULT_OK) {                showMsg("Take photo failed.");}else{              //处理返回数据}break;

}

}

关于FileProvider

FileProvider 是 ContentProvider 的一个特殊的子类,它有利于安全地分享应用相关的文件,通过对一个文件创建content:// Uri而不是file:/// Uri。

由于FileProvider的默认功能包括文件的content URI的生成,你并不需要在代码中定义一个子类。相反,你可以在你的应用中包含一个FileProvider通过在XML文件中指定它。对于指定FileProvider,添加一个元素在你应用的清单文件中。设置android:name属性为android.support.v4.content.FileProvider。根据你控制的域名设置android:authorities属性为一个URI authority(authorities可以随意填写,但是要保证使用时与authority保持一致,推荐applicationId.fileprovider,以免定义重复)。设置android:exported属性为false;FileProvider不需要公开。设置android:grantUriPermissions属性为true,为了允许你进行临时访问文件的授权。

一个FileProvider只能生成一个content

URI

对应你事先指定目录下的文件。对于指定一个目录,使用元素的子元素,在XML中指定它的存储区域和路径。例如,下面的paths元素告诉FileProvider你打算请求你的私有文件区域的

images/ 子目录的content URIs

以下摘自Androiddeveloper 文档:

虚拟文件

在较早的 Android 版本中,您的应用可以使用存储访问框架来允许用户从他们的云存储帐户中选择文件,如 Google Drive。但是,不能表示没有直接字节码表示的文件;每个文件都必须提供一个输入流。

Android 7.0 在存储访问框架中添加了虚拟文件的概念。虚拟文件功能可以让您的DocumentsProvider返回可与ACTION_VIEWintent

使用的文件 URI,即使它们没有直接字节码表示。Android 7.0 还允许您为用户文件(虚拟或其他类)提供备用格式。

为获得您的应用中的虚拟文件的 URI,首先您应创建一个Intent以打开文件选择器 UI。由于应用不能使用openInputStream()方法来直接打开一个虚拟文件,因此如果您包括了CATEGORY_OPENABLE类别,您的应用不会收到任何虚拟文件。

在用户选择之后,系统调用onActivityResult()方法。您的应用可以检索虚拟文件的 URI,并得到一个输入流,这表现在以下片段中的代码。

// Other Activity code ...finalstaticprivateintREQUEST_CODE=64;// We listen to the OnActivityResult event to respond to the user's selection.@OverridepublicvoidonActivityResult(intrequestCode,intresultCode,IntentresultData){try{if(requestCode==REQUEST_CODE&&resultCode==Activity.RESULT_OK){Uriuri=null;if(resultData!=null){uri=resultData.getData();ContentResolverresolver=getContentResolver();// Before attempting to coerce a file into a MIME type,// check to see what alternative MIME types are available to// coerce this file into.String[]streamTypes=resolver.getStreamTypes(uri,"*/*");AssetFileDescriptordescriptor=resolver.openTypedAssetFileDescriptor(uri,streamTypes[0],null);// Retrieve a stream to the virtual file.InputStreaminputStream=descriptor.createInputStream();}}}catch(Exceptionex){Log.e("EXCEPTION","ERROR: ",ex);}}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容