Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Cordova Plugin Developer Guide

Cordova Plugin Development Guide (iOS and Android)

Version: 0.0.1 updated 7/1/2016

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.

Building Cordova plugins is scary for many Cordova and Ionic developers, but it doesn't have to be. This simple guide walks through the what, when, why, and how of Cordova plugin development for iOS and Android.

Introduction

Before we jump into building a real plugin, some backstory is in order.

What is a Cordova Plugin?

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.

When do you need a Cordova Plugin?

Cordova apps run primarily in a web browser which makes it easy to rapidly build apps just like we build websites. However, the browser 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 through our browser context.

Cordova comes with many plugins, and there are hundreds more in the Cordova community. However, it's very possible that a Native SDK or library we want to use lacks a corresponding Cordova plugin, and we will find we have to build our own.

Crash Course

The best way to start building a plugin is to clone an existing one! We've put together a simple starter template for a Cordova plugin here: https://github.com/driftyco/cordova-plugin-template

  1. Clone the repo:
git clone git@github.com:driftyco/cordova-plugin-template.git
cd cordova-plugin-template
  1. Create your app

In a different terminal, create your app:

Run ionic start if using Ionic, or cordova create if not.

We will be testing an developing our plugin from this app. Plugins are always built and developed from within an existing Cordova project.

  1. Add platforms

cordova platform add android ios

  1. Install and Link your Plugin
cordova plugin add --link ~/path/to/plugin

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.

Note: to remove the plugin, use the symbolic name of the plugin instead:

cordova plugin rm my-cordova-plugin
  1. Testing process

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 (as far as I know, I am trying to find a way around this).

cordova plugin rm my-cordova-plugin
cordova plugin add --link ~/path/to/plugin
  1. Building our 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.

JavaScript Plugin Development

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.

Example

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 it
  • errorCallback is called when the plugin encounters an error. We've omitted this above
  • pluginName 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.

iOS Plugin Development

Let's focus on iOS quick. We can build Cordova plugins with Objective-C or Swift, but we will focus on Objective-C for this tutorial (here's a great Swift tutorial).

Make sure to add the ios platform to your app: cordova platform add ios, then open the X Code project in platforms/ios.

Back in our plugin repo, we can edit the code in src/ios/ and as we modify the files in here, they will update in X Code 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.

Handling Actions

On iOS, Cordova commands map to functions in the implementation of our Plugin's class. For example, to handle the echo command, we can define the function and then implement it as such:

MyCordovaPlugin.h

#import <Cordova/CDVPlugin.h>

@interface MyCordovaPlugin : CDVPlugin {
}

// The handler for the 'echo' action
- (void)echo:(CDVInvokedUrlCommand *)command;

@end

Then, in the implementation of the plugin class:

MyCordovaPlugin.m

#import "MyCordovaPlugin.h"

#import <Cordova/CDVAvailability.h>

@implementation MyCordovaPlugin

- (void)pluginInitialize {
}

- (void)echo:(CDVInvokedUrlCommand *)command {
  NSString* phrase = [command.arguments objectAtIndex:0];
  NSLog(@"%@", phrase);
}
@end

echo is a simple command and doesn't return any data back. Here's an example of a more complicated routine that returns a date string back to JavaScript:

- (void)getDate:(CDVInvokedUrlCommand *)command {
  NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  NSLocale *enUSPOSIXLocale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
  [dateFormatter setLocale:enUSPOSIXLocale];
  [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];

  NSDate *now = [NSDate date];
  NSString *iso8601String = [dateFormatter stringFromDate:now];

  CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:iso8601String];
  [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}

Android Plugin Development

This assumes you've downloaded and installed the Android Studio.

Make sure to add the android platform to your app: cordova platform add ios. 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.

Handling Actions

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

package com.example;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult;
import org.apache.cordova.PluginResult.Status;
import org.json.JSONObject;
import org.json.JSONArray;
import org.json.JSONException;

import android.util.Log;

import java.util.Date;

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 args, final CallbackContext callbackContext) throws JSONException {
    if(action.equals("echo")) {
      String phrase = args.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;
  }

}

Useful Tips

Adding Variables

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>
    <platform name="ios">
      <preference name="MY_IOS_SETTING" default=" " />
      ...
</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

Adding 3rd party libraries

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.

Troubleshooting

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.

  1. Renaming a plugin

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/ios.json or app/plugins/android.json and remove any offending lines that reference the old plugin.

Resources

Some great reading to continue your Cordova plugin efforts:

Thank you for this guide. Can you please briefly talk about how to asynchronously update the UI via callbacks from the plugin? For example, suppose I have updates from my native side (Java plugin) processing some kind of events every second that it wishes to update the UI with (JavaScript side). How to prevent UI from getting hung up, and ensure a smooth user experience?

Hi !
if you look to this plugin
https://github.com/edimuj/cordova-plugin-audioinput
you can see a working method to do what u need
enjoy

Thank you for this guide.
I had one question. Can you please tell me how to add a gradle module dependency while creating a plugin. I want to add a gradle based project dependency inside my plugin.
Thank you.
Please help

redent commented Jun 14, 2017

You can add a reference to a gradle file in your plugin.xml file: https://cordova.apache.org/docs/en/latest/plugin_ref/spec.html#framework

alexpdb commented Jun 15, 2017 edited

I solved mainly everything that was written here Stackoverflow Question: Ionic2 integrate custom ios plugin with alamofire framework as dependency

Except one thing:

Is there any way to add use_frameworks! in the podfile when generating it from the plugin.xml with the tag?

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment