欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Ionic跨平台项目(九) 自定义cordova plugin(iOS)

程序员文章站 2022-06-15 20:31:35
...

插件的意义

plugin(全文都叫插件)是一个注入代码的包,它允许app呈现的Cordova
webview与其运行的native平台进行通信。插件可以访问基于Web的app通常不可用的设备和平台功能。所有主要的Cordova
API功能都可以实现为插件,还有许多其他功能可用于实现诸如条码扫描器,NFC通信或定制日历界面等功能。您可以在Cordova插件搜索页面上搜索可用的插件。
插件包含一个单一的JavaScript界面​​,以及每个受支持平台的相应native代码库。本质上,这隐藏了一个常见的JavaScript界面​​背后的各种native代码实现。

介绍一个插件

以cordova-plugin-http为例,简单介绍它是如何实现js(ts)与native代码(oc、swift)进行交互的。
进入ionic官网/http插件,看介绍安装。也可以直接执行命令:

 npm install --save @ionic-native/http
 ionic cordova plugin add cordova-plugin-http

执行完这两句后,插件就可以正常使用了,js就可以调用原生的方法了,具体做了什么?

npm部分

首先看第一句命令,主要是在项目目录里的node_modules/@ionic-native下载了一个名叫http的npm包,包内容如下图Ionic跨平台项目(九) 自定义cordova plugin(iOS)
打开index.d.ts,可以看到声明了很多方法,以post方法为例。在ts中调用的this.http.post方法就是在这个文件定义的。
Ionic跨平台项目(九) 自定义cordova plugin(iOS)
然后打开index.js,给HTTP添加了一个方法,入参和声明的方法一样,使用了es6的prototype语法。
Ionic跨平台项目(九) 自定义cordova plugin(iOS)
而index.js中的这段代码,则指示了如何寻找对应的插件:

HTTP = __decorate([
    Plugin({
        pluginName: 'HTTP',
        plugin: 'cordova-plugin-http',
        pluginRef: 'cordovaHTTP',
        repo: 'https://github.com/wymsee/cordova-HTTP',
        platforms: ['Android', 'iOS']
    })
], HTTP);

其中的“pluginName”写npm包中使用的类名,“plugin”写插件的名称,每个插件都有个固定的名称,“pluginRef”写插件目录中www里的js文件的名称(下文讲到),“repo”写如果找不到去哪个git地址找,“platforms”写适用的平台。

plugin部分

然后我们看一下第二句命令,主要是在项目项目目录里的plugins中添加了“cordova-plugin-http”文件夹,如下图
Ionic跨平台项目(九) 自定义cordova plugin(iOS)
先看配置文件plugin.xml

id="cordova-plugin-http"
version="1.2.0">
    <name>SSL Pinning</name>
    <description>
        Cordova / Phonegap plugin for communicating with HTTP servers using SSL pinning
    </description>
    <dependency id="cordova-plugin-file" version=">=2.0.0" />
    <js-module src="www/cordovaHTTP.js" name="CordovaHttpPlugin">
        <clobbers target="CordovaHttpPlugin" />
    </js-module>
    <platform name="ios">
        <config-file target="config.xml" parent="/*">
            <feature name="CordovaHttpPlugin">
                <param name="ios-package" value="CordovaHttpPlugin"/>
            </feature>
        </config-file>

        <header-file src="src/ios/CordovaHttpPlugin.h" />
        <source-file src="src/ios/CordovaHttpPlugin.m" />

        <header-file src="src/ios/TextResponseSerializer.h" />
        <source-file src="src/ios/TextResponseSerializer.m" />
  • id: 插件的标识,即发布到 plugins.cordova.io 的 ID
  • name:插件的名称
  • description:描述信息
  • js-module:对应我们的 javascript 文件,src 属性指向 www/cordovaHTTP.js
  • platform:支持的平台,这里仅仅截取了iOS

接下来,cordovaHTTP.js的内容是

var exec = require('cordova/exec');
var http = {
    headers: {},
    post: function(url, params, headers, success, failure) {
        headers = mergeHeaders(this.headers, headers);
        return exec(success, failure, "CordovaHttpPlugin", "post", [url, params, headers]);
    },
};
module.exports = http;

仅截取了post方法。当ts部分调用插件的post方法时,实际上调用了cordova中的exec方法,将成功回调、错误回调、插件中的类名、插件中的方法名、ts传过来的参数的数组作为参数。用过 Nodejs 或者了解过 AMD、CMD 的话,一定会觉得很熟悉。简单的说,require 用于引入我们的类,exports 用于导出我们的方法。这里对外公开了 post 方法,以便我们在 app 中可以用到。
Ionic跨平台项目(九) 自定义cordova plugin(iOS)
最后看CordovaHttpPlugin.m的内容

@interface CordovaHttpPlugin : CDVPlugin
@implementation CordovaHttpPlugin {
- (void)post:(CDVInvokedUrlCommand*)command {
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.securityPolicy = securityPolicy;
    NSString *url = [command.arguments objectAtIndex:0];
    NSDictionary *parameters = [command.arguments objectAtIndex:1];
    NSDictionary *headers = [command.arguments objectAtIndex:2];
    [self setRequestHeaders: headers forManager: manager];

    CordovaHttpPlugin* __weak weakSelf = self;
    manager.responseSerializer = [TextResponseSerializer serializer];
    [manager POST:url parameters:parameters progress:nil success:^(NSURLSessionTask *task, id responseObject) {
        NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
        [self setResults: dictionary withTask: task];
        [dictionary setObject:responseObject forKey:@"data"];
        CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
        [weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
    } failure:^(NSURLSessionTask *task, NSError *error) {
    }
}

继承了CDVPlugin类,使用command.arguments拿到从ts传过来的参数,然后通过导入的AFN库,使用AFHTTPSessionManager发送post请求,接下来就和iOS原生一样了;拿到响应以后,使用CDVPluginResult将responseObject包装起来,然后用commandDelegate的sendPluginResult方法将原生拿到的字典传回给ts。

开始制作一个插件

安装plugman

sudo npm install -g plugman

生成插件

  • 进入ionic项目
cd project
  • 创建插件
plugman create --name <pluginname> --plugin_id <pluginid> --plugin_version 0.0.1

例如:

plugman create --name XXXXX --plugin_id cordova-plugin-xxxxx --plugin_version 0.0.1

此时生成的插件放在项目根目录,可以通过在上面的命令中添加path选项修改路径,也可以在生成之后再拖走。

Ionic跨平台项目(九) 自定义cordova plugin(iOS)

初始情况下src是空的,根据自己的需求,将插件需要的原生代码拷进来。

  • 添加平台
cd XXXXX
plugman platform add --platform_name ios
  • 使用git
    在代码托管网站(建议github)创建仓库,将XXXXX目录放入仓库。最好在目录中添加一个readme文件,帮助其他人使用你的插件。如果不会可以看github的步骤。再不会的话看我其他的博客哦,有仔细讲git。
git commit -m -a "创建项目xxxxx"
git push 
  • 添加npm配置文件
    想要发表,能让别人用,就得配置package.json
sudo plugman createpackagejson .

然后终端会提供提问式的交互,按顺序进行即可,或者一直按回车也行,反正生成出来也可以修改;package.json生成以后,打开做修改:
name值最好改成cordova-plugin-xxxxx这种形式,比较好看,跟cordova官网的一样,如果没有生成”repository”属性,要添加下列代码:

"repository": {
    "type": "git",
    "url": "git+https://github.com/xxx/cordova-vxxxxx.git"
  },

其他属性如果有需要,可以参照别人写的plugin的package文件修改。

  • 登录npm并发表
npm adduser

然后也是提问式交互,按顺序进行后,会自动登录,如果已经注册过账号
登录npm:

npm login

检查是否登录成功:

npm who am i

发表:

sudo npm publish .

这个时候可能出现no_perms Private mode enable, only admin can publish this module,八成是因为使用了淘宝镜像,设置会原来的就可以
npm config set registry http://registry.npmjs.org

成功发表后,你就可以通过

ionic cordova plugin add cordova-plugin-xxxxx --save

来安装你自己写的插件了。当然这个插件还不能投入使用,还要继续做ts的部分

生成npm包

此处是借用了@ionic-native的代码来生成我们需要的插件的代码,属于借鸡生蛋,这个方法应该不是最好的,但是我目前没有找到更好的方法。
详见Ionic Native插件开发指南

  • 克隆ionic-native仓库
git clone https://github.com/ionic-team/ionic-native.git
cd ionic-native
  • 使用gulp创建一个插件封装器
sudo npm install gulp@latest -g
gulp plugin:create -n PluginName

然后就会在src/@ionic-native/plugins里的对应的插件里,生成一个index.ts文件,文件的核心代码如下:

import { Injectable } from '@angular/core';
import { Plugin, Cordova,  IonicNativePlugin } from '@ionic-native/core';
@Plugin({
  pluginName: 'XXXXX',
  plugin: 'cordova-plugin-xxxxx', // npm package name, example: cordova-plugin-camera
  pluginRef: 'XXXXX', // the variable reference to call the plugin, example: navigator.geolocation
  repo: '', // the github repository URL for the plugin
  platforms: ['iOS'] // Array of platforms supported, example: ['Android', 'iOS']
})
export class XXXXX extends IonicNativePlugin {
  doSomething(): Promise<any> {
    return; 
  }
}

上述这些代码看起来比较面熟,基本都在第二部分介绍http插件见过,我简单介绍一下这个文件做了什么。

首先,我们要创建一个代表我们的插件的类,在这种情况下是XXXXX。

export class XXXXX extends IonicNativePlugin {
}

接下来,我们需要指定一些关于这个插件的信息。Ionic Native是用TypeScript编写的,它使用了一个名为decorators的功能。长话短说,装饰器允许我们使用声明性语法修改或添加信息到类和属性。
例如,@Plugin装饰器将关于插件的信息添加到我们的XXXXX类中:

plugin: 'cordova-plugin-xxxxx'
pluginRef: 'XXXXX'

这里plugin是npm上的插件包的名称,在调用时使用ionic cordova plugin add
pluginRef指的window是底层的Cordova插件通常暴露在哪里。例如,在使用http插件时,通常你会调用cordovaHTTP.js,而我们的插件的plugin里的js名字叫XXXXX,所以pluginRef在这种情况下写XXXXX。

  • 生成插件所需的包
npm run build

运行后会创建一个dist目录,该dist目录将包含一个子目录,@ionic-native其中包含所有包。这个时候把创建好的这个包拷贝到Ionic app的node_modules里就可以用了,但是这是不够的,最好能够发表到npm上。

  • 发表到npm
    和发表plugin基本一样的步骤,好在package.json已经创建好了,直接弄一下git,配一下package.json就可以了,确定无误以后发表:
npm publish .

制作完成

这样插件就制作完成了,然后可以做的就是在包中添加或者用ts调用的方法,而在plugin部分添加调用原生时所需的iOS或者android的代码,甚至可以添加framework,只要在plugin.xml中添加配置就好。可以创建一个demo专门用来开发这个插件。正常地使用git做代码管理,使用npm进行发布就可以了。自己和队友以及陌生的人也都可以通过npm install xxxxx和ionic cordova plugin add cordova-plugin-xxxxx来安装咱自定义的插件了。

参考文章:ionic2中利用自定义cordova插件实现ts和原生传值

相关标签: Ionic plugin