美文网首页程序员
WebViewJavascriptBridge优化开发

WebViewJavascriptBridge优化开发

作者: freesan44 | 来源:发表于2018-10-10 12:00 被阅读15次

    背景

    WebViewJavascriptBridge作为JS和原生OC的交互,通常都是在WebView中用self.bridge注册方法来进行调用,但这样对于WebView来说比较脓肿,全部逻辑处理都放在WebView下面实现,并且入参出参都是要用字符串来实现影响开发效率,后来考虑用runtime方法,让JS调用的方法都放在类里面实现

    处理办法

    批量注册方法

    创建一个handler类,用来批量注册JS方法

    @interface WKWebJSHandler : NSObject
    typedef void (^JSResponseCallback)(id responseData);
    @property (nonatomic,copy)NSString* handleName;//控件名称
    @property (nonatomic,copy)NSDictionary* infoDic;//入参
    @property (nonatomic,strong)JSResponseCallback  jsResponseCallback;//回参
    -(NSArray *)getSubClassArr;//获取所有继承该类的方法
    //注册控件
    - (void)messageWithHandler:(NSString*)className
                    withMethod:(NSString*)methodName
                      withData:(id)data
                      complete:(void (^)(id responseData))completeBlock;
    @end
    

    通过运行时,把注册的控件的入参出参model化

    - (void)messageWithHandler:(NSString*)className
                    withMethod:(NSString*)methodName
                      withData:(id)data
                      complete:(void (^)(id responseData))completeBlock
    {
        @synchronized(self)
        {
            
            Class class = NSClassFromString(className);
            id obj = [[class alloc]init];
            
            SEL superSelector = NSSelectorFromString(@"registPluginWithHandlerName:withData:complete:");
            SEL subSelector = NSSelectorFromString(methodName);
            if ([obj respondsToSelector:superSelector]) {
                void (*func)(id, SEL, id, id, id) = (void (*)(id, SEL, id, id, id))objc_msgSend;
                func(obj,superSelector,methodName,data, completeBlock);
            }
            if ([obj respondsToSelector:subSelector]) {
                void (*func)(id, SEL) = (void (*)(id, SEL))objc_msgSend;
                func(obj, subSelector);
            }
        }
    }
    

    获取要进行注册的控件类名方法名,为了方便开发,就定义所有继承WKWebJSHandler的子类的方法都进行注册

    - (void)registPluginWithHandlerName:(id)handlerName
                               withData:(id)data
                               complete:(void (^)(id responseData))completeBlock
    {
        self.handleName = handlerName;
        self.infoDic = data;
        self.jsResponseCallback = ^(id responseData) {
            //返回数据给JS
            completeBlock(responseData);
        };
    }
    //获取子类的所有类
    -(NSArray *)getSubClassArr
    {
        int numClasses;
        Class * classes = NULL;
        numClasses = objc_getClassList(NULL, 0);
        //类:方法
        NSMutableArray * methodListArr = [NSMutableArray array];
        
        if (numClasses>0) {
            classes = (__unsafe_unretained Class *)malloc(sizeof(Class)* numClasses);
            numClasses = objc_getClassList(classes, numClasses);
            for (int i = 0; i < numClasses; i++) {
                if (class_getSuperclass(classes[i]) == [WKWebJSHandler class]) {
                    NSString * className = NSStringFromClass(classes[i]);
                    
                    //获取子类下面的全部方法名
                    unsigned int count;
                    Method * methods = class_copyMethodList(classes[i], &count);
                    for (int j = 0; j < count; j++) {
                        Method method = methods[j];
                        SEL selector = method_getName(method);
                        NSString * methodName = NSStringFromSelector(selector);
                        
    //                    DebugLog(@"方法 名字 ==== %@",methodName);
    //                    DebugLog(@"类 名字 ==== %@",className);
                        NSDictionary * dic = [NSDictionary dictionaryWithObject:methodName forKey:className];
                        [methodListArr addObject:dic];
                        
                    }
                }
            }
            free(classes);
        }
        return (NSArray*)methodListArr;
    }
    

    bridge进行注册

    WebView和UIWebView注册大同小异

    // 给哪个webview建立JS与OjbC的沟通桥梁
        [WebViewJavascriptBridge enableLogging];
        self.bridge = [WebViewJavascriptBridge bridgeForWebView:webView];
        [self.bridge setWebViewDelegate:self];
    
        WKWebJSHandler * handle = [[WKWebJSHandler alloc]init];
        NSArray * arr = [handle getSubClassArr];
        //对所有子类方法进行注册
        for (NSDictionary * each in arr) {
            NSString * className = each.allKeys.firstObject;
            NSString * methodName = each.allValues.firstObject;
            [self.bridge registerHandler:methodName handler:^(id data, WVJBResponseCallback responseCallback) {
                [handle messageWithHandler:className withMethod:methodName withData:data complete:responseCallback];
            }];
        }
    

    编写被JS调用方法

    以后开发给JS调用的方法,只要在继承WKWebJSHandler类的子类下编写就行:

    #import "WKWebJSHandler.h"
    
    @interface WKWebControl : WKWebJSHandler
    
    @end
    

    调用方法,方法名就是注册方法名

    @implementation WKWebControl
    -(void)holdingActionFromNative
    {
        DebugLog(@"收到的参数------%@",self.infoDic);
        
        //返回给JS的参数
        self.jsResponseCallback(@"调用原生方法成功!");
    }
    

    JS

    JS的调用写法还是不变

    document.getElementById('button').onclick = function (e) {
             log('js call objc: holdingActionFromNative')
             bridge.callHandler('holdingActionFromNative', {'title':'JStitle'}, function(response) {
                              log('JS got response', response)
                              })
           }
    

    相关文章

      网友评论

        本文标题:WebViewJavascriptBridge优化开发

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