调用相机和相册android_android 调用相机和系统相册 - CSDN
精华内容
参与话题
  • Android7.0调用照相、相册总结

    千次阅读 2019-03-21 18:08:00
    -权限校验 -权限申请 -赋予第三方应用Uri权限 -打开照相机 -打开相册 -裁剪图片

    前言

    前段时间写了一个调用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为表示对应类型的根目录

    <?xml version="1.0" encoding="utf-8"?>
    <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调用相机和相册详解

    千次阅读 2019-06-18 18:15:46
    Android调用相机和相册详解 主要是想实现头像的更改 xml内容 我用的是XUI的自定义控件 gradient_background是自定义的渐变背景色 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=...

    Android调用相机和相册详解

    主要是想实现头像的更改

    xml内容

    我用的是XUI的自定义控件 gradient_background是自定义的渐变背景色

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/rootView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <LinearLayout
            android:id="@+id/nodata"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/gradient_background"
            android:gravity="center"
            android:orientation="vertical"
            >
            <com.xuexiang.xui.widget.imageview.RadiusImageView
                android:id="@+id/headImage"
                android:clickable="true"
                android:layout_width="150dp"
                android:layout_height="150dp"
                android:src="@drawable/default_head_img"
                app:riv_border_color="@color/xui_config_color_gray_6"
                app:riv_border_width="1px"
                app:riv_is_circle="true"
                app:riv_selected_border_color="@color/xui_config_color_gray_4"
                app:riv_selected_border_width="1px"
                android:layout_marginBottom="80dp"
                app:riv_selected_mask_color="@color/xui_config_color_gray_8"/>
        </LinearLayout>
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:overScrollMode="never"
            tools:listitem="@android:layout/simple_list_item_2" />
    </LinearLayout>
    

    gradient_background.xml内容如下,渐变色背景

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android" >
    
        <!-- 变化率 -->
        <gradient
            android:endColor="#c1efbb"
            android:centerColor="#c2eaf3"
            android:startColor="#56d1ea" />
    </shape>
    

    实现的页面效果如下
    Alt

    activity部分

    package cn.lision.mas.activity.mine;
    
    import android.Manifest;
    import android.annotation.TargetApi;
    import android.content.ContentUris;
    import android.content.Context;
    import android.content.Intent;
    import android.content.pm.PackageManager;
    import android.database.Cursor;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Matrix;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Bundle;
    import android.provider.DocumentsContract;
    import android.provider.MediaStore;
    import android.view.View;
    
    import com.xuexiang.xui.widget.actionbar.TitleBar;
    import com.xuexiang.xui.widget.dialog.bottomsheet.BottomSheet;
    import com.xuexiang.xui.widget.imageview.RadiusImageView;
    import com.xuexiang.xutil.tip.ToastUtils;
    
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    import androidx.core.app.ActivityCompat;
    import androidx.core.content.ContextCompat;
    import androidx.core.content.FileProvider;
    import cn.lision.mas.R;
    import cn.lision.mas.base.BaseActivity;
    
    /**
     * 头像更换
     */
    public class HeadChangeActivity extends BaseActivity {
    
        private Context context;
        private RadiusImageView headImage;
    
        private Uri imageUri;
    
        public static final int TAKE_PHOTO = 1;
        public static final int CHOOSE_PHOTO = 2;
        private String orientation = null;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_head_change);
            context = this;
            TitleBar titleBar = initTitle("更换头像");
            initViews();
    
        }
    
        @Override
        public void initViews() {
            headImage = (RadiusImageView) findViewById(R.id.headImage);
            headImage.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    showSimpleBottomSheetList();
                }
            });
    
    
        }
    
        private void showSimpleBottomSheetList() {
            new BottomSheet.BottomListSheetBuilder(context)
                    .addItem("从相册选择图片")
                    .addItem("拍照")
                    .addItem("取消")
                    .setIsCenter(true)
                    .setOnSheetItemClickListener(new BottomSheet.BottomListSheetBuilder.OnSheetItemClickListener() {
                        @Override
                        public void onClick(BottomSheet dialog, View itemView, int position, String tag) {
                            dialog.dismiss();
                            if (position == 0) {
                                if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                                    ActivityCompat.requestPermissions(HeadChangeActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 2);
                                } else {
                                    goPhotoAlbum();
                                }
                            } else if (position == 1) {
                                File file = new File(getExternalCacheDir(), "output_image.jpg");
                                try {
                                    if (file.exists()) {
                                        file.delete();
                                    }
                                    file.createNewFile();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
    
                                if (Build.VERSION.SDK_INT >= 24) {
                                    imageUri = FileProvider.getUriForFile(HeadChangeActivity.this, "com.example.cameraalbumtest.fileprovider", file);
                                } else {
                                    imageUri = Uri.fromFile(file);
                                }
    
                                if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                                    ActivityCompat.requestPermissions(HeadChangeActivity.this, new String[]{Manifest.permission.CAMERA}, 1);
                                } else {
                                    callCamera();
                                }
                            } else {
                                dialog.dismiss();
                            }
                        }
                    })
                    .build()
                    .show();
        }
    
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            switch (requestCode) {
                case TAKE_PHOTO:
                    if (resultCode == RESULT_OK) {
                        try {
                            Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                            headImage.setImageBitmap(bitmap);
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case CHOOSE_PHOTO:
                    if (resultCode == RESULT_OK) {
                        //判断手机系统版本号
                        if (Build.VERSION.SDK_INT >= 19) {
                            //4.4及以上系统使用
                            handleImageOnKitKat(data);
                        } else {
                            handleImageBeforeKitKat(data);
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    
        //激活相册操作
        private void goPhotoAlbum() {
            Intent intent = new Intent("android.intent.action.GET_CONTENT");
            intent.setType("image/*");
            startActivityForResult(intent, CHOOSE_PHOTO);
        }
    
        //打开相机
        private void callCamera() {
            //启动相机权限
            Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
            intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
            startActivityForResult(intent, TAKE_PHOTO);
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
            switch (requestCode) {
                //打开相册
                case CHOOSE_PHOTO:
                    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        goPhotoAlbum();
                    } else {
                        ToastUtils.toast("您没有打开相册的权限");
                    }
                    break;
                //相机的权限
                case TAKE_PHOTO:
                    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        callCamera();
                    } else {
                        ToastUtils.toast("您没有打开相机的权限");
                    }
                    break;
                default:
                    break;
            }
        }
    
        @TargetApi(19)
        private void handleImageOnKitKat(Intent data) {
            String imagePath = null;
            Uri uri = data.getData();
            if (DocumentsContract.isDocumentUri(this, uri)) {
                String docId = DocumentsContract.getDocumentId(uri);
                if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
                    String id = docId.split(":")[1];
                    String selection = MediaStore.Images.Media._ID + "=" + id;
                    imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
                } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
                    Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
                    imagePath = getImagePath(contentUri, null);
                }
            } else if ("content".equalsIgnoreCase(uri.getScheme())) {
                //如果是content类型的Uri,则使用普通方式处理
                imagePath = getImagePath(uri, null);
            } else if ("file".equalsIgnoreCase(uri.getScheme())) {
                imagePath = uri.getPath();
            }
            dispalyImage(imagePath);
        }
    
        private void handleImageBeforeKitKat(Intent data) {
            Uri uri = data.getData();
            String imagePath = getImagePath(uri, null);
            dispalyImage(imagePath);
        }
    
        private String getImagePath(Uri uri, String selection) {
            String path = null;
            //通过uri和selection来获取真实的图片路径
            Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
            if (cursor != null) {
                if (cursor.moveToFirst()) {
                    path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                }
                orientation = cursor.getString(cursor.getColumnIndex("orientation"));// 获取旋转的角度
                cursor.close();
            }
            return path;
        }
    
        private void dispalyImage(String imagePath) {
            if (imagePath != null) {
                //根据path读取资源路径
                Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
                int angle = 0;
                if (orientation != null && !"".equals(orientation)) {
                    angle = Integer.parseInt(orientation);
                }
                if (angle != 0) {
                    // 下面的方法主要作用是把图片转一个角度,也可以放大缩小等
                    Matrix m = new Matrix();
                    int width = bitmap.getWidth();
                    int height = bitmap.getHeight();
                    m.setRotate(angle); // 旋转angle度
                    bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, m, true);// 从新生成图片
                }
                headImage.setImageBitmap(bitmap);
            } else {
                ToastUtils.toast("获取照片失败");
            }
        }
    }
    
    

    最终实现的结果

    在这里插入图片描述)
    在这里插入图片描述
    在这里插入图片描述

    啦啦啦 更换成功啦

    展开全文
  • Android调用系统相机和相册

    千次阅读 2019-02-13 10:17:13
    最近做了调用系统相机和相册,在其他博客中看到还有对图像进行剪切,大家都知道,我们在玩微信的时候,头像更换是方形图片,接下来我们就对这种情况具体进行描述: 布局: &amp;lt;ImageView android:id=&...

    最近做了调用系统相机和相册,在其他博客中看到还有对图像进行剪切,大家都知道,我们在玩微信的时候,头像更换是方形图片,接下来我们就对这种情况具体进行描述:
    布局:

    <ImageView      
         android:id="@+id/mIcon"    
         android:layout_width="100dp"   
         android:layout_height="100dp"        
         android:layout_margin="10dp"     
         android:src="@mipmap/weixin_fenlei" />
    

    代码:

    在onCreat()方法中:
    
     mIcon = (ImageView) findViewById(R.id.mIcon);
    
     mIcon.setOnClickListener(this);
    
    
    @Override
    
        public void onClick(View v) {
    
            switch (v.getId()) {
    
                case R.id.mIcon:
    
                    new AlertDialog.Builder(this)
    
                            .setPositiveButton("相机", new DialogInterface.OnClickListener() {
    
                                @Override
    
                                public void onClick(DialogInterface dialog, int which) {
    
                                    //动态权限:点击相机时获取相机权限
    
                                    DongTaiShare();
    
                                    //从相机获取图片
    
                                    getPicFromCamera();
    
                                }
    
                            }).setNegativeButton("相册", new DialogInterface.OnClickListener() {
    
                        @Override
    
                        public void onClick(DialogInterface dialog, int which) {
    
                            //从相册获取图片
    
                            getPicFromAlbm();
    
                        }
    
                    }).create().show();
    
                    break;
    
            }
    
     
    
        }
    
     
    
        //添加动态权限
    
        private void DongTaiShare() {
    
            if (Build.VERSION.SDK_INT >= 23) {
    
                String[] mPermissionList = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CALL_PHONE, Manifest.permission.READ_LOGS, Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.SET_DEBUG_APP, Manifest.permission.SYSTEM_ALERT_WINDOW, Manifest.permission.GET_ACCOUNTS, Manifest.permission.WRITE_APN_SETTINGS, Manifest.permission.CAMERA};
    
                ActivityCompat.requestPermissions(this, mPermissionList, 123);
    
            }
    
        }
    
     
    
        //调用系统相机
    
        private void getPicFromCamera() {
    
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    
            startActivityForResult(intent, 1);
    
        }
    
     
    
        //调用相册
    
        private void getPicFromAlbm() {
    
            Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
    
            photoPickerIntent.setType("image/*");
    
            startActivityForResult(photoPickerIntent, 2);
    
     
    
        }
    
     
    
        @Override
    
        protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    
            switch (requestCode) {
    
                // 调用相机后返回
    
                case 1:
    
                    if (resultCode == RESULT_OK) {
    
                        final Bitmap photo = intent.getParcelableExtra("data");
    
                        //给头像设置你相机拍的照片
    
                        mIcon.setImageBitmap(photo);
    
     
    
                    }
    
                    break;
    
                //调用相册后返回
    
                case 2:
    
                    if (resultCode == RESULT_OK) {
    
                        Uri uri = intent.getData();
    
                        cropPhoto(uri);//裁剪图片
    
                    }
    
                    break;
    
                //调用剪裁后返回
    
                case 3:
    
                    Bundle bundle = intent.getExtras();
    
                    if (bundle != null) {
    
                        //在这里获得了剪裁后的Bitmap对象,可以用于上传
    
                        Bitmap image = bundle.getParcelable("data");
    
                        //设置到ImageView上
    
                        mIcon.setImageBitmap(image);
    
                        //也可以进行一些保存、压缩等操作后上传
    
                        String path = saveImage("userHeader", image);
    
                        File file = new File(path);
    
                        /*
    
                         *这里可以做上传文件的额操作
    
                         */
    
                    }
    
                    break;
    
            }
    
        }
    
     
    
        /**
    
         * 裁剪图片
    
         */
    
        private void cropPhoto(Uri uri) {
    
            Intent intent = new Intent("com.android.camera.action.CROP");
    
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    
            intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    
            intent.setDataAndType(uri, "image/*");
    
            intent.putExtra("crop", "true");
    
            intent.putExtra("aspectX", 1);
    
            intent.putExtra("aspectY", 1);
    
            intent.putExtra("outputX", 300);
    
            intent.putExtra("outputY", 300);
    
            intent.putExtra("return-data", true);
    
            startActivityForResult(intent, 3);
    
        }
    
     
    
        /**
    
         * 保存图片到本地
    
         *
    
         * @param name
    
         * @param bmp
    
         * @return
    
         */
    
        public String saveImage(String name, Bitmap bmp) {
    
            File appDir = new File(Environment.getExternalStorageDirectory().getPath());
    
            if (!appDir.exists()) {
    
                appDir.mkdir();
    
            }
    
            String fileName = name + ".jpg";
    
            File file = new File(appDir, fileName);
    
            try {
    
                FileOutputStream fos = new FileOutputStream(file);
    
                bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);
    
                fos.flush();
    
                fos.close();
    
                return file.getAbsolutePath();
    
            } catch (IOException e) {
    
                e.printStackTrace();
    
            }
    
            return null;
    
        }
    
    

    别忘记加权限哦:

    <uses-permission android:name="android.permission.CAMERA" />
    
    展开全文
  • android7.0以上调用相机和相册

    千次阅读 2018-08-13 16:13:54
    Android6.0中Google提出了动态申请权限的Api,调用相机拍照,访问SDcard等操作都需要先申请对应的权限如下:   &lt;uses-permission android:name="android.permission.CAMERA" /&gt; &...

    关于Android7.0调用系统相机拍照、访问相册的一些问题:

    在Android6.0中Google提出了动态申请权限的Api,调用相机拍照,访问SDcard等操作都需要先申请对应的权限如下:

     

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    Google是反对放宽私有目录的访问权限的,所以收起对私有文件的访问权限是Android将来发展的趋势。

     

    Android7.0中尝试传递 file:// URI 会触发 FileUriExposedException,因为在Android7.0之后Google认为直接使用本地的根目录即file:// URI是不安全的操作,直接访问会抛出FileUriExposedExCeption异常,这就意味着在Android7.0以前我们访问相机拍照存储时,如果使用URI的方式直接存储剪裁图片就会造成这个异常,那么如何解决这个问题呢?(文章结尾会附上demo的连接)

    补充说明:本文Demo是直接在activity中访问相机、相册,发布后很多老哥留言说需要在Fragment中使用,为了大家使用方便,博主又增加了一个在fragment中调用的Demo,在文章结尾我会附上两个Demo的链接。

    Google为我们提供了FileProvider类,进行一种特殊的内容提供,FileProvider时ContentProvide的子类,它使用了和内容提供器类似的机制来对数据进行保护,可以选择性地将封装过的Uri共享给外部,从而提高了应用的安全性。下面就让我们看一下如何使用这个内容提供者进行数据访问的:

    使用FileProvider获取Uri就会将以前的file:// URI准换成content:// URI,实现一种安全的应用间数据访问,内容提供者作为Android的四大组件之一,使用同样需要在清单文件AndroidManifest.xml中进行注册的,注册方法如下:

     

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

    provider标签里的 android:name的值是FileProvider的包名+类名为固定值。android:authorities的值相当于一个标志,当我们使用FileProvider的getUriForFile方法时的一个参数需和清单文件注册时的保持一致,这里我使用的是:com.zz.fileprovider可自行定义。exported:要求必须为false,为true则会报安全异常。grantUriPermissions:true,表示授予 URI 临时访问权限。<meta-data />标签里面是用来指定共享的路径。 android:resource="@xml/file_paths"就是我们的共享路径配置的xml文件。关于xml文件的配置如下:

     

    在res目录下创建xml文件夹,file_paths.xml文件内容如下:

     

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <paths>
            <external-path
                name="camera_photos"
                path="" />
        </paths>
    </resources>

    external-path标签用来指定Uri共享的,name属性的值可以自定义,path属性的值表示共享的具体位置,设置为空,就表示共享整个SD卡,也可指定对应的SDcard下的文件目录,根据需求自行定义。接下来就是调用系统相机进行拍照了,代码如下:

     

    首先获取相机和访问SDcard权限:

     

    /**
     * 自动获取相机权限
     */
    private void autoObtainCameraPermission() {
    
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
                ToastUtils.showShort(this, "您已经拒绝过一次");
            }
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, CAMERA_PERMISSIONS_REQUEST_CODE);
        } else {//有权限直接调用系统相机拍照
            if (hasSdcard()) {
                imageUri = Uri.fromFile(fileUri);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                    imageUri = FileProvider.getUriForFile(MainActivity.this, "com.zz.fileprovider", fileUri);//通过FileProvider创建一个content类型的Uri
                PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_REQUEST);
            } else {
                ToastUtils.showShort(this, "设备没有SD卡!");
            }
        }
    }

    动态申请权限的回调方法:

     

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    
        switch (requestCode) {
            case CAMERA_PERMISSIONS_REQUEST_CODE: {//调用系统相机申请拍照权限回调
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    if (hasSdcard()) {
                        imageUri = Uri.fromFile(fileUri);
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                            imageUri = FileProvider.getUriForFile(MainActivity.this, "com.zz.fileprovider", fileUri);//通过FileProvider创建一个content类型的Uri
                        PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_REQUEST);
                    } else {
                        ToastUtils.showShort(this, "设备没有SD卡!");
                    }
                } else {
    
                    ToastUtils.showShort(this, "请允许打开相机!!");
                }
                break;
    
    
            }
            case STORAGE_PERMISSIONS_REQUEST_CODE://调用系统相册申请Sdcard权限回调
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    PhotoUtils.openPic(this, CODE_GALLERY_REQUEST);
                } else {
    
                    ToastUtils.showShort(this, "请允许打操作SDCard!!");
                }
                break;
        }
    }

    *注:PhotoUtils是博主对拍照和相册获取照片的封装下面会给出,PhotoUtils类和完整的MainActivity类

     

    重点看一下imageUri的获取,代码中imageUri是用于存储拍照后照片的Uri,调用相机拍照之前首先判断一下系统版本,AndroidN也就是Android7.0以上的系统通过FileProvider获取Uri方法的参数分别为,上下文对象、清单文件配置的android:authorities和对应的拍照存储的图片。之后就是通过PhotoUtils调用系统相机进行拍照。

    PhotoUtils相应代码如下:

     

    /**
     * @param activity    当前activity
     * @param imageUri    拍照后照片存储路径
     * @param requestCode 调用系统相机请求码
     */
    public static void takePicture(Activity activity, Uri imageUri, int requestCode) {
        //调用系统相机
        Intent intentCamera = new Intent();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intentCamera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
        }
        intentCamera.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        //将拍照结果保存至photo_file的Uri中,不保留在相册中
        intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        activity.startActivityForResult(intentCamera, requestCode);
    }

    方法说明:通过Intent调用系统相机拍照,如果本机版本大于等于anroid7.0需要临时授权Uri的访问权限如下:

    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    
    1. 其他部分和以前正常调用系统相机一样。

    2. 接下来就是对拍完的照片进行剪裁:

    3.  
    4.  
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
    
        if (resultCode == RESULT_OK) {
            switch (requestCode) {
                case CODE_CAMERA_REQUEST://拍照完成回调
                    cropImageUri = Uri.fromFile(fileCropUri);
                    PhotoUtils.cropImageUri(this, imageUri, cropImageUri, 1, 1, output_X, output_Y, CODE_RESULT_REQUEST);
                    break;
                case CODE_GALLERY_REQUEST://访问相册完成回调
                    if (hasSdcard()) {
                        cropImageUri = Uri.fromFile(fileCropUri);
                        Uri newUri = Uri.parse(PhotoUtils.getPath(this, data.getData()));
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                            newUri = FileProvider.getUriForFile(this, "com.zz.fileprovider", new File(newUri.getPath()));
                        PhotoUtils.cropImageUri(this, newUri, cropImageUri, 1, 1, output_X, output_Y, CODE_RESULT_REQUEST);
                    } else {
                        ToastUtils.showShort(this, "设备没有SD卡!");
                    }
                    break;
                case CODE_RESULT_REQUEST:
                    Bitmap bitmap = PhotoUtils.getBitmapFromUri(cropImageUri, this);
                    if (bitmap != null) {
                        showImages(bitmap);
                    }
                    break;
            }
        }
    }

    剪裁代码如下:

    /**
     * @param activity    当前activity
     * @param orgUri      剪裁原图的Uri
     * @param desUri      剪裁后的图片的Uri
     * @param aspectX     X方向的比例
     * @param aspectY     Y方向的比例
     * @param width       剪裁图片的宽度
     * @param height      剪裁图片高度
     * @param requestCode 剪裁图片的请求码
     */
    public static void cropImageUri(Activity activity, Uri orgUri, Uri desUri, int aspectX, int aspectY, int width, int height, int requestCode) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
        intent.setDataAndType(orgUri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", aspectX);
        intent.putExtra("aspectY", aspectY);
        intent.putExtra("outputX", width);
        intent.putExtra("outputY", height);
        intent.putExtra("scale", true);
        //将剪切的图片保存到目标Uri中
        intent.putExtra(MediaStore.EXTRA_OUTPUT, desUri);
        intent.putExtra("return-data", false);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.putExtra("noFaceDetection", true);
        activity.startActivityForResult(intent, requestCode);
    }
    

    和以前正常剪裁代码基本相同,和上面意图打开相机一样,如果本机版本大于等于anroid7.0需要临时授权Uri的访问权限如下:

    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    
    
     
    1. 到此整体调用系统相机拍照、剪裁完成,剪裁后照片存储到cropImageUri对应路径。

    2.  

    访问相册代码如下:

    /**
     * @param activity    当前activity
     * @param requestCode 打开相册的请求码
     */
    public static void openPic(Activity activity, int requestCode) {
        Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
        photoPickerIntent.setType("image/*");
        activity.startActivityForResult(photoPickerIntent, requestCode);
    }
    

    上文中已贴出访问相册后的onActivityResult的回调,主要也是一样的操作解析Uri调用剪裁图片:

    
     
     if (hasSdcard()) {
                        cropImageUri = Uri.fromFile(fileCropUri);
                        Uri newUri = Uri.parse(PhotoUtils.getPath(this, data.getData()));
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                            newUri = FileProvider.getUriForFile(this, "com.zz.fileprovider", new File(newUri.getPath()));
                        PhotoUtils.cropImageUri(this, newUri, cropImageUri, 1, 1, output_X, output_Y, CODE_RESULT_REQUEST);
                    } else {
                        ToastUtils.showShort(this, "设备没有SD卡!");
                    }
                    break;

    *注:Android4.4之后选取中的图片不再返回真实的Uri了,而是封装过的Uri,所以在4.4以上,就要对这个Uri进行解析,即上面的PhotoUtils.getPath()方法,
    具体Uri的解析见
    PhotoUtils类。android4.4以前直接data.getData就可以获取到真是Uri不用解析。

    解析获取真实的Uri后,判断系统版本开始通过FileProvider获取新的Uri之后就可以同样的图片剪裁了。 

    MainActivity代码如下:

    package choicemmed.com.android60permissionsdemo;
    
    import android.Manifest;
    import android.content.Intent;
    import android.content.pm.PackageManager;
    import android.graphics.Bitmap;
    import android.graphics.Matrix;
    import android.media.ExifInterface;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Bundle;
    import android.os.Environment;
    import android.support.annotation.NonNull;
    import android.support.v4.app.ActivityCompat;
    import android.support.v4.content.ContextCompat;
    import android.support.v4.content.FileProvider;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    
    import com.google.android.gms.common.api.GoogleApiClient;
    import com.lidroid.xutils.ViewUtils;
    import com.lidroid.xutils.view.annotation.ViewInject;
    import com.lidroid.xutils.view.annotation.event.OnClick;
    
    import java.io.File;
    
    import de.hdodenhof.circleimageview.CircleImageView;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        private static final String TAG = "MainActivity";
        @ViewInject(R.id.photo)
        private CircleImageView photo;
        @ViewInject(R.id.takePic)
        private Button takePic;
        @ViewInject(R.id.takeGallery)
        private Button takeGallery;
        @ViewInject(R.id.test)
        private Button test;
        private static final int CODE_GALLERY_REQUEST = 0xa0;
        private static final int CODE_CAMERA_REQUEST = 0xa1;
        private static final int CODE_RESULT_REQUEST = 0xa2;
        private static final int CAMERA_PERMISSIONS_REQUEST_CODE = 0x03;
        private static final int STORAGE_PERMISSIONS_REQUEST_CODE = 0x04;
        private File fileUri = new File(Environment.getExternalStorageDirectory().getPath() + "/photo.jpg");
        private File fileCropUri = new File(Environment.getExternalStorageDirectory().getPath() + "/crop_photo.jpg");
        private Uri imageUri;
        private Uri cropImageUri;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ViewUtils.inject(this);
        }
        
    
        @OnClick({R.id.takePic, R.id.takeGallery})
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.takePic:
                    autoObtainCameraPermission();
                    break;
                case R.id.takeGallery:
                    autoObtainStoragePermission();
                    break;
            }
        }
    
        /**
         * 自动获取相机权限
         */
        private void autoObtainCameraPermission() {
    
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                    || ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
                    ToastUtils.showShort(this, "您已经拒绝过一次");
                }
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, CAMERA_PERMISSIONS_REQUEST_CODE);
            } else {//有权限直接调用系统相机拍照
                if (hasSdcard()) {
                    imageUri = Uri.fromFile(fileUri);
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                        imageUri = FileProvider.getUriForFile(MainActivity.this, "com.zz.fileprovider", fileUri);//通过FileProvider创建一个content类型的Uri
                    PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_REQUEST);
                } else {
                    ToastUtils.showShort(this, "设备没有SD卡!");
                }
            }
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    
            switch (requestCode) {
                case CAMERA_PERMISSIONS_REQUEST_CODE: {//调用系统相机申请拍照权限回调
                    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        if (hasSdcard()) {
                            imageUri = Uri.fromFile(fileUri);
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                                imageUri = FileProvider.getUriForFile(MainActivity.this, "com.zz.fileprovider", fileUri);//通过FileProvider创建一个content类型的Uri
                            PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_REQUEST);
                        } else {
                            ToastUtils.showShort(this, "设备没有SD卡!");
                        }
                    } else {
    
                        ToastUtils.showShort(this, "请允许打开相机!!");
                    }
                    break;
    
    
                }
                case STORAGE_PERMISSIONS_REQUEST_CODE://调用系统相册申请Sdcard权限回调
                    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        PhotoUtils.openPic(this, CODE_GALLERY_REQUEST);
                    } else {
    
                        ToastUtils.showShort(this, "请允许打操作SDCard!!");
                    }
                    break;
            }
        }
    
        private int output_X = 480;
        private int output_Y = 480;
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
    
            if (resultCode == RESULT_OK) {
                switch (requestCode) {
                    case CODE_CAMERA_REQUEST://拍照完成回调
                        cropImageUri = Uri.fromFile(fileCropUri);
                        PhotoUtils.cropImageUri(this, imageUri, cropImageUri, 1, 1, output_X, output_Y, CODE_RESULT_REQUEST);
                        break;
                    case CODE_GALLERY_REQUEST://访问相册完成回调
                        if (hasSdcard()) {
                            cropImageUri = Uri.fromFile(fileCropUri);
                            Uri newUri = Uri.parse(PhotoUtils.getPath(this, data.getData()));
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                                newUri = FileProvider.getUriForFile(this, "com.zz.fileprovider", new File(newUri.getPath()));
                            PhotoUtils.cropImageUri(this, newUri, cropImageUri, 1, 1, output_X, output_Y, CODE_RESULT_REQUEST);
                        } else {
                            ToastUtils.showShort(this, "设备没有SD卡!");
                        }
                        break;
                    case CODE_RESULT_REQUEST:
                        Bitmap bitmap = PhotoUtils.getBitmapFromUri(cropImageUri, this);
                        if (bitmap != null) {
                            showImages(bitmap);
                        }
                        break;
                }
            }
        }
    
    
        /**
         * 自动获取sdk权限
         */
    
        private void autoObtainStoragePermission() {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSIONS_REQUEST_CODE);
            } else {
                PhotoUtils.openPic(this, CODE_GALLERY_REQUEST);
            }
    
        }
    
        private void showImages(Bitmap bitmap) {
            photo.setImageBitmap(bitmap);
        }
    
        /**
         * 检查设备是否存在SDCard的工具方法
         */
        public static boolean hasSdcard() {
            String state = Environment.getExternalStorageState();
            return state.equals(Environment.MEDIA_MOUNTED);
        }
    
    
    }
    

    PhotoUtils代码如下:

    package choicemmed.com.android60permissionsdemo;
    
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.content.ContentUris;
    import android.content.Context;
    import android.content.Intent;
    import android.database.Cursor;
    import android.graphics.Bitmap;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Environment;
    import android.provider.DocumentsContract;
    import android.provider.MediaStore;
    
    /**
     * Created by:zheng zhong on 2016/8/6 16:16
     * Email zheng_zhong@163.com
     */
    public class PhotoUtils {
        private static final String TAG = "PhotoUtils";
    
        /**
         * @param activity    当前activity
         * @param imageUri    拍照后照片存储路径
         * @param requestCode 调用系统相机请求码
         */
        public static void takePicture(Activity activity, Uri imageUri, int requestCode) {
            //调用系统相机
            Intent intentCamera = new Intent();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                intentCamera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
            }
            intentCamera.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
            //将拍照结果保存至photo_file的Uri中,不保留在相册中
            intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
            activity.startActivityForResult(intentCamera, requestCode);
        }
    
        /**
         * @param activity    当前activity
         * @param requestCode 打开相册的请求码
         */
        public static void openPic(Activity activity, int requestCode) {
            Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
            photoPickerIntent.setType("image/*");
            activity.startActivityForResult(photoPickerIntent, requestCode);
        }
    
        /**
         * @param activity    当前activity
         * @param orgUri      剪裁原图的Uri
         * @param desUri      剪裁后的图片的Uri
         * @param aspectX     X方向的比例
         * @param aspectY     Y方向的比例
         * @param width       剪裁图片的宽度
         * @param height      剪裁图片高度
         * @param requestCode 剪裁图片的请求码
         */
        public static void cropImageUri(Activity activity, Uri orgUri, Uri desUri, int aspectX, int aspectY, int width, int height, int requestCode) {
            Intent intent = new Intent("com.android.camera.action.CROP");
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            }
            intent.setDataAndType(orgUri, "image/*");
            intent.putExtra("crop", "true");
            intent.putExtra("aspectX", aspectX);
            intent.putExtra("aspectY", aspectY);
            intent.putExtra("outputX", width);
            intent.putExtra("outputY", height);
            intent.putExtra("scale", true);
            //将剪切的图片保存到目标Uri中
            intent.putExtra(MediaStore.EXTRA_OUTPUT, desUri);
            intent.putExtra("return-data", false);
            intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
            intent.putExtra("noFaceDetection", true);
            activity.startActivityForResult(intent, requestCode);
        }
    
        /**
         * 读取uri所在的图片
         *
         * @param uri      图片对应的Uri
         * @param mContext 上下文对象
         * @return 获取图像的Bitmap
         */
        public static Bitmap getBitmapFromUri(Uri uri, Context mContext) {
            try {
                Bitmap bitmap = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), uri);
                return bitmap;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
        /**
         * @param context 上下文对象
         * @param uri     当前相册照片的Uri
         * @return 解析后的Uri对应的String
         */
        @SuppressLint("NewApi")
        public static String getPath(final Context context, final Uri uri) {
    
            final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
            String pathHead = "file:///";
            // DocumentProvider
            if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
                // ExternalStorageProvider
                if (isExternalStorageDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];
                    if ("primary".equalsIgnoreCase(type)) {
                        return pathHead + Environment.getExternalStorageDirectory() + "/" + split[1];
                    }
                }
                // DownloadsProvider
                else if (isDownloadsDocument(uri)) {
    
                    final String id = DocumentsContract.getDocumentId(uri);
    
                    final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
    
                    return pathHead + getDataColumn(context, contentUri, null, null);
                }
                // MediaProvider
                else if (isMediaDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];
    
                    Uri contentUri = null;
                    if ("image".equals(type)) {
                        contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                    } else if ("video".equals(type)) {
                        contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                    } else if ("audio".equals(type)) {
                        contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                    }
    
                    final String selection = "_id=?";
                    final String[] selectionArgs = new String[]{split[1]};
    
                    return pathHead + getDataColumn(context, contentUri, selection, selectionArgs);
                }
            }
            // MediaStore (and general)
            else if ("content".equalsIgnoreCase(uri.getScheme())) {
                return pathHead + getDataColumn(context, uri, null, null);
            }
            // File
            else if ("file".equalsIgnoreCase(uri.getScheme())) {
                return pathHead + uri.getPath();
            }
            return null;
        }
    
        /**
         * Get the value of the data column for this Uri. This is useful for
         * MediaStore Uris, and other file-based ContentProviders.
         *
         * @param context       The context.
         * @param uri           The Uri to query.
         * @param selection     (Optional) Filter used in the query.
         * @param selectionArgs (Optional) Selection arguments used in the query.
         * @return The value of the _data column, which is typically a file path.
         */
        private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
    
            Cursor cursor = null;
            final String column = "_data";
            final String[] projection = {column};
            try {
                cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
                if (cursor != null && cursor.moveToFirst()) {
                    final int column_index = cursor.getColumnIndexOrThrow(column);
                    return cursor.getString(column_index);
                }
            } finally {
                if (cursor != null)
                    cursor.close();
            }
            return null;
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is ExternalStorageProvider.
         */
        private static boolean isExternalStorageDocument(Uri uri) {
            return "com.android.externalstorage.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is DownloadsProvider.
         */
        private static boolean isDownloadsDocument(Uri uri) {
            return "com.android.providers.downloads.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is MediaProvider.
         */
        private static boolean isMediaDocument(Uri uri) {
            return "com.android.providers.media.documents".equals(uri.getAuthority());
        }
    
    }
    

     

    最后附上:

    1、Activity中调用demo的GitHub地址点击打开链接

    2、Fragment中调用Demo的GitHub地址:点击打开链接

    展开全文
  • android 调用相机和相册,里面用了两种方式。一种是郭霖的,但不能适配小米,另一种是自己找的,亲测小米通过
  • Unity调用Android 相机和相册

    千次阅读 2016-10-26 14:47:38
    Unity调用Android 相机和相册
  • 清单文件中增加对应权限,动态申请权限(此部分请参考Android 动态申请权限,在此不作为重点描述) private static final int REQUEST_CODE_ALBUM = 100;//打开相册private static final int REQUEST_CODE_CAMERA =...
  • android调用相机和相册

    千次阅读 2012-07-16 20:10:58
    很多同学在做客户端的时候,都需要做上传图片,那么上传图片如何上传呢?...android调用相机和相册" border="0"> 首先: 1.首先在AndroidManifest.xml中设置权限: 2.调用相机和相册: Intent t
  • Androidstudiounity 交互 调用相机相册 适配安卓6.0以上
  • Android 8.0+调用相机相册

    千次阅读 2019-07-28 23:36:09
    公司的测试机试Android6.0以下的 所以之前调用相机一点都没问题 可是跑在Android8.0+的手机上 调用相机相册就会出现错误 暴露的Url 所以在博客找到了相关文章,结合自身的需求 总结了这篇文章 希望能给您带来帮助 ...
  • Android7.0及以下版本调用系统相机和相册Android7.0拍照,动态权限的获取
  • 关于android webview调用相册和相机

    千次阅读 2015-12-10 15:08:56
    android webView 调用系统相册和相机 这里我只展示选择图库的代码,调用相册和相机的完整代码到这里下载点击打开链接 private ValueCallback mFilePathCallback; private ValueCallback mUploadCallbackAboveL; @...
  • Android 10.0调用相机和相册

    千次阅读 2020-03-22 16:46:05
    首先判断版本,判断是否授权,如果未授权,采用弹出框动态授权。 如果版本号大于7.0采用虚拟路径临时保存,如果版本号小于7.0采用绝对路径。 先使用PackageManager.checkPermission检测对方的app有没有取得文件读写...
  • Android 调用相机相册(适配6.0)

    千次阅读 2020-05-18 15:05:34
    又好久没有写博客了,好习惯不能断,该写点就得写点,今天带来的笔记是关于Android 项目调用系统相机调用系统相册的之后拿到照片的基本操作,我感觉好多人还是不太熟悉的哈。项目兼容 Android 5.0设备、Android ...
  • 最近在做一个项目需求是在Android原生的Activity中嵌套一个WebView来做混合开发,...2:H5中调用本地的相机相册和视频拍摄是调用不起来的,需要原生自己调用。 3:WebView在使用过程中会出现一系列问题。 首先解...
  • Android调用手机相机和相册

    千次阅读 2018-01-05 22:22:06
    上面就是我的小项目的界面图,因为这里我主要写的调用手机相机和相册,所有我的圆形头像是我用的一个框架,就不用我们自己去写一个圆形的头像,地址如下:https://github.com/lopspower/CircularImageView ...
  • 由于是调用系统功能,... //调用相机 PhotoUtils.camera(supportFragmentManager,"你的authority"){ uri, success, msg -> if(success) Glide.with(this).load(uri).into(binding.ivImage) } //调用相册 .
  • Android WebView调用系统相册和相机,注入以及与H5的交互 推荐: 如何设计一个优雅健壮的Android WebView?(上) 如何设计一个优雅健壮的Android WebView?(下) Android Webview在使用的过程中,其实也是挺简单的...
1 2 3 4 5 ... 20
收藏数 5,704
精华内容 2,281
关键字:

调用相机和相册android