2011年12月30日金曜日

今年はいろいろあった

日本に住んでいる人のすべてがそうであったと思うが、自分も今年はいろいろあった。
今後の人生に大きく影響するだろう出来事が7〜8はあったと思う。

地震はあるし、そんとき海外にいたし、会社はリストラ始まるし、転職先でも粉飾が起こるし、1年で2回転職するし。

思い返せば毎年、何かしらその後の人生に影響するだろうことが起こっている訳だが、今年ほど様々なことが起こるのは珍しいだろう。


地震があり原発に対する考え方が揺らいだ。ただ、政治やテレビ番組や新聞などが、それらに対して驚くほど鈍感であった。もっと大きな変化があってもよさそうなものであるが、ほとんど何も変わっていない。今までも別に変わらなかったのだとは思うが、自分がいる業界や生活の変化と比べて、あまりにも変わらなすぎて今まで以上に遠い存在になってしまったように思える。


Androidが興味の中心だった。twitterとかbookmarkとかを1年分さらっと見返してみたが、自分にとってはAndroidが関心の中心となった一年だったようだ。今も仕事で関わっているので、たぶん来年もだろう。端末のスペックの進化は、もう少し続くかもしれないけど来年くらいからモバイルのみのソフトウェアの競争が始まるのであろうか?
個人的にはWindowsPhone7が年末にヒットして来年に普及し始めるだろうくらいに思っていたのだが、日本のみならず海外でも鳴かず飛ばずのようで非常に残念だった。

情報の取得の方法も去年までとは様変わりしたように思う。
twitterはもう少し前からやっていたけど、facebookも始めて、知り合いが調べたことや興味のあることがTL上に並んで、RSSやGoogleAlertで情報を取得していた頃よりも、情報の幅とか深さが増して、尚かつ情報にたどり着くまでの時間が減ったように思える。IT業界以外の人たちも同じような体験をし始めているだろうか?だとしたらとても面白い。

来年は自分に何が起こって、世の中がどう変わるのか、元々予想など出来ないけれども、予想不可能であるということを実感したのは今年が始めてであった気がする。

2011年12月11日日曜日

WebViewからJavaScriptをコールしたり



AndroidとかiPhoneのアプリ開発はWebViewを使ったWebアプリが増えていく感じがあるが、
WebViewだけだと読み込みが遅いとかレスポンスが悪いとかまだまだNativeで作った方がユーザとしてはストレスが少ないものが作れるような気がする。
HTML5でアプリがWebアプリになったとしてもなかなかレスポンスの部分は解決が難しいのではないかな?というのが個人的な印象。
そんなときにはNativeとWebViewの組み合わせでアプリを作ろうとする場合があると思う。
両者を橋渡しすることになるのはJavaScriptになりそうだけど、それぞれのプラットフォームでコールの仕方とか違うみたいなので少し調べてみた。

AndroidとiPhoneを比べると
NativeからJSを呼び出すのはiPhoneのが整っていて
JSからNativeを呼び出すのはAndroidの方が整っている印象。


Androidの場合は、
・NativeからJSの呼び出し
mWeb.loadUrl("javascript:コールしたいJSの関数");
のようにWebViewのインスタンスからmethodをコールして
JSを呼び出すような感じになっている。
ただ、この関数戻り値がvoidのなので結果が分からない。。。
結果を知ろうと思ったら、関数コールの引数にcallbackを指定するような文字列を
入れるなどして結果を取得しなければならない。サンプルではconsole.logをフックして結果を表示しているけど、ほめられた方法ではない。


・JSからNativeの呼び出し
mWeb.addJavascriptInterface(new NativeClass(), "Android");
のようにするとNativeClassが"Android"がJS内における名前空間にように扱えるので
Android.callNative("arg");
のようにJS側からコールスことが出来る。callNativeはJavaのNativeClassのmethodになっている。
この関数は戻り値をとることが出来るので同期でコールすることが出来そうだ。


iPhoneの場合は、
・NativeからJSの呼び出し
[_webView stringByEvaluatingJavaScriptFromString:@"IPHONE.CallJSfromNative('hoge')"];
のように、WebViewのメソッドをコールスことでJSを呼び出すことが出来る。
ここでは、IPHONE.CallJSFromNativeがJS側で宣言されている関数になる。
stringByEvaluatingJavaScriptFromStringは戻り値があるので同期でコールすることが出来そうだ。


・JSからNativeの呼び出し
iPhoneの場合はJSからNativeをコールする方法はきちんと用意されていないようで、少し調べた限りでは、いろんな人がそれぞれ工夫しながら実現しているような印象だ。
具体的には独自のスキームを利用してコンテンツをJSからロードしたときにshouldStartLoadWithRequestがコールされるので、独自のスキームをフックして、処理を行うような感じにするのが一般的のようだ。
- (BOOL) webView:(UIWebView *)webView
                shouldStartLoadWithRequest:(NSURLRequest *)request
                navigationType:(UIWebViewNavigationType)navigationType {
    
    NSString *requestString = [[request URL] absoluteString];
    if (![requestString hasPrefix:@"callobjc:"]) return YES;
    
    NSArray *components = [requestString componentsSeparatedByString:@":"];
    NSString *function = [components objectAtIndex:1];
    [self performSelector:NSSelectorFromString(function)];   
    return NO;
}
上のような感じで、関数名を取り出した後にself performSelector:NSSelectorFromString()で内部に宣言した関数をコールしている。
サンプルをここにおいておいた。
WebがわはDjandoで作っているが、アプリではなく静的なファイルを戻すだけなので、
必要なのは、それぞれのディレクトリ内にあるindex.htmlとsite_templeteの中にあるJSのファイルだけだ。AndroidについてはeclipseにPydevさえ入れてあればwebサーバとかたてなくても試せるはず。


少し調べてみた感じだと、すべてのフレームワークに共通のIFを用意するのはなかなか難しそうで、用意するとしたら全部非同期になりそうだ。なぜなら戻り値がなかったりするから。
https://github.com/callback/callback-ios.git
にPhoneGapのソースがあって、これは結構面白かった。
JS側からNativeをコールするときにはPhoneGap.exec()を利用する。
内部では、gap:のスキームをloadするとWebViewのコールバックが呼ばれて、その中でJS側でキューイングされている文字列を取得して、Native側の関数をキューイングされている分だけすべて関数をコールする感じになっている。
独自にJSのNativeの連携部分を作るよりもこういったコードを流用する方がよいかもしれない。
./PhoneGapLib/javascripts/core/phonegap.js.base
は拡張子が微妙だけどJS部分だろうと思う。
./PhoneGapLib/Classes/PhoneGapDelegate.m
の中にJSからのコールバック部分があったりした。


実際にWebViewとNativeの組み合わせのアプリ作ってみて感じたけど、やっぱりWebだと連打はつらいなー。というのが現状のようだ。
それと思いのほかWebViewとNativeの組み合わせでやり取りしても、画面表示のレスポンスは結構よかった。