アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

PhoneGapアプリ開発のちょっとしたコツ

PhoneGapはスマートフォンにてハイブリッドアプリケーションを作成するためのフレームワークです。この記事では、PhoneGapによりワンソース・マルチユースクロスプラットフォーム)なアプリを開発するためのコツをご紹介します。

従来まで、スマートフォンアプリの開発形態は、

・ネイティブアプリ
・Webアプリ

に大別されていました。ネイティブアプリでは端末の機能を全て活用できる一方で、クロスプラットフォーム性がありません(iOSAndroidで別々に実装)。他方、WebアプリではWebViewを使ったり、ブラウザを使用することで、HTML5などの機能を使用します。これにより、クロスプラットフォーム性が担保されています。一方で、ネイティブ機能を利用できない、などの制約も発生していました。

PhoneGapを使用したハイブリッドアプリは、上記の2つの手法の間に存在し、次の特徴を持っています。

HTML5によるビューの実装
クロスプラットフォーム
・端末機能の使用

一見、良いことだらけのように見えます。しかし、実際にプロジェクトで使用し、iOSAndroidの両方に適用しようとなると、様々な問題につきあたります(当然のことながら)。多くの問題とその解決方法の中から次の4つについてご紹介します。

Android, iOS4, iOS5の区別
javascriptの読み込み
③ DOMContentLoaded
④ ライブラリ(jQuery OR Zepto)



Android, iOS4, iOS5の区別


javascriptによりnavigatorのuserAgent, appVersionなどを使用して切り分けます。特に、iOS4iOS5とではCSSなどで挙動が異なる部分が多く、区別は必須です。以下に一例を示します。



var IS_ANDROID = (/android/gi).test(navigator.appVersion);
var IS_IOS4    = navigator.userAgent.match(/OS 4_[0-9_]+ like Mac OS X/i) !== null;
var IS_IOS5    = navigator.userAgent.match(/OS 5_[0-9_]+ like Mac OS X/i) !== null;


こういった値を何らかのオブジェクトにまとめておくと、とても便利です。


javascriptの読み込み


画面数が増えるに従い、javascriptファイルが増えるに従い、javascriptファイルを読み込み・使用することが多くなります。その一方で、javascript言語の仕様上、依存関係を各ファイルに記述できません。そんな時には、scriptタグを書きだすスクリプトファイルを1つ用意します。そして、そのファイルを各画面にて読み込みます。例えば、次のようになります。

main.js



var IS_ANDROID = (/android/gi).test(navigator.appVersion);

(function() {
  var phonegapJs = '';

  // PhoneGapライブラリの設定
  if(IS_ANDROID) {
    phonegapJs = 'phonegap-android.js';
  } else {
    phonegapJs = 'phonegap-ios.js';
  }

  // 読み込むファイルのリスト生成
  var scripts = [
    // 各種ライブラリ
    'js/vendor/phonegap/' + phonegapJs,
    'js/vendor/zepto/zepto.js',

    // アプリ固有のスクリプト
    'js/app/...',
    '...'
  ];

  for (var i = 0, len = scripts.length; i < len; i++) {
    loadScript(scripts[i]);
  }
})();

function loadScript(filename) {
  // 以下のように書かないと、xcodeでのハイライトがおかしくなる
  // 実際には、普通にdocument.writeでタグを書きだしても良い
  var script = '%3Cscript type="text/javascript" src="' + filename + '"%3E%3C/script%3E';
  document.write(unescape(script));
}



そして、各HTMLファイル内にて、まず上記のスクリプトを読み込みます。

index.html



<html>
<head>
  <script type="text/javascript" src="js/main.js"></script>
  ...
</head>
<body>
  ...
</body>
</html>


極々当たり前のことですが、これだけでかなり楽になります。同時に、javascriptファイルを分割できるため、コード自体も読みやすくなります(分割には賛否両論ありそうですが・・・)。また、require.jsなど、似たような機能を持ったライブラリもあります。興味のある方は、お試しください。

③ DOMContentLoaded


DOMContentLoadedイベント内にて、devicereadyイベントをバインドしましょう。DOMContentLoadedイベントは、DOMの読み込みが終わった際に発生します(これ以降、DOMを使えます)。

PhoneGapでは、プラグイン機構を通じてネイティブ機能へアクセス可能です。ただし、アクセスできる条件として、PhoneGapにより、javascriptのdevicereadyイベントが発生している必要があります。



document.addEventListener('deviceready', function(){
  // この中でアプリの内容・ロジックを実行する
});


実際にアプリの内容を実行する際には、DOMを活用したり、CSSを使ったりと、HTMLの構造を必ず利用します。そのため、HTML構造などが読み込まれてからdevicereadyをバインドする必要があります。次のように、BODYタグのonLoadやloadイベントでバインドすることも可能です。



<html>
<head>
  <script type="text/javascript" src="phonegap.js"></script>
  <script type="text/javascript">
    function onBodyLoad() {
      document.addEventListener('deviceready', onDeviceReady);
    }

    function onDeviceReady() {
      // PhoneGap開始後の処理を記述する
    }
</script>
</head>
<body onLoad="onBodyLoad();">
  <div>...</div>
  <div>...</div>
  <div>...</div>
</body>
</html>


ただ、onLoadやloadイベントはDOMContentLoadedイベントに比べて遅くなる場合があります。というのも、画像ファイル等の読み込みも待ってしまうからです。そのため、アプリの開始が遅れる恐れがあります。DOMContentLoaded発生時にdevicereadyをバインドする方法は、次の通りです。



<html>
<head>
  <script type="text/javascript" src="phonegap.js"></script>
  <script type="text/javascript">
    document.addEventListener('DOMContentLoaded', function(){
        document.addEventListener('deviceready', onDeviceReady);
    });

    function onDeviceReady() {
      // PhoneGap開始後の処理を記述する
    }
  </script>
</head>
<body>
  <div>...</div>
  <div>...</div>
  <div>...</div>
</body>
</html>


④ ライブラリ(jQuery OR Zepto)


javascriptの操作性や利便性を向上させるライブラリとしては、Zeptoを使いましょう。ZeptoはjQeuryからIE対応を取り除いた、軽いライブラリです(jQueryに比べて)。スマートフォン用のjQueryと思って下さい。jQueryも便利ですが、スマートフォンで使うとかなり重くなります。



まずは、極々基本的なお話をしました。実際、使ってみると、PhoneGapやHTML5でのスマートフォンアプリ開発がかなりスムーズになります。機会があれば、ぜひ試してみて下さい。