お?いけるくさい?

iPhoneアプリエンジニアのたまごです。いっちょまえエンジニア目指してちいさな発見や学んだことを覚え書きしていきます!Objective-C/iOS/開発

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を有効活用しましょう!

f:id:simamikiii:20121008193645p:plain

「ボタンがクリックされたとき」でいったんとめて、

止まった地点にマウスを持っていくと、

ふよよんとステータスを表示してくれるのです!!(機嫌がよければ)

これによりこのボタンがなにで反応するのかを判別できます。

押しても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とかいまいちわかってないなあ..