- 之前项目中OC和JS交互一直用的对UIWebview方法拦截方案,根据自定义的url来调用OC的方法.
- 考虑到性能问题,现在切换WKWebView
下面主要讲述下从iOS6至今,Native与JavaScript的交互方法
iOS 6 UIWebview&&JavaScript
- 1、iOS6原生没有提供js直接调用Objective-C的方式,只能通过UIWebView的UIWebViewDelegate协议
#pragma mark UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = [request URL];
// hybrid://Smart:3/pushViewController?{}
if ([url.scheme isEqualToString:@"hybrid"]) {
[self handleRequest:url];
return NO;
}
return YES;
}
- (void)handleRequest:(NSURL *)url {
NSString *handlerName = [url.path substringFromIndex:1];
NSString *queryString = [url.query stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSInteger sid = [url.port integerValue];
NSDictionary *parameters = [queryString tp_objectFromJSONString];
SEL selector = NSSelectorFromString([NSString stringWithFormat:@"%@:parameters:", handlerName]);
if (![self respondsToSelector:selector]) {
return;
}
IMP imp = [self methodForSelector:selector];
void (*func)(id, SEL,NSInteger, NSDictionary *) = (void *)imp;
func(self, selector,sid, parameters);
}
- (void)pushViewController:(NSInteger)sid parameters:(NSDictionary *)parameters
{
}
-
2、通过自定义方法来做拦截,并在这个方法中,根据url来调用Objective-C方法
-
3、如果要OC调JS, stringByEvaluatingJavaScriptFromString方法可以将javascript嵌入页面中
[self.webView stringByEvaluatingJavaScriptFromString:@""];
iOS 7 UIWebview&&JavaScriptCore
-
1、iOS7中加入了JavaScriptCore.framework框架。把 WebKit 的 JavaScript 引擎用 Objective-C 封装。该框架让Objective-C和JavaScript代码直接的交互变得更加的简单方便。
-
2、JavaScriptCore中类及协议:
- JSContext:给JavaScript提供运行的上下文环境
-
JSValue:JavaScript和Objective-C数据和方法的桥梁
-
JSExport:协议,如果采用协议的方法交互,自己定义的协议必须遵守此协议
-
3、JS -> OC
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"js call oc";
NSString *path = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"JSCallOC.html"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]];
[self.webView loadRequest:request];
}
#pragma mark - UIWebViewDelegate
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
// 以 html title 设置 导航栏 title
self.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
// Undocumented access to UIWebView's JSContext
self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
// 打印异常
self.context.exceptionHandler =
^(JSContext *context, JSValue *exceptionValue)
{
context.exception = exceptionValue;
NSLog(@"%@", exceptionValue);
};
// 以 block 形式关联 JavaScript function
self.context[@"alert"] =
^(NSString *str)
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"msg from js" message:str delegate:nil cancelButtonTitle:@"ok" otherButtonTitles:nil, nil];
[alert show];
};
}
- 4、OC -> JS
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"oc call js";
self.context = [[JSContext alloc] init];
[self.context evaluateScript:[self loadJsFile:@"test"]];
}
- (NSString *)loadJsFile:(NSString*)fileName
{
NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:@"js"];
NSString *jsScript = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
return jsScript;
}
- (IBAction)sendToJS:(id)sender {
NSNumber *inputNumber = [NSNumber numberWithInteger:[self.textField.text integerValue]];
JSValue *function = [self.context objectForKeyedSubscript:@"factorial"];
JSValue *result = [function callWithArguments:@[inputNumber]];
self.showLable.text = [NSString stringWithFormat:@"%@", [result toNumber]];
}
iOS 8 WKWebView && JavaScript
-
1、WebKit框架使得开发者可以在原生App中使用Nitro来提高网页的性能和表现,Nitro就是Safari的JavaScript引擎 WKWebView 不支持JavaScriptCore的方式但提供message handler的方式为JavaScript 与Native通信.
-
2、WKWebView的好处:
- 1、在性能、稳定性、功能方面有很大提升(加载速度,内存的提升谁用谁知道
- 2、更多的支持 HTML5 的特性
- 3、官方宣称的高达60fps的滚动刷新率以及内置手势
- 4、Safari 相同的 JavaScript 引擎
- 5、将 UIWebViewDelegate 与 UIWebView 拆分成了14类与3个协议,包含该更细节功能的实现。
-
在 UIWebView 中,一句简单的webView.stringByEvaluatingJavaScriptFromString() 就可以用 JS 脚本操纵 WebView,
在 WKWebView 中,我们可能需要用到 WKScriptMessageHandler 这个协议中的
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
if ([message.name isEqualToString:@"Native"]) {
NSLog(@"message.body:%@", message.body);
//如果是自己定义的协议, 再截取协议中的方法和参数, 判断无误后在这里手动调用oc方法
NSMutableDictionary *param = [self queryStringToDictionary:message.body];
NSLog(@"get param:%@",[param description]);
NSString *func = [param objectForKey:@"func"];
//调用本地函数
if([func isEqualToString:@"alert"])
{
[self showMessage:@"来自网页的提示" message:[param objectForKey:@"message"]];
}
}
}
- (NSMutableDictionary*)queryStringToDictionary:(NSString*)string {
NSMutableArray *elements = (NSMutableArray*)[string componentsSeparatedByString:@"&"];
NSMutableDictionary *retval = [NSMutableDictionary dictionaryWithCapacity:[elements count]];
for(NSString *e in elements) {
NSArray *pair = [e componentsSeparatedByString:@"="];
[retval setObject:[pair objectAtIndex:1] forKey:[pair objectAtIndex:0]];
}
return retval;
}
- 把 JS 脚本注入到 WebView 的途径是初始化一个 WebView,所以你需要在 WebView 初始化之前写好自己的脚本
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"JS调用WKWebView";
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.userContentController = [[WKUserContentController alloc] init];
[config.userContentController addScriptMessageHandler:self name:@"Native"];
self.myWebView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
self.myWebView.UIDelegate = self;
[self.view addSubview:self.myWebView];
[self loadHtml:@"JSWKWebView"];
}
网友评论