WKWebView基類封裝
項(xiàng)目一直使用UIWebView捉兴,相關(guān)基類方法封裝使用比較完善钓觉,業(yè)務(wù)量重,想整體替換為WKWebView有點(diǎn)難度肢娘,需要時(shí)間完善。所以我在自己的demo中初步封裝了WKWebView舆驶,參考原有的項(xiàng)目的UIWebView橱健。
BaseViewController
由于后續(xù)導(dǎo)航欄返回事件需要處理,自定義BaseViewController沙廉,自定義返回方法拘荡。代碼如下:
- (void)viewDidLoad {
? ? [super viewDidLoad];
? ? [self setBaseView];
}
- (void)setBaseView{
? ? UIBarButtonItem *item = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:@"title_new_back"] style:UIBarButtonItemStylePlain target:self action:@selector(backButtonAction:)];
? ? NSInteger index = [self.navigationController.viewControllers indexOfObject:self];
? ? if (index != 0) {
? ? ? ? self.navigationItem.leftBarButtonItem = item;
? ? }
}
- (void)backButtonAction:(UIBarButtonItem *)item{
? ? Class backController = NSClassFromString(self.backController);
? ? NSArray *reverseArray = [[self.navigationController.viewControllers reverseObjectEnumerator] allObjects];
? ? if (!self.backController) {
? ? ? ? [self.navigationController popViewControllerAnimated:YES];
? ? }else {
? ? ? ? for (UIViewController *controller in reverseArray) {
? ? ? ? ? ? if ([controller isKindOfClass:backController]) {
? ? ? ? ? ? ? ? [self.navigationController popToViewController:controller animated:YES];
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
viewdidload中設(shè)置導(dǎo)航欄,leftBarButtonItem的設(shè)置圖片撬陵,對(duì)應(yīng)點(diǎn)擊方法定義珊皿。
BaseWKWebViewController
然后我的BaseWKWebViewController基于BaseViewController創(chuàng)建。在.h定義幾個(gè)參數(shù)代碼如下:
/**
*@briefwkWebview
*/
@property (nonatomic, strong) WKWebView? ? ? ? ? ? ? ? *wkWebView;
/**
*@briefwkConfiguration配置
*/
@property (nonatomic, strong) WKWebViewConfiguration? ? *wkConfiguration;
/**
*@briefwebUrl
*/
@property (nonatomic, copy) NSString? ? ? ? ? ? ? ? ? ? *urlString;
對(duì)應(yīng)的webView巨税,wkWebView一些屬性設(shè)置值蟋定,加載url的地址。
然后在.m中創(chuàng)建webView草添,其中有一點(diǎn)需要注意:方法重名問題驶兜。當(dāng)初我再父類BaseViewController中和BaseWKWebView中都用setUpUi這個(gè)方法,結(jié)果父類的方法就失效了果元,被子類覆蓋了促王。所以子類創(chuàng)建視圖的方法調(diào)整為setBaseWK犀盟,具體代碼如下:
- (void)viewDidLoad {
? ? [super viewDidLoad];
? ? [self setBaseWK];
}
- (void)setBaseWK{
? ? if (!self.wkConfiguration) {
? ? ? ? self.wkConfiguration = [[WKWebViewConfiguration alloc]init];
? ? ? ? //設(shè)置一些屬性
? ? }
? ? self.wkWebView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) configuration:self.wkConfiguration];
? ? self.wkWebView.UIDelegate = self;
? ? self.wkWebView.navigationDelegate = self;
? ? self.wkWebView.allowsBackForwardNavigationGestures = YES;
? ? [self.view addSubview:self.wkWebView];
? ? [self.wkWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.urlString]]];
? ? [self.wkWebView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
}
創(chuàng)建WKWebView而晒,設(shè)置它的兩個(gè)代理:UIDelegate和navigationDelegate。代理方法稍后再講阅畴。allowsBackForwardNavigationGestures這個(gè)屬性是控制webView側(cè)滑返回的倡怎,默認(rèn)是NO,設(shè)置為YES后贱枣,web頁(yè)面能像原生頁(yè)面一樣策劃返回了监署。然后將webView加到當(dāng)前視圖,加載對(duì)應(yīng)的url地址纽哥。最后是網(wǎng)上看到的方法钠乏,利用KVO設(shè)置WKWebView的title,相比較UIWebView的設(shè)置這個(gè)有一絲繁瑣春塌,具體代碼稍后提及晓避。
UIDelegate
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{
在這個(gè)方法中寫如下代碼:
if (!navigationAction.targetFrame.isMainFrame) {
? ? ? ? [webView loadRequest:navigationAction.request];
? ? }
? ? return nil;
WKNavigationDelegate
這個(gè)代理里面寫了三個(gè)方法:
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
didFinishNavigation就是完成加載webView時(shí)候的方法簇捍。后面兩個(gè)對(duì)應(yīng)UIWebView中的shouldLoad,將要加載方法俏拱。WK中分為請(qǐng)求發(fā)起前即navigationAction和接口請(qǐng)求相應(yīng)后navigationResponse暑塑。對(duì)面方法下面允許加載,不然url不會(huì)跳轉(zhuǎn)锅必。
KVO設(shè)置WKWebView的title
代碼如下:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
? ? if ([keyPath isEqualToString:@"title"]) {
? ? ? ? if (object == self.wkWebView) {
? ? ? ? ? ? self.title = self.wkWebView.title;
? ? ? ? }else {
? ? ? ? ? ? [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
? ? ? ? }
? ? }else {
? ? ? ? [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
? ? }
}
- (void)dealloc{
? ? [self.wkWebView removeObserver:self forKeyPath:@"title"];
}
注意在dealloc中移除KVO事格。
返回問題
重寫父類的backButton方法:
- (void)backButtonAction:(UIBarButtonItem *)item{
? ? if ([self.wkWebView canGoBack]) {
? ? ? ? [self.wkWebView goBack];
? ? }else {
? ? ? ? [self.navigationController popViewControllerAnimated:YES];
? ? }
}
當(dāng)web頁(yè)面多次進(jìn)入跳轉(zhuǎn)新頁(yè)面后,為了防止逐級(jí)返回搞隐,參考老項(xiàng)目做了close按鈕操作驹愚。當(dāng)判斷當(dāng)前頁(yè)面是要做回退跳轉(zhuǎn)的時(shí)候,在左上角增加關(guān)閉當(dāng)前web控制器的按鈕劣纲。代買如下:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
? ? if (navigationAction.navigationType == WKNavigationTypeBackForward) {
? ? ? ? [self addCloseItemAction];
? ? }
- (void)addCloseItemAction{
? ? if (self.navigationItem.leftBarButtonItems.count<2) {
? ? ? ? UIButton* closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
? ? ? ? [closeButton setImage:[UIImage imageNamed:@"title_new_close"] forState:UIControlStateNormal];
? ? ? ? closeButton.frame = CGRectMake(0, 0, 30, 30);
? ? ? ? [closeButton addTarget:self action:@selector(closeWeb) forControlEvents:UIControlEventTouchUpInside];
? ? ? ? UIBarButtonItem* closeBarItem = [[UIBarButtonItem alloc] initWithCustomView:closeButton];
? ? ? ? self.navigationItem.leftBarButtonItems = @[self.navigationItem.leftBarButtonItem,closeBarItem];
? ? }
}
- (void)closeWeb{
? ? [self.navigationController popToRootViewControllerAnimated:YES];
}
這樣返回操作就得到了優(yōu)化么鹤。
WKTestWebViewController
最后我用WKTestWebViewController基于WKWebViewController創(chuàng)建相關(guān)web頁(yè)面對(duì)之前代碼進(jìn)行校驗(yàn),返現(xiàn)能夠跳轉(zhuǎn)味廊,但是在WKTestWebViewController中如果再寫UIDelegate和NavigationDelegate的時(shí)候蒸甜,發(fā)現(xiàn)父類的方法又被覆蓋了,所以將父類實(shí)現(xiàn)的wk代理方法代理出來余佛。對(duì)WKWebViewController做操作:在.h中添加代理柠新,對(duì)應(yīng).m實(shí)現(xiàn)代碼如下:
.h添加代理
@protocol GFWKWebViewDelegate;
@interface BaseWKWebViewController : BaseViewController
/**
*@briefGFwkWebDelegate
*/
@property (nonatomic, weak) id? ? wkWebDelegate;
@end
@protocol GFWKWebViewDelegate
@optional
//wkUIDelegate
- (WKWebView *)GF_webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;
//wkNavigationDelegate
- (void)GF_webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
- (void)GF_webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
- (void)GF_webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
@end
.m實(shí)現(xiàn)代理
UIDelegate
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{
? ? if (self.wkWebDelegate && [self.wkWebDelegate respondsToSelector:@selector(GF_webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:)]) {
? ? ? ? [self.wkWebDelegate GF_webView:webView createWebViewWithConfiguration:configuration forNavigationAction:navigationAction windowFeatures:windowFeatures];
? ? }
NavigationDelegate
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
? ? if (self.wkWebDelegate && [self.wkWebDelegate respondsToSelector:@selector(GF_webView:didFinishNavigation:)]) {
? ? ? ? [self.wkWebDelegate GF_webView:webView didFinishNavigation:navigation];
? ? }
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
? ? if (self.wkWebDelegate && [self.wkWebDelegate respondsToSelector:(@selector(GF_webView:decidePolicyForNavigationAction:decisionHandler:))]) {
? ? ? ? [self.wkWebDelegate GF_webView:webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler];
? ? }
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
? ? decisionHandler(WKNavigationResponsePolicyAllow);
? ? if (self.wkWebDelegate && [self.wkWebDelegate respondsToSelector:@selector(GF_webView:decidePolicyForNavigationResponse:decisionHandler:)]) {
? ? ? ? [self.wkWebDelegate GF_webView:webView decidePolicyForNavigationResponse:navigationResponse decisionHandler:decisionHandler];
? ? }
}
這樣四個(gè)方法都實(shí)現(xiàn)了,其實(shí)只要實(shí)現(xiàn)子類用到的方法就好了辉巡。當(dāng)然如果父類在做統(tǒng)一設(shè)置恨憎,實(shí)現(xiàn)了相關(guān)wk代理的方法,需要后續(xù)再完善郊楣。
代理使用
在WKTestWebViewController使用父類設(shè)置的代理憔恳,頭文件中引入代理,設(shè)置代理等于self净蚤,對(duì)應(yīng)代理方法調(diào)整钥组,代碼如下:
@interface WKTestWebViewController ()<GFWKWebViewDelegate>
@end
@implementation WKTestWebViewController
- (void)viewDidLoad {
? ? [super viewDidLoad];
? ? [self setTestWK];
}
- (void)setTestWK{
? ? self.wkWebDelegate = self;
}
#pragma mark GFWKWebView UIDelegate
- (void)GF_webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
? ? NSLog(@"%ld", (long)navigationAction.navigationType);
//? ? decisionHandler(WKNavigationActionPolicyAllow);
}
注意子類代理方法中不能在寫decisionHandler(WKNavigationActionPolicyAllow),不然報(bào)錯(cuò)重復(fù)decisionHandler今瀑。這樣就能在實(shí)現(xiàn)父類返回關(guān)閉功能以及未來需要統(tǒng)一增加的功能同時(shí)程梦,還能完成具體子類個(gè)性化處理。
總結(jié)
如上就是我對(duì)WKWebView相關(guān)認(rèn)識(shí)橘荠,期間的父類子類重名問題卡了一段時(shí)間屿附,后續(xù)功能方法的優(yōu)化需要再實(shí)踐中逐步完善。