PhoneGap(Cordova) 2.3.0 から使える InAppBrowser でURLのマルチバイト対応
PhoneGap(Cordova) は 2.3.0 からプラグインだった childBrowser 相当のものを本家にとりこんだ。PhoneGapとは別に WebView をたちあげたい場合に使う。
PhoneGap API Documentation
まあドキュメントのまんまで、 window.open をラップしてくる。というか勝手にラップしてしまう。URL を指定、cordova の WebView (つまりアプリ)に立ち上げるか、InAppBrowser を立ち上げるか、システムデフォルトにするか選べる。オプションとしてなんかまあ渡せる。便利。open はいいとして、 close があり、イベントリスナーとして loadstart, loadstop, exit ととれるので URL のフックもできる。
ちなみに関係ないが console.log もラップしてくれて Eclipse の LogCat や Xcode の Output に出力してくれる。便利。
問題
Android だと問題なかったのだけど、iOS だとなんだかうごかなかった。トラブルシューティングした結果、日本語を含む文字列だと動かなかった。なので、オレオレ対応した。まあ、要は URL のエスケープだ。ありがち。
トラブルシューティング
CDVInAppBrowser.m を読む。
#define kInAppBrowserTargetSystem @"_system"
ここが使われているところが該当部分。探す。すると、条件分岐がある。
- (void)open:(CDVInvokedUrlCommand*)command { CDVPluginResult* pluginResult; NSString* url = [command argumentAtIndex:0]; NSString* target = [command argumentAtIndex:1 withDefault:kInAppBrowserTargetSelf]; NSString* options = [command argumentAtIndex:2 withDefault:@"" andClass:[NSString class]]; self.callbackId = command.callbackId; if (url != nil) { NSURL* baseUrl = [self.webView.request URL]; NSURL* absoluteUrl = [[NSURL URLWithString:url relativeToURL:baseUrl] absoluteURL]; if ([target isEqualToString:kInAppBrowserTargetSelf]) { [self openInCordovaWebView:absoluteUrl withOptions:options]; } else if ([target isEqualToString:kInAppBrowserTargetSystem]) { [self openInSystem:absoluteUrl]; } else { // _blank or anything else [self openInInAppBrowser:absoluteUrl withOptions:options]; } ...
で、以下で実行している。
- (void)openInSystem:(NSURL*)url { if ([[UIApplication sharedApplication] canOpenURL:url]) { [[UIApplication sharedApplication] openURL:url]; } else { // handle any custom schemes to plugins [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]]; } }
最初は NSURL をどうこうできないか探したけど、なんか難しいっぽかった。独自スキームを実行してね!って書いてあるけど、そういうわけでもなさそうだった。というかObj-Cはほぼ読めない。ちょっと最近独学しようとしてたところで、まだなにもできない。
しかしどうやら NSString で先にエスケープしてしまえばいいっぽいと気がついたので、そうした。
- (void)open:(CDVInvokedUrlCommand*)command { CDVPluginResult* pluginResult; NSString* url = [command argumentAtIndex:0]; NSString* target = [command argumentAtIndex:1 withDefault:kInAppBrowserTargetSelf]; NSString* options = [command argumentAtIndex:2 withDefault:@"" andClass:[NSString class]]; // ここを追加 // modified by atasatamatara, escape multibyte url = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; ...
できました
まあ
ありがちな話。Objective-Cを軽くかじっていてよかった。