一、权限
权限有两个作用:其一:防止其它程序随便调用。
其二:能够在安装程序时,显式的给用户看,当前要安装的这个程序要用到哪个功能。这个是最重要的,试想,如果你装一个斗地主游戏,却看到要用到打电话、发短信的功能,便可以判定这个程序里面可能包含恶意代码,还是不装为好。
下面以打电话为例,来讲解一下系统对权限的要求:
一般情况下,要调用打电话的Activity,代码是这样写的:
Uri uri = Uri.parse("tel:12345678");
Intent intent = new Intent(Intent.ACTION_CALL, uri);
startActivity(intent);
如果我们此时直接执行,会出现下面的错误:
ERROR/AndroidRuntime: java.lang.SecurityException: Permission Denial:
starting Intent { act=android.intent.action.CALL dat=tel:12345678 cmp=com.android.phone/.OutgoingCallBroadcaster }
......
requires android.permission.CALL_PHONE
说的是需要CALL_PHONE的访问权限,这个权限是Android系统自带的phone应用里定义的权限:
<uses-permission android:name="android.permission.CALL_PHONE"/>
这就是要告诉系统,我们的程序要用到打电话的功能。所以当用户安装程序时,系统只需要遍历AndroidManifest.xml文件就能知道我们需要访问哪些外部程序,即需要哪些程序的权限,比如打电话、发短信等,并以列表的形式告诉用户,当前你要安装的程序要用到哪些权限,以便用户决定确定安装,还是取消安装。
二、自定义权限
1、首先申明一个权限<permission
android:name="com.zhangquanit.permission.act"
android:icon="@mipmap/ic_launcher"
android:label="测试权限"
android:protectionLevel="signature"/>
其中name和protectionLevel是必须的,其他都是非必须的。
关于name
权限的名称,通常应该遵循Android的命名方案(*.permission.*)
关于protectionLevel:
normal, dangerous, signature, signatureOrSystem ,取决于保护级别,在确定是否授予权限时,系统可能采取不同的操作。
normal 低风险权限,只要申请了就可以使用,安装时不需要用户确认;
dangerous 高风险权限,安装时需要用户的确认才可使用;
signature 只有当申请权限的应用程序的数字签名与声明此权限的应用程序的数字签名相同时(如果是申请系统权限,则需要与系统签名相同),才能将权限授给它;
signatureOrSystem 签名相同,或者申请权限的应用为系统应用。
2、为组件添加权限访问,以Activity为例,其他组件类似
<activity
android:name=".PermissionActivity"
android:permission="com.zhangquanit.permission.act"
android:exported="true"
/>
设置exported=true,允许被外部应用调用。
3、在其他应用中访问PermissionActivity,就需要在AndroidManifest.xml中申请权限
<!-- 必须声明自定义权限-->
<permission android:name="com.zhangquanit.permission.act" android:protectionLevel="signature"/>
<!-- 使用权限-->
<uses-permission android:name="com.zhangquanit.permission.act"/>
打开PermissionActivity
Intent intent = new Intent();
intent.setClassName("com.xx","com.xx.PermissionActivity");
startActivity(intent);
注意:应用程序内部访问是不需要申请权限的。
设置共享组件时设置permission的其他几个属性:
以provider为例
<provider
android:name="com.review.datastorage.contentprovider.TestProvider"
android:authorities="com.review.provider"
android:permission="com.review.provider.permission.readwrite"
android:exported="true">
</provider>
android:exported 设置此provider是否可以被其他应用使用。
android:readPermission 从该provider读取数据需要的权限(query)
android:writePermission 从该provider写入数据需要的权限(insert、update、delete)
android:permission provider 读写该provider需要的权限 (query、insert、update、delete)
android:grantUriPermissions 临时权限标识,true时,意味着该provider下所有数据均可被临时使用;false时,则反之,
但可以通过设置<grant-uri-permission>标签来指定哪些路径可以被临时使用。这么说可能还是不容易理解,
我们举个例子,比如你开发了一个邮箱应用,其中含有附件需要第三方应用打开,但第三方应用又没有向你申请该附件的读权限,
但如果你设置了此标签,则可以在start第三方应用时,传入FLAG_GRANT_READ_URI_PERMISSION或FLAG_GRANT_WRITE_URI_PERMISSION来让第三方应用临时具有读写该数据的权限。
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);