关于iOS与HTML5交互方法大概主要有5种方式:
1. 利用WKWebView进行交互(系统API)
2. 利用UIWebView进行交互(系统API)
3. 苹果的javascriptcore.framework框架;
4. 跨平台cordova框架;
5. oc第三方WebViewJavascriptBridge
一 创建配置
在创建WKWebView之前,需要先创建配置对象,用于做一些配置:
WKWebViewConfiguration*config = [[WKWebViewConfigurationalloc] init];
二 对配置设置偏好设置
//偏好设置
config.preferences = [[WKPreferences alloc] init];
// 默认为0
config.preferences.minimumFontSize =10;
// 默认认为YES
config.preferences.javaScriptEnabled =YES;
// 在iOS上默认为NO,表示不能自动通过窗口打开config.preferences.javaScriptCanOpenWindowsAutomatically =NO;
配置web处理池
// web内容处理池,由于没有属性可以设置,也没有方法可以调用,不用手动创建config.processPool = [[WKProcessPoolalloc] init];
配置JS webView内容进行交互
WKUserContentController是用于给JS注入对象的,注入对象后,JS端就可以使用:
js 代码 window.webkit.messageHandlers.name.postMessage(message)
来调用发送数据给iOS端,比如window.webkit.messageHandlers.AppModel.postMessage({body:'传数据'});
AppModel就是我们要注入的名称,注入以后,就可以在JS端调用了,传数据统一通过body传,可以是多种类型,只支持NSNumber, NSString, NSDate, NSArray,NSDictionary, and NSNull类型。
下面我们配置给JS的main frame注入AppModel名称,对于JS端可就是对象了:
config.userContentController = [[WKUserContentControlleralloc] init];
// 注入JS对象名称AppModel,当JS通过AppModel来调用时,
// 我们可以在WKScriptMessageHandler代理中接收到
[config.userContentController addScriptMessageHandler:selfname:@"AppModel"];
当JS通过AppModel发送数据到iOS端时,会在代理中收到
- (void)userContentController:(WKUserContentController *)userContentController
didReceiveScriptMessage:(WKScriptMessage
*)message {if([message.name isEqualToString:@"AppModel"]) {//
打印所传过来的参数,只支持NSNumber, NSString, NSDate, NSArray,// NSDictionary, and
NSNull类型NSLog(@"%@", message.body);
}
}
所有JS调用iOS的部分,都只可以在此处使用。当然我们也可以注入多个名称(JS对象),用于区分功能。
//创建WKWebview
self.webView = [[WKWebViewalloc] initWithFrame:self.view.bounds configuration:config];
NSURL *path =[[NSBundle mainBundle] URLForResource:@"test" withExtension:@"html"];
[self.webView loadRequest:[NSURLRequest requestWithURL:path]];
配置代理
如果需要处理web导航条上的代理处理,比如链接是否可以跳转或者如何跳转,需要设置代理;而如果需要与在JS调用alert、confirm、prompt函数时,通过JS原生来处理,而不是调用JS的alert、confirm、prompt函数,那么需要设置UIDelegate,在得到响应后可以将结果反馈到JS端:
// 导航代理
self.webView.navigationDelegate =self;
// 与webview UI交互代理
self.webView.UIDelegate =self;
[self.view addSubview:self.webView];
添加对WKWebView属性的监听
// 添加KVO监听[self.webViewaddObserver:selfforKeyPath:@"loading"options:NSKeyValueObservingOptionNew
context:nil];
[self.webViewaddObserver:selfforKeyPath:@"title"options:NSKeyValueObservingOptionNew
context:nil];
[self.webViewaddObserver:selfforKeyPath:@"estimatedProgress"options:NSKeyValueObservingOptionNew
context:nil];
然后我们就可以实现KVO处理方法,在loading完成时,可以注入一些JS到web中。这里只是简单地执行一段web中的JS函数:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary*)change
context:(void *)context {
if ([keyPath isEqualToString:@"loading"]) {
NSLog(@"loading");
} else if ([keyPath isEqualToString:@"title"]) {
self.title = self.webView.title;
} else if ([keyPath isEqualToString:@"estimatedProgress"]) {
NSLog(@"progress: %f", self.webView.estimatedProgress);
self.progressView.progress = self.webView.estimatedProgress;
}
// 加载完成
if (!self.webView.loading) {
// 手动调用JS代码
// 每次页面完成都弹出来,大家可以在测试时再打开
NSString *js = @"callJsAlert()";
[self.webView evaluateJavaScript:js completionHandler:^(id _Nullable response, NSError * _Nullable error) {
NSLog(@"response: %@ error: %@", response, error);
NSLog(@"call js alert by native");
}];
[UIView animateWithDuration:0.5 animations:^{
self.progressView.alpha = 0;
}];
}
}
WKUIDelegate
与JS原生的alert、confirm、prompt交互,将弹出来的实际上是我们原生的窗口,而不是JS的。在得到数据后,由原生传回到JS:
- (void)webViewDidClose:(WKWebView *)webView {
NSLog(@"%s", __FUNCTION__);
}
-
(void)webView:(WKWebView *)webView
runJavaScriptAlertPanelWithMessage:(NSString *)message
initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void
(^)(void))completionHandler {
NSLog(@"%s", __FUNCTION__);
UIAlertController
*alert = [UIAlertController alertControllerWithTitle:@"alert"
message:@"JS调用alert" preferredStyle:UIAlertControllerStyleAlert];
[alert
addAction:[UIAlertAction actionWithTitle:@"确定"
style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull
action) {
completionHandler();
}]];
[self presentViewController:alert animated:YES completion:NULL];
NSLog(@"%@", message);
}
-
(void)webView:(WKWebView *)webView
runJavaScriptConfirmPanelWithMessage:(NSString *)message
initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL
result))completionHandler {
NSLog(@"%s", __FUNCTION__);
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];
NSLog(@"%@", message);
}
-
(void)webView:(WKWebView *)webView
runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt
defaultText:(nullable NSString *)defaultText
initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void
(^)(NSString * __nullable result))completionHandler {
NSLog(@"%s", __FUNCTION__);
NSLog(@"%@", prompt);
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];
}
WKNavigationDelegate
如果需要处理web导航操作,比如链接跳转、接收响应、在导航开始、成功、失败等时要做些处理,就可以通过实现相关的代理方法:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSString *hostname = navigationAction.request.URL.host.lowercaseString;
if (navigationAction.navigationType == WKNavigationTypeLinkActivated
&& ![hostname containsString:@".baidu.com"]) {
// 对于跨域,需要手动跳转
[[UIApplication sharedApplication] openURL:navigationAction.request.URL];
// 不允许web内跳转
decisionHandler(WKNavigationActionPolicyCancel);
} else {
self.progressView.alpha = 1.0;
decisionHandler(WKNavigationActionPolicyAllow);
}
NSLog(@"%s", __FUNCTION__);
}
-
(void)webView:(WKWebView *)webView
decidePolicyForNavigationResponse:(WKNavigationResponse
*)navigationResponse decisionHandler:(void
(^)(WKNavigationResponsePolicy))decisionHandler {
decisionHandler(WKNavigationResponsePolicyAllow);
NSLog(@"%s", __FUNCTION__);
}
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation {
NSLog(@"%s", __FUNCTION__);
}
-
(void)webView:(WKWebView *)webView
didReceiveServerRedirectForProvisionalNavigation:(null_unspecified
WKNavigation *)navigation {
NSLog(@"%s", __FUNCTION__);
}
-
(void)webView:(WKWebView *)webView
didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation
withError:(NSError *)error {
NSLog(@"%s", __FUNCTION__);
}
- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation {
NSLog(@"%s", __FUNCTION__);
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
NSLog(@"%s", __FUNCTION__);
}
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
}
-
(void)webView:(WKWebView *)webView
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge
*)challenge completionHandler:(void
(^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential
*__nullable credential))completionHandler {
NSLog(@"%s", __FUNCTION__);
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
}
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {
NSLog(@"%s", __FUNCTION__);
}
// 对于HTTPS的都会触发此代理,如果不要求验证,传默认就行// 如果需要证书验证,与使用AFN进行HTTPS证书验证是一样的- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void(^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *__nullable credential))completionHandler {NSLog(@"%s", __FUNCTION__);
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling,nil);
}// 9.0才能使用,web内容处理中断时会触发- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {NSLog(@"%s", __FUNCTION__);
}
网友评论