美文网首页
Android 7.0调用系统相机适配-bo

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

作者: Kerry202 | 来源:发表于2017-06-22 14:44 被阅读658次

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

    目录(?)[+]

    对于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);}}

    相关文章

      网友评论

          本文标题:Android 7.0调用系统相机适配-bo

          本文链接:https://www.haomeiwen.com/subject/lcdfcxtx.html