WindVane容器提供的JSAPI,如果不能满足您的业务需求,您可以通过自定义JSAPI,实现特定的功能特性。本文介绍在Android/iOS平台自定义JSAPI的详细操作。
Android端
本文以如何扩展一个Toast为例进行说明。
首先加入您的原生插件实现。
public class CustomToastPlugin extends WVApiPlugin { @Override protected boolean execute(Stringaction, String params, WVCallBackContext wvCallBackContext) { JSONObject jsonObject = null; try { jsonObject = new JSONObject(params); String content =jsonObject.optString("content"); if("long".equals(action)) { Toast.makeText(mContext,content, Toast.LENGTH_LONG).show(); } else if("short".equals(action)) { Toast.makeText(mContext,content, Toast.LENGTH_SHORT).show(); } } catch (JSONException e) { e.printStackTrace(); } return true; } }调用插件管理器注册该插件。
EmasHybridApi.registerPlugin("Toast", CustomToastPlugin.class);
这样就成功注册了一个叫做Toast的插件,它含有两个函数short和long两个JSAPI,需要前端传递叫做content的参数,即Toast需要显示的内容。
iOS端
注册JSAPI。容器提供了两种注册方案:动态注册和静态注册。
动态注册:无需主动注册给WindVane容器,使用简单方便。但是要求类名与JSAPI调用时的ClassName相同。
静态注册:需要调用WindVane容器的注册方法,使用操作复杂。不要求特定的类名,会更加灵活。
总之,只要JSAPI调用的ClassName并没有被占用,那么建议使用动态注册的方式。
iOS动态注册JSAPI。
WindVane容器提供了新版本的用法,在
WVBridgeCallbackContext中统一提供了JSAPI需要的所有功能。假设需要实现JSAPI:
WVPay.pay,那么JSAPI的ClassName是WVPay,HandlerName是pay。创建一个WVPay类(动态注册要求与JSBridge调用时的ClassName相同),需要确保不会有同名类。
令WVPay类继承自
WVDynamicHandler(引入头文件<WindVaneCore/WindVaneCore.h>)。实现pay方法,要求方法的签名必须为
+ (void)pay:(NSDictionary *)params withWVBridgeContext:(id<WVBridgeCallbackContext>)context,其中:方法可以是静态方法,也可以是动态方法。实例方法会直接调用,实例方法会先创建一个实例,然后在实例上调用。
方法名与JSAPI调用的HandlerName相同,这里为pay。
第一个参数为
NSDictionary *,是JS传入的参数对象。第二个参数为
id<WVBridgeCallbackContext>,是JSBridge的调用上下文。
在方法中实现JSAPI的逻辑,使用
[context callbackSuccess:RESULT]/[context callbackFailure:RET withResult:RESULT]来输出执行成功/失败的结果返回给JSAPI调用方。请保证任何情况下都会调用、且只会调用一次[context callbackXXX]系列方法。说明JSAPI总是在主线程调用,如果有耗时操作,请务必自行切换线程。
您提供的服务可能带有多个阶段输出性,请使用
[context dispatchEvent:eventName withParam:param]将结果通过事件的方式输出给JSBridge调用方。当你的JSAPI逻辑执行完毕,可以主动调用
[context releaseHandler:self]方法来主动释放内存,否则就只能等到页面销毁的时候才会释放。注意在dealloc中调用是没有意义的,因为此时对象已经被释放了。
@interface WVPay : WVDynamicHandler @end @implementation WVPay + (void)pay:(NSDictionary *)params withWVBridgeContext:(id<WVBridgeCallbackContext>)context { NSString * merchant = [params wvStringValue:@"merchant"]; if ([NSString wvIsBlank:merchant]) { [context callbackFailure:WMBridgeStatusParamError withResult:@{@"message": @"Empty merchant"}]; } else { //后续操作 [context callbackSuccess:nil]; } }@objc(WVPay) class WVPay: WVDynamicHandler { @objc static func pay(_ params: [String: Any], withWVBridgeContext context: WVBridgeCallbackContext) { if let merchant = params["merchant"] as? String, merchant.count > 0{ //后续操作 context.callbackSuccess(nil) }else { context.callbackFailure(WMBridgeStatus.paramError, withResult: ["message":"Empty merchant"]) } } }动态注册的JSAPI,要求类名不能重复。若希望扩展现有ClassName,可以使用JSAPI别名。
iOS静态注册。
WindVane容器允许注册到全局,可以在任意 WebView 中调用。
#import <WindmillBridge/WMBridgeProtocol.h> WMBridgeHandler handler = ^(NSDictionary * params, id<WMBridgeCallbackContext> context) { [context callbackSuccess:nil]; }; WMBridgeRegisterHandler(@"WVPay.pay", handler);let handler: WMBridgeHandler = { (params:Dictionary?, context: WMBridgeCallbackContext) in context.callbackSuccess(nil) } WMBridgeRegisterHandler("WVPay.pay", handler)
前端
前端需集成windvane.js,在Android或iOS中添加相应接口后,则可以在前端业务代码里直接调用自定义JSAPI,示例代码如下。
window.WindVane.call(
'WVPay',
'pay',
{merchant: ''},
function(e) {
alert('success:' + JSON.stringify(e));
}, function(e) {
alert('failure:' + JSON.stringify(e));
});