iOSアプリ開発の逆引き辞典

iPhone/iPadで使えるアプリ開発のTipsをまとめてみました

UIWebViewからアプリへ文字列を渡す方法とアプリからUIWebViewへ文字列を渡す方法

UIWebViewに表示されたHTMLととアプリケーションとを連携させる方法を紹介します。

本記事で紹介する方法としては、HTML(UIWebViewオブジェクト)からアプリケーションへ通知をおこない、それをトリガーとしてアプリケーション側からHTML(UIWebViewオブジェクト)のfunctionを実行させています。

f:id:ch3cooh393:20130208112606j:plain

アプリケーションからHTMLへ何らかのアクションをおこなう場合には、以下のメソッドを利用することが可能です。

- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;

UIWebViewには、リンクをクリックしてページ遷移をおこなう直前に「本当にページ遷移をおこなってよいのかどうか?」を検証することが可能なデリゲートが用意されています。

- (BOOL)webView:(UIWebView *)webView
     shouldStartLoadWithRequest:(NSURLRequest *)request
                 navigationType:(UIWebViewNavigationType)navigationType;

iOSにはアプリケーションへ直接文字列を渡す方法が用意されていませんので、故意にページ遷移を発生させ、クエリ文字列にアプリケーションへ渡したい文字列を追加し、遷移先のURLをshouldStartLoadWithRequest:navigationType:メソッドで受け取り、ページ遷移を拒否します。

HTML側で準備させること

HTMLでは、2つのJavaScriptのfunctionを定義しています。

notifyメソッドは、ch3coohスキームで始まる「ch3cooh://notify?msg=sakusan」へ遷移しようとします。[通知をおこなう]というリンクをクリックすると、実行されます。

replaceHtmlメソッドは、アプリケーションから呼び出されるのを期待しているメソッドで、渡された文字列をdivタグを書き換えるだけのものです。

<html>
    <head>
        <script type="text/javascript">
            function notify(msg) {
              result.innerHTML = '応答待ち';
              document.location = 'ch3cooh://notify?msg=' + msg;
            }
            function replaceHtml(parm1) {
              result.innerHTML = parm1;
            }
        </script>
    </head>
    <body>
    <a href="javascript:void(0);" onclick="notify('sakusan');">通知をおこなう</a>
    <div id="result">
        None Data.
    </div>
    </body>
</html>

アプリケーション側の実装

まずはUIWebViewに先ほど作成したテストページを表示させます。

- (void)viewDidAppear:(BOOL)animated
{
    // テストページを読み込む
    NSURL* url = [NSURL URLWithString:@"https://dl.dropbox.com/u/2258039/send/sample/ios_notify.html"];
    [self.contentView loadRequest:[NSURLRequest requestWithURL:url]];
}

[通知をおこなう]というリンクをクリックすると、document.locationを変更するのでページ遷移が発生します。

// ページ遷移が発生したら実行される
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
    navigationType:(UIWebViewNavigationType)navigationType
{
    // ch3coohスキーマ以外は通常にページ遷移をさせる
    NSString* scheme = [[request URL] scheme];
    if (![scheme isEqualToString:@"ch3cooh"]) {
        return YES;
    }
    
    // クエリ文字列をパースする
    NSString* query = [[request URL] query];
    NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
    for (NSString *param in [query componentsSeparatedByString:@"&"]) {
        NSArray *elts = [param componentsSeparatedByString:@"="];
        if([elts count] < 2) continue;
        [params setObject:[elts objectAtIndex:1] forKey:[elts objectAtIndex:0]];
    }
        
    // アプリから送信されたメッセージを受信する
    NSString* message = [params valueForKey:@"msg"];
    NSLog(@"%@", message);
        
    // 遅延実行させる
    [self performSelector:@selector(notificationHtmlFunction:)
               withObject:message afterDelay:10];
    
    // ch3coohスキーマの場合はページ遷移させない
    return NO;
}

1秒待ってからnotificationHtmlFunctionメソッドが実行されます。実行されるまでの間、「応答待ち」を表示させていたので下図のように表示されます。

f:id:ch3cooh393:20130208133530p:plain

notificationHtmlFunctionメソッドでは、シンプルに既存のJavaScriptのメソッド呼び出しをおこなうだけです。

// HTML側で定義されているfunctionを引数付きで実行する
- (void)notificationHtmlFunction:(NSString*)message
{
    NSString* msg = [NSString stringWithFormat:@"received:%@", message];
    NSString* script = [NSString stringWithFormat:@"replaceHtml('%@');", msg];
    [self.contentView stringByEvaluatingJavaScriptFromString:script];
}

上記のコードが実行されると、HTMLの文字列を変更します。下図のように表示されます。

f:id:ch3cooh393:20130208133518p:plain

以上で、iOSでのアプリケーションからUIWebView(HTML)へ文字列を送る方法と、UIWebView(HTML)から送られてきた文字列をアプリケーション側で受け取る方法をご紹介させていただきました。

ソースコード

このエントリにて紹介したサンプルプロジェクトはGitHubにて公開しております。

参考