【Swift|ObjC 】 UIWebViewをWKWebViewで置き換える方法

Developer News And Updates に2019年12月23日、UIWebViewは廃止され、今後、UIWebViewが使われているアプリは受付されないという記事が投稿されました。このブログでも次の記事に書きました。

今後はWKWebViewやSFSafariViewControllerを使用することが推奨されています。今回はUIWebViewからWKWebViewに置き換えるために、どのようなコードが書けるかをまとめました。

また、WKWebViewについてのその他の関連記事をこのブログに追加しています。この記事末の関連記事をご覧ください。

目次

ページの読み込み

URLの読み込み

UIWebViewでURLを読み込む処理は次のようなコードです。

// Swift版
// UIWebView用
func load(url: URL) {
 let request = URLRequest(url: url)
 uiWebView.loadRequest(request)
}
// Objective-C版
// UIWebView用
- (void)loadWithURL:(NSURL *)url {
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [self.uiWebView loadRequest:request];
}

WKWebViewもURLを読み込むコードは同じです。

// Swift版
// WKWebView用
func load(url: URL) {
    let request = URLRequest(url: url)
    wkWebView.load(request)
}
// Objective-C版
// WKWebView用
#import <WebKit/WebKit.h>

- (void)loadWithURL:(NSURL *)url {
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [self.wkWebView loadRequest:request];
}

ローカルHTMLの表示

UIWebViewで文字列渡しでローカルHTMLを表示するコードは次のようになります。

// Swift版
uiWebView.loadHTMLString(html, baseURL: baseURL)
// Objective-C版
[self.uiWebView loadHTMLString:html
                       baseURL:baseURL];

WKWebViewの場合は次のようなコードです。WKWebViewの方は戻り値があるくらいの違いです。

// Swift版
_ = wkWebView.loadHTMLString(html, baseURL: baseURL)
// Objective-C版
[self.wkWebView loadHTMLString:html
                       baseURL:baseURL]

JavaScriptを実行する

UIWebViewでJavaScriptを実行するコードは次のようになります。

// Swift版
let result = uiWebView.stringByEvaluatingJavaScript(from: script)
// Objective-C版
id result = [self.uiWebView stringByEvaluatingJavaScriptFromString:script];

WKWebViewの場合は次のようなコードになります。

// Swift版
wkWebView.evaluateJavaScript(script) { (result, error) in

}
// Objective-C版
NSString *script = @"document.title";
[self.wkWebView evaluateJavaScript:script completionHandler:^(id _Nullable result, NSError * _Nullable error) {

}];

UIWebViewは同期処理になっていて、JavaScriptの実行が完了してからアプリに制御が戻ります。

WKWebViewの方は非同期処理になっていて、JavaScriptの実行が完了すると、指定したブロックが実行されます。

順番にJavaScriptを実行していくような処理は、完了ブロックで次のJavaScriptを実行していくように変更します。

ページの読み込み開始時と終了時に処理を行う

UIWebViewでは、UIWebViewDelegateプロトコルに適合させたクラスを実装して、処理を実装します。

// Swift版
import UIKit

class ViewController: UIViewController, UIWebViewDelegate {
    
    @IBOutlet var uiWebView: UIWebView!

    override func viewDidLoad() {
        super.viewDidLoad()        
        uiWebView.delegate = self
        
        load(url: URL(string: "http://www.example.com")!)
    }

    func load(url: URL) {
        let request = URLRequest(url: url)
        uiWebView.loadRequest(request)
    }
    
    /// ページの読み込み開始時に呼ばれる
    func webViewDidStartLoad(_ webView: UIWebView) {
        print("Start Loading Page")
    }
    
    /// ページの読み込み完了時に呼ばれる
    func webViewDidFinishLoad(_ webView: UIWebView) {
        print("Finish Loading Page")
    }
    
    /// 読み込みエラー発生時に呼ばれる
    func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
        print("Failed Loading Page: \(error)")
    }
}
// Objective-C版
#import "ViewController.h"

@interface ViewController () <UIWebViewDelegate>

@end

@implementation ViewController
@synthesize uiWebView = _uiWebView;

- (void)viewDidLoad {
    [super viewDidLoad];
    self.uiWebView.delegate = self;
    
    [self loadWithURL:[NSURL URLWithString:@"https://www.example.com"]];
}

- (void)loadWithURL:(NSURL *)url {
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [self.uiWebView loadRequest:request];
}

/// ページの読み込み開始時に呼ばれる
- (void)webViewDidStartLoad:(UIWebView *)webView {
    NSLog(@"Start Loading Page");
}

/// ページの読み込み完了時に呼ばれる
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    NSLog(@"Finish Loading Page");
}

/// 読み込みエラー発生時に呼ばれる
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
    NSLog(@"Failed Loading Page: %@", error.localizedDescription);
}

@end

WKWebViewの場合は、WKNavigationDelegateプロトコルに適合させたクラスを実装して、処理を実装します。

WKNavigationDelegateプロトコルの方が少し細かい単位になっています。ページの読み込み処理を開始と内容受信が分かれています。例えば、接続出来ないURLが指定されたときに、 webView(_: didStartProvisionalNavigation:) メソッドは呼ばれますが、 webView(_: didCommit:) は呼ばれないという動作になります。

// Swift版
import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate {
    
    @IBOutlet var wkWebView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        wkWebView.navigationDelegate = self
        load(url: URL(string: "https://www.example.com/")!)
    }

    func load(url: URL) {
        let request = URLRequest(url: url)
        wkWebView.load(request)
    }
    
    /// ページの読み込み開始時に呼ばれる
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        print("Start Provisional Navigation")
    }
    
    /// ページの内容受信開始時に呼ばれる
    func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
        print("Did Commit")
    }
    
    /// ページの読み込み完了時に呼ばれる
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        print("Did Finish")
    }
    
    /// ページの読み込みエラー発生時に呼ばれる
    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        print("Did Fail Provisional Navigation")
    }
}
// Objective-C版
#import "ViewController.h"

@interface ViewController () <WKNavigationDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.wkWebView.navigationDelegate = self;
    [self loadWithURL:[NSURL URLWithString:@"https://www.example.com"]];
}

- (void)loadWithURL:(NSURL *)url {
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [self.wkWebView loadRequest:request];
}

/// ページの読み込み開始時に呼ばれる
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
    NSLog(@"Start Provisional Navigation");
}

/// ページの内容受信開始時に呼ばれる
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
    NSLog(@"Did Commit");
}

/// ページの読み込み完了時に呼ばれる
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    NSLog(@"Did Finish");
}

/// ページの読み込みエラー発生時に呼ばれる
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
    NSLog(@"Did Fail Provisional Navigation");
}

@end

まとめ

UIWebViewとWKWebViewを比較すると、WKWebViewの方が機能が多く、デリゲートメソッドも多いため、もっと細かく制御出来る印象です。UIWebViewが使えなくなっても困らないと思います。

関連性が高い記事

WKWebViewに関連するその他の記事です。

著書紹介

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

Akira Hayashi (林 晃)のアバター Akira Hayashi (林 晃) Representative(代表), Software Engineer(ソフトウェアエンジニア)

アールケー開発代表。Appleプラットフォーム向けの開発を専門としているソフトウェアエンジニア。ソフトウェアの受託開発、技術書執筆、技術指導・セミナー講師。note, Medium, LinkedIn
-
Representative of RK Kaihatsu. Software Engineer Specializing in Development for the Apple Platform. Specializing in contract software development, technical writing, and serving as a tech workshop lecturer. note, Medium, LinkedIn

目次