在某些行业,APP可能被禁止使用存储权限,或公司在写SDK功能,不方便获取权限
所以需要有 无存储权限拍照方案。这里两种方案都列出里。
对于写入权限,在高版本中,已经废弃, 不可用文件写入读取权限,所以拍照功能也最好使用无权限方式(如果需要获取相册, 需要使用新的权限---媒体权限)
业务前提
判断拍照权限
java
if(activity.checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED){
//开始拍照流程
}else{
activity.requestPermissions(new String[]{Manifest.permission.CAMERA},1001);
}
存储地址及Uri
一、无存储权限
1)、创建存储路径
Kotlin
var filePath:String?=null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
filePath = mActivity.filesDir!!.absolutePath + Environment.DIRECTORY_PICTURES + File.separator;
} else {
filePath = FileUtil.getCachePath() + Environment.DIRECTORY_PICTURES + File.separator;
}
工具类 FileUtil.getCachePath
Kotlin
public static String getCachePath() {
File externalCacheDir = context.getExternalCacheDir();
if (null != externalCacheDir) {
return externalCacheDir.getAbsolutePath();
}
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
return Environment.getExternalStorageDirectory().getAbsolutePath();
}
return context.getCacheDir().getAbsolutePath();
}
2)、path转Uri
Kotlin
// 指定拍照存储位置的方式调起相机
var fileName = "IMG_" + DateFormat.format(
"yyyyMMdd_hhmmss",
Calendar.getInstance(Locale.CHINA)
) + ".jpg";
val file = File(filePath + fileName);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val contentValues = ContentValues()
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
imageUri = mActivity.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
} else {
imageUri = Uri.fromFile(file)
}
二、有存储权限
1)配置provider(官方适配方案)
1、androidx.core.content.FileProvider 可以用v4包 也可用 Androidx,看自己项目用哪个库
2、applicationId 是在build.gradle文件中定义的一个进程Id,也是应用唯一id
java
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
3、在main/res/xml 路径下创建文件 filepaths.xml
java
<paths>
<files-path name="name" path="path" />
//物理路径相当于Context.getFilesDir() + /path/
<cache-path name="name" path="path" />
//物理路径相当于Context.getCacheDir() + /path/
<external-path name="name" path="path" />
//物理路径相当于Environment.getExternalStorageDirectory() + /path/
<external-files-path name="name" path="path" />
//物理路径相当于Context.getExternalFilesDir(String) + /path/
<external-cache-path name="name" path="path" />
//物理路径相当于Context.getExternalCacheDir() + /path/
</paths>
代码中每一个path配置,都对应一个java api,例如
mActivity.getExternalFilesDir("MyFilePath")
对应external-files-path的地址:
/storage/emulated/0/Android/data/{applicationId}/files/MyFilePath
后面需要自己拼接"/path"
getExternalFilesDir 入参可为null
4、java代码
java
//判断三个权限 写入写出 拍照
//android.permission.READ_EXTERNAL_STORAGE,android.permission.WRITE_EXTERNAL_STORAGE
if (activity.checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
String path = FileUtil.getCachePath() + File.separator + cameraPath + System.currentTimeMillis() + ".jpg";
File file = new File(path);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
imageUri= FileProvider.getUriForFile(activity.getApplication(), activity.getPackageName() + ".provider", file);
activity.grantUriPermission(activity.getPackageName(), outputFileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
} else {
imageUri= Uri.fromFile(file);
}
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
outputFile.add(file);
activity.startActivityForResult(intent, 1011);
}
调用拍照
Kotlin
var intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
mActivity.startActivityForResult(intent, 1011);
获取结果
java
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
if (resultCode == RESULT_OK) {
if(requestCode==1011){
//两种方式获取结果
//1 直接使用 拍照传入的Uri 参数
//2 data.getData() 返回一个Uri
}
}
}