• android 7.0+ FileProvider 访问隐私文件 相册、相机、安装应用的适配


        从 Android 7.0 开始,Android SDK 中的 StrictMode 策略禁止开发人员在应用外部公开 file:// URI。具体表现为,当我们在应用中使用包含 file:// URI 的 Intent 离开自己的应用时,程序会发生FileUriExposedException 异常

     这里我们要使用到的 FileProvider,就是 ContentProvider 的一个特殊子类,帮助我们将访问受限的 file:// URI 转化为可以授权共享的 content:// URI。

    首先 要去 Manifest文件里注册FileProvider

     <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
            <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="${applicationId}.FileProvider" //此处的属性值后面获取URI用到
                android:grantUriPermissions="true"
                android:exported="false">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/file_paths"/>
            </provider>
        </application>

     其次在 res 目录下新建一个 xml 文件夹 里边添加一个xml文件 名字比如:path.xml

    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <external-path name="my_images" path="."/> <!-- 此处的name可以随便取--!>
        
    </paths>

    元素必须包含一到多个子元素。这些子元素用于指定共享文件的目录路径,必须是这些元素之一:

    <files-path>:内部存储空间应用私有目录下的 files/ 目录,等同于 Context.getFilesDir() 所获取的目录路径;

    <cache-path>:内部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getCacheDir() 所获取的目录路径;

    <external-path>:外部存储空间根目录,等同于 Environment.getExternalStorageDirectory() 所获取的目录路径;

    <external-files-path>:外部存储空间应用私有目录下的 files/ 目录,等同于 Context.getExternalFilesDir(null) 所获取的目录路径;

    <external-cache-path>:外部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getExternalCacheDir();

      获取URI的方法:

     在Android7.0以下 获取相册图片URI的方式:

    Uri uri= Uri.from ( file );

     Android 7.0+获取相册图片的方式:

       //注意此处的 第二个参数必须与 Manifest文件中Provider 的 android:authorities 一致
    Uri contentUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".FileProvider", outputFile);

    Android 7.0以下 安装应用:

    Intent installIntent = new Intent(Intent.ACTION_VIEW);
    installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    installIntent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
    startActivity(installIntent);

    Android 7.0+ 安装应用:

    //采用FileProvider的方式访问文件

    File apkFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app_sample.apk");
    Uri apkUri = FileProvider.getUriForFile(this,
    BuildConfig.APPLICATION_ID+".FileProvider", apkFile);


    Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    //添加此处 是临时对文件的授权 必须加上此句 installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); installIntent.setDataAndType(apkUri,
    "application/vnd.android.package-archive"); startActivity(installIntent);

    调用相机的时候:

     public void camera() {
                Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
                tempFile = new File(Environment.getExternalStorageDirectory(),PHOTO_FILE_NAME);                  
                Uri uri;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    uri = FileProvider.getUriForFile(this, "com.camera.fileprovider",tempFile);
    //此处为Uri临时授权 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
    ); } else { uri = Uri.fromFile(tempFile); } intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(intent, PHOTO_REQUEST_CAMERA); }

      裁剪图片:

    public static void cropImageUri(Activity activity, Uri orgUri, Uri desUri, int aspectX, int aspectY, int width, int height, int requestCode) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    //此处为Uri临时授权 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } intent.setDataAndType(orgUri,
    "image/*"); //此处的Uri为 输入Uri用FileProvider的方式获取 intent.putExtra("crop", "true"); intent.putExtra("aspectX", aspectX); intent.putExtra("aspectY", aspectY); intent.putExtra("outputX", width); intent.putExtra("outputY", height); intent.putExtra("scale", true); //将剪切的图片保存到目标Uri中 intent.putExtra(MediaStore.EXTRA_OUTPUT, desUri);//此处的Uri为输出Uri 需要用Uri.fromFile()的方式获取 intent.putExtra("return-data", false); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); activity.startActivityForResult(intent, requestCode); }
  • 相关阅读:
    Nop中的Cache浅析
    使用DapperExtensions实现简单仓储
    使用nodejs爬取拉勾苏州和上海的.NET职位信息
    使用Microsoft Fakes进行单元测试(2)
    使用Microsoft Fakes进行单元测试(1)
    小程序之滚动到页面底部
    小程序之动态修改页面标题
    小程序之面试题
    小程序之公共组件的开发
    小程序之web-view打开外部链接
  • 原文地址:https://www.cnblogs.com/bimingcong/p/10328429.html
Copyright © 2020-2023  润新知