背景
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)
})
}
网友评论