Libraries and Dangerous Permissions
If you publish a library for Android, you can request that
developers have specific <uses-permission>
elements, to
allow your library to perform secured actions. If you are
publishing an AAR, you can have those <uses-permission>
elements in your own manifest, and those will be merged
automatically into apps’ manifests, without those developers
having to lift a finger. You can even check at runtime —
perhaps as part of library initialization — whether
or not those permissions actually appear in the manifest,
failing fast if they do not.
This is all fine.
However, if you publish a library for Android, there are some basic rules to follow, particularly given Android 6.0’s runtime permissions.
Rule #1: Automatic Merging Does Not Mean You Can Skimp on Documentation
Developers get
confused when permissions show up unexpectedly.
Just because you don’t need developers to add
<uses-permission>
elements manually does not mean that you
can skip telling them about the permissions. This is particularly
true for dangerous
permissions, as it is fairly likely that
the app developer will need to be the one to request those
permissions from the user at runtime.
Rule #2: Gracefully Degrade If Permissions Are Missing
For dangerous
permissions, users may elect to not grant them
to the app, and by extension your library. Moreover, developers
may not even want to ask the users for certain permissions,
either by having the permissions in the manifest (and triggering
prompts at install time prior to Android 6.0) or by popping
up the permission dialog at runtime on Android 6.0+. Just because
you want the permission does not mean that anyone else wants
you to have the permission.
For permissions that are clearly essential, requiring them is fine. But if developers or users cannot clearly see why the permission is needed, you need to be able to live without that permission, gracefully degrading and performing a subset of your functionality, with sufficient notification to developers about the reduced functionality.
Rule #3: Document What Happens When Permissions Are Denied
Developers cannot somehow force users at gunpoint to grant
dangerous
permissions. Yet, developers need to be in position to
support users who deny those permissions, then wonder why certain
things do not work. Hence, if those permissions stem from libraries, the
developers using the libraries need to know exactly what will stop
working if the user elects to deny the permissions.
Rule #4: Make Sure That You Really Need Those Permissions
Asking for permissions that are not necessary, particularly
dangerous
ones, are good ways to aggravate developers and
users alike.
For example, let’s review this Twitter thread.
Ty Smith, a well-known Android developer at Twitter, pointed out
that the StockTwits app pops up a dialog indicating that the
user needs to grant access to contacts in order to receive
push notifications. That dialog appears to be tied to
shouldShowPermissionRequestRationale()
, displayed to help
explain to the user why StockTwits is asking for access to
contacts.
Further discussion on that thread points out that StockTwits
uses Parse, and Parse requires GET_ACCOUNTS
for push
notifications. It is unclear why Parse needs GET_ACCOUNTS
for push notifications, other than that
GCM requires it on older Android devices.
And, if I am understanding
one tweet
properly, Parse complains if your manifest lacks GET_ACCOUNTS
.
It’s entirely possible that I am missing pieces, as I don’t use Parse, I don’t use StockTwits, and I haven’t played with GCM in quite some time.
UPDATE: Mike Evans
pointed out
that Parse
no longer requires GET_ACCOUNTS
.
This means that Parse’s documentation
needs updating.
But, if my synopsis is correct:
- Parse should point out that
GET_ACCOUNTS
is not needed, for apps with aminSdkVersion
of 15 or higher, in the documentation for Android developers. Ideally, they would provide code snippets showing how to block this permission from the manifest merger process in the app’s own manifest. If Parse does not needGET_ACCOUNTS
for anything else, this avoids bothering users of most devices with this permission. Since this permission has some scary-sounding language around it, this would help improve adoption and usage of apps integrating with Parse.
UPDATE: An earlier version of this blog post suggested
the use of android:maxSdkVersion
, but Steven Jones pointed out
that android:maxSdkVersion
is new to API Level 19, which makes it
not a good choice for this circumstance.
- Even if Parse would like
GET_ACCOUNTS
for some other reason, Parse needs to gracefully degrade ifGET_ACCOUNTS
is skipped by the developer or denied by the user. Again, specifically for GCM,GET_ACCOUNTS
is not needed on over 90% of Android devices; on those devices, Parse should not be complaining if this permission is missing. And, since this permission is part of the contacts permission group on Android 6.0, this really needs to be optional on Android 6.0+ devices, as users may say, as Ty did, that they do not want to give apps that permission.
The problem here is that Parse is a library, backed by Web services. From a brand standpoint, it is a brand for developers; users do not see Parse. So, when users complain about StockTwits wanting access to contacts, StockTwits gets blamed, even if StockTwits is just doing what Parse asks. Of course, StockTwits gets blamed because their CEO seems to be a jerk, but that’s a separate issue.
On Android 6.0+, dangerous
permissions demand transparency. Users need
to understand what the rationale is for the dangerous
permission,
and educated users may look askance at what appears to be flimsy rationale.
In turn, developers need to understand why libraries want those
dangerous
permissions and what happens when the permissions are not
granted or not requested. And that means that library authors need to
do a good job of knowing why they need permissions, not only to minimize
their requests for permissions, but to explain to developers the reasons,
so developers can in turn explain this to users.
IOW, manifest merger is not enough.