2014年11月22日土曜日

iOS WebView(UIWebView, WKWebView)をバージョンで分けて利用する

WebView

iOSでWebページを表示させる場合, UIWebViewを利用します. しかし, iOS8から, WKWebViewが登場しました.
WKWebViewは, Safariに搭載されている機能と同様の機能を含んでおり, Safariに似た,機能を利用できます.
またパフォーマンス面でも, WKWebViewは, UIWebViewを上回っています.
ですが, この機能は, WebKit というFrameworkを利用しており, これは, iOS8より利用できるので, iOS7以下ではりようできません そこで, OSのバージョンによりUIWebView, WKWebViewを分ければ, iOS8によりよい機能を提供できるのでは.

サンプル

UIWebView, WKWebViewをハンドルクラスでラップして, iOS7,8で使い分けられるようにする
UIWebViewの機能をベースにする
Delegateは, 外で実装, delegateのセットは内部で行う(WKWebViewは, Navigationのみ)
storyboardを使わずコードのみで実装


サンプルの構成



WebHandler : iOS7, iOS8で, UIWebView, WKWebViewを分ける, 機能もそれぞれ分ける
そのほかのView
カテゴリ : UIWebView+Info.m : UIWebViewで, タイトルや, URLを取得するための拡張機能 コードは, 一部省略しています(AppDelegate.mなど)

UIWebView+Info.h

#import 

@interface UIWebView (Info)

- (NSString *)title;
- (NSString *)URLString;
- (NSURL *)URL;

@end

UIWebView+Info.m

#import "UIWebView+Info.h"

@implementation UIWebView (Info)

- (NSString *)title {
    return [self stringByEvaluatingJavaScriptFromString:@"document.title"];
}

- (NSString *)URLString {
    return [self stringByEvaluatingJavaScriptFromString:@"document.URL"];
}

- (NSURL *)URL {
    return [NSURL URLWithString:self.URLString];
}

@end


WebHandler.h

#import 
#import 

typedef void (^CompletionBlock)(id, NSError*);

@interface WebHandler : NSObject

- (id)webView;
- (void)layout:(CGRect)frame;
- (void)setDelegate:(id)delegate;
- (void)clean;

// Load
- (void)loadRequest:(NSURLRequest *)request;
- (void)loadURL:(NSString *)url;
- (void)stopLoading;

// Web history
- (void)goBack;
- (void)goForward;
- (BOOL)canGoBack;
- (BOOL)canGoForward;
- (BOOL)isLoading;

// JavaScript
- (void)stringByEvaluatingJavaScriptFromString:(NSString *)javascript completion:(CompletionBlock)completion;

// Info
- (NSString *)title;
- (NSURL *)URL;

@end


WebHandler.m

#import "WebHandler.h"
#import 
#import "UIWebView+Info.h"

@interface WebHandler()

@property (nonatomic) UIWebView *uiwebView;
@property (nonatomic) WKWebView *wkwebView;
@property (nonatomic) BOOL ios8;

@end

@implementation WebHandler

- (id)init {
    if (self = [super init]) {
        self.ios8 = [WKWebView class] != nil;
        if (self.ios8) {
            self.wkwebView = [[WKWebView alloc] init];
        }
        else {
            self.uiwebView = [[UIWebView alloc] init];
        }
    }
    return self;
}

- (id)webView {
    if (self.ios8) {
        return self.wkwebView;
    }
    return self.uiwebView;
}

- (void)layout:(CGRect)frame {
    if (self.ios8) {
        self.wkwebView.frame = frame;

    }
    else {
        self.uiwebView.frame = frame;
    }
}

- (void)setDelegate:(id)delegate {  // This is for Navigation Delegate
    if (self.ios8) {
        self.wkwebView.navigationDelegate = delegate;
    }
    else {
        self.uiwebView.delegate = delegate;
    }
}

- (void)setUIDelegate:(id)delegate {  // This is for only ios8
    if (self.ios8) {
        self.wkwebView.UIDelegate = delegate;
    }
}

- (void)clean {
    if (self.ios8) {
        self.wkwebView.navigationDelegate = nil;
    }
    else {
        self.uiwebView.delegate = nil;
    }
    
    if ([self isLoading]) {
        [self stopLoading];
    }
}


#pragma mark - Common Features

/*
 * Load
 */
- (void)loadRequest:(NSURLRequest *)request {
    if (self.ios8) {
        [self.wkwebView loadRequest:request];
    }
    else {
        [self.uiwebView loadRequest:request];
    }
}

- (void)loadURL:(NSString *)url {
    [self loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];
}

- (void)stopLoading {
    if (self.ios8) {
        [self.wkwebView stopLoading];
    }
    else {
        [self.uiwebView stopLoading];
    }
}

/*
 *  History
 */
- (void)goBack {
    if (self.ios8) {
        [self.wkwebView goBack];
    }
    else {
        [self.uiwebView goBack];
    }
}

- (void)goForward {
    if (self.ios8) {
        [self.wkwebView goForward];
    }
    else {
        [self.uiwebView goForward];
    }
}

- (BOOL)canGoBack {
    if (self.ios8) {
        return [self.wkwebView canGoBack];
    }
    else {
        return [self.uiwebView canGoBack];
    }
}

- (BOOL)canGoForward {
    if (self.ios8) {
        return [self.wkwebView canGoForward];
    }
    else {
        return [self.uiwebView canGoForward];
    }
}

- (BOOL)isLoading {
    if (self.ios8) {
        return [self.wkwebView isLoading];
    }
    else {
        return [self.uiwebView isLoading];
    }
}

// goToBackForwardListItem is only for iOS8 WKWebView

#pragma mark - JavaScript
- (void)stringByEvaluatingJavaScriptFromString:(NSString *)javascript completion:(CompletionBlock)completion {
    if (self.ios8) {
        [self.wkwebView evaluateJavaScript:javascript completionHandler:completion];
    }
    else {
        [self.uiwebView stringByEvaluatingJavaScriptFromString:javascript];
    }
}


#pragma mark - Info
/*
 * Info
 */
- (NSString *)title {
    if (self.ios8) {
        return [self.wkwebView title];
    }
    else {
        return [self.webView title];
    }
}

- (NSURL *)URL {
    if (self.ios8) {
        return [self.wkwebView URL];
    }
    else {
        return [self.webView URL];
    }
}
@end


UIHeaderView.h

#import 

@interface UIHeaderView : UIView

@property (nonatomic) UILabel *titleLabel;

@end


UIHeaderView.m

#import "UIHeaderView.h"

@implementation UIHeaderView

- (id)init {
    if(self = [super init]) {
        [self setBackgroundColor:[UIColor grayColor]];
        
        self.titleLabel = [[UILabel alloc] init];
        [self.titleLabel setTextColor:[UIColor whiteColor]];
        [self.titleLabel setTextAlignment:NSTextAlignmentCenter];
        [self addSubview:self.titleLabel];
    }
    return self;
}

- (void)layoutSubviews {
    self.titleLabel.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
}

@end


UIFooterView.h

import 

@interface UIFooterView : UIView

@property (nonatomic) UIButton *backButton;
@property (nonatomic) UIButton *forwardButton;

@end


UIFooterView.m

#import "UIFooterView.h"

#define kBUTTONSIZE 80

@implementation UIFooterView

- (id)init {
    if(self = [super init]) {
        [self setBackgroundColor:[UIColor grayColor]];
        self.backButton = [[UIButton alloc] init];
        [self.backButton setTitle:@"Back" forState:UIControlStateNormal];
        [self.backButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
        
        self.forwardButton = [[UIButton alloc] init];
        [self.forwardButton setTitle:@"Forward" forState:UIControlStateNormal];
        [self.forwardButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
        
        [self addSubview:self.backButton];
        [self addSubview:self.forwardButton];
    }
    return self;
}

- (void)layoutSubviews {
    CGRect viewRect = self.frame;
    self.backButton.frame = CGRectMake(0, 0, kBUTTONSIZE, viewRect.size.height);
    self.forwardButton.frame = CGRectMake(0 + kBUTTONSIZE + 10, 0, kBUTTONSIZE, viewRect.size.height);
}
@end


ViewController.h

#import 
#import 

@interface ViewController : UIViewController

@end

ViewController.m

#import "ViewController.h"
#import "WebHandler.h"
#import "UIHeaderView.h"
#import "UIFooterView.h"

#define kHEADERHEIGHT 44
#define kFOOTERHEIGHT 44

@interface ViewController ()

@property (nonatomic) WebHandler *webhandler;
@property (nonatomic) UIHeaderView *header;
@property (nonatomic) UIFooterView *footer;
@property (nonatomic) int webCount;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    
    // Web
    self.webhandler = [[WebHandler alloc] init];
    [self.webhandler setDelegate:self];
    
    self.webCount = 0;
    
    // Header
    self.header = [[UIHeaderView alloc] init];
    
    // Footer
    self.footer = [[UIFooterView alloc] init];
    [self.footer.backButton addTarget:self action:@selector(backClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.footer.forwardButton addTarget:self action:@selector(forwardClick:) forControlEvents:UIControlEventTouchUpInside];
    
    [self.view addSubview:self.header];
    [self.view addSubview:self.webhandler.webView];
    [self.view addSubview:self.footer];
    
    [self.webhandler loadURL:@"http://google.com.sg"];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
   
    if (self.isViewLoaded && [self.view window] == nil) {
        [self dispose];
        self.view = nil;
    }
}

- (void)dealloc {
    [self dispose];
}

- (void)dispose {
    if (self.webhandler != nil) {
        [self.webhandler clean];
    }
}

- (void) viewWillLayoutSubviews {
    
    // Calculate layout
    CGRect viewRect = self.view.frame;
    self.header.frame = CGRectMake(viewRect.origin.x,
                                   viewRect.origin.y,
                                   viewRect.size.width,
                                   kHEADERHEIGHT);
    [self.webhandler layout:CGRectMake(viewRect.origin.x,
                                      viewRect.origin.y + kHEADERHEIGHT,
                                      viewRect.size.width,
                                      viewRect.size.height - kHEADERHEIGHT - kFOOTERHEIGHT)];
    
    self.footer.frame = CGRectMake(viewRect.origin.x,
                                   viewRect.origin.y + viewRect.size.height - kFOOTERHEIGHT,
                                   viewRect.size.width,
                                   kFOOTERHEIGHT);
    
}

#pragma mark - UIWebViewDelegate(iOS7)
- (void)webViewDidStartLoad:(UIWebView *)webView {
    // Start Loading
    NSLog(@"Start iOS7");
    self.webCount++;
}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    self.webCount--;
    if (self.webCount == 0) {
        NSLog(@"Finish iOS7");
        [self.header.titleLabel setText:[self.webhandler title]];
    }
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
    NSLog(@"Erorr iOS7");
}

#pragma mark - WKWebViewDelegate(iOS8)
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
    NSLog(@"Start iOS8");
}

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    [self.header.titleLabel setText:[self.webhandler title]];
    NSLog(@"title %@", [self.webhandler title]);
    NSLog(@"Finish iOS8");
}

- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
    NSLog(@"Error iOS8");
}

#pragma mark - Button Click
- (void)backClick:(id)sender {
    if ([self.webhandler canGoBack]) {
        [self.webhandler goBack];
    }
}

- (void)forwardClick:(id)sender {
    if ([self.webhandler canGoForward]) {
        [self.webhandler goForward];
    }
}
@end


実行結果

iOS7, iOS8 ともに, 同じ結果が得られます


リファレンス

NS(WKWebView)
Professional Programmer

0 件のコメント:

コメントを投稿