现在写插件我觉得使用 plugman 更加方便,请移步:http://blog.csdn.net/b2259909/article/details/52471178
一、 前言
cordova是什么? 和 phonegap 差不多的东东,用到了自然回去查,你就懂了。
cordova 官方已经有很多现成的插件,但有时你需要的插件没有,你只能自己实现了。 但是cordova 官方的文档说明看着挺累,照着例子做,好多概念不理清的话,总是会让你感觉,这次成功是偶然的。
二、 准备工作
1. 先下载cordova最新版本
2. 使用cordova的命令创建工程,添加 android 和 iOS 平台
三、 开始制作插件
目录结构:
说明: 插件开发是从 js 层 往本地底层走,本地底层先执行一句打印就好。方便验证是否跑到本地底层的代码了
1. 先制作 plugin.xml 这里面的内容很重要,需要非常小心。本地代码放置在 src 下,js文件放在www下
先看例子:后面再理理概念的东西。
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
id="com.cordova.plugins.barcodescanner"
version="3.1.0">
<name>BarcodeScanner</name>
<description>You can use the BarcodeScanner plugin to scan different types of barcodes (using the device's camera)within your application.</description>
<license>MIT</license>
<engines>
<engine name="cordova" version=">=3.5.0" />
</engines>
<js-module src="www/barcodescanner.js" name="BarcodeScanner">
<clobbers target="cordova.plugins.barcodeScanner" />
</js-module>
<!-- ios -->
<platform name="ios">
<!-- Cordova >= 2.8 -->
<config-file target="config.xml" parent="/*">
<feature name="BarcodeScanner">
<param name="ios-package" value="HXBarcodeScanner" />
</feature>
</config-file>
<resource-file src="src/ios/HXBarcodeScannerViewController.xib" />
<header-file src="src/ios/HXBarcodeScannerViewController.h" />
<source-file src="src/ios/HXBarcodeScannerViewController.m"/>
<source-file src="src/ios/HXBarcodeScanner.m"/>
<framework src="AVFoundation.framework" />
</platform>
<!-- android -->
<platform name="android">
<span style="white-space:pre"> </span><!-- -->
<span style="white-space:pre"> </span><source-file src="src/android/HXBarcodeScanner.java" target-dir="src/com/hxsmart/XZbar" />
<source-file src="src/android/armeabi/libiconv.so" target-dir="libs/armeabi" />
<source-file src="src/android/armeabi/libZBarDecoder.so" target-dir="libs/armeabi" />
<source-file src="src/android/armeabi-v7a/libiconv.so" target-dir="libs/armeabi-v7a" />
<source-file src="src/android/armeabi-v7a/libZBarDecoder.so" target-dir="libs/armeabi-v7a" />
<source-file src="src/android/XZbar.jar" target-dir="libs" />
<source-file src="src/android/beep.ogg" target-dir="res/raw" />
<span style="white-space:pre"> </span><source-file src="src/android/qr_code_bg.9.png" target-dir="res/drawable" />
<span style="white-space:pre"> </span><source-file src="src/android/scan_line.png" target-dir="res/drawable" />
<span style="white-space:pre"> </span><source-file src="src/android/shadow.png" target-dir="res/drawable" />
<config-file target="res/xml/config.xml"parent="/*">
<feature name="BarcodeScanner">
<param name="android-package" value="com.hxsmart.XZbar.HXBarcodeScanner" />
</feature>
</config-file>
<!-- -->
<config-file target="AndroidManifest.xml" parent="/manifest">
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:xlargeScreens="true" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
</config-file>
<!-- activity -->
<config-file target="AndroidManifest.xml" parent="/manifest/application">
<activity android:name="com.ZbarZxing.XZbar.ZbarActivity" >
<intent-filter>
<span style="white-space:pre"> </span><action android:name="com.hxsmart.XZbar.SCAN" />
<span style="white-space:pre"> </span><category android:name="android.intent.category.DEFAULT" />
<span style="white-space:pre"> </span></intent-filter>
<span style="white-space:pre"> </span></activity>
<span style="white-space:pre"> </span></config-file>
</platform>
</plugin>
解释一下 :
1. 前面几个字段比较普通,除了插件都有一个唯一id,其他你爱咋写咋写。
2. 下面这句
<js-module src="www/barcodescanner.js" name="BarcodeScanner">
<clobbers target="cordova.plugins.barcodeScanner" />
</js-module>
这里很重要, 它指明了 插件的原始 js 文件放在哪里,clobbers target有用。等会用到,这会我们把它叫做 clobbers
3. 添加平台代码:
1.) ios的先讲,以下的
feature name="BarcodeScanner" 表示服务名为BarcodeScanner 。 记住这个服务名,有用
value="HXBarcodeScanner" 对应的.m文件中插件的类名
<config-file target="config.xml" parent="/*">
<feature name="BarcodeScanner">
<param name="ios-package" value="HXBarcodeScanner" />
</feature>
</config-file>
后面就是一些原始文件,标记在哪里获取,以便cordova放到工程。
注意:
<framework src="AVFoundation.framework" /> 可以在后面添加 custom=“true”来加载第三方的framework。</span></span>
2)android 的,和iOS大同小异,主要是 添加文件需要指明文件放置的目的地target-dir 而且不区分文件类型。
<config-file target="res/xml/config.xml"parent="/*">
<span style="white-space:pre"> </span><feature name="BarcodeScanner">
<span style="white-space:pre"> </span><param name="android-package" value="com.hxsmart.XZbar.HXBarcodeScanner" />
<span style="white-space:pre"> </span></feature>
</config-file>
服务名一般和 ios 保持一致。
value 值 为 你写的类在包中的位置,也就是 包名.类名
其他的字段一看就知道了,无非就是你写android底层需要在
AndroidManifest.xml 中添加的字段。 依照规则写就好了。
3) 写 barcodescanner.js 文件。注意红色部分
var exec = require("cordova/exec");
/**
* Constructor.
*
* @returns {BarcodeScanner}
*/
function BarcodeScanner() {};
/**
* Read code from scanner.
*
* @param {Function} successCallback
* @param {Function} errorCallback
*/
BarcodeScanner.prototype.scan = function (successCallback, errorCallback) {
if (errorCallback == null) {
errorCallback = function () {
};
}
if (typeof errorCallback != "function") {
console.log("BarcodeScanner.scan failure: failure parameter not a function");
return;
}
if (typeof successCallback != "function") {
console.log("BarcodeScanner.scan failure: success callback parameter must be a function");
return;
}
exec(successCallback, errorCallback, 'BarcodeScanner', 'scan', ["AVMetadataObjectTypeQRCode,AVMetadataObjectTypeUPCECode,AVMetadataObjectTypeAztecCode,AVMetadataObjectTypeCode128Code,AVMetadataObjectTypeCode39Code,AVMetadataObjectTypeCode39Mod43Code,AVMetadataObjectTypeCode93Code,AVMetadataObjectTypeEAN13Code,AVMetadataObjectTypeEAN8Code,AVMetadataObjectTypePDF417Code"]);
};
var barcodeScanner = new BarcodeScanner();
module.exports = barcodeScanner;
按照模板写,第一句红色的必须有,绿色部分的函数名字,你自己起,最后面两句也是必须的,名字也是你自己起,new 的那个对象是你前面绿色部分写的。
注意后面 红色部分,分别表示 服务名 ,动作名
服务名: 按照 plugin.xml 写的,应该写为 BarcodeScanner
动作名: 在android中,由 intent.getAction 得到这个动作名,你依据这个执行不同的底层代码
在iOS中,是指类中,实现了 CDplugin 接口的方法。
这样js 文件写好后,别人怎么调用?
还记得那个 clobbers 吗? 我不懂里面具体什么规则,反正你要调的话是类似这样:
(clobbers-target). scan 这个scan 是 上面js文件中写的 BarcodeScanner的其中一个方法
这样可以这样写:
function test18() {
cordova.plugins.barcodeScanner.scan(onSuccess, onFailure);
}
function onSuccess(result) {
alert("Result:"+ result);
}
function onFailure(err) {
alert("Failure:"+ err);
}
4)本地代码怎么写?
1. android
写一个类继承 CordovaPlugin , 类名要与 plugin.xml 的一致
public class HXBarcodeScanner extends CordovaPlugin
{
public CallbackContext callbackContext;
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
this.callbackContext = callbackContext;
if (action.equals("scan")) {
//do something
}
return true;
}
return false;
}
}
2. iOS
写一个类继承 CDVPlugin,动作方法要带有 CDVInvokedUrlCommand的参数即可
//------------------------------------------------------------------------------
// plugin class
//------------------------------------------------------------------------------
@interface HXBarcodeScanner : CDVPlugin
@property (nonatomic, retain) NSString* callback;
- (void)scan:(CDVInvokedUrlCommand*)command;
@end
@implementation HXBarcodeScanner
//--------------------------------------------------------------------------
- (void)scan:(CDVInvokedUrlCommand*)command
{
_callback = [[NSString alloc] initWithString:command.callbackId];
NSString *scannerCodeTypesString = nil;
if ( [command.arguments count] >= 1 )
{
scannerCodeTypesString = [command.arguments objectAtIndex:0];
}
NSLog(@"scannerCodeTypesString = %@", scannerCodeTypesString);
}
command.argumentsobjectAtIndex:0
可以得到一个 dict 然后就是用key 去取值了。android的则是用JSONObject json = new JSONObject(args.getString(0)); args 是 exec 中的 CordovaArgs参数
至于是什么 key,自己在js层定义并用json格式传进来就行,本文不涉及。
cordova.plugins.barcodeScanner<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">.scan(onSuccess, onFailure,param);后面增加一个param参数</span>
传给它 {"key":"value","key1":"value1"} 在里面传给 exec(successCallback, errorCallback, '
BarcodeScanner', '
scan', [params]);
3. 返回结果:
最好也是返回一个 json数据,这些函数都是异步的
比如
android :
callbackContext.error("{\"ErrorMsg\": \"设备未连接,请检查蓝牙是否打开并且与设备配对成功\"}");
iOS:
CDVPluginResult* pluginResult = [CDVPluginResultresultWithStatus:CDVCommandStatus_ERRORmessageAsString:[NSStringstringWithFormat:@"{\"ErrorMsg\":\"参数错误\"}"]];
[self.commandDelegate sendPluginResult:pluginResultcallbackId:_callbackId];
最后,直接使用 cordova plugin add 你的插件所在路径