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
        }
    }
}
相关推荐
橙子199110163 小时前
在 Kotlin 中什么是委托属性,简要说说其使用场景和原理
android·开发语言·kotlin
androidwork4 小时前
Kotlin Android LeakCanary内存泄漏检测实战
android·开发语言·kotlin
笨鸭先游4 小时前
Android Studio的jks文件
android·ide·android studio
gys98955 小时前
android studio开发aar插件,并用uniapp开发APP使用这个aar
android·uni-app·android studio
H309195 小时前
vue3+dhtmlx-gantt实现甘特图展示
android·javascript·甘特图
像风一样自由5 小时前
【001】renPy android端启动流程分析
android·gitee
千里马学框架6 小时前
重学安卓14/15自由窗口freeform企业实战bug-学员作业
android·framework·bug·systrace·安卓framework开发·安卓窗口系统·自由窗口
xianrenli3812 小时前
android特许权限调试
android
*拯15 小时前
Uniapp Android/IOS 获取手机通讯录
android·ios·uni-app
天天打码17 小时前
Lynx-字节跳动跨平台框架多端兼容Android, iOS, Web 原生渲染
android·前端·javascript·ios