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
        }
    }
}
相关推荐
hnlgzb1 小时前
常见的Android Jetpack库会有哪些?这些库中又有哪些常用类的?
android·android jetpack
钛态5 小时前
Flutter 三方库 http_mock_adapter — 赋能鸿蒙应用开发的高效率网络接口 Mock 与自动化测试注入引擎(适配鸿蒙 HarmonyOS Next ohos)
android·网络协议·flutter·http·华为·中间件·harmonyos
王码码20355 小时前
Flutter for OpenHarmony:Flutter 三方库 algoliasearch 毫秒级云端搜索体验(云原生搜索引擎)
android·前端·git·flutter·搜索引擎·云原生·harmonyos
左手厨刀右手茼蒿5 小时前
Flutter for OpenHarmony: Flutter 三方库 shamsi_date 助力鸿蒙应用精准适配波斯历法(中东出海必备)
android·flutter·ui·华为·自动化·harmonyos
代码飞天5 小时前
wireshark的高级使用
android·java·wireshark
2501_915918416 小时前
苹果App Store上架审核卡住原因分析与解决方案指南
android·ios·小程序·https·uni-app·iphone·webview
skiy6 小时前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
小小小点7 小时前
Android四大常用布局详解与实战
android
MinQ8 小时前
binder和socket区别及原理
android
Ehtan_Zheng8 小时前
Jetpack Compose 中绘制发光边框的多种方式
android