Apache CordovaでAndroidアプリを作ってみる

Posted by nogajun - 2014/10/24

_

Apache Cordovaを使うとHTML/CSS/JavaScriptでできたWebアプリをパッケージにして、モバイルデバイスのアプリにすることができます。

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のインストールは、アーカイブをホームディレクトリの適当な場所に展開して、パスを通せば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

サンプルアプリをビルドしてみる

この辺からは公式ドキュメントそのままです。テストでサンプルアプリを作成します。

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: '&copy; <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

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: '&copy; <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>