博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HBuilder 第三方插件开发
阅读量:5747 次
发布时间:2019-06-18

本文共 6118 字,大约阅读时间需要 20 分钟。

本人最近开发了 HBulider 集成极光推送(JPush)的插件,鉴于 HBuilder 官网上缺少 iOS 的示例 ,而且官网也只给出了 JavaScript 调用 native 代码的接口,对于 native 调用 JavaScript 并且向 JavaScript 发送 event 事件的方法却在 native层 进行了封装。笔者在踩过了一些小坑之后,终于成功的开发了插件,并且 实现了 JavaScript 和 native 的双向沟通 。特此跟大家分享一下在 HBuilder 插件开发过程中的经验和关键代码。

JPush 实例展示


首先附上完整 demo 并为大家展示一下:

实例及功能展示

以上即为根据本文内容开发出的实例

如您需使用极光推送产品请至此

新插件配置


配置 manifest.json

首先用源码的方式打开工程 /Pandora/ 目录下的 manifest.json ,在 "permissions" 中添加新的插件名称:

"permissions": {    "Push":{        "description": "极光推送插件"    }},复制代码
配置 feature.plist

在 Xcode 中打开 /PandoraApi.bundle/ 目录下的 feature.plist ,为插件添加新的 item:

feature.plist

其中需要注意的是:

  • 最顶部的 key 值 Push ,必须跟 manifest.json 中配置的插件名一致
  • class 的值需要跟 native 代码中的类名一致,此处为 JPushPlugin
  • 因为本插件拓展自 HBuilder 已经封装好的 PGPush ,故 baseclass 为父类

通过以上配置,就可以在 JavaScript 中通过 Push --> JPushPlugin 的对应关系,调用 native 代码了。

JavaScript 调用本地代码的实现


这部分在 中已经给出了较详细的说明,这里就不再赘述,附上关键代码:

document.addEventListener("plusready", function() {    var _BARCODE = 'Push';    // 插件名称    var B = window.plus.bridge;    var JPushPlugin = {        callNative : function(fname, args, successCallback) {            var callbackId = this.getCallbackId(successCallback, this.errorCallback);            if (args != null) {                args.unshift(callbackId);            } else {                var args = [callbackId];            }            return B.exec(_BARCODE, fname, args);        },        getCallbackId : function(successCallback) {            var success = typeof successCallback !== 'function' ? null : function(args)             {                successCallback(args);            };            callbackId = B.callbackId(success, this.errorCallback);            return callbackId;        },        errorCallback : function(errorMsg) {            console.log("Javascript callback error: " + errorMsg);        },        jsHello : function(args){            this.callNative("nativeHello", args, null);        },    window.plus.Push = JPushPlugin;}, true);复制代码

其中 callNative 为封装好用于调用 native 代码的方法,参数如下:

  • fname:要调用的 native 的方法名
  • args:传给 native 的参数,必须是数组
  • successCallback:成功回调,null 为没有

以上代码最后面的 "jsHello" 方法,即为封装好的 js 方法,在工程的其他文件里通过

window.plus.Push.jsHello(args);复制代码

的方式即可调用本地的 "nativeHello" 方法。

Objective-C 调用 js 的实现


与 Phonegap 的差异

在 HBuilder 官方文档中并没有提及 OC 调用 js 的方法,从 OC 中的类名(PGPlugin 等)可以看出,其应该是对 Phonegap 的封装,但是却并没有提供 Phonegap 中直接调用 js 的接口,例如:

NSString *evalString = [NSString stringWithFormat:@"jsFunction(%@)",args];[self.commandDelegate evalJs:evalString];复制代码

也无法向 js 发送 event ,例如:

NSString *evalString = [NSString stringWithFormat:@"cordova.fireDocumentEvent('event_name',%@)",args];[self.commandDelegate evalJs:evalString];复制代码

其中 self 为继承自 CDVPlugin 的插件类实例。

经过笔者的查找,发现在 HBuilder 提供的 PDRCoreAppFrame(:PDRNView :UIView) 类中,有如下方法可以调用 js 代码:

/** @brief 在当前页面同步执行Javascript @param js javasrcipt 脚本 @return NSString* 执行结果 */- (NSString*)stringByEvaluatingJavaScriptFromString:(NSString*)js;复制代码

获取 PDRCoreAppFrame 对象

其中 PDRCoreAppFrame 为控制 webView 的实例,数量可能为多个,且在视图层级中的位置不确定,故需要通过遍历 app 中所有 view ,来找出 PDRCoreAppFrame ,以下是通过 递归 找出所有 PDRCoreAppFrame 的方法:

-(NSMutableArray*)searchViews:(NSArray*)views{    NSMutableArray *frames = [NSMutableArray array];    for (UIView *temp in views) {        if ([temp isMemberOfClass:[PDRCoreAppFrame class]]) {            [frames addObject:temp];        }        if ([temp subviews]) {            NSMutableArray *tempArray = [self searchViews:[temp subviews]];            for (UIView *tempView in tempArray) {                if ([tempView isMemberOfClass:[PDRCoreAppFrame class]]) {                    [frames addObject:tempView];                }            }        }    }    return frames;}复制代码

其中:

  • 参数 views 为同一层级中的 views
  • 返回值 frames 为从该层级中找到的 PDRCoreAppFrame

调用 js

这样我们就可以用上述方法获取到所有的 PDRCoreAppFrame 进而调用 js 代码了:

-(void)evaluatingJavaScriptFromString:(NSString*)string{    UIWindow *window = [[UIApplication sharedApplication] keyWindow];    NSArray *views = [[[window rootViewController] view] subviews];    //调用上述方法    NSArray *frames = [self searchViews:views];    for (PDRCoreAppFrame *appFrame in frames) {        dispatch_async(dispatch_get_main_queue(), ^{            [appFrame stringByEvaluatingJavaScriptFromString:string];        });    }}复制代码

调用示例:

NSString *evalString = @"alert("make a js call");";[self evaluatingJavaScriptFromString:evalString];复制代码

但是并不建议用这种方式,因为该方法会强制向每个 webView 的页面都发送一条执行语句,有时会出现并不希望的结果。因此,建议使用下面发送 event 的方式,并在 js 中接收后进行处理。

向 js 发送 event

笔者对上述方法再次进行了封装:

-(void)fireEvent:(NSString*)event args:(id)args{    NSString *evalString = nil;    NSError  *error      = nil;    NSString *argsString = nil;    if (args) {        if ([args isKindOfClass:[NSString class]]) {            argsString = args;        }else{            NSData   *jsonData   = [NSJSONSerialization dataWithJSONObject:args options:0 error:&error];            argsString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];            if (error) {                NSLog(@"%@",error);            }        }        evalString = [NSString stringWithFormat:@"\                      var jpushEvent = document.createEvent('HTMLEvents');\                      jpushEvent.initEvent('%@', true, true);\                      jpushEvent.eventType = 'message';\                      jpushEvent.arguments = '%@';\                      document.dispatchEvent(jpushEvent);",event,argsString];    }else{        evalString = [NSString stringWithFormat:@"\                      var jpushEvent = document.createEvent('HTMLEvents');\                      jpushEvent.initEvent('%@', true, true);\                      jpushEvent.eventType = 'message';\                      document.dispatchEvent(jpushEvent);",event];    }    //调用上述方法    [self evaluatingJavaScriptFromString:evalString];}复制代码

其中对传入的 args 进行了简单的处理。

最后我们通过调用一行代码即可做到向 js 发送 event :

[self fireEvent:@"event_name" args:args];复制代码

js 接收 event 并处理

在上一步中发送了 "event_name" 的事件之后,可以在 html 的 script 中通过以下方式捕获:

document.addEventListener("event_name", onEventFunc, false);function onEventFunc(args){    var obj = JSON.parese(args);    window.setTimeout(function(){        alert(obj);    },0);}复制代码

至此,就彻底实现了 Objective-C 向 js 的沟通

* 如您对本文有任何疑问或建议,欢迎交流

转载地址:http://knazx.baihongyu.com/

你可能感兴趣的文章
MAVEN 属性定义与使用
查看>>
hadoop2.7.2 HA搭建
查看>>
shell高级视频答学生while循环问题
查看>>
无法SSH到Ubuntu
查看>>
使用@media实现IE hack的方法
查看>>
《11招玩转网络安全》之第一招:Docker For Docker
查看>>
hive_0.11中文用户手册
查看>>
hiveserver2修改线程数
查看>>
XML教程
查看>>
oracle体系结构
查看>>
Microsoft Exchange Server 2010与Office 365混合部署升级到Exchange Server 2016混合部署汇总...
查看>>
Proxy服务器配置_Squid
查看>>
开启“无线网络”,提示:请启动windows零配置wzc服务
查看>>
【SDN】Openflow协议中对LLDP算法的理解--如何判断非OF区域的存在
查看>>
纯DIV+CSS简单实现Tab选项卡左右切换效果
查看>>
栈(一)
查看>>
ios 自定义delegate(一)
查看>>
创建美国地区的appleId
查看>>
例题10-2 UVa12169 Disgruntled Judge(拓展欧几里德)
查看>>
[c语言]c语言中的内存分配[转]
查看>>