WebViewDelegateでリンク先の判別〜フックとはなんぞや〜
「フック」「奪う」とかよくわからん表現で、
今でも実際ちゃんと理解できているのかよくわかっていないけど
WebView内のリンククリックをしたときに、
その挙動を一旦こちらで制御するということができます。
これにより、ボタンの判別を行って、
例えばSafariでリンク先を開いたり、
メーラを起動してメールを送るようにできたりします(∀`*)
この処理を行うのが、WebViewのDelegateちゃんです。
Delegateをつなぎこんだら、
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
という関数でこの「フック」というやつを行えます。
こいつはコンテンツの読み込みが開始する直前に呼ばれて、
YESを返すとコンテンツの読み込みをWebViewに任せるけど
NOを返すとWebViewは読み込み処理をしないというやつです。
今回は中にある3種類のボタンを判別します。
ボタン1:http://へのリンクボタン→Safariで開く
ボタン2:更新ボタン→何もしない
ボタン3:アプリ起動のURLスキームボタン→アプリ起動
見事みんな違う役割です\( ^ヮ゜)>
◆ボタン1 http://へのリンクボタンだったらSafariで開く
ボタン判別の前に、このshouldStart〜メソッドはどうやら挙動を見ていると、
WebViewが働いている間は常に呼ばれているような感じで、
ぐるぐると挙動を監視しているぽいです。
なので、まずは「ボタンがクリックされたとき」という状況を判別させます。
if(navigationType == UIWebViewNavigationTypeLinkClicked) {
これで認知できるようになります。
では次に「リンク先がhttp://だったら」という状況を判別させます。
これには便利な小技があります。
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSString *scheme = [[request URL] scheme];
NSString * query = [[request URL] query];
NSURL *path = [[request URL] absoluteURL];
NSLog(@"scheme : %@ query : %@ path : %@ linkURL:%@", scheme , query, path, self.linkURL);
このように書くと、(NSURLRequest*)requestの中から各要素を取り出して、
ログで見るとどのボタンで何のスキームが使われているかなどを見ることができます!
便利!
これでスキームがhttp:だったら良いわけですので
if(navigationType == UIWebViewNavigationTypeLinkClicked) {//リンクがクリックされた
if ([@"http" compare:scheme] == NSOrderedSame) {//スキームと比較
//アラートなど出したければここに
[[UIApplication sharedApplication] openURL:_linkURL];
return NO;
と書けばOKー!
◆ボタン2 更新ボタンだったら何もしない
ボタン2に関しては、何もしないなら放っておけばいいんでない?と思うかもですが
このボタン、ログをとってもスキームもリンク先も何も入ってない。
...さてどうしよう。
何もしないにしても判別をしなければいけません。
そんなときは!BreakPointを有効活用しましょう!
「ボタンがクリックされたとき」でいったんとめて、
止まった地点にマウスを持っていくと、
ふよよんとステータスを表示してくれるのです!!(機嫌がよければ)
これによりこのボタンがなにで反応するのかを判別できます。
押してもURLとれないなあと思っていたら、
このボタンは「FormSubmitted」という場合に反応するとみれます。
なので判定式をこれで書いてあげると見事反応してくれました!
} elseif (navigationType == UIWebViewNavigationTypeFormSubmitted){
//更新ボタン
NSLog(@"更新ボタン!!");
[selfsendCurrentPointAPI];
//return NO;
}
◆ボタン3 アプリ起動のURLスキームボタンだったらアプリ起動
ボタンの種類自体はLinkClickedなのですが、
スキームがhttp:以外だったら、そのスキームを開け!と書くだけです。
スキームはボタン1で拾っているので楽勝!
ちなみに多くのURLスキームは「****:」という形で開かせるようになっているので、
今回は「URLスキーム:」という形で記述しています。
(これだと「****://」とかに対応できないけど...)
} else {
NSLog(@"アプリ起動ボタン");
[[UIApplicationsharedApplication] openURL:[NSURLURLWithString:[NSStringstringWithFormat:@"%@:",scheme]]];
return NO;
}
こんな感じです。
全体像はこうなりました!
やりたいことはばっちし出来ます∩(´∀`)∩
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSString *scheme = [[request URL] scheme];
NSString * query = [[request URL] query];
NSURL *path = [[request URL] absoluteURL];
NSLog(@"scheme : %@ query : %@ path : %@ linkURL:%@", scheme , query, path, self.linkURL);
//リンクがクリックされたとき
if(navigationType == UIWebViewNavigationTypeLinkClicked) { // リンクがクリックされた
//ポイントGETボタン
if ([@"http" compare:scheme] == NSOrderedSame) {//スキームと比較
UIAlertView* tweetAlert = [[UIAlertView alloc]initWithTitle:@"つぶやきますか?"
message:@"Twitterでつぶやくと\n5ポイントゲット!\nつぶやきますか?\n(「はい」を押すと\n自動でつぶやきが完了します。)"
delegate:self
cancelButtonTitle:@"いいえ"
otherButtonTitles:@"はい", nil];
tweetAlert.cancelButtonIndex = 0;
tweetAlert.tag = TWEET_CHECK_ALERT;
[tweetAlert show];
[tweetAlert release];
return NO;
} else {
NSLog(@"アプリ起動ボタン");
[[UIApplicationsharedApplication] openURL:[NSURLURLWithString:[NSStringstringWithFormat:@"%@:",scheme]]];
return NO;
}
} elseif (navigationType == UIWebViewNavigationTypeFormSubmitted){
//更新ボタン
NSLog(@"更新ボタン!!");
[selfsendCurrentPointAPI];
//return NO;
}
returnYES;//リクエストを完了
}
でもまだreturn NOとかいまいちわかってないなあ..