Apache CordovaでAndroidアプリを作ってみる
Apache Cordovaを使うとHTML/CSS/JavaScriptでできたWebアプリをパッケージにして、モバイルデバイスのアプリにすることができます。
- Apache Cordova: http://cordova.apache.org/
- Apache Cordova API Documentation: http://cordova.apache.org/docs/en/4.0.0/index.html
leaflet.jsで地図が出て、GeoJSONのデータ位置にピンを打つことができたので、これをCordovaでアプリにしてみました。
Android開発環境の準備
Apache Cordovaは、Ubuntu TouchやFirfoxOSにも対応しているので、それらでもいいのですが、せっかくなら実機で動かしたいので、ターゲットデバイスをAndroidに設定しました。
ということで、まずはApache Cordovaが利用するAndroid開発環境を整えます。
Android SDK関係のインストールは、Debian Sidではパッケージが揃っているので、それを使っても良かったのですが、Androidの開発自体不慣れなのでAndroid Studioをダウンロードして使いました。
ちなみにEclipseを使わなかったのは、Eclipseがコアを吐きまくって、まともに動かなかったからです。
- Android Studio | Android Developers: https://developer.android.com/sdk/installing/studio.html
Android Studioのインストールは、アーカイブをホームディレクトリの適当な場所に展開して、パスを通せばOKです。
$ tar xvfa android-studio-bundle-135.1339820-linux.tgz
パスの場所は、Android StudioのbinとバンドルされているAndroid SDKのtools、platform-toolsがあるので気をつけて下さい。 そして、LD_LIBRARY_PATHは、Android SDKのqemuがlibOpenglRender.soを見つけられないので、これも一緒に追加しておきます。
~/.bashrc抜粋(Android Studio 1.0になってSDKが~/Android/Sdk/に入るようになったのでアップデート版)
# android
export PATH=$PATH:$HOME/Android/Sdk/tools:$HOME/Android/Sdk/platform-tools:$HOME/bin/android-studio/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/Android/Sdk/tools/lib
終わったら、Android StudioのアップデートとAndroid SDK Managerで必要なAPIのインストール。そして、Android Virtual Device Managerで検証用の仮想デバイスを作っておきます。 実機で検証してもいいのですが、cordovaのコマンド一発でビルドからエミュレーター上でアプリ起動までできるので、ちょっと確認するときには便利です。
(Android Studio) $ studio.sh
(Android SDK Manager) $ android
(Android Virtual Device Manager) $ android avd
Apache Cordovaのインストール
Apache Cordovaは、node.jsで動くので、Debianパッケージのnode.jsとnode.jsのパッケージマネージャnpmをインストールします。
$ sudo apt-get install nodejs nodejs-legacy npm
続いてnpmを使ってcordovaをインストールします。
$ sudo npm install -g cordova
サンプルアプリをビルドしてみる
この辺からは公式ドキュメントそのままです。テストでサンプルアプリを作成します。
- Apache Cordova API Documentation: http://cordova.apache.org/docs/en/4.0.0//guide_cli_index.md.html#The%20Command-Line%20Interface
cordova createコマンドで、ひな型をを作ります。
$ cordova create hello com.example.hello HelloWorld
最初の引数は、ひな型のディレクトリ名です。 2番目はドメイン名を逆から並べた識別子です。逆ドメインの形でない、おかしな識別子にしているとAndroidプラットフォームが追加できずハマるので気をつけて下さい。 3番目はアプリ名です。省略可能でconfig.xmlを編集して後から追加もできますが、最初に適切な名前をつけておいたほうがよいでしょう。
作成できたら、ひな型のディレクトリに下ります。
$ cd hello
用意されたファイルを見てみます。
$ ls
config.xml hooks/ platforms/ plugins/ www/
config.xmlには、cordova createで設定したアプリの設定が書いてあります。
それでは作成するアプリのプラットフォームを追加します。 追加できるプラットフォームは、cordova platformをなにもつけずに実行すると一覧が表示されます。
$ cordova platform
Installed platforms:
Available platforms: amazon-fireos, android, blackberry10, browser, firefoxos, ubuntu
Androidを追加しました。
$ cordova platform add android
wwwディレクトリにマスコットキャラクターを表示するだけのHTML/CSS/JavaScriptファイル一式が用意されています。 これらのファイルはブラウザで普通に見ることができるので試しに見てみます。
$ iceweasel www/index.html
ビルドするとこれと同じものが表示されるはずです。cordova buildコマンドを実行してビルドしてみましょう。
$ cordova build
しばらく時間がかかりますが、正常に終了すると hello/platforms/android/ant-build/CordovaApp-debug.apk というapkファイルが作成されます。
apkファイルをエミュレータ上で実行するには、cordova emulateを実行します。
$ cordova emulate android
_ leaflet.jsの地図をAndroidアプリにしてみる
これで一通りの流れがわかったので、leaflet.jsを使った地図をアプリにしてみます。
まずはひな型を作って、プラットフォームを登録する。
$ cordova create leaflet tv.nofuture.leaflet LeafletTest $ cordova platform add android
wwwディレクトリにleaflet.jsとプラグイン、jQuery、bootstrapを置く。 ざっくりコピーしたので無駄なものも多いけど、treeで表示するとこんな感じ。
├── css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap.css │ ├── bootstrap.css.map │ ├── bootstrap.min.css │ ├── index.css │ └── leaflet.css ├── data (leaflet.jsに読み込ませたいGeoJSONファイル) │ └── map.geojson ├── fonts (bootstrapのフォントファイル) │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── img │ └── logo.png ├── index.html (ここに書く) └── js ├── bootstrap.js ├── bootstrap.min.js ├── images │ ├── layers-2x.png │ ├── layers.png │ ├── marker-icon-2x.png │ ├── marker-icon.png │ └── marker-shadow.png ├── index.js ├── jquery-2.1.1.min.js ├── leaflet-src.js ├── leaflet.ajax.js ├── leaflet.ajax.min.js └── leaflet.js
index.htmlを編集して、leaflet.jsで地図を表示したコードをコピペする。
head要素にscript要素でライブラリを読み込む。
<script src="js/jquery-2.1.1.min.js"></script> <script src="js/bootstrap.min.js"></script> <script src="js/leaflet.js"></script> <script src="js/leaflet.ajax.js"></script>
続いてライブラリのスタイルシートなど。
<link rel="stylesheet" type="text/css" href="css/index.css" /> <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css" /> <link rel="stylesheet" type="text/css" href="css/bootstrap-theme.min.css" /> <link rel="stylesheet" type="text/css" href="css/leaflet.css" /> <style> body{ margin: 0; padding: 0; } div#map{ width: 100%; height: 500px; } </style>
body要素に移って、内容をごっそり削って地図用のdiv要素とスクリプトを移す。
<div id="map"></div> <script> var map = L.map('map').setView([34.839378, 134.694097],15); var tileLayer = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{ attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors', maxZoom: 19 }); tileLayer.addTo(map); var marker = L.marker([34.839378, 134.694097],{ title: 'test', draggable: true }).addTo(map); marker.bindPopup("<b>Hello world!</b><br>I am a popup."); $.getJSON("data/map.geojson",function(data){ L.geoJson(data).addTo(map); }); </script>
この2行は、cordovaのライブラリで必要なので消さないこと。
<script type="text/javascript" src="cordova.js"></script> <script type="text/javascript" src="js/index.js"></script>
コピーし終わったらビルドしてエミュレーターで実行してみる。
$ cordova build $ cordova emulate android
きゃー!動いたー!
apkを実機で実行してみると…。
動いたー!
leaflet.jsで地図アプリを作る野望の大枠が見えたので、これで生きる希望が出た。
cordovaで動かしたindex.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="format-detection" content="telephone=no" /> <meta name="msapplication-tap-highlight" content="no" /> <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 --> <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" /> <script src="js/jquery-2.1.1.min.js"></script> <script src="js/bootstrap.min.js"></script> <script src="js/leaflet.js"></script> <script src="js/leaflet.ajax.js"></script> <link rel="stylesheet" type="text/css" href="css/index.css" /> <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css" /> <link rel="stylesheet" type="text/css" href="css/bootstrap-theme.min.css" /> <link rel="stylesheet" type="text/css" href="css/leaflet.css" /> <style> body{ margin: 0; padding: 0; } div#map{ width: 100%; height: 500px; } </style> <title>leaflet.js Test</title> </head> <body> <div id="map"></div> <script> var map = L.map('map').setView([34.839378, 134.694097],15); var tileLayer = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{ attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors', maxZoom: 19 }); tileLayer.addTo(map); var marker = L.marker([34.839378, 134.694097],{ title: 'test', draggable: true }).addTo(map); marker.bindPopup("<b>Hello world!</b><br>I am a popup."); $.getJSON("data/map.geojson",function(data){ L.geoJson(data).addTo(map); }); </script> <script type="text/javascript" src="cordova.js"></script> <script type="text/javascript" src="js/index.js"></script> </body> </html>