7.0以上版本(包括7.0)实现拍照功能有两个需要注意的地方
拍照权限的动态获取内容提供器的使用注意⚠️:如果是调用系统相机,是不用动态申请相机权限的!但是如果AndroidManifest.xml里面写了相机权限声明,那么就需要动态申请权限了
在6.0系统之前,需要指定的权限可以在AndroidManifest.xml文件中进行权限声明 例如:
<user-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>但是这样会涉及到一个安全性问题,在6.0系统之前通过此方法声明的权限会在安装app的时候告诉用户该app需要的所有权限,一旦安装就表示授权,用户没有选择的余地。因此6.0后android将权限分级,不重要的权限可以在AndroidManifest.xml文件中 声明,等级较高(比如涉及到相机,电话等权限)权限则需要动态授权,并且用户可以随时在设置中取消授权。
重要权限可以查阅相关文档 官方说明
调用ActivityComapt的requestPermissions的方法
public static void requestPermissions(@NonNull final Activity activity, @NonNull final String[] permissions, @IntRange(from = 0L) final int requestCode)实例
ActivityCompat.requestPermissions(MainActivity.this,new String [] {permission},1);调用这个方法获取权限后,将会回调MainActivity中的onRequestPermissionsResult()方法,在此方法中可以通过requestCode来判断是否获得到了权限进而进行下一步操作。
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { swich(requestCode){ case 1: if(grantResults.length > 0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){ // to do }else{ Toast.makeText(this,"You denied the permission",Toast.LENGTH_SHORT).show(); } break; default: } }在实际开发中,为了程序能适应多个版本的系统,需要对系统版本进行检测,从而来执行不同的操作
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // 7.0 以上 }else { // 7.0 以下 }PackageManager.PERMISSION_DENIED 表示没有权限 PackageManager.PERMISSION_GRANTED 有权限
详细参考内容提供器 content provider
在application标签中添加
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.example.baiduocr.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>在res下创建一个xml文件夹再创建一个file_paths.XML 文件 file_paths.XML文件内容
<Paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="camera_photos" path=""/> </Paths>Ui层是由一个ImageView和一个button构成
public class MainActivity extends AppCompatActivity { private ImageView imageView=null; private Uri imageUri; private Button button=null; private static final int TAKE_PHOTO = 1; private File outputFile; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); setListener(); } /** * 如果用户拒绝相机权限就再次获取 **/ @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { } else { requestPermission(Manifest.permission.CAMERA); } } protected void init(){ button=(Button)findViewById(R.id.button); imageView=(ImageView)findViewById(R.id.imageView); requestPermission(Manifest.permission.CAMERA); } private void setListener(){ button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { takePhoto(); } }); } public void takePhoto(){ outputFile = new File(MainActivity.this.getExternalCacheDir(),"output.jpg"); try{ if (outputFile.exists()){ outputFile.delete(); } outputFile.createNewFile(); }catch (Exception e){ } if (Build.VERSION.SDK_INT>=24){ imageUri=FileProvider.getUriForFile(MainActivity.this,"com.example.baiduocr.fileprovider",outputFile); }else{ imageUri=Uri.fromFile(outputFile); } Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri); startActivityForResult(intent,TAKE_PHOTO); } public void requestPermission(String permission){ if (ContextCompat.checkSelfPermission(this,permission)!= PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(this,new String [] {permission},1); } } public void startPhotoZoom(Uri uri) { Log.e("uri=====", "" + uri); //com.android.camera.action.CROP,这个action是调用系统自带的图片裁切功能 Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, "image/*");//裁剪的图片uri和图片类型 intent.putExtra("crop", "true");//设置允许裁剪,如果不设置,就会跳过裁剪的过程,还可以设置putExtra("crop", "circle") intent.putExtra("aspectX", 4);//裁剪框的 X 方向的比例,需要为整数 intent.putExtra("aspectY", 1);//裁剪框的 Y 方向的比例,需要为整数 intent.putExtra("outputX", 100*4);//返回数据的时候的X像素大小。 intent.putExtra("outputY", 100);//返回数据的时候的Y像素大小。 //uritempFile为Uri类变量,实例化uritempFile if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (TAKE_PHOTO == 1) {//如果是7.0的拍照 //开启临时访问的读和写权限 intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); //针对7.0以上的操作 intent.setClipData(ClipData.newRawUri(MediaStore.EXTRA_OUTPUT, uri)); imageUri = uri; } else {//如果是7.0的相册 //设置裁剪的图片地址Uri imageUri = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + "clip.jpg"); } } else { imageUri = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + "clip.jpg"); Toast.makeText(this,imageUri.toString(),Toast.LENGTH_SHORT).show(); } Log.e("uriClipUri=====", "" + imageUri); //Android 对Intent中所包含数据的大小是有限制的,一般不能超过 1M,否则会使用缩略图 ,所以我们要指定输出裁剪的图片路径 intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); intent.putExtra("return-data", false);//是否将数据保留在Bitmap中返回 intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());//输出格式,一般设为Bitmap格式及图片类型 startActivityForResult(intent, PHOTO_PHOTOCLIP);//裁剪完成的标识 } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); try { switch (requestCode){ case TAKE_PHOTO: //to do break; } }catch (FileNotFoundException e){ } } }