Cordova Plugins are the magic that enable our mobile web app content to access the full power of Native SDKs underneath, but through clean JavaScript APIs that work the same across all platforms we target.
This simple guide, walks through the what, when, why, and how of Cordova plugin development for Android.
Before start, understand their
A Cordova plugin consists of some JavaScript code and Native code that communicates with each other to pass data between the web and native worlds.
A plugin is how we extend the functionality of the browser environment our Cordova apps run in to add the full power of the underlying native SDKs.
Cordova apps run primarily in a web context which makes it easy to rapidly build apps just like we build web apps. However, the web doesn't always have all the features we need at a native level, so we need a way to write native code and communicate with it.
npm install -g cordova
First you have to initialize your plugin using a scaffolder, plugman . To install plugman run with this shell command:
npm install -g plugman
plugman create --name <name> --plugin_id <id> --plugin_version <version> --variable description="<description>"
Example:
plugman create --name PluginCustom --plugin_id "cordova-plugin-custom" --plugin_version 0.0.1 --variable description="Awesome PLugin"
It will generate in the current directory the folders: www
, src
and file plugin.xml
.
To add a supported platfrom and the sample files (e.g. the java files for android) for it, run:
plugman platform add --platform_name <platform_name>
To create package.json
, in order to have the possibility to publish on a npm
repo, run:
plugman createpackagejson .
In the www folder will contain a javascript file <plugin name>.js
(in our example will be PluginCustom.js
)
var exec = require('cordova/exec');
exports.coolMethod = function(arg0, success, error) {
exec(success, error, "PluginCustom", "coolMethod", [arg0]);
};
This is the file where we have to write the javascript api (used in your Cordova App) that allow access to the native code.
In this case you can call from javaScript the coolMethod
that will be linked to the platform native code.
In the Plugin Manifest will be defined how the Javascript API will be made available to hosted app.
<?xml version='1.0' encoding='utf-8'?>
<plugin id="cordova-plugin-custom" version="0.0.1" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
<name>PluginCustom</name>
<DESCRIPTION>Awesome Plugin</DESCRIPTION>
<js-module name="PluginCustom" src="www/PluginCustom.js">
<!-- API will be available through Object 'PluginCustom' -->
<clobbers target="cordova.plugins.PluginCustom" />
</js-module>
</plugin>
If you want add a new dependency we have to insert a new framework
tag in the plugin.xml
file within the <platform name:"android">
<framework src="yourDependency" />
Example:
<platform name="android">
....
<framework src="com.github.nkzawa:socket.io-client:0.3.0" />
</platform>
If you want customize Gradle configuration concerning dependencies, you can create a file named build-extras.gradle
and append it as framework
within plugin.xml
<framework src="build-extras.gradle" custom="true" type="gradleReference" />
In the build-extras.gradle
file you can configure, according Gradle syntax, every dependency.
Example:
configurations {
all*.exclude group: 'org.json', module: 'json'
}
cordova create <PATH> [ID [NAME [CONFIG]]] [options]
Create a Cordova project
PATH ......................... Where to create the project
ID ........................... Reverse-domain-style package name - used in <widget id>
NAME ......................... Human readable name
CONFIG ....................... json string whose key/values will be included in
[PATH]/.cordova/config.json
Options
--template=<PATH|NPM PACKAGE|GIT URL> ... use a custom template located locally, in NPM, or GitHub.
--copy-from|src=<PATH> .................. deprecated, use --template instead.
--link-to=<PATH> ........................ symlink to custom www assets without creating a copy.
Example
cordova create myapp com.mycompany.myteam.myapp MyApp
cordova platform add android --save
cordova plugin add --link ~/path/to/plugin
Note:
With the
--link
flag, Cordova creates a symbolic link to our plugin so we can update the plugin locally and rebuild without having to copy anything.
to remove the plugin, use the symbolic name of the plugin instead:
cordova plugin rm my-cordova-plugin
When our plugin is linked, we can make modifications to the native code in our plugin and rebuild our app immediately. If we make modifications to the JavaScript portion of our plugin, we need to reinstall the plugin (currently is the only way to update Cordova stuff within web app).
cordova plugin rm my-cordova-plugin
cordova plugin add --link ~/path/to/plugin
Now that the scaffolding is in place to build and test the plugin, follow the JavaScript and then platform-specific guides below to get coding.
Ideally, we should try to have our native plugin code do as little work as possible by focusing on sending data from the native layer up to the JavaScript layer and processing it there. This approach maximizes our ability to create cross-platform code, and minimizes the amount of native code to maintain. Of course, you may decide to perform more work at the native layer for performance reasons, but this is increasingly rare.
Here is a simple example of a Cordova plugin JS:
var exec = require('cordova/exec');
var PLUGIN_NAME = 'MyCordovaPlugin';
var MyCordovaPlugin = {
echo: function(phrase, cb) {
exec(cb, null, PLUGIN_NAME, 'echo', [phrase]);
}
};
module.exports = MyCordovaPlugin;
This is, largely, just standard JavaScript. The Cordova magic happens with the exec
call, which takes a few params:
exec(callback, errorCallback, pluginName, actionName, argumentArray)
callback
is called when the plugin successfully returns, and any arguments from the native plugin are passed into iterrorCallback
is called when the plugin encounters an error. We've omitted this abovepluginName
is the plugin class name on the native side.actionName
is the action we will perform on the native side.argumentArray
is an array of arguments to pass to the native side
With this call, we can send and receive data from our native plugin, and this is really 95% of what you need on the JavaScript side to interact with Cordova.
This assumes you've downloaded and installed the Android Studio.
Make sure to add the android
platform to your app: cordova platform add android
. Open Android Studio, then Import a project and choose your app's platforms/android
folder.
Back in our plugin repo, we can edit the code in src/android/
and as we modify the files in here, they will update in Android Studio and we can rebuild the app and re-run it.
If we make code modifications to our plugin's www/plugin.js
file, we will need to remove the plugin and re-install it otherwise the changes won't take effect.
Unlike iOS, Android handles actions by sending them through a single method and then doing a String compare on the name of the action:
MyCordovaPlugin.java
public class MyCordovaPlugin extends CordovaPlugin {
private static final String TAG = "MyCordovaPlugin";
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
super.initialize(cordova, webView);
Log.d(TAG, "Initializing MyCordovaPlugin");
}
public boolean execute(String action, JSONArray arg, final CallbackContext callbackContext) throws JSONException {
if(action.equals("echo")) {
String phrase = arg.getString(0);
// Echo back the first argument
Log.d(TAG, phrase);
} else if(action.equals("getDate")) {
// An example of returning data back to the web layer
final PluginResult result = new PluginResult(PluginResult.Status.OK, (new Date()).toString());
callbackContext.sendPluginResult(result);
}
return true;
}
}
Cordova plugins support preference variables that can control the settings that go into the AndroidManifest (Android) and info plist (iOS). We can also specify preferences for all platforms or only for specific ones.
To add support for preferences in our plugin.xml
, use <preference
:
<preference name="URL_SCHEME" />
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
id="my-plugin"
version="1.0.8">
<preference name="MY_SETTING" />
<platform name="android">
<preference name="MY_ANDROID_SETTING" default=" " />
...
</platform>
</plugin>
To specify variables on plugin install, add each with a --variable
flag:
cordova plugin add --link ~/path/to/plugin --variable MY_SETTING=bar --variable MY_ANDROID_SETTING=foo --variable MY_IOS_SETTING=baz
There are two options for including 3rd party libraries in Cordova plugins and/or projects that rely on them. The first is to include the code directly in the plugin itself. The second is to import the library into the app that relies on it.
Cordova plugins aren't built on their own (meaning they are built only in a real app project), so the second one is probably preferable.
Cordova plugins can get into an inconsistent state if modifications are made to things like the name of the plugin, and other lower-level plugin settings.
If you need to rename a plugin, first remove it from the app with cordova plugin rm my-plugin
. Rename the plugin in the plugin's plugin.xml
and reinstall it.
If Cordova complains that the plugin is already installed, or there are duplicate symbols, modify the app/plugins/android.json
and remove
any offending lines that reference the old plugin.
Great, how can I develop a plugin that has User interface?