Android6.0发布后,其一系列新特新足够让我们这些Android程序员兴奋一段时间了。首先我们先看看具体有哪些新特性:
-锁频下语音搜索
-指纹识别
-更完整的应用权限管理
-Doze电量管理
-Now on Tap
-App link
具体可以参考 Android 6.0有哪些新特性 。
上面六个新特性中 更完整的应用权限管理
应该是和我们开发者关系最密切的了,接下来我们就来具体了解一下如何在Android 6.0上更好的使用Android系统权限。
在Android 6.0中谷歌摒弃了之前的 install time permissions model
取而代之的是 runtime permissions model
。先来说说 install time permissions model
,这个大家不陌生,就是当Android App安装的时候会向用户展示一坨权限,如果此时用户选择安装,则表示用户同意将这些权限赋予App,如果用户不同意那么这个App就会取消安装。 runtime permissions model
就牛逼了,在App安装的时候同样会向用户展示所需要的权限,并且在用户选择安装App的时候并不表示用户将这些权限赋予了App,而是需要App在运行阶段主动去申请这些权限。这样做的好处显而易见,App对权限的申请对于用户来说变得更加透明,而且用户对App权限的控制也更加灵活。
Android将系统权限分成了四个保护等级 normal
, dangerous
, signature
, signatureOrSystem
,其中最常见的是 normal permission
和 dangerous permission
两类。
normal permission涵盖的一系列权限的共同点是:App需要访问App运行沙盒以外的数据或资源,但是这些资源对用户的隐私或其他App的危险性较小,下面列举一下这些权限:
ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
FLASHLIGHT
GET_PACKAGE_SIZE
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
SET_ALARM
INSTALL_SHORTCUT
以上这些就是Android 6.0中所有的 normal permissions
了。
dangerous permissions 涵盖的一系列权限的共同点是:这些权限会读写用户的隐私信息,也可能会读写用户存储的数据或影响其他App的正常运行。下面例举出这些权限:
| 权限组| 权限|
|------------------|--------------------------------------------------------------------------------------------------------------|
|CALENDAR | READ_CALENDAR,WRITE_CALENDAR |
|CAMERA | CAMERA |
|CONTACTS | READ_CONTACTS,WRITE_CONTACTS,GET_ACCOUNTS |
|LOCATION | ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION |
|MICROPHONE | RECORD_AUDIO |
|PHONE | READ_PHONE_STATE,CALL_PHONE,READ_CALL_LOG,WRITE_CALL_LOG,ADD_VOICEMAIL,USE_SIP,PROCESS_OUTGOING_CALLS |
|SENSORS | BODY_SENSORS |
|SMS | SEND_SMS,RECEIVE_SMS,READ_SMS,RECEIVE_WAP_PUSH,RECEIVE_MMS |
|STORAGE | READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE |
以上这些权限就是Android6.0中所有的 dangerous permissions
。
Runtime Permissions针对的是 dangerous permissions
, normal permissions
还是会在App安装期间被默认赋予。
下面我们就以 STORAGE
组中的 WRITE_EXTERNAL_STORAGE
为例子,尝试在Android 6.0中使用 runtime permission
相关api。
我们要做的事情非常简单,在手机的存储设备上新建一个hello.txt。
1.在AndroidManifest文件中添加如下权限生命
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2.在MainActivity中添加如下方法:
//在sdcard上新建一个名为fileName的文件 private void createFile(String fileName){ File sdcard = Environment.getExternalStorageDirectory(); File newFile = new File(sdcard,"/" + fileName) ; if(!newFile.exists()){ try { newFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } }
好的,如果没有 runtime permissions
这个概念的话,那其实这个功能已经完成了,我们来看看它在Android 6.0之前的版本上的运行情况,
首先是安装时的界面:
它提示用户该应用会修改会删除SD卡的内容,如果此时用户选择安装,那么也就是默认将 WRITE_EXTERNAL_STORAGE
这个权限赋予了该应用。
再来看运行结果:
看吧,文件直接就创建成功了,这样真的是很危险的。
接下来再在Android6.0的机子上安装这个应用,安装截图如下:
这个安装界面和之前的一样,也是向用户展示了App所涉及的权限。
下面看运行结果:
这里就出问题了,log显示App没有权限在SD卡上创建文件。这里要再讲一下 runtime permissions
原理
对于权限分类中的 dangerous permissions
,runtime permissions要求App在运行的时候做权限请求,某则App则无法获得相应请求。
接下来看一下怎么在代码中进行权限的申请:
public static final int EXTERNAL_STORAGE_REQ_CODE = 10 ; public void requestPermission(){ //判断当前Activity是否已经获得了该权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { //如果App的权限申请曾经被用户拒绝过,就需要在这里跟用户做出解释 if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { Toast.makeText(this,"please give me the permission",Toast.LENGTH_SHORT).show(); } else { //进行权限请求 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, EXTERNAL_STORAGE_REQ_CODE); } } }
当进行权限申请,并且用户做出选择后会回调onRequestPermissionsResult这个方法,在这个方法中做相关处理
@Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case EXTERNAL_STORAGE_REQ_CODE: { // 如果请求被拒绝,那么通常grantResults数组为空 if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { //申请成功,进行相应操作 createFile("hello.txt"); } else { //申请失败,可以继续向用户解释。 } return; } } }
到这里 runtime permissions
的权限申请操作就结束了,我们看一下效果:
允许后会再次调用createFile("hello.txt")方法,这次文件会被成功创建。
其实还有一些内容需要写,这里先//TODO一下,希望以上内容对你有所帮助。