FileFrovider的使用

在Android中,如果需要创建一个文件去保存数据,就需要这个文件URI,在Android 7.0之后,直接使用Uri.fromFile()方法会报不安全错误。FileProvider就是提供了一种安全的Uri转化方式。

FileProvider is a special subclass of ContentProvider that facilitates secure sharing of files associated with an app by creating a content:// Uri for a file instead of a file:/// Uri.

FileProvider的具体用法在Android的API文档中有具体的介绍,链接在这。这篇文章主要是结合一个相机拍照的例子。

FileProvider的使用步骤

创建FileProvider

由于FileProvider是继承自ContentProvider的,所以需要在AndroidManifest文件中声明。

<application
	.../>
	<provider
	    android:name="androidx.core.content.FileProvider"
	    android:authorities="${applicationId}"
	    android:exported="false"
	    android:grantUriPermissions="true">
	    ...
	</provider>
</application>

其中authorities一般设置为包名,exported必须为false,grantUriPermission为true。

指定名称转化文件

开发者文档上叫 Specifying Available Files
这个文件的作用是指定目标文件的目录的别名,以屏蔽真实的路径。有点凌乱,举例说明。
比如文件的真实路径为
/…/Android/data/data/yourApplicationId/fruit/banana.jpg
这个文件的作用就是为fruit路径设置一个别名,比如叫eatable,这个别名会在Uri中使用。
反应在文件中就是:

res/xml/file_path.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-cache-path name="eatable" path="fruit" />
</paths>

在写好这个文件之后,回到Manifest中,把该文件配置到FileProvider中的mate-data属性里。并添加android:name="android.support.FILE_PROVIDER_PATHS"属性。

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

还有要注意的地方就是在file_paths.xml文件的<paths>标签下要用什么子标签呢?
这个其实和在代码中怎么获取路径有关系,上面的代码中我用了<external-cache-path>这个子标签,在代码里就要使用Context.getExternalCacheDir()方法获取路径。
下面是开发者文档上抄的对应关系:

子标签对应方法
files-pathContext.getFilesDir()
cache-pathgetCacheDir()
external-pathEnvironment.getExternalStorageDirectory()
external-files-pathContext#getExternalFilesDir(String) Context.getExternalFilesDir(null)
external-cache-pathContext.getExternalCacheDir()

从File中创建Uri

现在就能通过FileProvider获取到安全的Uri了。

// 创建路径和文件的File对象
// 因为xml中用了external-cache-path标签
// 所以这里用Context.getExternalCacheDir()方法获取路径
val fruit = File(enteralCacheDir, "fruit")
val banana = File(fruit, "banana.jpg")
fruit.mkdirs()
if (banana.exists()) {
	banana.delete()
}
banana.createNewFile()
// 获取Uri
val eatableUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
	// Android N之后使用FileProvider的getUriForFile()方法来获取Uri
	FileProvider.getUriForFile(context!!, MyUtils.PACKAGE_NAME, photo)
} else {
	Uri.parse(photo.path)
}

在onCreate()方法里添加这段代码,运行结果如下:
可以看到真实路径被转化成Uri了,并且fruit也变成eatable了。

应用Uri

这里结合相机程序来使用:

// 开启相机
private fun openCamera() {
	val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    intent.putExtra(MediaStore.EXTRA_OUTPUT, cameraUri) // 把uri传入
    startActivityForResult(intent, REQUEST_CODE_CAMERA)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
	super.onActivityResult(requestCode, resultCode, data)
    if (resultCode == Activity.RESULT_OK) {
    	when (requestCode) {
        	REQUEST_CODE_CAMERA -> {
            	showImage(cameraUri) // 返回数据时,相机已经把数据存入Uri所对应的文件了
            }
        }
	}
}

private fun showImage(uri: Uri) {
	val bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(uri))
	imageView.setImageBitmap(bitmap)
}

运行结果:
在这里插入图片描述
参考链接:Android Crop Image Using UCrop Library一个结合UCrop裁剪框架的具体例子。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值