plugin example create javascript android cordova plugins ionic2

javascript - example - ionic create cordova plugin



Creación de plugins de cordova personalizada para el proyecto ionic2 (3)

Muchos de nosotros habríamos tenido problemas similares, pero incluso después de seguir los enlaces más relevantes, enlace de referencia1 y enlace de referencia2 , no puedo resolverlo.

Problema:

Cree un complemento personalizado (Cordova) para usar esto en el proyecto ionic2.

Expectativa : este complemento podrá interactuar con las funciones nativas de iOS y Android. Para ser precisos, intento acceder a las características de un SDK nativo (SDK de posicionamiento interno de Aruba) usando cordova en el proyecto Ionic.

Paso 1 Plugin creado inicialmente según el enlace de referencia 1

Paso 2: creó el proyecto Ionic 2 (creado con estos pasos básicos)

Paso 3 El archivo JavaScript en el complemento no fue capaz de referirse y acceder en Ionic2.

Después de buscar en Google, encontré esta discusión , donde se dice que cree una interfaz en el plugin por el siguiente motivo.

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

No funcionará porque el complemento no es parte del paquete nativo iónico.

Si tiene un complemento personalizado, puede hacer algunas cosas.

1) Haga un PR para agregarlo a iónico nativo

2) Use la API de complemento sin formato. Puede usar la API del complemento sin procesar sin que forme parte de Ionic Native. El complemento está en el objeto ventana, por lo que apuntarías a la API normalmente

window.plugin.myPlugin.myMethod ()

De acuerdo con el proyecto de ejemplo GITHUB de esta manera, la interfaz debería implementarse

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

Ahora creé una interfaz similar en mi complemento que es la siguiente en la carpeta www de los complementos

interface CordovaPlugins { Communicator: Communicator; } interface Communicator { getInfo(successCallback: any, errorCallback: any); }

Esta interfaz idealmente se dirigiría a este método en el archivo 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", []); };

Ahora estoy atascado, ya que mi proyecto Ionic no está teniendo la carpeta de los típings .

En la muestra Github Project , los paquetes cordova se envían utilizando la carpeta typings . El archivo TypeScript en el proyecto se refiere a Cordova utilizando index.t.js

La importación utilizada para referirse debería funcionar como

declare var cordova: Cordova;

Dudas:

  1. ¿Estoy en la dirección correcta del proceso?
  2. ¿Es esta la manera de crear el complemento de Cordova y usar en iónica
  3. Por qué no puedo obtener la carpeta de typings en Ionic2

EDIT 1:

Después de simplemente agregar el complemento sin siquiera referirme al proyecto Ionic, traté de ejecutarlo en un dispositivo Android. Pero me dio el siguiente error.

Error principal es esto

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

¿Por qué este error estaría causando? Registros detallados han dado a continuación

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: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)  12-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



Su complemento debe verse así:

En: / [nombre del complemento personalizado] /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;

En: / [nombre del complemento personalizado] / src / [android] || [ios], las clases con código nativo.

Y en: / [nombre del complemento personalizado] /plugin.xml (este es un ejemplo, la configuración debe ajustarse a su caso):

<?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>

luego agregas tu complemento con la CLI: ionic plugin add [folder of your plugin]

En su proyecto Ionic, en las clases (directivas angulares2) en las que desea usar su complemento, escriba antes de la sección @Component: declare var CustomPlugin: any; . Luego, en esa clase, puede usar su complemento al CustomPlugin a CustomPlugin que se exporta con module.exports = CustomPlugin; del archivo: /[custom plugin name]/js/custom_plugin.js .

PARA RESPONDER A LA EDICIÓN 1 DE LA PREGUNTA, AQUÍ ALGUNOS DETALLES DE LA PARTE ANDROID : En el proyecto de complemento de Android (una vez que Android se ha agregado y construido al menos una vez, con CLI iónico), en Android Studio (2.2.2), cuando mira en el proyecto de construcción en "[mi proyecto] / plataformas / android":

En la jerarquía, el archivo MainActivity se autogenera en: "android / java / com / ionicframework. [Mi nombre de proyecto + un gran número] / 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); } }

Para mi complemento personalizado (sin entrar en detalles aquí) en "android / java [paquete del complemento personalizado]:

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(); } } }

Y finalmente android / manifiestats / manifiestats.xml se ve así:

<?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>


Después de muchas pruebas y errores, encontré la solución.

Estoy anotando a continuación los detalles para futuras referencias a cualquiera que esté intentando cosas similares.

Los problemas con el código eran los siguientes (el nombre de mi complemento es Inject )

  • Inject/www/Inject.js no tenía una función esencial para instalar el complemento
  • Cualquier nombre de método mencionado en Inject.js debe ser el mismo hasta Inject/src/Inject.java ya que hay opciones en el método de execute para referir el nombre del método diferente en función de las etiquetas recibidas

Pasos:

  1. Use plugman para crear el esqueleto del plugin Reference Link
  2. En lugar de usar nombres como cordova-plugin-am-i-late , use cordova.plugin.Inject . Me enfrenté a problemas de compilación / tiempo de ejecución usando - símbolo
  3. Agregar la plataforma de plugman platform add --platform_name android
  4. Verifique plugin.xml comparando la misma referencia
  5. Incluye permisos en plugin.xml si es necesario
  6. Ahora verifica Inject.js sus llamadas a métodos esenciales que faltan. Actualmente solo tiene el siguiente código.

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

  1. Pero tenemos que incluir a continuación también para que se instale y funcione

function Inject(){ } Inject.install = function () { if (!window.plugins) { window.plugins = {}; } window.plugins.Inject = new Inject(); return window.plugins.Inject; }; cordova.addConstructor(Inject.install);

  1. Por ejemplo, me estoy orientando para mostrar un mensaje de Toast para el cual a continuación está mi archivo completo 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. Ahora Inject.java implementar nuestro 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''s 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. Para dejar esto en claro, estoy publicando mi último 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. Ahora crea un proyecto Ionic2 de muestra y agrega la plataforma Android / IOS
  2. Agregue el complemento creado usando el cordova plugin add command
  3. Navegue al proyecto iónico en el símbolo del sistema de Nodejs y proporcione este comando (consulte Plugin folder base after add ) cordova plugin add D:/PluginTrial/Inject
  4. El complemento agregado debe estar poblado en la carpeta Ionic2Project/plugins
  5. Llame a esta función usando el objeto window . A continuación está mi 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. Ahora refiera este método home.html en el archivo home.html

<button ion-button (click)="showToast(''Yo Man! Its working '', ''center'')">Default</button>

  1. Eso es. ¡Deberías poder probar el plugin exitosamente! Happy Coding

Referencia: referencia uno , referencia dos , referencia tres