UIWebViewでhttpなURLにアクセスしようとしたら代わりにSFSafariViewControllerで開くようにする

  • 47
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

ATS対応におけるホワイトリスト問題

iOS 9からATSが導入され、UIWebViewで http:// で始まるURLにアクセスしようとすると、以下のようなエラーメッセージが出てしまいサイトを表示することができなくなりました。

App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.

これに対応するには

  1. https:// も用意する
  2. httpしか用意されていないドメインをATSのホワイトリストに入れる
  3. ATSを無効にする

といった手が考えられるのですが、3はやりたくないし、管理下にない外部のサイトを表示している場合は1はできないし、消去法で2になるかと思います。

でも、外部のサイトがそこから先どんなURLへリンクしているかをすべて把握できるはずもなく、表示する可能性があるけどhttpしか用意されていないサイトをすべてリストアップできない、という問題があります。

解決策

まずATSは有効にします。その上で、UIWebViewで https:// 以外のURLにアクセスしようとした場合、エラーが出る前にUIWebViewDelegateの webView:shouldStartLoadWithRequest: で捕まえられるので、そこでSFSafariViewControllerを開いてしまいます。

以下のコードを実行して、GoogleからHTTPS対応していないサイト(例えば http://bricklife.com/ とか…)へ行ってみると挙動を確認できます。ここではiOS 9未満ではSafariを開くようにしましたが、この辺はアプリの要件に応じて工夫するとよいでしょう。

#import "ViewController.h"

#import <SafariServices/SafariServices.h>

@interface ViewController () <UIWebViewDelegate>

@property (weak, nonatomic) IBOutlet UIWebView *webView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.webView.delegate = self;

    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.google.co.jp/"]];
    [self.webView loadRequest:request];
}

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSURL *url = request.URL;
    NSLog(@"%@", url);

    if ([url.scheme isEqualToString:@"https"]) {
        return YES;
    }

    if ([SFSafariViewController class]) {
        SFSafariViewController *vc = [[SFSafariViewController alloc] initWithURL:url];
        [self presentViewController:vc animated:YES completion:nil];
    } else {
        [[UIApplication sharedApplication] openURL:url];
    }

    return NO;
}

@end

「表示UIをデザインしたい」「ネイティブ側と連携させたい」などの理由から自サイトはUIWebViewで表示したいけど、そこからリンクを貼られている外部のサイトは必ずしもUIWebViewで表示する必要がない場合、これが解決策としては簡単でいいかなと思います。特に既存アプリをiOS 9対応する場合、ネイティブ側もHTML側も実装をほとんど変えずに対応できますよ。