GCWKWebViewJSBridge 让 iOS 原生与WKWebView交互更简单

项目中大量使用了Hybrid开发,对native与js的交互做了个bridge,有需要的可以下载直接使用。使用Object-c语言,目前支持cocoapods导入。

pod 'GCWKWebViewJSBridge', '~> 0.1.0'
项目地址点击这里,有用的上的给个star吧

实现功能有:

  • 实现了对web控制台打印的信息在xcode控制台输出
//注册xcode控制台 输出web控制台信息
    [bridge registCaptureJSConsoleLog];

简书首页 log输出

js console log:{
    details =     {
        dns = 33;
        onload = 634;
        ttfb = 1269;
    };
    display = 1522;
    lifecycle =     {
        "_1" =         {
            desc = "\U7f51\U9875\U91cd\U5b9a\U5411\U7684\U8017\U65f6";
            key = redirect;
            value = 0;
        };
        "_2" =         {
            desc = "\U68c0\U67e5\U672c\U5730\U7f13\U5b58\U7684\U8017\U65f6";
            key = cache;
            value = 14;
        };
        "_3" =         {
            desc = "DNS\U67e5\U8be2\U7684\U8017\U65f6";
            key = dns;
            value = 33;
        };
        "_4" =         {
            desc = "TCP\U8fde\U63a5\U7684\U8017\U65f6";
            key = tcp;
            value = 464;
        };
        "_5" =         {
            desc = "\U5ba2\U6237\U7aef\U53d1\U8d77\U8bf7\U6c42\U7684\U8017\U65f6";
            key = request;
            value = 755;
        };
        "_6" =         {
            desc = "\U670d\U52a1\U7aef\U54cd\U5e94\U7684\U8017\U65f6";
  • 实现了对JS 异常的捕获,输出到控制台
[bridge registCaptureJSExceptionLog];

存在跨域问题,只能收集到Script error.,打印不出详细信息。
这个不是bug,webkik源码判断有跨域问题时候,为了安全,不提供具体错误信息

bool ScriptExecutionContext::sanitizeScriptError(String& errorMessage, int& lineNumber, String& sourceURL)
    {
        KURL targetURL = completeURL(sourceURL);
        if (securityOrigin()->canRequest(targetURL))
            return false;
        errorMessage = "Script error.";
        sourceURL = String();
        lineNumber = 0;
        return true;
    }

对于OC调用JS函数时,web端未实现,此时可以打印出错误信息如下

js exception Message: ReferenceError: Can't find variable: 
ocCallJS1 - URL: https://www.jianshu.com/ - Line: 1 - Column:
 10 - Error object: {"line":1,"column":10,"sourceURL":
"https://www.jianshu.com/"}
  • 对URL拦截交互,统一封装成block进行回调,集中管理。还涉及处理匹配优先级问题

在实际开发中可能会遇到拦截URL的时候,URL还需要给我们传递参数,这时候完全去匹配URL将匹配不到,只能进行包含kw进行匹配。block会返回keyURL和完整路径,我们可以通过处理完整路径获取参数。

实际还会遇到匹配URL时候,能够匹配到多个,这时候我们以完全匹配到,得分最高;匹配到的长度进行积分计算,然后返回积分最高的匹配。实际匹配中会出现 share:123,share:12345,share#等,如果被拦截的链接是www.share12345.com/?,这时候会计算出匹配到的是share12345,在回掉中进行相关逻辑处理。

匹配规则如下:这里对匹配规则放在一个函数里,方便你根据业务可以对它进行扩展

- (NSString *)_machRuleWithUrl:(NSString *)URL{
    NSString * matchedURL = @"";
    //匹配积分,取匹配最高的
    NSInteger currentMatchKeyScore = 0;
    for (NSString * keyURL in self.interceptKeyURLArray) {
        if ([keyURL isEqualToString:URL]){
            //精准匹配到了,退出循环
            matchedURL = keyURL;
            currentMatchKeyScore = MaxMatchScore;
            break;
        }
        //计算模糊匹配积分,以匹配到的keyURL长度计算积分,拦截得分最高的keyURL
        if ([URL containsString:keyURL]) {
            //以匹配到的字符长度为匹配分数
            NSInteger matchScore = keyURL.length;
            if (currentMatchKeyScore < matchScore) {
                matchedURL = keyURL;
                currentMatchKeyScore = matchScore;
            }
        }else continue;
    }
    return matchedURL;
}
//批量注册拦截www.baidu.com
    [bridge registInterceptURLKeys:@[@"share:123",@"share:12345",@"share://info#"] handler:^(NSString * _Nonnull keyURL, NSString * _Nonnull URL) {
        NSLog(@"%@====\n%@",keyURL,URL);
    }];
  • 通过注入变量方式,向JS传入参数,支持json对象,和字符对象传入;比如渲染网页前,需要拿到用户token等等
//oc向JS注入实例变量,可用来向h5注入用户token,信息等等
    NSDictionary * userInfo = @{@"uid":@"10086",@"name":@"中国移动",@"age":@"22",@"token":@"oidahnfjabfiabfuaojfbaiufbafo"};
    [bridge nativeUploadJSArguments:userInfo filedName:@"uoloadUser" inTime:WKUserScriptInjectionTimeAtDocumentStart];

*通过注入函数方式,向JS传入参数

//oc向JS注入参数,可用来向h5注入一个带参数返回值的函数,供h5调用
    NSArray * lists = @[@"周1",@"周2",@"周3",@"周4"];
    [bridge nativeUploadJSArguments:lists useMethod:@"getOCMessage" inTime:WKUserScriptInjectionTimeAtDocumentStart];
  • 注册JS调用OC回调,通过messageName进行回调逻辑区分
 //批量注册JS调用oc函数
    [bridge registJSMethods:@[@"ocShare",@"getUserJson"] nativeHandler:^(NSString * _Nonnull messageName, id  _Nonnull messageBody) {
         NSLog(@"%@:%@",messageName,messageBody);
    }];
  • 注册OC调用JS函数,支持单参跟可变参数
if (button.tag == 1) {
        //app调用js,带一个参数的,参数可以为字典和字符串
        [bridge nativeCallJSMethod:@"ocCallJS" arguments:@"app调用JS成功" completionHandler:^(id  _Nullable result, NSError * _Nullable error) {
            
        }];
    }else{
         //app调用js,带多个可变参数,个数与JS端保持一致
        [bridge nativeCallJSMethod:@"ocCallJS1" completionHandler:^(id  _Nullable result, NSError * _Nullable error) {
            
        } arguments:@"我叫中国移动",@"今年1岁了",@"性别男",@"uid10086",nil];
    }
头文件
@interface GCWKWebViewJSBridge : NSObject<WKScriptMessageHandler>
+ (instancetype)bridgeWithWKWebView:(WKWebView *)webView;
//注册捕获JS异常,跨域问题详细信息可能捕获不到;能捕获到JS未实现OC需要调用的函数错误
- (void)registCaptureJSExceptionLog;
/// 注册输出web端控制台信息
- (void)registCaptureJSConsoleLog;
- (void)registInterceptURLKeys:(NSArray *)keyUrls handler:(interceptURLHandler)handler;
- (void)registInterceptURLKey:(NSString *)keyURL handler:(interceptURLHandler)handler;
- (BOOL)webViewBridgeCanInterceptURL:(NSString *)URL;

/// native向H5注入js脚本
/// @param jsCode js代码以字符串形式
/// @param userScriptInjectionTime 注入时机
- (void)registNativeUserScript:(NSString *)jsCode inTime:(WKUserScriptInjectionTime)userScriptInjectionTime;

/// 向JS注入一个全局变量,供JS使用
/// @param param  变量值,可以是字符串,或者JSON对象
/// @param filedName 变量名称
/// @param userScriptInjectionTime 注入时机
/// 前端使用:取值即可
- (void)nativeUploadJSArguments:(id)param filedName:(NSString *)filedName inTime:(WKUserScriptInjectionTime)userScriptInjectionTime;

/// 向JS注入带返回值得函数,供JS获取native信息
/// @param param 变量值 可以是字符串,或者JSON对象
/// @param methodName  js调用函数名
/// @param userScriptInjectionTime js注入时机
/**
 前端使用:
 Let x = window.【methodName()】
 x为获得参数值
 */
- (void)nativeUploadJSArguments:(id)param useMethod:(NSString *)methodName inTime:(WKUserScriptInjectionTime)userScriptInjectionTime;

/// JS调用native
/// @param jsMethod js函数名称
/// @param nativehandler native响应的回调
/**
 前端用法
 window.webkit.messageHandlers.【jsMethod】.postMessage(【需要传给native的参数】)
 */
- (void)registJSMethod:(NSString *)jsMethod nativeHandler:(handler)nativehandler;
/// 批量注册
- (void)registJSMethods:(NSArray *)jsMethods nativeHandler:(handler)nativehandler;
/**
native 调用JS函数
@param methodName JS函数名
@param param 向JS传入参数,只支持一个参数,可以是字符串,或者JSON对象
@param completionHandler JS回调

前端:
实现 相应的method
*/
- (void)nativeCallJSMethod:(NSString *)methodName arguments:(id)param completionHandler:(void (^)(id _Nullable result, NSError * _Nullable))completionHandler;
/**
native 调用JS函数
@param methodName JS函数名
@param param 向JS传入多个参数,必须都为字符串形式,参数个数 与JS端保持一致,可以是字符串,或者JSON对象
@param completionHandler JS回调
前端:
实现 相应的method
*/
- (void)nativeCallJSMethod:(NSString *)methodName completionHandler:(void (^)(id _Nullable result, NSError * _Nullable))completionHandler arguments:(NSString *)param, ...;

- (void)removeAllUserScripts;
- (void)removeScriptMessageHandlerForName:(NSString *)method;
@end
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容