随着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;
}
}
}
}
这里有点特殊 需要添加一些东西