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
        }
    }
}
相关推荐
一笑的小酒馆8 小时前
Android在ksp中简单使用Room
android
meimeiqian9 小时前
flutter android端抓包工具
android·flutter
Android技术之家9 小时前
谷歌决定终止开源Android以及对开发者的影响
android·开源
每次的天空10 小时前
Android Jetpack学习总结(源码级理解)
android·学习·android jetpack
木子庆五11 小时前
Android设计模式之代理模式
android·设计模式·代理模式
在雨季等你11 小时前
创业之旅 - 反思 - 整改 - 新的方向 - 诚邀
android
Long_poem11 小时前
【自学笔记】PHP语言基础知识点总览-持续更新
android·笔记·php
fatiaozhang952713 小时前
晶晨S905L3A(B)-安卓9.0-开启ADB和ROOT-支持IPTV6-支持外置游戏系统-支持多种无线芯片-支持救砖-完美通刷线刷固件包
android·游戏·adb·华为·电视盒子·机顶盒rom·魔百盒固件
行墨13 小时前
Kotlin语言的==与===比较操作
android
圣火喵喵教13 小时前
Pixel 8 pro 刷AOSP源码 Debug 详细教程(含救砖)
android