WebViewJavaScriptBridgeの登録方法を優雅に使用

4042 ワード

最近WebViewJavaScriptBridgeを研究して、ネット上の原理は大体同じで、自分と結びつけてソースコードを見て、流れがはっきりして、まとめてみます.1 WebViewJavaScriptBridgeはWKWebViewが使用するかURLをブロックするかの方法に合わせてJSとWebViewのインタラクションを実現する.簡単に使うと、まずページのロードが終わった後、JSをページに注入し、JSメソッド呼び出し時にパラメータなどを変換してwebviewが認識をブロックできるようにします.内部では、辞書のようなメカニズムを使用して、登録されたメソッド名と対応する処理を格納します.2公的文書の登録方法の例
 [self.jsBridge registerHandler:jsName
            handler:^(id data, WVJBResponseCallback responseCallback) {
                                  //
                               }];

このような状況は簡単でいいですが、方法が多い場合は、頭が痛いです.私のソリューションは、JSの呼び出しを専門に処理するクラスを作成することです.クラス中のメソッドの名前はJS呼び出しと同じで、runtimeでメソッドのリストを取得し、self.jsBridge登録方法.配布によってメソッドを呼び出す.最後の姿はこうだった
//   JS
    for (NSString *jsName in [self.helper.ymHelperMethodDic allKeys]) {
    
        __weak typeof(self) weakSelf = self;
        [self.jsBridge registerHandler:jsName
                               handler:^(id data, WVJBResponseCallback responseCallback) {
                                   __strong typeof(weakSelf) strongSelf = weakSelf;
                                   [strongSelf.helper ymHelperHandleName:jsName
                                                              data:data
                                                          callBack:responseCallback];
                               }];

    }

具体的な解決策は、まずメソッドのリストを取得し、変換後のJSNameと、関係のないメソッドをフィルタリングすることを覚えています.
/**
 *    runtime       
 *
 *  @return       js         
 */
- (NSDictionary *)ymHelperMethodListDic
{
    unsigned int count;
    Method *methods = class_copyMethodList([WebViewJSHandler class], &count);
    NSMutableDictionary *methodDictionary = [NSMutableDictionary dictionaryWithCapacity:count];
    
    for (int i = 0; i < count; i++)
    {
        Method method = methods[i];
        SEL selector = method_getName(method);
        NSString *name = NSStringFromSelector(selector);
        
        /**
         *          
         */
        if (![name containsString:@"mHelper"] &&
            ![name containsString:@"."] &&
            ![name containsString:@"dealloc"]) {
            
            NSString *jsName = [[name componentsSeparatedByString:@":"] firstObject];
            NSLog(@"      ==== %@",name);
            NSLog(@"js    ==== %@",jsName);
            [methodDictionary setObject:name forKey:jsName];
        }
        
    }
    return methodDictionary;
}


辞書を半分取った.JSNameでSELを変換してから転送します.
/**
 *     methodName    
 *
 *  @param methodName           
 *  @param data               
 *  @param responseCallback   
 */
- (void)ymHelperHandleName:(NSString *)methodName
              data:(id)data
          callBack:(YMResponseCallback)responseCallback{
    
    NSString *selString = [self ymHelperFindSELByJSName:methodName];
    //   string to SEL
    SEL sel = NSSelectorFromString(selString);
    
    if ([self.ymHelperWebViewJSHandler respondsToSelector:sel]) {
        
//    
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        [self.ymHelperWebViewJSHandler performSelector:sel withObject:data withObject:responseCallback];
#pragma clang diagnostic pop
    }   
}

そしてperformSelectorで転送します.
webビューではこれで終わりです
//   JS
    for (NSString *jsName in [self.helper.ymHelperMethodDic allKeys]) {
    
        __weak typeof(self) weakSelf = self;
        [self.jsBridge registerHandler:jsName
                               handler:^(id data, WVJBResponseCallback responseCallback) {
                                   __strong typeof(weakSelf) strongSelf = weakSelf;
                                   [strongSelf.helper ymHelperHandleName:jsName
                                                              data:data
                                                          callBack:responseCallback];
                               }];

    }

1つのcontrollerに登録方法の実装を書く必要はありません.