日常App 项目中存在很多嵌入的H5页面,前端和移动端就需要有很多交互。这里简单罗列汇总一下常见的交互方,不包括使用第三方库,且仅针对 WKWebView。
OC 调用 JS
1. 通过evaluateJavaScript 方法
[webView evaluateJavaScript:@"OCCallJS('params')"
completionHandler:^(id _Nullable data,
NSError * _Nullable error) {
if (error) {
NSLog(@"error:%@",error);
}
}];
2. JS 方法注入
向网页中注入我们的js方法,
- (void)addUserScript:(WKUserScript *)userScript;
这种注入后,任何时候都可以注入,或者参数改变后可以再次注入。
项目中有一种场景是:
前端页面正常可以浏览,但需要同步获取原生登录状态。 目前前端的做法是缓存了登录成功后的Token,根据token 是否存在,判断登录状态。
未登录时
NSString *js =
[NSString stringWithFormat:@"window.sessionStorage.setItem('token','%@')",@""];
成功登录时
NSString *js =
[NSString stringWithFormat:@"window.sessionStorage.setItem('token','%@')",token];
每次登录状态更改后都可以再次注入
WKUserScript * userScript
= [[WKUserScript alloc]initWithSource:js
injectionTime:WKUserScriptInjectionTimeAtDocumentStart
forMainFrameOnly:NO];
[self.webView.configuration.userContentController addUserScript:userScript];
JS 调用 OC
1. 通过 messageHandlers postMessage 方式
前端调用OC 最常用最便捷的方式
window.webkit.messageHandlers.callNativeAndSend.postMessage('params');
方法名:callNativeAndSend 参数就是:params 移动端通过解析params 获取相应的值
但这种方法很难获取获取回调值,或者说前端通过这个方法获取回调值还没成功过。
2. 通过WKUIDelegate 代理方法
在JS端调用alert函数alert(content)时,会触发此代理方法,
通过message可以拿到JS端所传的数据,在iOS端得到结果后,需要回调JS
通过completionHandler回调给JS端
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"JS调用alert" message:message preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}]];
[self presentViewController:alert animated:YES completion:nil];
}
JS端调用confirm函数时,会触发此方法,通过message可以拿到JS端所传的数据,
在iOS端显示原生alert得到YES/NO后,通过completionHandler回调给JS端
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"confirm" message:@"JS调用confirm" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(YES);
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler(NO);
}]];
[self presentViewController:alert animated:YES completion:NULL];
}
JS端调用prompt函数时,会触发此方法,要求输入一段文本,
在原生输入得到文本内容后,通过completionHandler回调给JS
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler {
NSLog(@"%s", __FUNCTION__);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"textinput" message:@"JS调用输入框" preferredStyle:UIAlertControllerStyleAlert];
[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.textColor = [UIColor redColor];
}];
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler([[alert.textFields lastObject] text]);
}]];
[self presentViewController:alert animated:YES completion:NULL];
}
3. 拦截URL 请求
事先跟前端约定好需要拦截的请求地址
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURL * url = navigationAction.request.URL;
NSString * scheme = url.scheme;
NSString * query = url.query;
NSString * host = url.host;
if ([[url absoluteString] hasSuffix:@"js_oc"]) {
[self handleJSMessage];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
回调JS方法
- (void)handleJSMessage {
[_wkWebView evaluateJavaScript:@"nativeCallbackJscMothod('123')"
completionHandler:^(id _Nullable result,
NSError * _Nullable error) {
NSLog(@"x = %@, error = %@", result, error.localizedDescription);
}];
}