How to create Ionic 4 wrapper for native libraries
When you have experience in native mobile apps development and start to use Hybrid technology, the first thing you look up is the usage of native libraries. When I have started to use Ionic 4, I had a problem with the usage of some native libraries in my new Ionic 4 project. Spent a lot of time to find full instruction on how can I do it but found just separate parts of wrapper creation steps and decided to create full instruction based on some articles and my experience.

The wrapper for Ionic 4 should have 3 layers:
- Native library for iOS and Android
- Cordova Custom Plugin which contains:
- Native interface (swift for iOS and java for Android) to call methods from native libraries. The native interface should extend CDVPlugin class and should have the same public methods for both platforms Android and iOS.
- JS interface to be able to call java interface methods from the Cordova-based applications.
3. Ionic 4 wrappers based on the Cordova custom plugin to be able to use the functionality of the native libraries.
Prerequisite installation
- Plugman — npm install -g plugman
- Cordova — npm install -g cordova
- Ionic — npm install -g ionic@latest
Step 1 — Create Cordova Plugin
Navigate the directory we would like the plugin created, open the terminal and run this command. This command will generate all the necessary files for our plugin but we will need to add the platforms.
plugman create --plugin_id <plugin_id> --plugin_version <plugin_version> --name <plugin_name>
Replace plugin_id, version and name with your plugin parameters.
Now when we have the main structure of the plugin we can add platform support for our library. Navigate to the newly created folder and run the following commands to add Android and iOS support
Android
plugman platform add --platform_name android
iOS
plugman platform add --platform_name ios
Adding package.json and plugin details
At this point, we have already added the platform we wish to build for, we will also need to add package.json file to the plugin directory and can do by this commend, this will prompt us to enter the details
plugman createpackagejson ./
Now we have a very basic plugin inside the plugin -> src folder, but we need to add our code into the Android/iOS plugin class, we also might need to adjust the class files respectively to individual packages/folders and class names. If encounter any error during this process, please make sure your class name and packages match the plugin package correctly or change it.
Add Android Plugin Class
package package_name_change_me;// Cordova-required packages
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;public class plugin_name_change_me extends CordovaPlugin {@Override
public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) {
// Verify that the user sent a you action
if (!action.equals(method_name_sent_from_js_change_me)) {
callbackContext.error("\"" + action
+ "\" is not a recognizedaction.");
return false;
}
// Get properties sent from JS
String msg;
try {
JSONObject options = args.getJSONObject(0);
message = options.getString("msg");
} catch (JSONException e) {
callbackContext.error("Error encountered: "
+ e.getMessage());
return false;
} //Add your functionality here
// Send a positive result to the callbackContext
callbackContext.success("Success");
return true;
}
}
Add iOS Plugin Class
@objc(plugin_name_change_me) class plugin_class_name_change_me :
CDVPlugin, CallbackListenerDelegate {
var callbackListener: CallbackListenerObjCImplementation! @objc(method_name_change_me:)
func method_name_change_me(command: CDVInvokedUrlCommand) {
// Get properties sent from JS
let msg = command.arguments[0] as? String ?? "def_value"
//Add your functionality here // Create a positive result.
pluginResult = CDVPluginResult(
status: CDVCommandStatus_OK,
messageAs: msg
)
// Send the result
self.commandDelegate!.send(pluginResult,
callbackId: command.callbackId
)
}
}
Update plugin.xml
Inside the plugin directory, we will find the plugin.xml for the plugin configuration
<?xml version='1.0' encoding='utf-8'?>
<plugin id="plugin_id_change_me" version="0.0.1"xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android">
<name>plugin_name_change_me</name>
<description>plugin_description_change_me</description>
<license>MIT</license>
<keywords>cordova,android,</keywords>
<repo>plugin_repo_change_me</repo>
<issue>issue_reporting_change_me</issue><engines>
<engine name="cordova" version=">=3.0.0" /></engines>
<js-module name=plugin_name_change_me src="www/toastyplugin.js"><clobbers target="plugin_target_change_me" />
</js-module><platform name="android">
<config-file parent="/*" target="res/xml/config.xml"><feature name="feature_chnagem_me">
<param name="android-package" value="java_class_pachage_change_me" />
</feature></config-file><framework custom="true" src="src/android/test.gradle" type="
gradleReference" /><lib-file src="src/android/replace_me.aar" /><resource-file src="src/android/assets/svm_models.zip" target="
assets/svm_models.zip" /><resource-file src="src/android/assets/tessdata.zip" target="
assets/tessdata.zip" /><source-file src="java1_file_with_path_change_me" target-dir="
target_dir_path_change_me" /><source-file src="java2_file_with_path_change_me" target-dir="
target_dir_path_change_me" /></platform><platform name="ios">
<config-file parent="/*" target="config.xml"><feature name="feature_chnagem_me">
<param name="ios-package" value="feature_change_me" /></feature>
</config-file><config-file target="*-Info.plist" parent="
NSCameraUsageDescription"><string>Used to scan QR code, MRZ and documents</string>
</config-file><source-file src="swift_file_path" /><header-file src="src/ios/lib/callbackListenerObjC.h"/><header-file src="src/ios/lib
/callbackListenerObjCImplementation.h"/>..........
<header-file src="src/ios/lib/public_types.h"/><source-file src="src/ios/lib
/callbackListenerObjCImplementation.mm"/><source-file src="src/ios/lib/libjpeg.a" framework="true"/><source-file src="src/ios/lib/replace_me.a"
framework="true" /><source-file src="src/ios/lib/libtiff.a" framework="true"/><framework src="QuartzCore.framework" />
<framework src="AVFoundation.framework" embed="false" />
<framework src="AudioToolbox.framework" embed="false" />
<framework src="CoreMedia.framework" embed="false" />
<framework src="libiconv.tbd"/>
<framework src="libc++.tbd"/><framework src="src/ios/lib/tesseract.framework" custom="true"/><framework src="src/ios/lib/leptonica/1.76.0/leptonica.
framework" embed="false" custom="true"/><framework src="src/ios/lib/opencv2.framework" embed="false"
custom="true"/> <resource-file src="src/ios/lib/svm_models.zip"/>
<resource-file src="src/ios/lib/tessdata.zip"/></platform>
</plugin>
Update the JavaScript bridge
Inside the www directory in the plugin, we will find the JavaScript bridge for the plugin and we need to change the content of this file as well to make sure that our nativeToast part of the plugin is called
var exec = require('cordova/exec');exports.<our_method_name> = function (arg0, success, error) {
exec(success, error, 'class_name_change_me',
'method_name_change_me', [arg0]);
};
Step 2 — Create Ionic 4 Wrapper
First of all, we need to clone the repository or download and install gulp CLI
git clone https://github.com/ionic-team/ionic-native
sudo npm install --global gulp-cli
npm install
Go to the ionic-native directory and run the following command to create the template file for the Ionic 4 new plugin.
gulp plugin:create -n plugin_name_change_me
The plugin will available at src -> @ionic-native -> plugins -> plugin_name_change_me
Here is the final change for our nativeToast plugin
import { Injectable } from '@angular/core';
import { Plugin, Cordova, IonicNativePlugin } from '@ionic-native/core';@Plugin({
pluginName: 'cordova_plugin_name_change_me',
plugin: 'cordova_plugin_pachage_change_me', // npm package name, example: cordova-plugin-camera
pluginRef: 'cordova_clobbers_target_change_me', // the variable reference to call the plugin, example: navigator.geolocation
repo: '', // the github repository URL for the plugin
platforms: ['Android', 'iOS'] // Array of platforms supported, example: ['Android', 'iOS']
})@Injectable()
export class native_plugin_name_change_me extends IonicNativePlugin {
@Cordova()
cordova_plugin_method_name_change_me(arg1: string,
arg2: number): Promise<any> {
return; // We add return; here to avoid any compiler errors
}
}
After all changes, we will run the following command in the root of the ionic-native directory to generate the build folder
npm run build
Step 3 — Integrate the wrapper
Install Cordova Plugin
Go to our Ionic 4 Application directory and run this command to install the plugin
cordova plugin add our_plugin_path
Install Ionic 4 Wrapper Plugin
To add the wrapper simply copy to ionic-native directory -> dist ->@ionic-native ->plugins ->plugin_name_our_project node_modules -> @ionic-native
Integration
Add the wrapper to the root module provider with the necessary imports
import { plugin_name_change_me } from '@ionic-native/plugin_name_change_me/ngx';@NgModule({
imports: [... ],
providers:[plugin_name_change_me]
})
In our component, we will call the plugin via the defined method
import { plugin_name_change_me } from '@ionic-native
/plugin_name_change_me/ngx';....
constructor(private plugin_obj:plugin_name_change_me){}public pluginMethodCall(){
this.plugin_obj.cordova_plugin_method_name_change_me("")
.then(r=>{
console.log('success');
}).catch((e)=>{
console.error(e);
})
}
Links
Ionic 4: https://ionicframework.com/docs
Cordova Plugin Development: https://cordova.apache.org/docs/en/10.x/guide/hybrid/plugins/