今天看了一篇关于系统权限的google官方文档,说道应用如果一味要求用户提供授权,可能会让用户无所适从。如果用户发现应用难以使用,或者担心应用会滥用其信息,他们可能不愿意使用该应用,甚至会将其完全卸载。以下最佳做法有助于避免此类糟糕的用户体验。
考虑使用 intent
当我们项目中需要用到相机时,我们一般都会去想在清单文件里设置一下权限,然后在项目里去调用相机。但是在我们调用相机时应该考虑一下,如果你只是拍照,然后拿到拍照后的照片,那就不需要相机权限,你只需要调用相机的拍照功能。你可能会说那什么时候设置相机权限呢?你可能遇到过扫描二维码的功能,此时你需要设置相机权限,因为此时不是拍照,是在调用相机让它可以识别图像,还有一个例子比如 美图秀秀app 它就需要设置相机权限,它的拍照功能不是调用系统的相机拍照功能而是在app内不实现的一个相机拍照功能,拿它就必须设置相机权限。相机不仅可以拍照而且还可以录像,也就是说当你需要在你自己的app内部实现一些有关相机的功能时才需要设置相机权限。下面是Google官网的原话:
许多情况下,您可以使用以下两种方式之一来让您的应用执行某项任务。您可以将应用设置为要求提供权限才能执行操作。或者,您可以将应用设置为使用 intent,让其他应用来执行任务。
例如,假设应用需要使用设备相机才能够拍摄照片。应用可以请求 CAMERA 权限,以便允许其直接访问相机。然后,应用将使用 Camera API 控制相机并拍摄照片。利用此方法,您的应用能够完全控制摄影过程,并支持您将相机 UI 整合至应用中。
不过,如果您无需此类完全控制,则可以使用 ACTION_IMAGE_CAPTURE intent 来请求图像。发送该 intent 时,系统会提示用户选择相机应用(如果没有默认相机应用)。用户使用选定的相机应用拍摄照片,该相机应用会将照片返回给应用的 onActivityResult() 方法。
同样,如果您需要拨打电话、访问用户的联系人或要执行其他操作,可以通过创建适当的 intent 来完成,或者您也可以请求相应的权限并直接访问相应的对象。每种方法各有优缺点。
如果使用权限:
您的应用可在您执行操作时完全控制用户体验。不过,如此广泛的控制会增加任务的复杂性,因为您需要设计适当的 UI。
系统会在运行或安装应用时各提示用户提供一次权限(具体取决于用户的 Android 版本)。之后,应用即可执行操作,不再需要用户进行其他交互。不过,如果用户不授予权限(或稍后撤销权限),您的应用将根本无法执行操作。
如果使用 intent
您无需为操作设计 UI。处理 intent 的应用将提供 UI。不过,这意味着您无法控制用户体验。用户可能与您从未见过的应用交互。
如果用户没有适用于操作的默认应用,则系统会提示用户选择一款应用。如果用户未指定默认处理程序,则他们每次执行此操作时都必须处理一个额外对话框。
关于intent起调系统的相机拍照功能的代码实现如下:
file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), System.currentTimeMillis()+".jpg");
uri=Uri.fromFile(file);
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);//设置照片的存储目录,第二个参数一定要是Uri类型,切记!不然图片保存不了,本文最后再说这里的坑。
startActivityForResult(intent,TAKEPHOTO);//TAKEPHOTO请求码
然后在onActivityResult()中调用:
if(resultCode == Activity.RESULT_OK){
if(requestCode == TAKEPHOTO){
if(data!=null){
Toast.makeText(this,data.getExtras().get("data").toString(),Toast.LENGTH_SHORT).show();
imageView.setImageBitmap((Bitmap) data.getExtras().get("data"));
}else {
imageView.setImageURI(uri);//uri全局变量Uri;
}//这里为什么会写一个判断语句最后会给出原因。
}
}
关于小米手机有时候会报错,说uri为空,有网友说当起调系统相机时,小米手机会把当前的activity finish掉,拍照完成重新从onCreate()开始,所以需要在方法onSaveInstanceState()中加上一句:
if(file!=null){
outState.putParcelable("fileUri",Uri.fromFile(file));
}
然后在onCreate()加上:
if(savedInstanceState!=null){
uri=savedInstanceState.getParcelable("fileUri");
}
最后不要忘了在配置文件中加上读写权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />//修改或删除存储设备中的内容,这句可以不加。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />//读取存储设备中的内容
这两个权限主要是让imageView.setImageURI(uri)
起作用,不然返回的时候图片设置不上,不要理解为用于拍照时对照片写入外部存储的权限。我们只是传给了相机一个Uri。没有创建file。
最后来说一说上面提到的一个坑,当我们在intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file))
时若第二个参数我们传入一个String类型的字符串(file.getPath
或Uri.fromFile(file).toString
)或者没有设置MediaStore.EXTRA_OUTPUT
参数,此时照片并不能在我们设置的文件路径中生成,但是此时相机会返回一个图片缩略图。但是如果你的第二个参数传入了一个Uri类型的uri,恭喜你,此时在onActivityResult()方法里data(intent)返回为null,我想这应该是API的问题,源码我也没有看,我猜测应该是当我们设置了图片的存储位置时,系统并没有调用setResult(),设置返回的intent。所以我才会在onActivityResult()方法里写了一个判断语句,也就是上面提到的地方。
这就是平时关于开发项目中关于相机权限的问题,不要每次调用相机就加权限,先想想你的需求用不用加。希望这篇博客可以帮到大家。(有错误欢迎指正,共同进步)