Building Cordova Plugins for BlackBerry 10 on Windows

Native SDK Development

Welcome to the third installment in our series on building Cordova plugins for BlackBerry 10. Last week we covered Mac and Linux. Today’s post is for our Windows developers and will detail steps for setting up all required tools, configuring your environment, how to leverage our plugins template and tips and tricks for troubleshooting issues throughout the development process.

Step 1: Install the required tools

The following tools are used to build your own Cordova plugin for BlackBerry 10. Download and install all of the following to your Windows machine:

Step 2: Request and install code signing keys

In order to build release-ready code and publish an application in BlackBerry World, you must request and install code signing keys. Code signing keys are used to securely imprint your digital signature on a compiled piece of code, such as a production-ready application. The Momentics IDE simplifies the code signing installation process and is recommended. See instructions on how to configure signing using Momentics.

Step 3: Optionally Sign BlackBerry Open Source contributor agreement

If you’d like to contribute your work back to the community through the BlackBerry repositories, you’ll need to sign a Contributor’s Agreement and submit a request to BlackBerry. The contribution process is designed to protect the interests of both the community and BlackBerry, while being lightweight and easy to follow. Once approved, your name will be included among the list of Approved Signatories.

Step 4: Optionally Install Git and create a GitHub account

The BlackBerry Open Source project is hosted in GitHub. In order to contribute or modify code from the project, developers must create a GitHub account and be familiar with how to use Git to upload and download submissions. Anyone can download the code without having an account.

Step 5: Starting a Project from the Template

There is a fair amount of boilerplate code involved in a new plugin, so the best place to start is with the Plugin Template. For convenience, the native portion of the template is included in the NDK New Project Wizard, but for a few reasons, the best place to get the template will always be the GitHub repository.

To create a new plugin, copy the template project into a new location. I would recommend building the sample application first before you attempt to do anything new. Only the “www” folder of the application is included, so you’ll want to create a new application with WebWorks 2 or Cordova first:

  1. In the “Template” folder, run “webworks create sample2”, or “cordova create sample2”.
  2. Remove the “www” folder from this new app, and replace it with the one from the template’s sample folder.
  3. Change to the “sample” folder: “cd sample2”.
  4. If you are using Cordova, make sure the BlackBerry NDK is on your path, or run the “bbndk-env” script to setup your path, and then run “cordova platform add blackberry10”.
  5. Add the plugin to this app with “webworks plugin add ../plugin” or “cordova plugin add ../plugin”
  6. Build and run the app on your device or sim with “webworks run” or “cordova run”. You may need to supply your signing key and device password.

You should see the template sample app run and give you the output from this screenshot:

WebWorks Windows

With that process completed, we’re in good shape to start breaking things!

Step 6: Renaming the Template

Remove the plugin from the app with “webworks plugin remove community.templateplugin”, or likewise with “cordova.” Import the native portion of the Template Project into the Momentics NDK. The project definition is in the “Template/plugin/src/blackberry10/native” folder. Now rename the template plugin and its various parts to suit the plugin that you want to create. Instructions for these steps are included in the Readme. Pay close attention here, as typos and missed renames will cause problems that can be hard to track down. Before actually changing any of the methods, just the names of the boilerplate files and classes, rebuild the sample including the native portion of the plugin and add it back to the sample. This way you can be certain that you’ve got a working base before making the more significant changes.

  1. Build the Native portion, following the instructions in the Readme. This will put native binaries into the simulator and device directories with the name that you chose.
  2. Make sure you updated the reference to the native code in the index.js file where it refers to “libTemplate” and “libTemplate.TemplateJS”. This is how the plugin dynamically loads the native binaries from the .so file.
  3. Also make sure that your “plugin.xml” file was updated with all the new file names. This file tells WebWorks and Cordova how to install the plugin.
  4. Add the plugin to the sample app with “webworks plugin add ../plugin” in the sample2 folder again.
  5. Change the function calls in the sample app function called “testPluginCalls” to reference the namespace that you chose earlier.
  6. Build the app again with “webworks run”.

Step 7: Adding Features and Plugin Communication

Provided all the name changes worked out, you should get the same results as before, but now it’s your new plugin that’s doing all the magic. With this, the door is open to more advanced features, and the template functions are available to show you how to transmit different types of data between the JavaScript and C++ layers. You can send a simple command with no data, with a string, or with JSON. You can get a result immediately, or asynchronously, or initiate a thread that returns multiple results. This is the flow and usage of each part of the plugin:

  1. When the app launches, an object with the contents of plugin/www/client.js is created using the name given in plugin/plugin.xml. In the case of the Template, this is “community.templateplugin”.
  2. In your app you can call a method on this plugin object, which will send the command and parameters through the Cordova framework. It looks up the plugin using the “_ID” value that is used in the exec function calls and defined in client.js.
  3. The “_ID” value matches the id defined in plugin.xml, which means Cordova calls the index.js method of the same name as the command passed from client.js. This index.js file is appended into the “frameworkModules.js” file that you can view in the Bootstrap WebView of your application. It’s the first WebView in the list when you connect WebInspector to your debug application, so you are able to open this WebView and put breakpoints in there for debugging.
  4. The first step of a function call in index.js is to create a new PluginResult object. This object handles communication back to the application through the Cordova framework. The PluginResult is stored in an object for lookup later using its own generated callbackId value.
  5. To get into the native code, the plugin will use the JNEXT bridge, defined at the bottom of the index.js file. This code loads and links the native object code and serializes function calls into it. It’s important that you send in the callbackId value from the PluginResult, and that any parameters are string, so make sure to call JSON.stringify on JSON objects here.
  6. From here the control passes into the InvokeMethod of the native code. The command and callbackId values are stripped off the string to determine the method to call, and the remainder is considered arguments. The architecture separates the JNEXT bridge portion of the code into a file named template_js.cpp while the true plugin is in the template_ndk.cpp file. You will likely have renamed these earlier. Based on the command given, a method from the plugin file is called.
  7. Besides running the native methods needed at this point, the arguments may need to be parsed from a string into JSON. If this is a method that should return a result immediately, you might simply return the result as a string. Otherwise, to return a result, use the “m_pParent->NotifyEvent(callbackId + “ “ + message)” method, where message is a string.

After each change to the native code, the native project needs to be rebuilt. Use the device and simulator targets to build the library in the right folders. When any change to the plugin code occurs, including native code changes, the plugin should be removed and re-added to the sample app. You can write a simple script to do so.

Step 8: Debugging and Logging

Take note of the Logging feature that is integrated into the native part of the template. This is a convenient wrapper for the device’s slog2 logging tool. Given a priority level and a string, the message will be written into slog2, which can be viewed by connecting to the device with Momentics.

When adding features into your plugin, make sure to note what library the code comes in. You’ll need to add that library to the linker setup on your native project. Otherwise, when the plugin library tries to load at runtime, it will fail to link and will not load. The error message states that the app can’t find the library, so this can be quite misleading. Information about adding libraries and special instructions for Qt libraries is in the Template Readme.

Step 9: You’re Good to Go!

At this point, you’re on your way to building plugins and doing some very cool things. Working together with the community, we’ve been able to release 18 community plugins already. Don’t be discouraged if you run into trouble; a lot of your fellow developers have been there before and we can help. If you’re interested in contributing to our BlackBerry repositories on GitHub, we’d appreciate your input. Contact me on Twitter or  GitHub to get started.

About Tim W.

Tim works on the Developer Relations team at BlackBerry, focusing on WebWorks, HTML5, and Open Source.

Join the conversation

Show comments Hide comments
+ -
blog comments powered by Disqus