PhoneGapはスマートフォンにてハイブリッドアプリケーションを作成するためのフレームワークです。この記事では、PhoneGapによりワンソース・マルチユース(クロスプラットフォーム)なアプリを開発するためのコツをご紹介します。
従来まで、スマートフォンアプリの開発形態は、
・ネイティブアプリ
・Webアプリ
に大別されていました。ネイティブアプリでは端末の機能を全て活用できる一方で、クロスプラットフォーム性がありません(iOSとAndroidで別々に実装)。他方、WebアプリではWebViewを使ったり、ブラウザを使用することで、HTML5などの機能を使用します。これにより、クロスプラットフォーム性が担保されています。一方で、ネイティブ機能を利用できない、などの制約も発生していました。
PhoneGapを使用したハイブリッドアプリは、上記の2つの手法の間に存在し、次の特徴を持っています。
・HTML5によるビューの実装
・クロスプラットフォーム性
・端末機能の使用
一見、良いことだらけのように見えます。しかし、実際にプロジェクトで使用し、iOSとAndroidの両方に適用しようとなると、様々な問題につきあたります(当然のことながら)。多くの問題とその解決方法の中から次の4つについてご紹介します。
① Android, iOS4, iOS5の区別
② javascriptの読み込み
③ DOMContentLoaded
④ ライブラリ(jQuery OR Zepto)
① Android, iOS4, iOS5の区別
javascriptによりnavigatorのuserAgent, appVersionなどを使用して切り分けます。特に、iOS4とiOS5とでは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でのスマートフォンアプリ開発がかなりスムーズになります。機会があれば、ぜひ試してみて下さい。