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.
これに対応するには
-
https://
も用意する - httpしか用意されていないドメインをATSのホワイトリストに入れる
- 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側も実装をほとんど変えずに対応できますよ。