网页交互框架/()

1初始化 注册moduleAPIs dict


1代码 FDWebViewController初始化时,要顺便把WAUserInterfaceAPI ,WebAppBridge 初始化
  • 代码
- (void)viewDidLoad
{
    self.webView = [[WAWebView alloc] init];
    self.webView.moduleAPIs = @[[WADeviceAPI sharedInstance],
                                [[WAUserInterfaceAPI alloc] initWithContext:self],
                                [WAUserAPI sharedInstance]];
}
  • 字典key
//self.webView.moduleAPIs _ type is NSMutableArray,val is:
[0]	(null)	@"user" : (no summary)	
[1]	(null)	@"device" : (no summary)	
[2]	(null)	@"UI" : (no summary)	(看情况手工处理)
2其中内部调用
//self.webView.moduleAPIs 中 setmoduleAPIs 方法

//调用某类里面的func. 其中obj为对应类,module为该类对应方法,该方法返回对应Key
NSString *module = (NSString *)[((NSObject *)obj) performSelector:@selector(module)];
[self.webAppBridge registerAPI:obj forModule:module]

//对应其他类的
- (NSString *)module
{
    return @"user";
}

2点击WEB 截取Url


  • 截取 onClick
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
		 NSURL *url = request.URL;
        NSString *module = url.host;
        NSString *json = url[@"p"];
        NSString *callback = url[@"cb"];
        NSArray *pathComponents = url.pathComponents;
        NSString *name = [pathComponents objectAtIndex:1];
  		NSData *jsonData = [json dataUsingEncoding:NSUTF8StringEncoding];
            id jsonObject =[NSJSONSerialization JSONObjectWithData:jsonData
                                                           options:NSJSONReadingAllowFragments
                                                             error:&parseError];
}
  • 数据经过注入JS解析后
url	NSURL *	@"webapi://UI/goto?p=%7B%22uri%22%3A%22djcar%3A%2F%2FPostDetailPage%3Fint%3D1%26long%3D14574327428951033%22%7D"	0x00007f9618e90820	0x00007ffed1cf1290
  • 如上链接 转换后如下,并传入_invokeClientMethod
module = 'UI'
name = 'goto'
parameter = jsonObject (%7B%22uri%22%3A%22djcar%3A%2F%2FPostDetailPage%3Fint%3D1%26long%3D14574327428951033%22%7D)
callbackBlock = nil

3分析Url中host作为Key找回对应moduleAPIs 所对应的类 调整对应方法


- (id)_invokeClientMethod:(NSString *)module
                     name:(NSString *)name
                parameter:(id)parameter
                 callback:(WACallback)callback
{
    id<WebAppAPI> api = [self _apiForModule:module];
    id result = [api invokeClientMethod:name parameter:parameter callback:callback];
    return result;
}

- (id<WebAppAPI>)_apiForModule:(NSString *)module
{
	//conformsToProtocol:@protocol()是用来检查对象是否实现了指定
    id obj = [self.moduleAPIs objectForKey:module];
    return [obj conformsToProtocol:@protocol(WebAppAPI)] ? obj : nil;
}

4协议存在情况下 跳转对应func


- (id)invokeClientMethod:(NSString *)name parameter:(id)parameter callback:(WACallback)callback
{
    // [+] WABaseAPIReflectionImpl invokeClientMethod
    if (callback == nil) {
        [Logger debug:NSStringFromClass(self.class) message:@"void(%@, %@, %@)", self.module, name, parameter];
    }else{
        [Logger debug:NSStringFromClass(self.class) message:@"void(%@, %@, %@, %@)", self.module, name, parameter, callback];
    }
    
    NSString *selectorName = [NSString stringWithFormat:@"%@:callback:", name];
    PKLog(@"调用方法是 %@:",name);
    SEL selector = NSSelectorFromString(selectorName);
    if (![self respondsToSelector:selector])
    {
        return nil;
    }
    // Call the selector
    id result = nil;
    //methodForSelector:方法,让我们可以获取到方法的指针
    IMP imp = [self methodForSelector:selector];
    if (imp) {
    	//强制转换函数指针
        id(*func)(id, SEL, id, WACallback) = (void *)imp;
        result = func(self, selector, parameter, callback);
    }
    return result;
}

//result = func(self, selector, parameter, callback);
selector	SEL	"goto:callback:"	0x00000001037a6a3e
parameter	__NSCFDictionary *	1 key/value pair	0x00007f8a00c92400
callback	WACallback	0x0	0x0000000000000000

5具体实现func


- (id)goto:(id)parameter callback:(WACallback)callback
{    
    NSString *uri = parameter[@"uri"];
    PKLog(@"跳转的URL是 %@",uri);    
    [[URINavigationCenter sharedObject] handleURI:uri fromViewController:(UIViewController *)self.context animated:YES];    
    return nil;
}

uri	__NSCFString *	@"djcar://PostDetailPage?int=1&long=14574327428951033"	0x00007fe864910140

PS所有网页加载前要先注入以下代码


JS源代码 WAWebAPI.js

oc 注入

- (void)_injectBridgeJavascript:(UIWebView *)webView
{
    NSString *filePath = [[NSBundle mainBundle]
                          pathForResource:@"WAWebAPI"
                          ofType:@"js"];
    NSString *js = [NSString stringWithContentsOfFile:filePath
                                             encoding:NSUTF8StringEncoding error:nil];
    [webView stringByEvaluatingJavaScriptFromString:js];
}

js 代码

 invokeClientMethod: function(module, name, parameters, callback) {
 var url = 'webapi://' + module + '/' + name + '?p=' + encodeURIComponent(JSON.stringify(parameters || {}));
 if (callback) {
 var name;
 if (typeof callback == "function") {
 name = WebApiCore.createGlobalFuncForCallback(callback);
 } else {
 name = callback;
 }
 url = url + '&cb=' + name;
 }

js data

<div class="set-collect-topic-list" onclick="
WebApiCore.invokeClientMethod('Info','statEvent', {'types':['string','JSONObject'],'args':['index_toutiaobrowse',{'tiezi-id':'14538013744691619'}]});
WebApiCore.invokeClientMethod('UI', 'goto', {'uri' :'djcar://PostDetailPage?int=1&amp;long=14538013744691619'});
">