随着Android 的版本更新迭代。本来以前代码很简单的打开相册或者相机  获取图片裁剪 给Unity3D 使用的过程 挺简单的。但是随着 Android 版本的 更新 和 安全 的加强 。有几点 和以前不一样的地方。在这里和大家分享下。

首先呢。在Unity3D 里面是 无法判断 手机摄像头 权限是否打开的, Android 原生是可以的。而6.0 和7.0 有是 有区别的。

package photos.john.com;

import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.StrictMode;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.ImageView;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.net.Uri;
import android.view.View.OnClickListener;
import android.support.v4.content.ContextCompat;
import android.support.v4.app.ActivityCompat;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.widget.Toast;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import java.io.File;
import java.io.IOException;
import java.util.logging.Logger;

public class MainActivity extends AppCompatActivity {

    private Button      buttonCamera;
    private Button      buttonPhoto;
    private ImageView   imageView;


    private static final int TAKE_PHOTO_PERMISSION_REQUEST_CODE = 0;        // 拍照的权限处理返回码
    private static final int WRITE_SDCARD_PERMISSION_REQUEST_CODE = 1;      // 读储存卡内容的权限处理返回码
    private static final int TAKE_PHOTOSDCARD_PERMISSION_REQUEST_CODE = 2;        // 拍照 存储权限

    private static final int TAKE_PHOTO_REQUEST_CODE = 3;                     // 拍照返回的 requestCode

    private static final int CHOICE_FROM_ALBUM_REQUEST_CODE = 4;             // 相册选取返回的 requestCode
    private static final int CROP_PHOTO_REQUEST_CODE = 5;                     // 裁剪图片返回的 requestCode

    private Uri     photoUri        = null;
    private Uri     photoOutputUri = null;                                       // 图片最终的输出文件的 Uri



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        buttonCamera = (Button)findViewById(R.id.buttonCamera);
        buttonPhoto  = (Button)findViewById(R.id.buttonPhoto);

        imageView  = (ImageView)findViewById(R.id.imageView);

        buttonCamera.setOnClickListener( new ButtonListener());
        buttonPhoto.setOnClickListener( new ButtonListener());


    }

    private class  ButtonListener implements View.OnClickListener {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            switch (v.getId()) {
                case R.id.buttonCamera:
                    // 同上面的权限申请逻辑
                    OnCamera();
                    break;
                case R.id.buttonPhoto:
                    OnPhotos();
                    break;
                default:
                    break;
            }
        }

    }

    //相机权限检查
    private boolean OnCameraPermission()
    {
        boolean isPass = true;
        if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
            isPass = false;
            // 申请相机权限
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.CAMERA}, TAKE_PHOTO_PERMISSION_REQUEST_CODE);
        }
        return  isPass;
    }


    //相机权限检查.- 存储
    private boolean OnCameraPermissionSTORAGE()
    {
        boolean isPass = true;
        if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            isPass = false;
            // 申请读写内存卡内容的权限
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, TAKE_PHOTOSDCARD_PERMISSION_REQUEST_CODE);
        }
        return isPass;
    }

    //相册权限检查 //实际是读取内存卡的权限
    private boolean OnPhotosPermission()
    {
        boolean isPass = true;
        if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            isPass = false;
            // 申请读写内存卡内容的权限
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_SDCARD_PERMISSION_REQUEST_CODE);
        }
       return isPass;
    }


    private void OnCamera()
    {
        if( !OnCameraPermission() || !OnCameraPermissionSTORAGE())//这里不光需要相机权限 还需要 读取储存卡
        {
            return;
        }

        /**
         * 设置拍照得到的照片的储存目录,因为我们访问应用的缓存路径并不需要读写内存卡的申请权限,
         * 因此,这里为了方便,将拍照得到的照片存在这个缓存目录中
         */
        File file = new File(getExternalCacheDir(), "image.jpg");
        try {
            if(file.exists()) {
                file.delete();
            }
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        /**
         * 因 Android 7.0 开始,不能使用 file:// 类型的 Uri 访问跨应用文件,否则报异常,
         * 因此我们这里需要使用内容提供器,FileProvider 是 ContentProvider 的一个子类,
         * 我们可以轻松的使用 FileProvider 来在不同程序之间分享数据(相对于 ContentProvider 来说)
         */

        if(Build.VERSION.SDK_INT >= 24) {
            photoUri = FileProvider.getUriForFile(this, this.getPackageName()+".provider", file);
        } else {
            photoUri = Uri.fromFile(file); // Android 7.0 以前使用原来的方法来获取文件的 Uri
        }
        // 打开系统相机的 Action,等同于:"android.media.action.IMAGE_CAPTURE"
        Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // 设置拍照所得照片的输出目录
        takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
        startActivityForResult(takePhotoIntent, TAKE_PHOTO_REQUEST_CODE);

    }
    private void OnPhotos()
    {
        if( !OnPhotosPermission() )
        {
            return;
        }

        // 打开系统图库的 Action,等同于: "android.intent.action.GET_CONTENT"
        Intent choiceFromAlbumIntent = new Intent(Intent.ACTION_GET_CONTENT);
        // 设置数据类型为图片类型
        choiceFromAlbumIntent.setType("image/*");
        startActivityForResult(choiceFromAlbumIntent, CHOICE_FROM_ALBUM_REQUEST_CODE);
    }


    /**
     * 裁剪图片
     */
    private void cropPhoto(Uri inputUri) {
        // 调用系统裁剪图片的 Action
        Intent cropPhotoIntent = new Intent("com.android.camera.action.CROP");
        // 设置数据Uri 和类型
        cropPhotoIntent.setDataAndType(inputUri, "image/*");
        // 授权应用读取 Uri,这一步要有,不然裁剪程序会崩溃
        cropPhotoIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        // 设置图片的最终输出目录
        cropPhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                photoOutputUri = Uri.parse("file:sdcard/image_output.jpg"));


        cropPhotoIntent.putExtra("noFaceDetection", false);
        cropPhotoIntent.putExtra("scale", true);
        //裁剪框比例
        cropPhotoIntent.putExtra("aspectX", 1);
        cropPhotoIntent.putExtra("aspectY", 1);
        //输出图片大小
        cropPhotoIntent.putExtra("outputX", 512);
        cropPhotoIntent.putExtra("outputY", 512);
        cropPhotoIntent.putExtra("return-data", false);
        cropPhotoIntent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        startActivityForResult(cropPhotoIntent, CROP_PHOTO_REQUEST_CODE);
    }


    /**
     * 在这里进行用户权限授予结果处理
     * @param requestCode 权限要求码,即我们申请权限时传入的常量
     * @param permissions 保存权限名称的 String 数组,可以同时申请一个以上的权限
     * @param grantResults 每一个申请的权限的用户处理结果数组(是否授权)
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            // 调用相机拍照:
            case TAKE_PHOTO_PERMISSION_REQUEST_CODE:
                // 如果用户授予权限,那么打开相机拍照
                if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    OnCamera();
                } else {
                    Toast.makeText(this, "拍照权限被拒绝", Toast.LENGTH_SHORT).show();
                }
                break;
            // 调用相机拍照: 存储
            case  TAKE_PHOTOSDCARD_PERMISSION_REQUEST_CODE:
                // 如果用户授予权限,那么打开相机拍照
                if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    OnCamera();
                } else {
                    Toast.makeText(this, "读写内存卡内容权限被拒绝", Toast.LENGTH_SHORT).show();
                }
                break;
            // 打开相册选取:
            case WRITE_SDCARD_PERMISSION_REQUEST_CODE:
                if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
                {
                    OnPhotos();
                } else {

                    Toast.makeText(this, "读写内存卡内容权限被拒绝", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }



    /**
     * 通过这个 activity 启动的其他 Activity 返回的结果在这个方法进行处理
     * @param requestCode 返回码,用于确定是哪个 Activity 返回的数据
     * @param resultCode 返回结果,一般如果操作成功返回的是 RESULT_OK
     * @param data 返回对应 activity 返回的数据
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(resultCode == RESULT_OK) {
            // 通过返回码判断是哪个应用返回的数据
            switch (requestCode) {
                // 拍照
                case TAKE_PHOTO_REQUEST_CODE:
                    cropPhoto(photoUri);
                    break;
                // 相册选择
                case CHOICE_FROM_ALBUM_REQUEST_CODE:
                    cropPhoto(data.getData());
                    break;
                // 裁剪图片
                case CROP_PHOTO_REQUEST_CODE:
                    File file = new File(photoOutputUri.getPath());
                    if(file.exists()) {
                        Bitmap bitmap = BitmapFactory.decodeFile(photoOutputUri.getPath());
                        imageView.setImageBitmap(bitmap);
                        //file.delete(); // 选取完后删除照片
                    } else {
                        Toast.makeText(this, "找不到照片", Toast.LENGTH_SHORT).show();
                    }
                    break;
            }
        }
    }
}





安卓11获取Pictures文件夹的绝对路径_android


安卓11获取Pictures文件夹的绝对路径_ide_02


这里有点特殊 需要添加一些东西


安卓11获取Pictures文件夹的绝对路径_ide_03

安卓11获取Pictures文件夹的绝对路径_Android_04


安卓11获取Pictures文件夹的绝对路径_ide_05