Android 拍照(有无存储权限两种方案,兼容Q及以上版本)

在某些行业,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
        }
    }
}
相关推荐
AnalogElectronic2 小时前
问题记录,在使用android studio 构建项目时遇到的问题
android·ide·android studio
我爱松子鱼3 小时前
mysql之InnoDB Buffer Pool 深度解析与性能优化
android·mysql·性能优化
江上清风山间明月6 小时前
Flutter开发的应用页面非常多时如何高效管理路由
android·flutter·路由·页面管理·routes·ongenerateroute
子非衣9 小时前
MySQL修改JSON格式数据示例
android·mysql·json
openinstall全渠道统计12 小时前
免填邀请码工具:赋能六大核心场景,重构App增长新模型
android·ios·harmonyos
双鱼大猫13 小时前
一句话说透Android里面的ServiceManager的注册服务
android
双鱼大猫13 小时前
一句话说透Android里面的查找服务
android
双鱼大猫13 小时前
一句话说透Android里面的SystemServer进程的作用
android
双鱼大猫13 小时前
一句话说透Android里面的View的绘制流程和实现原理
android
双鱼大猫14 小时前
一句话说透Android里面的Window的内部机制
android