美文网首页IOS
GCWKWebViewJSBridge 让 iOS 原生与WKW

GCWKWebViewJSBridge 让 iOS 原生与WKW

作者: StrivEver | 来源:发表于2019-11-21 15:48 被阅读0次

项目中大量使用了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

相关文章

网友评论

    本文标题:GCWKWebViewJSBridge 让 iOS 原生与WKW

    本文链接:https://www.haomeiwen.com/subject/ttrtwctx.html