基于安全需求,应用对Android系统提供的content provider或者service的访问需要在安装时进行许可,这就是AndroidManifest.xml文件中的permission中声称,之前已经很多例子。同样如果其他应用要访问我们的数据,我们也可以要求这些应用必须获得用户授权方可访问我们的数据。
申请授权:请求permission
申请许可的格式为
<uses-permission android:name="android.permission.ACCESS_LOCATION" />
Android系统所提供的均已android.permission开头,具体的定义参见reference中Manifest.permission的定义。例如INTENET,WRITE_EXTERNAL_STORAGE, ACCESS_COARSE_LOCATION(粗定位)、ACCESS_FINE_LOCATION,CALL_PHONE。第三方应用将有他们定义自定义的许可。
在安装的时候,系统会提示用户是否同意许可。但是如果通过USB安装,即开发模式,系统将不会出现提示。如果用户不授权,将不被安装和运行。如果在AndroidMenifest.xml中忘了申请授权,则会抛出SecurityException的异常信息。
要求访问者须获得授权:声明permission
如果应用有content provider或者服务,例如按有私人信息,基于安全,同样可要求对其他程序访问进行安全控制。声明permission比请求要复杂些,如下:
<!-- 包括三个部分:(1)android:name,为了避免出现冲突,使用应用的Java的命名空间作为前缀 -->
<permission android:name="com.wei.android.learning.READ_GRAVITY"
<!-- permission的标签说明,简单明了 -->
android:label="@string/read_gravity_label"
<!-- 对permission的进一步说明,比标签要长和详细 -->
android:description="@string/read_gravity_description" />
上面只是对这是个可能的permission进行定义,要真正起到保护还需要近一步声明在那里需要保护,可以通过下面两种方式之一。
方式一:在AndroidManifest中表明要求强制许可
这种方式简单。如果对于provider,有readPermission和writePermission,我们在上面已经将读的许可进行了定义,可以被外部引用。例子如下:
<provider android:name=".GravityProvider" android:authorities="com.wei.android.learning.provider"
android:readPermission="com.wei.android.learning.READ_GRAVITY"
android:writePermission="com.wei.android.learning.WRITE_GRAVITY" />
若某个应用要通过这个content provider访问数据,如果忘了在manifest中请求许可,运行则会报错,如下图所示。
为了访问该content provider,应用应在manifest中申请许可,在安装时,用户授权后,才能有权限通过该provider来读取信息。本例如下:
<uses-permission android:name="com.wei.android.learning.READ_GRAVITY" />
除了provider之外,activity,service,receiver都可以申明要求许可,增加参数android:permission即可,以activity为例,如下:
<activity android:name=".xxxxx" android:label="yyyyyy" android:permission="com.wei.android.learning.MY_PERMISSION">
<intent-filter> … … </intent-filter>
</activity>
对于安全架构而言,如果要求了声明了permission,对于activity,没有许可,则无法启动该activity;对于service,没有许可,则无法启动、停止、绑定activity;对于Intent receiver,没有许可,则会忽略通过sendBroadcast( )发送的消息。
方式二:在代码中声明
我们也可以在代码中要求检查权限。请注意,仍需在manifest中对权限进行声明。我们仍以content Provider为例子。我们首先在manifest中声明一个新的permission:<user-permission andriod:name="com.wei.android.learning.MYTEST">。我们将在读数据时进行检查。
public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder){
if ( getContext().checkCallingPermision(“com.wei.android.leanring.MYTEST”) !=PackageManager.PERMISSION_GRNTED )
throw new SecurityException(“Required <com.wei.android.learning.MYTEST> Permission”);
}
… …
}
也可用于service,或者在sendBroadcast( )中进行检查。对于service,如果提供多种级别的权限,例如只读,读写,我们可以在代码中根据权限的级别进行处理,而在manifest中只能提供一种权限,对于多种权限,考虑在代码中区分。对于sendBroadcast( ),如果没有获得权限,则不能接收该广播消息。
一些注意
由于是否获得许可不是在编译时检查,而是在运行是发现,如果我们提供的API要求许可,包括content provider,service,将被其他activity调取的intent,都应当在文档中声明。另外,我们也应当详细告知用户,使他们在安装时给予许可。这也就是为何在permission声明中使用了@string/xxxx的方式,方便多国语言的使用。
Android系统有时会增加一些许可,而之前版本是没有,这会造成以前编写程序的许可授权问题。Android的解决方式如下,在manifest中定义最新版本x:<uses-sdk android:minSdkVersion="x">,例如x=3,表明应用定义的最低版本为Android 1.5版本,那么在安装时,系统自动将以后增添的许可全列上,请求用户授权。
Android的许可方式也有一定的限制。例如所有的许可必须在安装时被授权,哪怕极少使用到的许可,不能在以后授权;用户授权只能同意或者不同意,没有可选的授权方式,例如授权一部分,不授权另一部分。