Android7.0调用照相、相册总结

文章目录

  • 前言
    • 异常错误:
    • 功能点:
    • 代码地址:https://github.com/zxlworking/test_picture_carmera
  • 1.权限校验
    • 1.1 Camera权限校验
    • 1.2 外部存储目录权限校验
  • 2.权限申请
    • 2.1 Camera权限申请
    • 2.2 外部存储目录权限申请
    • 2.3 权限申请结果回调
    • 2.4 权限申请结果校验
  • 3.赋予第三方应用Uri权限
    • 3.1 配置共享文件目录资源文件
    • 3.2 配置provider
    • 3.3 生成Uri
    • 3.4 赋予Uri读取权限
    • 3.5 赋予Uri写权限
  • 4.打开照相机
  • 5.打开相册
  • 6.裁剪图片

前言

前段时间写了一个调用Camera拍照,并从图库中选取图片的小程序,但是当它在7.0的系统上运行时,直接崩溃,根本不能使用。
原来Android5.0、6.0、7.0增加了很多特性,我并没有对此进行适配,从而导致了很多错误。

异常错误:

android.os.FileUriExposedException:
file:///storage/emulated/0/camera/1513393885728.jgp
exposed beyond app through ClipData.Item.getUri()


java.lang.SecurityException: Permission Denial:
reading android.support.v4.content.FileProvider uri content://com.zxl.test_picture_camera/camera_gallery/camera/1514101205911.jgp
from pid=5847, uid=10048 requires the provider be exported, or grantUriPermission()

java.lang.SecurityException:
Permission Denial: writing android.support.v4.content.FileProvider uri content://com.zxl.test_picture_camera/camera_gallery/camera/1514101317846.jgp
from pid=8336, uid=10048 requires the provider be exported, or grantUriPermission()

功能点:

-权限校验
-权限申请
-赋予第三方应用Uri权限
-打开照相机
-打开相册
-裁剪图片

代码地址:https://github.com/zxlworking/test_picture_carmera

1.权限校验

public static boolean checkPermission(Context context, String permissionStr){
    boolean result = true;
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
        result = context.checkSelfPermission(permissionStr) == PackageManager.PERMISSION_GRANTED;
    }else{
        result = PermissionChecker.checkSelfPermission(context,permissionStr) == PackageManager.PERMISSION_GRANTED;
    }
    return result;
}

1.1 Camera权限校验

Manifest.permission.CAMERA

public static boolean checkCameraPermission(Context context){
    return  checkPermission(context, Manifest.permission.CAMERA);
}

1.2 外部存储目录权限校验

Manifest.permission.READ_EXTERNAL_STORAGE
Manifest.permission.WRITE_EXTERNAL_STORAGE

public static boolean checkSDCardPermission(Context context){
    return  checkPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) && checkPermission(context,Manifest.permission.WRITE_EXTERNAL_STORAGE);
}

2.权限申请

AndroidManifest.xml添加权限:
android.permission.CAMERA
android.permission.READ_EXTERNAL_STORAGE
android.permission.WRITE_EXTERNAL_STORAGE

在Android6.0以后有的权限需要主动去申请
requestPermissions

@RequiresApi(api = Build.VERSION_CODES.M)
public static void requestPermission(Activity activity, String[] permissionStrs, int requestCode){					      
	activity.requestPermissions(permissionStrs,requestCode);
}

2.1 Camera权限申请

requestPermissions Manifest.permission.CAMERA

@RequiresApi(api = Build.VERSION_CODES.M)
public static void requestCameraPermission(Activity activity, int requestCode){
    requestPermission(activity,new String[]{Manifest.permission.CAMERA},requestCode);
}

2.2 外部存储目录权限申请

requestPermissions Manifest.permission.READ_EXTERNAL_STORAGE
Manifest.permission.WRITE_EXTERNAL_STORAGE

@RequiresApi(api = Build.VERSION_CODES.M)
public static void requestSDCardPermission(Activity activity, int requestCode){
    requestPermission(activity,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE},requestCode);
}

2.3 权限申请结果回调

通过Activity回调接口获取结果
onRequestPermissionsResult

@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
	super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

2.4 权限申请结果校验

PackageManager.PERMISSION_GRANTED

public static boolean checkRequestPermissionsResult(int[] grantResults){
    if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
        return true;
    }
    return false;
}

3.赋予第三方应用Uri权限

当获取到图片后,需要进行裁剪,这需要将原图片、裁剪后到图片的保存路径都要给裁剪应用,并且要封装成Uri通过Intent传递,在Android7.0增加了第三方应用读取Uri的权限校验

3.1 配置共享文件目录资源文件

在res/xml下新建资源文件file_path.xml
files-path与Context.getFilesDir()相同的目录
external-path与Environment.getExternalStorageDirectory()相同的目录
cache-path与getCacheDir()相同的目录
name为别名
path为表示对应类型的根目录


<resources>
    <paths>
        <files-path
            name="camera_gallery"
            path=""/>
        <external-path
            name="camera_gallery"
            path=""/>
        <cache-path
            name="camera_gallery"
            path=""/>
    paths> 
resources>

3.2 配置provider

AndroidManifest.xml添加provider

<provider
android:authorities="com.zxl.test_picture_camera"
android:name="android.support.v4.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
	<meta-data
		android:name="android.support.FILE_PROVIDER_PATHS"
		android:resource="@xml/file_path"/>
provider>

3.3 生成Uri

FileProvider.getUriForFile

private static Uri getFileUri(Context context,String filePath){
    Uri mUri = null;
    File mFile = new File(filePath);
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
        mUri = FileProvider.getUriForFile(context,"com.zxl.test_picture_camera",mFile);
    }else{
        mUri = Uri.fromFile(mFile);
    }
    return mUri;
}

3.4 赋予Uri读取权限

Intent.FLAG_GRANT_READ_URI_PERMISSION

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
	mIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}

3.5 赋予Uri写权限

通过Intent找到符合的要打开的Activity
activity.grantUriPermission
Intent.FLAG_GRANT_WRITE_URI_PERMISSION

List resInfoList = queryActivityByIntent(activity,mIntent);
if (resInfoList.size() == 0) {
    showMsg(activity, "没有合适的应用程序");
    return;
}
Iterator resInfoIterator = resInfoList.iterator();
while (resInfoIterator.hasNext()) {
    ResolveInfo resolveInfo = (ResolveInfo) resInfoIterator.next();
    String packageName = resolveInfo.activityInfo.packageName;
    activity.grantUriPermission(packageName, desUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}

private static List<ResolveInfo> queryActivityByIntent(Activity activity, Intent intent){
	List resInfoList = activity.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
	return resInfoList;
}

4.打开照相机

public static void startCamera(Activity activity,int requestCode,String filePath){
    if(hasSdcard()){
        Intent mOpenCameraIntent = new Intent();
        mOpenCameraIntent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);

        Uri desUri = getFileUri(activity,filePath);

        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
            //已申请camera权限
            //mOpenCameraIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }

        mOpenCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT,desUri);
        activity.startActivityForResult(mOpenCameraIntent,requestCode);
    }else{
        showMsg(activity,"设备没有SD卡!");
    }
}

5.打开相册

public static void startGallery(Activity activity,int requestCode){
    if(hasSdcard()){
        Intent mOpenGalleryIntent = new Intent(Intent.ACTION_GET_CONTENT);
        mOpenGalleryIntent.setType("image/*");
        activity.startActivityForResult(mOpenGalleryIntent,requestCode);
    }else{
        showMsg(activity,"设备没有SD卡!");
    }
}

6.裁剪图片

public static void startCropImage(Activity activity, Uri originUri, Uri desUri, int aspectX, int aspectY, int outputX, int outputY, int requestCode){
    Intent mIntent = new Intent();
    mIntent.setAction("com.android.camera.action.CROP");
    mIntent.setDataAndType(originUri,"image/*");

    List resInfoList = queryActivityByIntent(activity,mIntent);
    if (resInfoList.size() == 0) {
        showMsg(activity, "没有合适的应用程序");
        return;
    }
    Iterator resInfoIterator = resInfoList.iterator();
    while (resInfoIterator.hasNext()) {
        ResolveInfo resolveInfo = (ResolveInfo) resInfoIterator.next();
        String packageName = resolveInfo.activityInfo.packageName;
        activity.grantUriPermission(packageName, desUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    }


    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
        mIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    }


    mIntent.putExtra("crop","true");
    mIntent.putExtra("aspectX",aspectX);
    mIntent.putExtra("aspectY",aspectY);
    mIntent.putExtra("outputX",outputX);
    mIntent.putExtra("outputY",outputY);
    mIntent.putExtra("scale",true);

    mIntent.putExtra(MediaStore.EXTRA_OUTPUT, desUri);
    mIntent.putExtra("return-data",false);
    mIntent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
    mIntent.putExtra("noFaceDetection",true);

    activity.startActivityForResult(mIntent,requestCode);
}

你可能感兴趣的:(Android应用开发)