So, what’s in a plugin anyway? Plugins consist of several things:
- metadata (cordova, npm)
- documentation
- JavaScript code
- native code (iOS, Android, etc.)
- tests
- TypeScript types
- hooks
Aside from the metadata, everything else is optional — you should only include what you need in order to make your plugin function as desired. If you don’t need JavaScript code, don’t include it. If you aren’t using hooks, then you don’t need those either. Although documentation and tests aren’t required, both are highly suggested as they can help the user better understand your plugin, and provide your user with some assurance that the plugin will work correctly.
A plugin is typically structured as follows:
Plugin Structure | Description |
---|---|
cordova-plugin-your-plugin/ | Plugin root |
package.json | npm metadata |
plugin.xml | Plugin metadata and configuration |
README.md | English documentation |
doc/locale | Documentation other than English |
tests/ | Please add tests! |
types/ | TypeScript typings |
src/platform | Platform-specific native code |
android/ | Native Android code |
YourPlugin.java | |
ios/ | Native iOS code |
CDVYourPlugin.h | |
CDVYourPlugin.m | |
www/ | JavaScript code & web assets |
yourPlugin.js | API for JavaScript consumers |
Note: the structure above is representational. For a good example, see the Device Plugin.
When providing documentation, the convention is to provide the English translation in README.md
in your plugin’s root directory. Other translations go in docs/[local]/README.md
. Be sure to provide examples, constants, errors that can be thrown, etc. so that the user has an idea how to properly utilize your plugin.
Metadata
Metadata controls a lot of aspects of your plugin, including how people find your plugin, but also how your plugin is configured, and how it affects your consumer’s app. There are two types of metadata:
-
Plugin metadata is stored in
plugin.xml
. You can think of this as an analogue to an app’sconfig.xml
. Plugin metadata controls lots of things, such as id, version, author, license, name, description, repo, issue, keywords, platform (& assets), dependencies, engines, preferences, hooks, info, and more. -
npm metadata is stored in
package.json
. This is required for publishing your plugin to npm. It is focused mostly on presentation aspects of your plugin, including things such as name, version, author, license, description, repository, issue, keywords, platforms, and dependencies.Note: The
package.json
file can be automatically generated when it comes time to publish. We’ll go over this later. Once you have one, though, you’ll end up manually modifying this file.
Descriptive metadata
Descriptive metadata includes things like the name of the plugin, the version, the repository where it is located, and so on. In plugin.xml
, an example looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android"
id="cordova-plugin-device" version="1.1.5-dev">
<name>Device</name>
<description>Cordova Device Plugin</description>
<license>Apache 2.0</license>
<keywords>cordova,device</keywords>
<repo>https://git-wip-us.apache.org/repos/asf/cordova-plugin-device.git</repo>
<issue>https://issues.apache.org/jira/browse/CB/component/12320648</issue>
Note: The complete plugin metadata used in this section is from the Device Plugin’s Metadata.
The equivalent package.json
metadata looks like this:
{
"name": "cordova-plugin-device",
"author": "Apache Software Foundation",
"license": "Apache-2.0",
"version": "1.1.5-dev",
"description": "Cordova Device Plugin",
"types": "./types/index.d.ts",
"cordova": {
"id": "cordova-plugin-device",
"platforms": ["android", "ios", "windows", "wp8", ... ] },
"repository": { "type": "git", "url": "https://..." },
"keywords": ["cordova", "device", "ecosystem:cordova", "cordova-ios", "cordova-android", ... ],
Note: The sample is from the Device Plugin’s package.json file.
Tip: You’ll want to specify what platforms are supported in your plugin using the
cordova.platforms
key — this is used by the Cordova plugin search page to indicate what platforms your plugin supports.
Asset and code metadata
With the preamble out of the way, the plugin’s metadata typically moves on to defining the JavaScript entry point, native code files, and other assets.
JavaScript modules
Typically run-time plugins will provide some sort of JavaScript API that the consumer’s app can interact with. This isn’t a hard-and-fast rule, however, since some plugins can operate independently and don’t return data to the app’s webview. (docs)
To specify a module, the following pattern is used (note the path to the source file, and a unique name for the file):
<js-module src="www/device.js" name="device">
[<children/>]
</js-module>
You can then replace [<children/>]
with any of the following, depending upon your API’s needs:
Children | Description |
---|---|
<clobbers target="device" /> |
overwrites window.device |
<merges target="device" /> |
merges with window.device |
<runs /> |
runs, but doesn’t export |
It is important to point out that by specifying one or more JavaScript modules, references will be automatically injected into your consumer’s index.html
file.
Tip: Unless necessary, target
cordova.plugins.yourPlugin
. Polyfills and implementations of standards are example exceptions.
Assets and native code
Run-time plugins will also often provide native code and other assets (such as images and such). Because these are often platform-specific and we don’t want to copy unnecessary files to each platform, <platform>
tags are used to indicate which assets go to which platforms. (docs)
Here’s an example:
<platform name="android">
<source-file src="src/android/Device.java" target-dir="src/org/apache/cordova/device" />
</platform>
<platform name="ios">
<header-file src="src/ios/CDVDevice.h" />
<source-file src="src/ios/CDVDevice.m" />
<framework src="libz.tbd" />
</platform>
Note: the above example comes from the Device Plugin plugin metadata.
There are several additional tags that you can use: <asset>
, <resource-file>
, and lib-file
. See the docs for the low-down.
Tip: You can include third-party libraries: iOS supports Cocoapods, and Android supports AARs with Gradle.
Bug: On iOS hidden (dot) files may not be copied. See CB-10135
Plugin class mapping
The plugin metadata also maps calls from your JavaScript APIs to your native code, like so:
- Android (Geolocation)
<config-file target="res/xml/config.xml" parent="/*"> <feature name="Geolocation"> <param name="android-package" value="org.apache.cordova.geolocation.Geolocation" /> </feature> </config-file>
- iOS (Geolocation)
<config-file target="config.xml" parent="/*"> <feature name="Geolocation"> <param name="ios-package" value="CDVLocation"/> </feature> </config-file>
Tip: Use
<param name="onload" value="true" />
to initialize your plugin at startup — use only if necessary
Manifest modifications
Often times you’ll need to modify the consumer app’s configuration files. Sometimes this will be the app’s config.xml
file, but other times you may need to modify a plist or AndroidManifest.xml
file.
There are two types of modifications: insertion of elements to the manifest via config-file
, or additions of attributes to existing elements via edit-config
. For example:
config-file
(docs)- From File Transfer plugin for Android:
<config-file target="AndroidManifest.xml" parent="/*"> <uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE" /> </config-file>
- From Geolocation plugin for iOS
<config-file target="*-Info.plist" parent="NSLocationWhenInUseUsageDescription"> <string>$GEOLOCATION_USAGE_DESCRIPTION</string> </config-file>
- From File Transfer plugin for Android:
edit-config
(docs)- From Transparent Status Bar plugin for Android:
<edit-config file="AndroidManifest.xml" target="/manifest/application/activity[@android:name='MainActivity']" mode="merge"> <activity android:theme="@style/AppTheme" /> </edit-config>
- From Transparent Status Bar plugin for Android:
Dependencies
Sometimes you’ll need to specify dependencies for a plugin as well. This can be done in one of two ways: using plugin.xml
or using package.json
(preferred since 6.1.0).
Using plugin.xml
:
- plugin dependencies (eg, docs)
<dependency id="cordova-plugin-file" version="^4.0.0" />
- platform & tool dependencies(eg, docs)
<engines> <engine name="cordova" version=">=3.1.0" /> </engines>
Using package.json
(docs):
"engines": {
"cordovaDependencies": {
"2.0.0": { // plugin version (applies to any ver 2+)
"cordova-plugin-console": ">1.0.0",
"cordova": ">6.0.0" // cordova-cli above version 6
}
}
}
What about the rest?
Well, sometimes it helps to actually see everything in action. So, we’re going to create an actual plugin in the next step, and you’ll be able to see how we put everything together.
Navigation: