Writing an Ionic Native Wrapper
Ionic Native makes it very convenient to use Cordova plugins from Ionic applications. Although Ionic Native provides an impressive collection of wrappers for many Cordova plugins, there are still Cordova plugins out there without a corresponding plugin. In such cases you will need to either use them directly without a wrapper or write your own wrapper. The latter option is much simpler than you might think.
Using the Plugin Directly
WifiWizard is a Cordova plugin that's not yet supported by Ionic Native. It can be used to get the SSID of the Wi-Fi network that your Android or iOS device is currently connected to, and provides many other functions for Wi-Fi management on Android devices.
Actually, it's not all that difficult to invoke the plugin function from an Ionic application even without a wrapper:
WifiWizard.getCurrentSSID(
ssid => this.ssid = ssid,
error => console.log(error)
);
Since there are no TypeScript type definitions available for the plugin, you also need to add the following declaration at the top of each source file, where you're using it, or the code won't compile:
declare var WifiWizard;
That's already enough to make it work, but this approach has several disadvantages:
- Without type declarations, the code editor can't auto-complete the code for you. You'll need to look up the available functions in plugin documentation.
- There's no type safety at compile time. If the function signature is incorrect, the code will only fail at runtime.
- Callbacks as function parameters are not idiomatic for Ionic code. Promises or Observables, which could be used instead, would make the code easier to read.
- Direct plugin calls make testing difficult as they cannot be easily replaced with mocks.
Creating a Wrapper for the Plugin
The alternative is to write your own Ionic Native plugin. To make their lives easier, the authors of Ionic Native have written a lot of plumbing code. It might not be documented all that well, but it is distributed with the @ionic-native/core package and available for everyone to use.
This is a partial wrapper for the WifiWizard
plugin, exposing only the getCurrentSSID
function:
import { Injectable } from '@angular/core';
import { Plugin, IonicNativePlugin, Cordova } from '@ionic-native/core';
@Plugin({
pluginName: 'WifiWizard', // should match the name of the wrapper class
plugin: 'wifiwizard', // NPM package name
pluginRef: 'WifiWizard', // name of the object exposed by the plugin
repo: 'https://github.com/hoerresb/WifiWizard', // plugin repository URL
platforms: ['Android', 'iOS'] // supported platforms
})
@Injectable()
export class WifiWizard extends IonicNativePlugin {
@Cordova()
getCurrentSSID(): Promise<string> { return; }
}
Ionic Native wrappers are implemented as Ionic providers that extend the IonicNativePlugin
base class and require the Injectable
decorator because of dependency injection. Additionally, the wrapped Cordova plugin must be described with the Plugin
decorator. I explained the most important properties in the above code snippet. You can find a short description for other supported properties in source code comments.
Each exposed plugin function must be decorated with the Cordova
decorator. For standard asynchronous functions, which have the success and error callbacks as the last two arguments, no additional properties are required in the decorator. The wrapper function should skip these two arguments and return a Promise instead, which will automatically map to the callback functions. The promise type should match the argument type of the success callback. The function body should consist of a simple return
statement only.
If the callback arguments are at different positions, this can be specified with the successIndex
and errorIndex
properties of the Cordova
decorator. For synchronous functions sync
property must be set to true
. All the available options are again only documented in the decorator source code. A very useful resource is also the source code for all existing Ionic Native wrappers.
Once you add the wrapper to the AppModule
's providers
collection, you're ready to rewrite your code that's calling the plugin:
this.wifiWizard.getCurrentSSID()
.then(ssid => this.ssid = ssid)
.catch(error => console.log(error));
Instead of adding the declare
statement, you need to inject the provider in your class constructor:
constructor(wifiWizard: WifiWizard) { }
If you add JSDoc comments to the wrapper class, a good code editor will display them for you as well, so that you'll be much less likely to need the plugin documentation once your wrapper is ready.