前提知識
iPhoneアプリ内にWeb(HTML)を表示するには、UIWebViewを使います。そして、UIWebViewの中のJavaScriptから、Objective-Cにデータを渡す場合は、location.hrefの値を変更します。UIWebView発生した画面遷移イベントをどうするかは、UIWebViewのdelegate先が判定します。data://で始まるなどといったルールを満たしているURLにアクセスした場合にそれをトラッピングすることで、JavaScriptからのメッセージをobjective-cに渡します。
JavaScript
function sendDataToObjc(data){
location.href=”data://” + data;
}
location.href=”data://” + data;
}
Objective-c
UIWebViewを継承したクラスの一部を抜粋
- (id)init {
self = [super init];
if (self) {
self.delegate = self;
}
return self;
}
-(BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSString * urlStr = [[request URL] absoluteString];
if([urlStr hasPrefix:@"data://"]){
NSString * data = [urlStr substringFromIndex:7];
NSLog(@"%@", data);
return NO;
}else{
return YES;
}
}
<h2>問題</h2>
以下の2行を実行すると、1つめのデータは無視されhigehigeだけが渡される。<font color="#CCC">おそらく画面遷移イベントが発生するまえにURLが上書きされてしまうのだろう。Webブラウザの動きとしては妥当だけれど・・・・</font>
[cc lang="JavaScript"]
sendDataToObjc("hogehoge");
sendDataToObjc("higehige");
self = [super init];
if (self) {
self.delegate = self;
}
return self;
}
-(BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSString * urlStr = [[request URL] absoluteString];
if([urlStr hasPrefix:@"data://"]){
NSString * data = [urlStr substringFromIndex:7];
NSLog(@"%@", data);
return NO;
}else{
return YES;
}
}
<h2>問題</h2>
以下の2行を実行すると、1つめのデータは無視されhigehigeだけが渡される。<font color="#CCC">おそらく画面遷移イベントが発生するまえにURLが上書きされてしまうのだろう。Webブラウザの動きとしては妥当だけれど・・・・</font>
[cc lang="JavaScript"]
sendDataToObjc("hogehoge");
sendDataToObjc("higehige");
試してみた
location.href固有の問題かなーと思い、以下のように書き換えてみるものの、最後のデータしか渡されない状況は変わらず。。だめやん。おわった。諦めかけた。
閃いた
全部おくればえーやん。途中のデータ送信は飛んじゃうけど、最後のが必ず送信されるならこれで問題ないはず。少々汚い方法だけどこの方法なら問題ないはず。実際、問題なかった。
function sendDataToObjc(data){
location.href+= ”//:data://” + data;
}
location.href+= ”//:data://” + data;
}
この方法の欠点
受け側(Objective-C)の処理が増える
→1箇所実装すればおk。そんなに大変じゃない。
渡すデータの量が増える。
→今回の問題が発生しているアプリだとせいぜい数千バイト程度にしかならないので、気にすることはなさそう。
まとめ
iPhoneアプリでUIWebView内のJavaScriptからObjective-Cにデータを渡すときにlocation.hrefを使う方法があるが、location.hrefに連続で値を代入した場合に最後に代入した値しか送信されない。代入する代わりに、どんどん連接してしまえば、なんとかなる。