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
        }
    }
}
相关推荐
安东尼肉店7 小时前
Android compose屏幕适配终极解决方案
android
2501_916007477 小时前
HTTPS 抓包乱码怎么办?原因剖析、排查步骤与实战工具对策(HTTPS 抓包乱码、gzipbrotli、TLS 解密、iOS 抓包)
android·ios·小程序·https·uni-app·iphone·webview
feiyangqingyun8 小时前
基于Qt和FFmpeg的安卓监控模拟器/手机摄像头模拟成onvif和28181设备
android·qt·ffmpeg
用户20187928316712 小时前
ANR之RenderThread不可中断睡眠state=D
android
煤球王子12 小时前
简单学:Android14中的Bluetooth—PBAP下载
android
小趴菜822712 小时前
安卓接入Max广告源
android
齊家治國平天下12 小时前
Android 14 系统 ANR (Application Not Responding) 深度分析与解决指南
android·anr
ZHANG13HAO12 小时前
Android 13.0 Framework 实现应用通知使用权默认开启的技术指南
android
【ql君】qlexcel12 小时前
Android 安卓RIL介绍
android·安卓·ril
写点啥呢12 小时前
android12解决非CarProperty接口深色模式设置后开机无法保持
android·车机·aosp·深色模式·座舱