Creating a custom cordova plugin for the ionic2 project

Many of us would have gone through similar problems, but even after going through the following most relevant links link link1 and link link2 , I can’t solve it.

Question:

Create your own plugin (Cordova) to use it in the ionic2 project.

Waiting . This plugin will be able to interact with native iOS and Android features. To be precise, I am trying to access the functions of the native SDK (Aruba internal placement SDK) using the cord in the Ionic project.

Step 1 Originally created plugin according to link link 1

Step 2 Ionic 2 project created (created with these are the main steps)

Step 3 JavaScript file in the plugin is not able to find and access the Ionic2.

After searching on Google, I found this discussion where he is invited to create an interface in the plugin itself due to the following reason.

import {myPluginName} from '../../../plugins/xxx/*. js'

It will not work because the plugin is not part of the native ion package.

If you have a custom plugin, you can do several things.

1) Make a PR to add it to the ion-native itself

2) Use the source plugin API. You can use the original plugins API without being part of Ionic Native. The plugin is on the window object, so you should target your api usually

window.plugin.myPlugin.myMethod ()

GITHUB Example ,

interface CordovaPlugins {
  ZPLPrinter: ZPLPrinter;
}

interface ZPLPrinter {

  print(
    ipaddress: string,
    bclabels: any,
    printSuccess: (ip: string, labels: string[]) => void,
    printError: (message: string) => void): void;

}

, www..

interface CordovaPlugins {
  Communicator: Communicator;
}

interface Communicator {

  getInfo(successCallback: any, errorCallback: any);

}

JS

Device.prototype.getInfo = function(successCallback, errorCallback) {
    console.log("device.js: getInfo function called");
    argscheck.checkArgs('fF', 'Device.getInfo', arguments);
    exec(successCallback, errorCallback, "Device", "getDeviceInfo", []);
};

, Ionic typings.

Github Project cordova . TypeScript Cordova, index. t.js

, ,

declare var cordova: Cordova;

:

  • Cordova
  • typings Ionic2

1:

, Ionic, Android-. .

-

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ionicframework.cutepuppypics234138/com.ionicframework.cutepuppypics234138.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void org.apache.cordova.CordovaPlugin.privateInitialize(java.lang.String, org.apache.cordova.CordovaInterface, org.apache.cordova.CordovaWebView, org.apache.cordova.CordovaPreferences)' on a null object reference

?

12-08 16:10:49.079 20555-20555/? E/ApkAssets: Error while loading asset assets/natives_blob_64.bin: java.io.FileNotFoundException: assets/natives_blob_64.bin
12-08 16:10:49.079 20555-20555/? E/ApkAssets: Error while loading asset assets/snapshot_blob_64.bin: java.io.FileNotFoundException: assets/snapshot_blob_64.bin
12-08 16:10:49.682 20555-20555/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ionicframework.cutepuppypics234138, PID: 20555
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ionicframework.cutepuppypics234138/com.ionicframework.cutepuppypics234138.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void org.apache.cordova.CordovaPlugin.privateInitialize(java.lang.String, org.apache.cordova.CordovaInterface, org.apache.cordova.CordovaWebView, org.apache.cordova.CordovaPreferences)' on a null object reference
   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2339)
   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2413)
   at android.app.ActivityThread.access$800(ActivityThread.java:155)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1317)
   at android.os.Handler.dispatchMessage(Handler.java:102)
   at android.os.Looper.loop(Looper.java:135)
   at android.app.ActivityThread.main(ActivityThread.java:5343)
   at java.lang.reflect.Method.invoke(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void org.apache.cordova.CordovaPlugin.privateInitialize(java.lang.String, org.apache.cordova.CordovaInterface, org.apache.cordova.CordovaWebView, org.apache.cordova.CordovaPreferences)' on a null object reference
   at org.apache.cordova.PluginManager.getPlugin(PluginManager.java:171)
   at org.apache.cordova.PluginManager.startupPlugins(PluginManager.java:97)
   at org.apache.cordova.PluginManager.init(PluginManager.java:86)
   at org.apache.cordova.CordovaWebViewImpl.init(CordovaWebViewImpl.java:115)
   at org.apache.cordova.CordovaActivity.init(CordovaActivity.java:149)
   at org.apache.cordova.CordovaActivity.loadUrl(CordovaActivity.java:224)
   at com.ionicframework.cutepuppypics234138.MainActivity.onCreate(MainActivity.java:39)
   at android.app.Activity.performCreate(Activity.java:6010)
   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1129)
   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2292)
   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2413at android.app.ActivityThread.access$800(ActivityThread.java:155at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1317at android.os.Handler.dispatchMessage(Handler.java:102at android.os.Looper.loop(Looper.java:135at android.app.ActivityThread.main(ActivityThread.java:5343at java.lang.reflect.Method.invoke(Native Method) 
   at java.lang.reflect.Method.invoke(Method.java:372at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:70012-08 16:10:49.879 20656-20656/? E/SubDex: SubDex Config : .dex 2
12-08 16:10:50.285 20656-20656/? E/project: extsdcard==/storage/emulated/0/Android/data/com.cleanmaster.mguard/files
12-08 16:10:50.303 20656-20656/? E/project: extsdcard==/storage/emulated/0/Android/data/com.cleanmaster.mguard/files
+4
3

.

, !

( Inject)

  • Inject\www\Inject.js
  • , Inject.js, Inject\src\Inject.java, execute

:

  • , cordova-plugin-am-i-late, cordova.plugin.Inject. / , -
  • plugman platform add --platform_name android
  • plugin.xml,
  • plugin.xml
  • Inject.js . .

var exec = require('cordova/exec');
exports.coolMethod = function(arg0, success, error) {
exec(success, error, "Inject", "coolMethod", [arg0]);
};
  1. ,
function Inject(){
}
Inject.install = function () {
  if (!window.plugins) {
    window.plugins = {};
  }

  window.plugins.Inject = new Inject();
  return window.plugins.Inject;
};

cordova.addConstructor(Inject.install);
  1. , Toast, Inject.js
function Inject(){
}

Inject.prototype.coolMethod = function (options, successCallback, errorCallback) {
  cordova.exec(successCallback, errorCallback, "Inject", "coolMethod", []);
};

Inject.install = function () {
  if (!window.plugins) {
    window.plugins = {};
  }

  window.plugins.Inject = new Inject();
  return window.plugins.Inject;
};

cordova.addConstructor(Inject.install);
  1. Inject.java
public class Inject extends CordovaPlugin {

private static final int GRAVITY_CENTER = Gravity.CENTER_VERTICAL|Gravity.CENTER_HORIZONTAL;
private static final String TAG = "InjectCordovaPlugin";
String messageReceived;

    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        Log.v(TAG, "execute , action =" + action);
        if (action.equals("coolMethod")) {
            String message = args.getString(0);
            Log.v(TAG, "coolMethod called with message =" + message);
            this.coolMethod(message, callbackContext);
            return true;
        }

        return false;
    }
    private void coolMethod(String message, CallbackContext callbackContext) {
    Log.v(TAG, "Inject coolMethod called ,message="+message);
    messageReceived = message;
        if (message != null && message.length() > 0) {
            cordova.getActivity().runOnUiThread(new Runnable() {
            public void run() {

            final android.widget.Toast toast = android.widget.Toast.makeText(
              cordova.getActivity().getWindow().getContext(),
              messageReceived,
              android.widget.Toast.LENGTH_LONG 
                );
                toast.setGravity(GRAVITY_CENTER, 0, 0);
                toast.show();
            }
            });
            callbackContext.success(message);
        } else {
            callbackContext.error("Expected one non-empty string argument.");
        }
    }
}
  1. , plugin.xml
<?xml version='1.0' encoding='utf-8'?>
<plugin id="cordova.plugin.Inject" 
    version="1" 
    xmlns="http://apache.org/cordova/ns/plugins/1.0" 
    xmlns:android="http://schemas.android.com/apk/res/android">
<name>Inject</name>
<js-module name="Inject" src="www/Inject.js">
    <clobbers target="window.plugins.Inject"/>
</js-module>
<platform name="android">
<config-file parent="/*" target="res/xml/config.xml">
<feature name="Inject">
<param name="android-package" 
        value="cordova.plugin.Inject.Inject" />
        </feature>
</config-file>
<config-file parent="/*" target="AndroidManifest.xml">
</config-file>
<source-file src="src/android/Inject.java" 
target-dir="src/cordova.plugin.Inject/Inject" />
</platform>
</plugin>
  1. Ionic2 Android/IOS.
  2. cordova plugin add
  3. Nodejs (. add) cordova plugin add D:\PluginTrial\Inject
  4. Ionic2Project\plugins
  5. window. home.ts
import { Component } from '@angular/core';

import { NavController, Platform } from 'ionic-angular';

declare var window: any;
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  constructor(public navCtrl: NavController, private platform: Platform) {

  }
    showToast(message, position) {
        this.platform.ready().then(() => {
            window.plugins.Inject.coolMethod(message, "short", position);
        });
    }
}
  1. showToast home.html
<button ion-button (click)="showToast('Yo Man! Its working ', 'center')">Default</button>
  1. . !

: Reference One, 2, 3

+9

:

:/[ ]/js/custom_plugin.js

var CustomPlugin = function(){};

CustomPlugin.someFunction = function(){
    console.log("someFunction starts");

    return new Promise(function(resolve,reject){
    cordova.exec(
        resolve,
        reject,
        [PLUGIN_NAME],
        [ACTION_ON_NATIVE_SIDE],
        []
    );

    });
    console.log("someFunction stops");
}

.... more functions

module.exports = CustomPlugin;

:/[ ]/src/[android] || [ios], .

:/[ ]/plugin.xml( , ):

<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
    id="[CustomPlugin]"
    version="1.0.0">
    <name>CustomPlugin</name>
    <description>...</description>
    <license>...</license>
    <author>...</author>

    <engines>
        <engine name="cordova" version=">=6.0.0" />
    </engines>



    <js-module src="www/js/custom_plugin.js" name="CustomPlugin">
        <clobbers target="CustomPlugin" />
    </js-module>


    <platform name="ios">
        <config-file target="config.xml" parent="/*">
            <preference name="orientation" value="portrait"/>
            <feature name="CustomPlugin">
                <param name="ios-package" value="CustomPlugin" />
                <param name="onload" value="true"/>
            </feature>
        </config-file>

        <header-file src="src/ios/CustomPlugin.h" />
        <source-file src="src/ios/CustomPlugin.m" />
        <!--framework src="QuartzCore.framework" /> 
        <framework src="AssetsLibrary.framework" />
        <framework src="CoreGraphics.framework" />
        <framework src="MobileCoreServices.framework" /-->
    </platform>

    <platform name="android">
        <config-file target="res/xml/config.xml" parent="widget">
            <preference name="orientation" value="portrait"/>
            <feature name="CustomPlugin" >
                <param name="android-package" value="[package name].CustomPlugin"/>
                <param name="onload" value="true"/>
            </feature>
        </config-file>

        <config-file target="AndroidManifest.xml" parent="/*">
            <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
            <uses-permission android:name="..." />
            <uses-feature android:name="..." />
        </config-file>

        <source-file src="src/android/CustomPlugin.java" target-dir="[package folder directory organization like: com.android.something]" />
        <source-file ... />
        <source-file src="src/android/custom_plugin.xml" target-dir="res/layout" />

    </platform>

</plugin>

CLI: ionic plugin add [folder of your plugin]

Ionic ( angular2), , @Component: declare var CustomPlugin: any;. , CustomPlugin, module.exports = CustomPlugin;   : /[custom plugin name]/js/custom_plugin.js.

1 , : android plugin ( , android ​​ , CLI), android studio (2.2.2), "[ ]\platform\android":

MainActivity : "android\java\com\ionicframework. [ + ]\MainActivity":

  package com.ionicframework.[my project name + a large number];

import android.os.Bundle;
import org.apache.cordova.*;

public class MainActivity extends CordovaActivity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // enable Cordova apps to be started in the background
        Bundle extras = getIntent().getExtras();
        if (extras != null && extras.getBoolean("cdvStartInBackground", false)) {
            moveTaskToBack(true);
        }

        // Set by <content src="index.html" /> in config.xml
        loadUrl(launchUrl);
    }
}

( ) "android\java [ ]:

package [package of the custom plugin];

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;

// + other imports needed

public class CustomPlugin extends CordovaPlugin  {

    private static CallbackContext customDeferredCallback;

    public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException {
//all the thing corresponding to your case need to end if with either:
//   if OK: callbackContext.success(); return true;  ;
//   if not OK: callbackContext.error(error.getMessage()); return false;
//   if JAVA returns a result to JS do: actionBindListener(callbackContext);



}

    private boolean actionBindListener(final CallbackContext callbackContext){
    cordova.getThreadPool().execute(new Runnable() {
            public void run(){
                try{
                    customDeferredCallback= callbackContext;
                }catch(Exception e){e.printStackTrace();}
            }
        });
        return true;
    }


    //in your program when you get the result you want to send back to javascript call this function
    public static void sendResultToJS(res){
        JSONObject eventData = new JSONObject();
        try {
            eventData.put("CUSTOM_KEY", res);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, eventData);
        pluginResult.setKeepCallback(true);
        try{
                customDeferredCallback.sendPluginResult(pluginResult);
        } catch(NullPointerException e){
            e.printStackTrace();
        }
    }
}

, , android\manifestests\manifestests.xml :

<?xml version='1.0' encoding='utf-8'?>
<manifest android:hardwareAccelerated="true" android:versionCode="1" android:versionName="0.0.1" package="com.ionicframework.[project name + large number]" xmlns:android="http://schemas.android.com/apk/res/android">
    <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
    <uses-permission android:name="android.permission.INTERNET" />
    <application android:hardwareAccelerated="true" android:icon="@mipmap/icon" android:label="@string/app_name" android:supportsRtl="true">
        <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/activity_name" android:launchMode="singleTop" android:name="MainActivity" android:theme="@android:style/Theme.DeviceDefault.NoActionBar" android:windowSoftInputMode="adjustResize">
            <intent-filter android:label="@string/launcher_name">
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:exported="true" android:name="com.adobe.phonegap.push.PushHandlerActivity" />
        <receiver android:name="com.adobe.phonegap.push.BackgroundActionButtonHandler" />
        <receiver android:exported="true" android:name="com.google.android.gms.gcm.GcmReceiver" android:permission="com.google.android.c2dm.permission.SEND">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <category android:name="${applicationId}" />
            </intent-filter>
        </receiver>
        <service android:exported="false" android:name="com.adobe.phonegap.push.GCMIntentService">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </service>
        <service android:exported="false" android:name="com.adobe.phonegap.push.PushInstanceIDListenerService">
            <intent-filter>
                <action android:name="com.google.android.gms.iid.InstanceID" />
            </intent-filter>
        </service>
        <service android:exported="false" android:name="com.adobe.phonegap.push.RegistrationIntentService" />
    </application>
    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="24" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
    <permission android:name="${applicationId}.permission.C2D_MESSAGE" android:protectionLevel="signature" />
</manifest>
+3

, . typescript npm, npm install @types/package_name. https://www.npmjs.com/~types https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/README.md ,

npm install typings

// <reference path="" />

typescript

+1

Source: https://habr.com/ru/post/1662840/


All Articles