随着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; } } } }
这里有点特殊 需要添加一些东西
资源下载 源码下载
过两天有空 我会把它 嵌入 Unity3d 中使用