Building a Cordova plugin for your native SDK

Arjun Attam
HyperTrack
Published in
4 min readJan 16, 2017

The HyperTrack SDK powers location features, like live tracking, real-time delay alerts, and metering distance traveled, in apps all over the world. The SDK is built to collect and transmit a battery-efficient stream of location data. The SDKs for Android and iOS are fully native to access the core platform level location and network APIs.

Our SDK users build their apps on a variety of native and non-native platforms. The need for better location features is not limited to native Android and iOS apps — apps that are built on React Native, Cordova, Ionic, and Xamarin are also starved for better location APIs.

In the quest to enable developers on these platforms, we have struggled with setting up build environments, juggling other native dependencies, and then distributing these bindings. In this post, we share our learnings from building a Cordova plugin for our SDK.

If you are building a Cordova plugin, the official documentation has a useful guide to start. The steps below are intended to cover some crucial steps and help avoid potential pitfalls.

Step 1: Create plugin boilerplate

Plugman is a handy tool that sets up the plugin project, with support for iOS and Android. In addition, you can also use it to create a package.json file to distribute the plugin via npm.

# Install plugman
$ npm install -g plugman
# Create a plugin
$ plugman create --name HyperTrackWrapper --plugin_id cordova-plugin-hypertrack --plugin_version 0.1.0
# Setup platforms
$ cd HyperTrackWrapper
$ plugman platform add --platform_name ios
$ plugman platform add --platform_name android
# Create a package.json file for npm
$ plugman createpackagejson .

After you create the plugin and add the platforms, the directory structure of the plugin will look like this. Once the directory structure is in place, it was useful to implement the Echo example in the Cordova docs.

HyperTrackWrapper
|-- src
| |-- android
| | |--HyperTrackWrapper.java
| |
| |-- ios
| | |--HyperTrackWrapper.m
|
|-- www
| |-- HyperTrackWrapper.js
|
|-- plugin.xml
|-- package.json

Step 2: Setup Android dependencies

Cordova plugins support native dependencies through Gradle. For the HyperTrack SDK wrapper, we created a gradle file with references to the SDK and relevant Google Play Services packages.

This gradle file was saved as hypertrack-gradle.xml in the src/android directory of the plugin.

dependencies {
compile('io.hypertrack:transmitter:1.4.20:release@aar') {
transitive = true;
}
compile 'com.google.android.gms:play-services-gcm:9.6.1'
compile 'com.google.android.gms:play-services-location:9.6.1'
}

For the gradle configuration to be picked up while compiling, the plugin.xml file needs to have a reference to the gradle file. This is done with the framework tag, with the gradleReference type attribute.

<platform name="android">  ...
<framework custom="true" src="src/android/hypertrack-sdk.gradle" type="gradleReference" />
</platform>

Step 3: Setup iOS dependencies

The HyperTrack iOS SDKs are distributed using CocoaPods. With the recent Cordova 6.4.0 release, CocoaPods support was added to the Cordova iOS platform.

To add the native iOS dependencies, we added the following framework tags to the plugin.xml file. The first one imports the SDK from CocoaPods, and the second one imports the sqlite dynamic library into the plugin. While defining CocoaPods dependencies, don’t forget to mention the version using the spec attribute, or else the build will fail!

<platform name="ios">   ...
<framework src="HTTransmitter" type="podspec" spec="~> 0.12.6" />
<framework src="libsqlite3.dylib" />
</platform>

The framework tag documentation is a useful reference link to have while adding native dependencies for Cordova platforms.

Step 4: Configure APIs

In this last step, we define some native API wrappers. The www/HyperTrackWrapper.js file defines the methods to be exported to the Cordova application. In our native SDKs, the startTrip method triggers the SDK to start trip.

hypertrack.startTrip = function(driverID, taskIDs, success, error) {
exec(success, error, "HyperTrack", "startTrip", [driverID, taskIDs]);
};

The js method is then individually defined for iOS and Android. Once the Cordova method is implemented, the respective native methods are invoked at runtime. These methods talk to the native SDKs — bringing native capability to the Cordova application.

The startTrip method is defined for iOS in the ios/HyperTrackWrapper.m file. Notice how it calls the native SDK method internally, to virtually translate the call from js to objective-C.

- (void)startTrip:(CDVInvokedUrlCommand*)command{
NSString* driverID = [command.arguments objectAtIndex:0];
NSMutableArray* taskIDs = [command.arguments objectAtIndex:1];
__block CDVPluginResult* pluginResult = nil;

HTTripParams* tripParams = [[HTTripParams alloc] init];
tripParams.driverID = driverID;
tripParams.taskIDs = taskIDs;
[[HTTransmitterClient sharedClient] startTripWithTripParams:tripParams completion:^(HTResponse <HTTrip *> * _Nullable response, NSError * _Nullable error) { if (error) { // Call failure callback
NSDictionary *failure = @{@"error" : error.localizedDescription};
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:failure];
} else { // If there is no error, use the tripID received in the callback in your app.
NSDictionary *success = @{@"trip" : response.result.dictionaryValue.jsonString};
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:success];
}
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; }];
}

The Android method is defined in the android/HyperTrackWrapper.java file. Like the iOS method, it calls the native SDK methods to translate the call.

private void startTrip(String driverID, ArrayList<String> taskIDs, final CallbackContext callbackContext) {    Context context = this.cordova.getActivity().getApplicationContext();
HTTransmitterService transmitterService = HTTransmitterService.getInstance(context);
HTTripParams htTripParams = new
HTTripParamsBuilder().setDriverID(driverID)
.setTaskIDs(taskIDs)
.createHTTripParams();
transmitterService.startTrip(htTripParams, new HTTripStatusCallback() {
@Override
public void onSuccess(boolean isOffline, HTTrip htTrip) {
// call success callback
callbackContext.success(result);
}
@Override
public void onError(Exception e) {
// call error callback
callbackContext.error(result);
}
});
}

The HyperTrack plugin for Cordova enables powerful location features in Cordova and Ionic apps with a few API calls. Sign up to track your phone within minutes and get started!

--

--

Arjun Attam
HyperTrack

Program Manager on Playwright at Microsoft. I ❤ developer tools!