読者です 読者をやめる 読者になる 読者になる
スポンサーリンク

AndroidやiOSの「ハイブリッドアプリ」で,JavaScriptとネイティブ・コードが連携する仕組みを図解 (おまけ:HTML側で施すべき,クロスプラットフォーム対策)

Android iOS Objective-C プログラミング ハイブリッドアプリ


HTMLやJavaScript等のWeb技術を使って,AndroidやiPhoneなどモバイル環境のネイティブ・アプリを作成する事ができる。

そういうアプリの事をハイブリッド・アプリと呼ぶ。


AndroidとiOSでは,ハイブリッド・アプリを実現するためのアイデアは,非常に似ている。

下記の図を見れば,仕組みが酷似している事が分かるはずだ。





なおWindows Phoneの場合も,だいたい似たようなフロー。


以下では,各プラットフォームごとの詳細な事情をメモする。

また,複数プラットフォーム間での移植性を向上させるために,HTML側でどのように対処したら良いか?という課題についても述べる。

(1)Androidの場合


Androidでハイブリッド・アプリを実現するための仕組みは,下記のエントリに記述した。

たった2ファイルで,HTML+JS製のネイティブAndroidアプリを作る手順 (動作するサンプルコード付き。WebViewの活用方法)
http://language-and-engineering.hatenablog.jp/entry/20120710/CreateAndroidApp...

  • WebViewにaddJavascriptInterfaceする

(2)iOSの場合

iPhoneアプリやiPadアプリで,ハイブリッドアプリを実現している仕組み:

PhoneGap APIを拡張する@iPhone(シーケンス図のUMLや,サンプルコード付きで解説している)
http://lab.dwango.jp/articles/extendi...

  • JS側のPhoneGap.exec()関数内部でgap://<Class>.<command>/[<arguments>][?<dictionary>]という形式のURIに変換し、Objective-C側へのブリッジを実現
  • JavaScript→UIWebView→UIWebViewDelegate


HTMLとJavaScriptでiPhoneアプリを超簡単に作る方法
http://d.hatena.ne.jp/uosoft/20100225...

  • UIWebViewの中にHTMLを表示したアプリの例。JS連携なし。


iPhoneのネイティブ機能をWebViewから呼び出す方法(1)
http://blog.engineer.adways.net/archi...

  • WebViewのdelegateメソッドである、shouldStartLoadWithRequestメソッドを利用するとWebViewがHTTPのリクエストを行う際に割り込んでネイティブ処理を行うことができる
  • HTML側でハイパーリンク等から特定のURLに接続要求があった際,リクエストされたURL文字列を解析して,場合によってネイティブ処理を実行するように分岐させる。例えば,呼び出し先のURLがnative://で始まっていたら要求されたネイティブメソッドを呼び出すという仕組み


[iOS] UIWebViewでWebとネイティブを相互連携させる方法について
http://d.hatena.ne.jp/ntaku/20111103/...

  • Webからネイティブ呼び出し:UIWebViewDelegateにある、ページがロードされる前に呼ばれるメソッドを利用

(3)Windows Phoneの場合

Windows Phoneでハイブリッドアプリを実現している仕組み:

JavaScript+html5とc#+xamlで作るwindows8アプリ(スライド)
http://www.slideshare.net/vsug_jim/20...

  • Windows Phone 7の場合は,Silverlight for WindowsPhone。
  • Windows Phone 8の場合は,WinRT+.NET 4。(17,24,27ページなどを参照)
    • 流れ: HTML+JS(WinJS)→Trident+Chakra(IEと同じエンジン)→WinRT API→Windows Kernel


Choosing between a web and native experience
http://msdn.microsoft.com/en-us/libra...
When we speak of hybrid apps, we are referring to apps that are built using both native code and web technologies. In general, these are native apps that use an embedded web browser.
(For example, in the case of Windows Phone it's the WebBrowser control.) The HTML, CSS, and JavaScript for such an app may live on a web server or be embedded in the native app itself.


クロスプラットフォームなフレームワークを使う場合:

Apache Cordova を使って Windows Phone の HTML 5 アプリを開発する
http://msdn.microsoft.com/ja-jp/magaz...

  • モバイル端末が持つ機能は JavaScript コードから使用できる JavaScript API として公開される。Cordova は、コードが実行されるスマートフォンの OS を問わず同じ JavaScript API を使って作業できるように、必要なネイティブ実装の提供にかかわる面倒な作業をすべて行う


Building cross platform mobile apps with Windows Phone and PhoneGap/Cordova
http://www.windowsphonegeek.com/artic...

  • PhoneGap利用時は,JS側からwindow.deviceやonDeviceReadyなどを利用可能
  • XAML中でCordovaViewを描画指定

HTML側で,複数プラットフォーム間の移植性を高めるための対処法

このように複数のモバイル・プラットフォームにおいて,JSとネイティブで連携する手段が提供されているわけだが,その手法はそれぞれ異なる。

この状況下で,いったん作ったコードの移植性を高めるためには…

  • HTML内で,JSからネイティブコードへの連携ロジックを隠ぺいしておき,のちのちクロスプラットフォームで使いまわせるようにしておく

必要がある。


例えばAndroidからWebViewに対して,下記のコードを記述したとする。

webView.addJavascriptInterface(jsObj, "droid");

この場合HTML側では,「droid」というDOMオブジェクトのメソッドを直接呼び出し可能になる。


しかし,後になってそのHTMLを,iOS向けに移植したくなった場合はどうなるか?

この場合,iOSなので,HTML側では「droid」というオブジェクトを直接参照してはならない。

droid.x(1) のようにメソッドを呼び出すためには,下記のようなJavaScriptを記述する必要があるのだ。

location.href = "native://droid:x:1";

そして,Objective-C側のフックメソッドで,要求されたリクエストURLをパース(コロン区切りで分割とか)して,

  • 呼び出したいオブジェクト名と
  • メソッド名と
  • 引数

を,各々判別したうえでネイティブコードの実行にもってゆく必要があるのだ。


Android側では生のJSオブジェクトとして扱えるが,iOS側ではURLの文字列として扱う必要がある。

この差異を吸収して,のちのちの保守性や移植性を高めるためには,

HTML側でプラットフォームの差をラップするような仕掛けが必要になる。


一例として,HTML内で下記のような記法を導入する事になる。

// ネイティブコード側のメソッド名と引数を指定して実行
NativeBridge.exec( "x", [1] );


そして,このexecメソッドの中身は,プラットフォームに応じて切り替わるようにしておくのだ。

Androidであれば,下記のようなJSコードをexec()内部で実行すればよい。

droid[ method_name ].apply( droid, arr_arguments );
// または,eval( "droid.x(1)" ) という手もある。

iOSであれば,簡単に書けば,下記のような感じ。

location.href = "native://droid:"
  + method_name
  + ":["
  + arr_arguments.join(",")
  + "]"
;


このように,プラットフォーム間でJSとネイティブの連携方法が違うので,その差異を吸収するような記法を最初から導入しておけばよい。

そうすれば,あるプラットフォームのために作成したハイブリッドアプリのHTML側の資産を,別のモバイルプラットフォームのために移し替えて流用する事が容易になる。


初めからこの点を意識しているかどうかで,のちのちの移植工数はかなり左右されるだろう。