zoukankan      html  css  js  c++  java
  • ionic3自定义android原生插件

    一.创建一个android项目,编写插件功能,并测试ok,这里以一个简单的调用原生Toast.makeText为例。

    1.新建android项目

    2.编写插件类

    package com.plugin.testPlugin;
    
    import org.apache.cordova.CallbackContext;
    import org.apache.cordova.CordovaInterface;
    import org.apache.cordova.CordovaPlugin;
    import org.apache.cordova.CordovaWebView;
    import org.json.JSONArray;
    import org.json.JSONException;
    
    import android.R.string;
    import android.app.Activity;
    import android.util.Log;
    import android.widget.Toast;
    
    /**
     * 插件类必须继承CordovaPlugin,(如果导入CordovaPlugin一系列包,见下面)
     * @author lzy
     *
     */
    public class TestPlugin extends CordovaPlugin {
        
        public Activity activity;/**
         * 该方法会在调用execute()方法之前调用,此时用来获取activity和webView等
         */
        @Override
        public void initialize(CordovaInterface cordova,CordovaWebView webView){
            super.initialize(cordova, webView);
            Log.i("initialize","============================");
            this.activity = cordova.getActivity();
        }
        
        /**
         * js方法接口,
         * js中通过调用该方法来执行原生的方法
         * @param action 方法名
         * @param args 参数(数组类型)
         * @param callbackContext 回掉
         *           原生方法执行完后,会执行js中传过来的回掉方法
         */
        @Override
        public boolean execute(String action,JSONArray args,CallbackContext callbackContext) throws JSONException{
            this.callbackContext = callbackContext;
            if(action=="hello"){
                String orderInfo = args.getString(0);
                hello(orderInfo,callbackContext);
                return true;
            }
            return false;
        }
        
        public void hello(String hello, CallbackContext callbackContext){

             //执行js中传过来的回调
             if(hello!=null && hello.length()>0){
               callbackContext.success(hello);
             }else{
               callbackContext.error("参数不能为空");
             }

           //原生代码,放在js回调后面,否则js回调不执行

        Toast.makeText(this.activity, hello, Toast.LENGTH_SHORT).show();
        }
    
    }

    3.因为编写插件需要继承CordovaPlugin,所以需要依赖cordova一系列包,编写时才不会出错,怎么做?

    3.1新建一个ionic3的项目ionic-plugin-hello(如何新建,查看这篇

    3.2 执行下命令 ionic cordova run android (安装到手机 ,确保数据线已连接到电脑)

    3.3执行成功后,查看该项目下文件夹E:myObjectmy etObjectionic-plugin-helloplatformsandroidCordovaLib

    3.4在eclipse(android studio也行)中导入该文件夹,成为一个项目

    File->import->

    3.5 在插件项目中,添加对CordovaLib项目的依赖

    到此就可以尽情的编写你的原生插件代码了。

    二.创建ionic3自定义插件项目

    (直接查看转载https://www.cnblogs.com/smartsensor/p/7904254.html)

    4.1新建一个ionic3的插件项目,

    (注意此时有点绕,刚才我们在eclipse中编写插件代码,是为了借助eclipse的开发环境,便于编写代码,这还不能算一个真正的ionic3插件)

      pluman的安装(有了pluman才能创建插件项目)
     npm install -g plugman

      创建插件项目

    plugman create --name TestPlugin --plugin_id com.plugin.testPlugin --plugin_version 1.0.0


    说明:

    --name TestPlugin //自定义插件名称
    --plugin_id com.plugin.testPlugin //自定义插件的包名
    --plugin_version 1.0.0 //自定义插件版本

    执行上述命令后会在Plugins文件夹下生成一个TestPlugin文件夹,并且TestPlugin文件夹内包含如下内容:

    —TestPlugin
    |——src
    |——www
    |——plugin.xml

    3 生成平台(android/ios)插件代码

    进入插件的根目录,然后执行创建android或者ios的平台支持命令

    cd TestPlugin
    plugman platform add --platform_name android

    命令执行后在TestPlugin/src目录下出现了android目录,把刚才编写好的,android项目中的TestPlugin.java文件直接拷贝过来

    拷贝到 TestPluginsrcandroidTestPlugin.java

    并且在www文件夹下也新生成TestPlugin.js,TestPlugin.js的作用是通过js暴露插件的功能给ionic

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

    说明:

    TestPlugin //插件名称
    coolMethod //方法名称

    4 介绍plugin.xml

    复制代码
    <?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="com.plugin.testPlugin" version="1.0.0">
      <name>TestPlugin</name>
      <js-module name="TestPlugin" src="www/TestPlugin.js">
        <clobbers target="cordova.plugins.TestPlugin"/>
      </js-module>
      <platform name="android">
        <config-file parent="/*" target="res/xml/config.xml">
          <feature name="TestPlugin">
            <param name="android-package" value="com.plugin.testPlugin.TestPlugin"/>
          </feature>
        </config-file>
        <config-file parent="/*" target="AndroidManifest.xml"/>
        <source-file src="src/android/TestPlugin.java" target-dir="src/com/plugin/testPlugin/TestPlugin"/>
      </platform>
    </plugin>
    复制代码

    说明:

    id: 插件的标识,即发布安装到plugin 的 ID
    name:插件的名称
    js-module:对应我们的 javascript 文件,src 属性指向 www/TestPlugin.js
    platform:支持的平台,这里仅仅用到了 android

    5 初始化package.json

    在ionic3项目中添加插件,所添加的插件必须包含package.json文件,网上一些生成的方式尝试失败,最后发现执行下面命令可行。

    npm init

    例如下面执行过程

    复制代码
    C:workionicpluginsTestPlugin>npm init
    This utility will walk you through creating a package.json file.
    It only covers the most common items, and tries to guess sensible defaults.
    
    See `npm help json` for definitive documentation on these fields
    and exactly what they do.
    
    Use `npm install <pkg>` afterwards to install a package and
    save it as a dependency in the package.json file.
    
    Press ^C at any time to quit.
    package name: (testplugin)
    version: (1.0.0)
    description:
    entry point: (index.js)
    test command:
    git repository:
    keywords:
    author:
    license: (ISC)
    About to write to C:workionicpluginsTestPluginpackage.json:
    
    {
      "name": "testplugin",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo "Error: no test specified" && exit 1"
      },
      "author": "",
      "license": "ISC"
    }
    
    
    Is this ok? (yes) yes
    
    C:workionicpluginsTestPlugin>
    复制代码

    标识红色的地方,可以自定义,也可以直接回车选择默认值。

    然后会在插件根目录下看到新建的package.json文件

    三.创建ionic3项目,并引用自定义插件

    1.创建ionic3项目

    ionic start ionic-plugin-hello tabs

    2.引用刚才自定义的插件

    ionic cordova plugin add E:myObjectmy etObjectTestPlugin

    3 使用自定义插件

    3.1 在home.html 上添加下面代码

    <p>
        <button ion-button color="primary" (click)="callMyPlugin()">call my plugin</button>
    </p>

    3.2 修改home.ts代码

    复制代码
    import { Component } from '@angular/core';
    import { NavController } from 'ionic-angular';
    declare let cordova: any;
    @Component({
      selector: 'page-home',
      templateUrl: 'home.html'
    })
    export class HomePage {
    
      constructor(public navCtrl: NavController) {
    
      }
      callTestPlugin(){
        cordova.plugins.TestPlugin.coolMethod("今天好运气,一老狼请吃鸡呀!",result=>alert(result),error=>alert(error));
      }
    }
    复制代码

    标识红色的部分是定义cordova对象,和引用自定义插件方法

    注意,这个变量的定义,是个全局的引用,表示所有的插件对象都加载进来

    declare let cordova: any;

    具体插件类的调用需要看被调用插件的配置文件plugin.xml中的节点

     <clobbers target="cordova.plugins.TestPlugin"/>

    如果这个节点被定义为

     <clobbers target="BaiduTTS"/>

    那么在调用时直接这样写

    BaiduTTS.XXX(xxxxx);//xxxx代表方法名或者参数

    4.安装到手机查看效果

    ionic cordova run android

    5.修改插件,多增加一个方法

    自定义插件修改后必须先删除插件,然后再安装插件才可生效。

    1)ionic cordova plugin list 列出所有已安装的插件
    2)ionic cordova  plugin remove com.plugin.testPlugin 从ionic3项目中删除插件
    3)ionic cordova plugin add 自定义插件路径 安装插件到ionic3项目

    执行顺序为1->2->修改代码->3

    例如在插件中增加一个方法,首先修改TestPlugin/Android/TestPlugin.java

    复制代码
    package com.plugin.testPlugin;
    
    import org.apache.cordova.CordovaPlugin;
    import org.apache.cordova.CallbackContext;
    
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    
    /**
     * This class echoes a string called from JavaScript.
     */
    public class TestPlugin extends CordovaPlugin {
    
        @Override
        public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
            if (action.equals("coolMethod")) {
                String message = args.getString(0);
                this.coolMethod(message, callbackContext);
                return true;
            }else if (action.equals("plus")) {//主方法中增加一段方法名称判断和调用的代码
                int x = args.getInt(0);
                int y = args.getInt(1);
                this.plus(x, y, callbackContext);
                return true;
            }
            return false;
        }
    
        private void coolMethod(String message, CallbackContext callbackContext) {
            if (message != null && message.length() > 0) {
                callbackContext.success(message);
            } else {
                callbackContext.error("Expected one non-empty string argument.");
            }
        }
    
        //新增一个传入两个参数求和的方法
        private void plus(int x, int y, CallbackContext callbackContext) {
            callbackContext.success(x + y);
        }
    }
    复制代码

     修改TestPlugin/www/TestPlugin.js代码

    复制代码
    var exec = require('cordova/exec');
    
    var testAPI = {}
    
    testAPI.coolMethod = function(arg0, success, error) {
        exec(success, error, "TestPlugin", "coolMethod", [arg0]);
    };
    //求和方法
    testAPI.plus = function(arg0,arg1, success, error) {
        exec(success, error, "TestPlugin", "plus", [arg0,arg1]);
    };
    
    module.exports = testAPI;
    复制代码

    修改自定义插件package.json和plugin.xml文件的版本号

    修改ionic项目home.html代码,增加一个button

     <p>
        <button ion-button color="primary" (click)="callTestPluginNew()">new plus function</button>
      </p>

    修改home.ts代码,增加一个调用方法

      callTestPluginNew(){
        cordova.plugins.TestPlugin.plus(3,7,result=>alert(result),error=>alert(error));
      }

    重新添加自定义插件后,再次重新生成apk,查看效果

    ionic cordova build android

    四.创建自定义插件时用到第三包

    详细参考https://www.jianshu.com/p/050ed1bd4973

    比如在上述插件中增加一个调用支付宝接口的方法,需要引入支付宝接口包

    此时目录结构是这样的:
    
    TestPlugin------
                    |------src
                    |         |-----android
                    |                      |------libs    (我们导入了一个jar嘛)
                    |                      |          |--------alipaySdk-20161009.jar
                    |                      | 
                    |                      |------AliPay.java
                    |                      |------AuthResult.java
                    |                      |------PayResult.java
                    |------www
                    |          |------TestPlugin.js
                    |-------plugin.xml
    anrdoid文件夹是我们自己创建的,里面的libs和java文件是我们之前项目中拷贝过来的
    
    

    Alipay.java实现代码:

    package com.plugin.testPlugin;
    
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.os.Handler;
    import android.os.Message;
    import android.text.TextUtils;
    import android.util.Log;
    import android.widget.Toast;
    
    import com.alipay.sdk.app.AuthTask;
    import com.alipay.sdk.app.PayTask;
    
    import org.apache.cordova.CallbackContext;
    import org.apache.cordova.CordovaInterface;
    import org.apache.cordova.CordovaPlugin;
    import org.apache.cordova.CordovaWebView;
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    
    import java.util.Map;
    
    
    /**
     * Created by Administrator on 2016/12/13.
     * 支付宝支付接口
     */
    
    public class AliPay extends CordovaPlugin {
      private Activity activity;
      private static final int SDK_PAY_FLAG = 1;
      private static final int SDK_AUTH_FLAG = 2;
    
      private CallbackContext callbackContext;
    
    
      @SuppressLint("HandlerLeak")
      private Handler mHandler = new Handler() {
        @SuppressWarnings("unused")
        public void handleMessage(Message msg) {
          switch (msg.what) {
            case SDK_PAY_FLAG: {
              @SuppressWarnings("unchecked")
              PayResult payResult = new PayResult((Map<String, String>) msg.obj);
              /**
               * 对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
               */
              String resultInfo = payResult.getResult();// 同步返回需要验证的信息
              String resultStatus = payResult.getResultStatus();
              // 判断resultStatus 为9000则代表支付成功
              if (TextUtils.equals(resultStatus, "9000")) {
                // 该笔订单是否真实支付成功,需要依赖服务端的异步通知。
                callbackContext.success(resultInfo);
              } else {
                // 该笔订单真实的支付结果,需要依赖服务端的异步通知。
                callbackContext.success(resultInfo);
              }
              break;
            }
            default:
              break;
          }
        }
      };
      @Override
      public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        super.initialize(cordova, webView);
         Log.e("initialize","============================");
        activity = cordova.getActivity();
      }
    
      @Override
      public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        this.callbackContext = callbackContext;
        switch (action) {
          case "payV2":
            String orderInfo = args.getString(0);
            payV2(orderInfo);
            break;
          default:
            return false;
        }
        return false;
      }
    
      /**
       * 支付宝支付业务
       * 返回ali20247 错误的原因是没有签约APP支付功能
       */
      public void payV2(final String orderInfo) {
    
        /**
         * 这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;
         * 真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;
         * 防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险;
         *
         * orderInfo的获取必须来自服务端;
         */
    
        Runnable payRunnable = new Runnable() {
    
          @Override
          public void run() {
            Log.e("run","run");
            PayTask alipay = new PayTask(activity);
            Log.e("orderInfo",orderInfo);
            Map<String, String> result = alipay.payV2(orderInfo, true);
            Log.e("msp", result.toString());
    
            Message msg = new Message();
            msg.what = SDK_PAY_FLAG;
            msg.obj = result;
            mHandler.sendMessage(msg);
          }
        };
    
        Thread payThread = new Thread(payRunnable);
        payThread.start();
      }
    }

    这个类必须继承CordovaPlugin(重要),必须重写execute方法(重要),选择使用initialize方法。

    根据支付宝官方要求在plugin.xml的<config-file target="AndroidManifest.xml" parent="/*">节点中配置权限

    • 文件拷贝:
        <source-file src="src/android/AliPay.java" target-dir="src/com/plugin/testPlugin/TestPlugin"/>
        <source-file src="src/android/AuthResult.java" target-dir="src/com/plugin/testPlugin/TestPlugin"/>
        <source-file src="src/android/PayResult.java" target-dir="src/com/plugin/testPlugin/TestPlugin"/>
    
        <source-file src="src/android/libs/alipaySdk-20161009.jar" target-dir="libs"/>

    说明:
    src:文件源,就是这个文件现在在哪。
    target-dir:目标路径,就是将这个文件拷到哪里去。
    这个配置就是,将:

    AliPay-----------
                    |------src
                    |         |-----android
    

    下的文件拷贝到Android项目的对应位置中去(注意包名)。
    无论是java文件还是jar文件甚至是xml文件,只要是Android项目中需要的文件,都按这种方式拷贝到相应的目录下面去。



  • 相关阅读:
    va_start和va_end使用详解
    Visual Assist X设置
    google 快捷键
    /bin/sh^M: bad interpreter: No such file or directory 异常
    动态链接库的学习(一)
    sprintf函数的用法详解
    错误:在 C99 模式之外使用‘for’循环初始化声明
    VC6.0在win7下显示行号的插件
    错误: 程序中有游离的‘\302’ ‘\240’等
    Linux Shell编程笔记一:相关命令
  • 原文地址:https://www.cnblogs.com/lvshoutao/p/8927128.html
Copyright © 2011-2022 走看看