Cordova Android 5.0.x plugin changes.

This is a post that will most likely end up on the Cordova blog. This will be posted here first.

Google has released Android 6.0.x on devices, and if you are an application developer, you should be worried about the following scenario.

This is an application crashing because some user decided that the application shouldn't have access to contacts. Why does this app need contacts anyway? So, instead of removing functionality, or losing users, you should gracefully handle permissions in your application, and this will tell you how the latest version of Cordova can do this. It should be clear that the only thing that we added to Cordova 5.0.x is the ability to handle these permissions, and nothing else should break with these changes. We've decided to keep the number of API changes small, and we did not remove any API calls in this release, since we know that major versions are likely to scare our users, and we want to try to avoid doing that this time. This is nothing like the 4.0.x change that we did earlier.

So, to get started, as an application developer, you will need to implement the following method:

    public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults)

We also added this method for most permission checking:

    public void requestPermission(CordovaPlugin plugin, int requestCode, String permission);

These methods must be implemented if you're implementing a Cordova Interface, but assuming that you're inheriting the CordovaInterfaceImpl class, this should be no problem. This allows for a plugin to request a permission. Right now, we don't have helper methods for checking permissions, and that has to be implemented manually as follows.

    private boolean hasReadPermission() {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
            return PackageManager.PERMISSION_GRANTED == cordova.getActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
            return true;

We're assuming that unless you're on Marshmallow, you already have the permission, since you should have already have it declared in your AndroidManifest.xml, which would be populated with the entry in your plugin.xml. However, you still need to handle these permission changes in your plugin. The basic flow for a plugin is as follows:

  1. Plugin checks for permission
  2. If the plugin doesn't have the permission, it requests the permission from Android
  3. Android prompts for a permission.
  4. Android then passes the permission to the Activity, which then passes it back to the plugin

  5. onRequestPermissionResult then processes the result

It's important that you setup various request codes, and ideally they should be enumerated to match the plugins that you are requesting. This will then allow you to continue the execution of the method. Of course, this may require the refactoring of the methods in your exec call.

It also should be noted that not every plugin is affected by this, only plugins that use what Android describes as dangerous permissions are affected. The list can be found here. Another thing that should be noted is that if you grant READ permission on a particular permission group, you will also be granting WRITE permissions on that group by design. Therefore, you may want to convey why you need access to the feature to begin somewhere else in your app, in addition to doing the due dilligence required in securing your application