WKWebViewでJavaScript(Alert,Confirm,Prompt)の処理


WKWebViewは自分で`WKUIDelegate`を指定してコードを書かない限り以下のような画面は表示されず、JavaScriptからの要求を無視します。

![wkwebview_uidelegate.png](https://qiita-image-store.s3.amazonaws.com/0/8920/10b5bdc6-739b-121a-4ca6-4751257f0c2a.png)


左から、JavaScriptの`alert`,`confirm`,`prompt`が実行された時の画面です。

以下WKUIDelegateのみを使うことを目的としたコードを記します。

iOS8であればXcodeで新規作成時に`Single View Application`テンプレートを作成し、`ViewController.m`にコピペするだけで動きますのでお試しください。

```objc
//
//  ViewController.m
//  MyWKWebView
//
//  Created by FukuyamaShingo on 9/22/14.
//  Copyright (c) 2014 Shingo Fukuyama. All rights reserved.
//

#import "ViewController.h"
#import <WebKit/WebKit.h>

@interface ViewController ()
<WKUIDelegate>
@property (nonatomic, strong) WKWebView *webView;
@property (nonatomic, strong) UIToolbar *toolbar;
@property (nonatomic, strong) UIBarButtonItem *buttonForAlert;
@property (nonatomic, strong) UIBarButtonItem *buttonForConfirm;
@property (nonatomic, strong) UIBarButtonItem *buttonForPrompt;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    /*
     * Setup WKWebView only for WKUIDelegate
     */
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    _webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
    _webView.UIDelegate = self;
    NSString *urlString = @"https://www.google.com";
    NSURL *url = [NSURL URLWithString:urlString];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [_webView loadRequest:request];
    
    
    /*
     * Setup Toolbar
     */
    _buttonForAlert = [[UIBarButtonItem alloc] initWithTitle:@"Alert"
                                                       style:UIBarButtonItemStylePlain
                                                      target:self
                                                      action:@selector(showAlert:)];
    _buttonForConfirm = [[UIBarButtonItem alloc] initWithTitle:@"Confirm"
                                                         style:UIBarButtonItemStylePlain
                                                        target:self
                                                        action:@selector(showConfirm:)];
    _buttonForPrompt = [[UIBarButtonItem alloc] initWithTitle:@"Prompt"
                                                        style:UIBarButtonItemStylePlain
                                                       target:self
                                                       action:@selector(showPrompt:)];
    _buttonForAlert.width   = 80.0;
    _buttonForConfirm.width = 80.0;
    _buttonForPrompt.width  = 80.0;
    _toolbar = [[UIToolbar alloc] initWithFrame:CGRectZero];
    UIBarButtonItem *spacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
                                                                            target:nil
                                                                            action:nil];
    _toolbar.items = @[_buttonForAlert, spacer, _buttonForConfirm, spacer, _buttonForPrompt];
    
    [self.view addSubview:_webView];
    [self.view addSubview:_toolbar];
    [self setupConstraints];
}

- (void)showAlert:(UIBarButtonItem *)sender
{
    NSString *promptCode = @"alert('Alertが押されました');";
    [_webView evaluateJavaScript:promptCode completionHandler:^(id object, NSError *error) { }];
}

- (void)showConfirm:(UIBarButtonItem *)sender
{
    NSString *promptCode = @"var confirmed = confirm('OK?');";
    [_webView evaluateJavaScript:promptCode completionHandler:^(id object, NSError *error) { }];
}

- (void)showPrompt:(UIBarButtonItem *)sender
{
    NSString *promptCode = @"var person = prompt('名前を入力してください', 'デフォルト');";
    [_webView evaluateJavaScript:promptCode completionHandler:^(id object, NSError *error) { }];
}


#pragma mark - WKUIDelegate

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)())completionHandler
{
    NSString *hostString = webView.URL.host;
    NSString *sender = [NSString stringWithFormat:@"%@からの表示", hostString];
    
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:sender preferredStyle:UIAlertControllerStyleAlert];
    
    [alertController addAction:[UIAlertAction actionWithTitle:@"閉じる" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
        completionHandler();
    }]];
    [self presentViewController:alertController animated:YES completion:^{}];
}

- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *))completionHandler
{
    NSString *hostString = webView.URL.host;
    NSString *sender = [NSString stringWithFormat:@"%@からの表示", hostString];
    
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:sender preferredStyle:UIAlertControllerStyleAlert];
    [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
        //textField.placeholder = defaultText;
        textField.text = defaultText;
    }];
    [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
        NSString *input = ((UITextField *)alertController.textFields.firstObject).text;
        completionHandler(input);
    }]];
    [alertController addAction:[UIAlertAction actionWithTitle:@"キャンセル" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
        completionHandler(nil);
    }]];
    [self presentViewController:alertController animated:YES completion:^{}];
}

- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler
{
    NSString *hostString = webView.URL.host;
    NSString *sender = [NSString stringWithFormat:@"%@からの表示", hostString];
    
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:sender preferredStyle:UIAlertControllerStyleAlert];
    [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
        completionHandler(YES);
    }]];
    [alertController addAction:[UIAlertAction actionWithTitle:@"キャンセル" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
        completionHandler(NO);
    }]];
    [self presentViewController:alertController animated:YES completion:^{}];
}


#pragma mark - Constraints

- (void)setupConstraints
{
    _webView.translatesAutoresizingMaskIntoConstraints = NO;
    [_webView.superview addConstraints:[NSLayoutConstraint
                                        constraintsWithVisualFormat:@"V:|-20.0-[view]-44.0-|"
                                        options:NSLayoutFormatDirectionLeadingToTrailing
                                        metrics:nil
                                        views:@{@"view":_webView}]];
    [_webView.superview addConstraints:[NSLayoutConstraint
                                        constraintsWithVisualFormat:@"H:|-0-[view]-0-|"
                                        options:NSLayoutFormatDirectionLeadingToTrailing
                                        metrics:nil
                                        views:@{@"view":_webView}]];
    
    _toolbar.translatesAutoresizingMaskIntoConstraints = NO;
    [_toolbar.superview addConstraints:[NSLayoutConstraint
                                        constraintsWithVisualFormat:@"V:[view]-0-|"
                                        options:NSLayoutFormatDirectionLeadingToTrailing
                                        metrics:nil
                                        views:@{@"view":_toolbar}]];
    [_toolbar.superview addConstraints:[NSLayoutConstraint
                                        constraintsWithVisualFormat:@"H:|-0-[view]-0-|"
                                        options:NSLayoutFormatDirectionLeadingToTrailing
                                        metrics:nil
                                        views:@{@"view":_toolbar}]];
    [_toolbar.superview addConstraint:[NSLayoutConstraint constraintWithItem:_toolbar
                                                               attribute:NSLayoutAttributeHeight
                                                               relatedBy:NSLayoutRelationEqual
                                                                  toItem:nil
                                                               attribute:0
                                                              multiplier:1.0
                                                                constant:44.0]];
    
}

@end

```

Alert地獄のサイトを回避するために"このページではこれ以上表示しない"などの対策も必要かと思います。

PR: iOS8向けのブラウザアプリを2つほど公開しますので、よろしくお願い致します。
ブログ: http://fukuyama.co/two-app-before-application