UIWebView(基础)
UIWebView(进阶)
UIWebView(高级)
看过前两篇博文的朋友,相信对UIWebView有一定的了解。但是有的地方不是很完善,今天是对UIWebView做一定的补充,实现的需求如下:
如果你还不知道JavaScriptCore库,详见我的博文《JavaScriptCore框架》
在WWDC 2013上,苹果公司推出了JavaScriptCore框架,这是一个基于JavaScript的框架,它完美的以面向对象的方式实现js和oc的交互。
今天我们使用JavaScriptCore为大家介绍更优雅的js和oc交互。
这次创建的项目是借用前两篇博文的组合模式。完成后的界面图和进阶篇的截面图一样。
我们使用新的UIViewController,命名为SeniorVC。我已经为大家搭建了基础代码。
//
// SeniorVC.m
// UIWebView
//
// Created by yangjun on 15/11/5.
// Copyright © 2015年 六月. All rights reserved.
//
#import "SeniorVC.h"
@interface SeniorVC () <UIWebViewDelegate>
@property (weak, nonatomic) IBOutlet UIWebView *webView; ///< UIWebView
@property (weak, nonatomic) IBOutlet UIProgressView *progressView; ///< 进度条
@end
@implementation SeniorVC
- (void)viewDidLoad {
[super viewDidLoad];
self.webView.delegate = self;// 代理
NSURL *url = [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"html"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url]; // url的位置
[self.webView loadRequest:urlRequest]; // 加载页面
}
#pragma mark 刷新
- (IBAction)reload:(id)sender {
NSLog(@"%d", self.webView.loading);
// 正在刷新界面时,停止刷新后重新刷新界面
if (self.webView.loading) {
[self.webView stopLoading]; // 停止刷新
}
[self.webView reload]; // 刷新界面
}
#pragma mark 去上一页
- (IBAction)goBack:(id)sender {
// 可以去上一页时,执行去上一页操作
if (self.webView.canGoBack) {
[self.webView goBack];
}
}
#pragma mark 去下一页
- (IBAction)goForward:(id)sender {
// 可以去下一页时,执行去下一页操作
if (self.webView.canGoForward) {
[self.webView goForward];
}
}
#pragma mark - UIWebViewDelegate
#pragma mark 开始加载网页
- (void)webViewDidStartLoad:(UIWebView *)webView {
NSLog(@"%@", NSStringFromSelector(_cmd));
}
#pragma mark 网页加载完成
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSLog(@"%@", NSStringFromSelector(_cmd));
}
#pragma mark 网页加载出错
- (void)webView:(UIWebView *)webView didFailLoadWithError:(nullable NSError *)error {
NSLog(@"%@:%@", NSStringFromSelector(_cmd), error.localizedDescription);
}
#pragma mark 网页监听
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSLog(@"%@", NSStringFromSelector(_cmd));
NSLog(@"%@", request.URL.absoluteString.stringByRemovingPercentEncoding);
return YES;
}
@end
运行项目后你会看到如下效果图,如果你看不见,代表项目搭建有误。
我们使用JSExport制造要暴露给JS调用的协议以及工具类JavaScriptUtil。
JavaScriptUtil.h
//
// JavaScriptUtil.h
// UIWebView
//
// Created by yangjun on 15/11/6.
// Copyright © 2015年 六月. All rights reserved.
//
#import
#import
/// 暴露给js使用的协议
@protocol JavaScriptDelegate <NSObject, JSExport>
- (void)jsCallOC:(NSString *)params;
@end
/// js对应的oc实现类
@interface JavaScriptUtil : NSObject <JavaScriptDelegate>
@property (nonatomic, weak) id javaScriptDelegate; ///< 代理
@end
这里使用了代理模式,思想就是JavaScript->JavaScriptUtil->SeniorVC。
值得注意的是,在JavaScriptDelegate中禁止使用@optional属性。使用了这个属性后,js则无法调用。
JavaScriptUtil.m
//
// JavaScriptUtil.m
// UIWebView
//
// Created by yangjun on 15/11/6.
// Copyright © 2015年 六月. All rights reserved.
//
#import "JavaScriptUtil.h"
@implementation JavaScriptUtil
- (void)jsCallOC:(NSString *)params {
if ([self.javaScriptDelegate respondsToSelector:@selector(jsCallOC:)]) {
[self.javaScriptDelegate jsCallOC:params];
}
}
@end
接下来,我们改造SeniorVC。
#import "SeniorVC.h"
#import
#import "JavaScriptUtil.h"
@interface SeniorVC () <UIWebViewDelegate, JavaScriptDelegate>
@property (weak, nonatomic) IBOutlet UIWebView *webView; ///< UIWebView
@property (weak, nonatomic) IBOutlet UIProgressView *progressView; ///< 进度条
@property (nonatomic, strong) JSContext *jsContext; ///< JSContext
@end
@implementation SeniorVC
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// 获取JSContext
self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
// 通过exceptionHandler捕获js错误
self.jsContext.exceptionHandler = ^(JSContext *con, JSValue *exception) {
NSLog(@"exception:%@", exception);
con.exception = exception;
};
// 注入JavaScriptUtil
JavaScriptUtil *jSUtil = [[JavaScriptUtil alloc] init];
jSUtil.javaScriptDelegate = self;
self.jsContext[@"app"] = jSUtil;
self.webView.delegate = self;// 代理
NSURL *url = [[NSBundle mainBundle] URLForResource:@"Senior" withExtension:@"html"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url]; // url的位置
[self.webView loadRequest:urlRequest]; // 加载页面
}
#pragma mark - JavaScriptDelegate
- (void)jsCallOC:(NSString *)params {
NSLog(@"%@", NSStringFromSelector(_cmd));
NSString *js = [NSString stringWithFormat:@"ocCallJS('%@')", params];
[self.jsContext evaluateScript:js];
// 或
// [self.webView stringByEvaluatingJavaScriptFromString:js];
}
@end
这里涉及到几个技术难点。
相信你也发现了我使用了一个新的html页面Senior.html。这个页面我们是使用的基础篇的index.html制造的。然后我们修改了里面核心js代码。