Nuggets of hard-won programming experience, brain-dumped for Googlability.

Monday, June 27, 2011

Android Custom Permissions

TL;DR: If your Android application can be used by other Android applications, don't use
custom permissions to control this interaction.

If you're writing an Android application that exposes functionality that other applications can use, it's tempting to add your own custom permissions to control access to that functionality. By adding a tag to your AndroidManifest.xml, you can give a name and description for the permission, and can apparently leave it up to Android to handle the UI aspects of policing this permission.

But it's not that simple. Firstly, notice that the Android installer doesn't have any mechanism to indicate or enforce dependencies. The consequence of this is that an app that uses your BLOOP_FUNCTION might get installed before your app is.

The next thing to notice is that the Android package manager only exposes permissions to the user at the point an app is installed, and that unknown permissions are not presented to the user. This actually makes some sense – at this point, all the PackageManager knows is the internal name for the permission (e.g. com.example.myapp.ACCESS_BLOOP_FUNCTIONALITY), not anything user-visible.

If the user installs the other app, then later installs your app, then the user has never been asked to approve your custom permission, and PackageManager.checkPermission("com.example.myapp.ACCESS_BLOOP_FUNCTION","com.other.bloop_user") returns false. The permission is still visible if you manually enumerate the permissions of the other app (using PackageManager.getPackageInfo("com.other.bloop_user",GET_PERMISSIONS).requestedPermissions), but that doesn't really help – any attempt by the other app to access an activity or service thatrequires the permission will be rejected.

So the only hope is to try to detect the situation, and request that the user re-install the other application – hardly a palatable option.

Android Library Resources

TL;DR: Make sure any resources you define in an Android library project have globally unique names (e.g. by using a unique-prefix convention).

An Android library project is a "development project that holds shared Android source code and resources". But the resources are treated a bit differently than the source code: any project that uses the library gets the contents of LibraryProject/gen/com/example/ merged in with its own file.

This is inevitable, because the underlying resources are identified by an int, and as all of the resources need to be merged into that single numbering space, they all have to be renumbered to ensure there are no clashes.

But in turn, this means that the identifiers for the resources (@id/this_thing, @string/that_thing) should also have globally unique names, because they are sharing the same namespace. As the docs say:

Since the tools merge the resources of a library project with those of a dependent application project, a given resource ID might be defined in both projects. In this case, the tools select the resource from the application, or the library with highest priority, and discard the other resource.

So if your library has a string called "@string/name", the chances are that it will be hard
for a user of your library to get at the resource – and it will be hard to figure out why not. So
it's best to stick with "@string/my_lib_name".