WKWebViewの使い方

WKWebView

WKWebViewはiOS8から新たに使用できるようになったWebViewで、WebKitFrameworkの中に含まれている。これまでのUIWebViewと比べると速くて高機能とのこと。使用方法は以下の通り。

WKWebViewの初期化

最初に初期化しておく。

private var webView = WKWebView()

各種設定

AutoLayout、Delegateなどの設定をviewDidLoad()で行う。デフォルトではジェスチャーが無効なので、有効にするためにはコードで明示する必要があることに注意が必要である。

    override func viewDidLoad() {
        // Autolayoutを設定
        webView.translatesAutoresizingMaskIntoConstraints = false
        // 親ViewにWKWebViewを追加
        self.view.addSubview(webView)
        // Delegateの設定
        self.webView.UIDelegate = self
        self.webView.navigationDelegate = self
        // WKWebViewを最背面に移動
        self.view.sendSubviewToBack(webView)
        // レイアウトを設定(後述)
        setWebViewLayoutWithConstant(0.0)
        // ジェスチャーを許可
        webView.allowsBackForwardNavigationGestures = true
        // ページのロード
        self.webView.loadRequest(NSURLRequest(URL: NSURL(string: url)!))
    }

終了時

親ビューから削除する。Autolayoutの値もリセットされる。

    override func viewDidDisappear(animated: Bool) {
        webView.removeFromSuperview()
    }

レイアウト設定

WKWebViewは、StoryBoard上で割り付けることが出来ない。他のパーツをStoryBoard上でAutolayout設定している場合は、Swift上でWKWebViewにAutolayout設定を行う。ConstraintはWebViewに対して指定するのではなく、親Viewに対して指定することに注意が必要である。

    func setWebViewLayoutWithConstant(constant: CGFloat){
        // Constraintsを一度削除する
        for constraint in self.view.constraints {
            let secondItem: WKWebView? = constraint.secondItem as? WKWebView
            if secondItem == self.webView {
                self.view.removeConstraint(constraint)
            }
        }
        // Constraintsを追加
        self.view.addConstraint(NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: webView, attribute: NSLayoutAttribute.Width, multiplier: 1.0, constant: 0.0))
        self.view.addConstraint(NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: webView, attribute: NSLayoutAttribute.CenterX, multiplier: 1.0, constant: 0.0))
        self.view.addConstraint(NSLayoutConstraint(item: self.topLayoutGuide, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: webView, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: 0.0))
        self.view.addConstraint(NSLayoutConstraint(item: self.bottomLayoutGuide, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: webView, attribute: NSLayoutAttribute.Bottom, multiplier: 1.0, constant: constant))
    }

以上により、ViewController上でWKWebViewを表示させることができる。goBack()やreload()はUIWebViewと同様に使用できる。

戻るボタンの実装

前のページに戻るためには、goForward()ではなぜかうまく動かなかった。以下のようにするとうまく動く。

let url = webView.backForwardList.forwardItem?.URL
webView.loadRequest(NSURLRequest(URL: url!))

プログレスビューの実装

ページ読み込みの進捗状況を表示するプログレスビューを表示することもできる。プログレスビュー自体のレイアウトや表示位置は、StoryBoard上で設定し、表示処理をSwiftで記述すると簡単である。

    // プログレスビュー描画間隔
    private let timerDur = 0.1

    override func viewDidAppear(animated: Bool) {
        // プログレスビューの描画
        progressView.setProgress(0.0, animated: false)
        progressView.hidden = false
        timer = NSTimer.scheduledTimerWithTimeInterval(timerDur, target: self, selector: "updateProgressView", userInfo: nil, repeats: true)
    }

    override func viewDidDisappear(animated: Bool) {
        if timer?.valid == true {
            timer?.invalidate()
        }
    }

    /**
        プログレスビューを更新する
    */
    func updateProgressView() {
        progressView.setProgress(Float(webView.estimatedProgress), animated: true)
        if webView.estimatedProgress == 1.0 && timer?.valid == true {
            timer?.invalidate()
            progressView.hidden = true
        }
    }

新規タブで開く

WKWebviewでURL読み込み時に任意の処理を実行したい場合には、decidePolicyForNavigationAction関数内に処理を記述する。新規タブで開く(target = _blank)の指定があった場合にデフォルトでは動作しないので、以下の記述が必要である。

if navigationAction.navigationType == WKNavigationType.LinkActivated{
                if targetFrame == nil {
                    webView.loadRequest(NSURLRequest(URL: url))
                }
            }

現在時刻を表示する

タイマーを用いて定期的に実行する

定期的にメソッドを実行するにはNSTimerクラスを利用する。

NSTimer *timer;

まずヘッダファイルでタイマーを定義する。タイマー処理はscheduledTimerWithTimeIntervalを用いる。

timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(tick:) userInfo:nil repeats:YES];

引数は、①呼び出し間隔(秒)②タイマー発火時に呼び出すメソッドのあるオブジェクト③タイマー発火時に呼び出すメソッド④タイマー発火時に呼び出すメソッドに渡す情報⑤繰り返しをするか否かの5項目。@selectorは、メソッド名を記述することでそのメソッドを呼び出すことができる。Objective-Cでは、Selectorを用いることで実行時に動的に呼び出すメソッドを変更できるとのこと。

- (void)viewDidUnload {
	[timer invalidate];
	timer = nil;
}
- (void)dealloc {
	if ( timer)
	[timer invalidate];
	[super dealloc];
}

なおタイマーを停止する際は、invalidateメソッドを使用する。invalidateはreleaseまでしてくれる。

現在時刻を表示する

最後に定期的に呼び出すメソッド内に現在の時刻を取得し、必要な形に整形する処理を記述する。

- (void)tick:(NSTimer *)theTimer {
	// 初期化(init)し現在の時刻を取得する
	NSDate *date = [NSDate date];
	// NSDateFomatter=NSDateの値を整形する
	NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
	[formatter setLocale:[NSLocale currentLocale]];
	// 年月日曜日を全て表示する
	[formatter setDateStyle:NSDateFormatterFullStyle];
	// 時分秒タイムゾーンを全て表示する
	[formatter setTimeStyle:NSDateFormatterFullStyle];
	// Date型からString型に置換する
	NSString *dateStr = [formatter stringFromDate:date];
	// allocしたformatterをreleaseする
	// なおClassObjectである*dateは自動的にメモリ解放されるので記述は不要
	[formatter release];
}

引数のtheTimerは、呼び出し元のタイマー自身を示す。