Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

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

$
0
0

插件的意义

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包,包内容如下图
打开index.d.ts,可以看到声明了很多方法,以post方法为例。在ts中调用的this.http.post方法就是在这个文件定义的。

然后打开index.js,给HTTP添加了一个方法,入参和声明的方法一样,使用了es6的prototype语法。

而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”文件夹,如下图

先看配置文件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 中可以用到。

最后看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选项修改路径,也可以在生成之后再拖走。

初始情况下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来安装咱自定义的插件了。

作者:gaoqinghuadage 发表于2017/6/23 15:18:10 原文链接
阅读:638 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>