目次


Bluemix を使用してクラウド内にモバイル・ジオフェンシング・アプリを作成する

Comments

例えば、ある店に入った途端、あるいは店先を通りがかったときに、その店の特別オファーを案内するメッセージを受信して、どんな仕掛けなのか不思議に思ったことはありませんか?それは、ジオフェンシングと呼ばれる手法です。現在、店舗のすぐ近くにいる買い物客の注意を引くために、この位置情報ベースのモバイス・サービスを採用する企業が増えています。

顧客が近くにいることがわかれば、企業はターゲットを絞ったメッセージやその特定の店舗の販売を促進するオファーを作成することができます。このような位置情報ベースのサービスにアナリティクス手法を結び合わせると、特定のオファーが顧客を店舗に呼び込むのに成功したかどうかを理解できるようになります。

この記事では、モバイル OS のジオロケーション機能と IBM Bluemix のサービスを利用して無数のジオフェンシングをモニタリングできる、IBM Bluemix モバイル・アプリケーションを作成するにはどのようにするのかを説明します。

モバイル・オペレーティング・システムでは、特定の地理的領域にデバイスが入ったというイベントや、そこから出たというイベントを検出できます。これらの円形の領域は、ジオフェンスと呼ばれています。この記事では、モバイル OS のジオロケーション機能とのサービスを利用して無数のジオフェンシングをモニタリングできる、IBM Bluemix モバイル・アプリケーションを作成するにはどのようにするのかを説明します。記事で説明するサンプル実装は、ジオロケーション検出に対応する iOS 用と Android 用のクライアント・サイドのコードと、複数の IBM Bluemix サービスを利用してジオフェンスを定義および保管するサーバー・サイドのコードで構成されています。

この記事では、Android と iOS で利用できる各種のテクノロジーと IBM Bluemix クラウド・プラットフォームを使用してジオフェンシング・ソリューションをどのようにして実装するのかを説明します。また、完全に機能するサンプル・コードを用いてソリューションの主要なアーキテクチャー要素を説明します。サンプル・コードを入手するには、下の「コードを入手する」ボタンをクリックしてください。

必要なもの

ジオフェンシングの仕組み

モバイル・アプリケーションは、どのようにして特定の対象領域内にデバイスが存在することを検出するのでしょうか?デバイスの存在を検出するのは、実際にはモバイル・デバイスのオペレーティング・システム自体です。したがって、モバイル・アプリケーションが実行されていないとしても、モニタリングを続行できます。

iOS と Android のどちらにも組み込まれているモニタリング・システムは、セルラー・データと付近の Wi-Fi ネットワークを組み合わせて使用してデバイスの位置を特定します。GPS も使用されますが、それは、デバイス上の別のアプリケーションが GPS を使用している場合だけです。こうすることで、モニタリングによるバッテリー消費量が抑えられることになります。検出の精度は、ジオフェンスの周囲で利用できるセンサーのタイプに依存します。概して、ジオフェンスの最小半径としては 200 メートルが推奨されます。

以下に、このサンプル・アプリケーション内で使用するソリューションの全体図を示します。

このソリューションのサーバー・サイドは、IBM Bluemix プラットフォーム上でホストされた Node.js アプリケーションからなります。ソリューションをサポートするために、以下の Bluemix サービスも利用します。

Node.js アプリケーションは、以下の 2 つの部分で構成されています。

  • REST API: スキーマに基づいて、モニタリングおよび表示対象のジオフェンスのリストを管理 API として作成および更新するために使用します。
  • イベント処理コンポーネント: デバイス自体からイベントを受信するコンポーネントです。

クライアント・サイドでは、モバイル・デバイスが最初にモニタリング対象のジオフェンスのリストを取得する必要があります。デバイスはまず、このリストを管理 API からフェッチして、該当するジオフェンスに対するデバイスの出入りのモニタリングを開始します。このモニタリングは、iOS または Android のモニタリング API を使用してバックグラウンドで行われます。詳細については、記事の後のほうで説明します。

デバイスは領域に入る際、または領域から出る際に、イベント処理セクションの REST エンドポイントを使用します。これにより、MQ Light サービスを介してイベントが送信されます。イベントが送信されると、MQ Light キューを listen する別のサービス (この記事では説明しません) がこの情報を取り込めるようになります。例えば、この存在検出情報を使用して、店舗が「特別オファー」の通知をデバイスに送信するといったことも可能です。

ジオフェンスのリストは変わる可能性があるため、モバイル・デバイスはリストが最新の状態になるように、更新されたジオフェンスのリストを定期的にフェッチします。

イベントが MQ Light キューに入れられた後はどうなるかと言うと、この記事のサンプル・コード内では何も起こりません。けれども実際のアプリケーション内では、1 つ以上のサービスがこのキューにサブスクライブして、対象領域内のデバイスの存在についての通知を受け取ることになります。この情報は、プッシュ通知を直ちにトリガーするために使用したり、今後の使用に備えて保管したりできます。

サンプル・コードを実行する

前述のとおり、完全に機能するサンプル・コードを Bluemix DevOps Services から入手できます。

  1. サンプルを実行するために、以下のコマンドを使用してサンプル・コードを複製します。
    git clone https://hub.jazz.net/git/Tissandier/geofencing-sample
  2. カレント・ディレクトリーを、Node.js app が格納されているサンプル・アプリケーションのディレクトリーに変更します。
    cd geofencing-sample/app
  3. manifest.yml ファイルを更新して、name および host パラメーターをサンプル・アプリケーションのインスタンスに固有の値で置き換えます。host パラメーターに選んだ値によって、サンプル・アプリケーションがホストされる URL (http://host.mybluemix.net) が決まるので、この値は固有でなければなりません。
    declared-services:
     GeofenceDatabase:
     label: cloudantNoSQLDB
     plan: Shared
     GeofenceMQLight:
     label: mqlight
     plan: standard
    applications:
    - disk_quota: 1024M
      host: my-geofencing-sample
      name: my-geofencing-sample
      command: node app.js
      path: .
      domain: mybluemix.net
      services:
      - GeofenceDatabase
      - GeofenceMQLight
  4. manifest.yml ファイル内で宣言されているように、Node.js アプリケーションでインスタンス化する必要があるサービスには、Cloudant データベースと MQ Light サービスの 2 つがあります。これら 2 つのサービスは、Bluemix コンソールから作成できます。Cloudant データベース・サービスには GeofenceDatabase という名前を付け、MQ Light サービスには GeofenceMQLight という名前を付けてください。
  5. 別の方法として、これらのサービスは、以下の Cloud Foundry コマンドを使用して作成することもできます (Cloud Foundry コマンド・ライン・インターフェースをダウンロードしてインストールする手順については、このリンク先のページを参照してください)。
    cf api https://api.ng.bluemix.net
    cf login -u <your-user-ID> -p <your-password> -o <your-org> -s <your-space>
    cf create-service cloudantNoSQLDB Shared GeofenceDatabase
    cf create-service mqlight standard GeofenceMQLight
  6. 2 つのサービスを作成して manifest.yml ファイルを更新した後は、cf push コマンドを使用してアプリケーションを Bluemix にデプロイできます。
    cf push
  7. アプリケーションが実行中の状態になると、Bluemix コンソールにも、サービスが関連付けられて実行中の Node.js アプリケーションが示されます (以下の図を参照)。

ジオフェンスを作成する

次は、前のセクションで選択したホスト名を使用して (https://<ホスト名>.mybluemix.net/) ジオフェンス・ダッシュボードを開きます。以下の図のようなダッシュボードが表示されるはずです。

新しいジオフェンスを作成するには、「Add geofence (ジオフェンスの追加)」をクリックします。ジオフェンスの作成は、既存の GeoJSon ファイルをインポートするという簡単な手順によって開始することもできます。このリンク先のページから、広範囲な対象領域が格納されたデータベースを GeoJSon としてエクスポートできます。

モバイル・アプリケーションを実行する

バックエンド・アプリケーションは実行中の状態になっているので、モバイル・アプリケーションを実行できます。リポジトリーでは、ジオフェンスをモニタリングして情報をバックエンドに送信するために必要なクラスを表す SDK と、その SDK を使用する iOS 向けおよび Android 向けのモバイル・アプリケーションが区別されています。

iOS アプリケーションは、geofencing-sample/client-sdks/ios/MFGeofenceSample ディレクトリーにあります。Android アプリケーションは、geofencing-sample/client-sdks/android/geofence-demo ディレクトリーにあります。

iOS アプリケーションを実行する

このサンプル・アプリケーションを実行するには、iOS 9.x 以降と最新バージョンの Xcode および CocoaPods がインストールされていることが要件となります。

  1. geofencing-sample/client-sdks/ios ディレクトリー内で、以下のコマンドを実行します。
    pod install

    このコマンドにより、以下の出力が表示されます。

  2. Xcode を使用して、以下のワークスペース・ファイルを開きます。
    geofencing-sample/client-sdks/ios/MFGeofenceSample/MFGeofence.xcworkspace
  3. MFGeofenceSample/AppDelegate.swift ファイル内で、Bluemix にデプロイした際に選んだホストを指すように baseUrl 変数を変更します。
  4. 次は、アプリケーションをコンパイルしてデプロイし、実行します。このサンプル・アプリケーションはジオフェンスをモニタリングするだけなので、アプリケーションを実行すると、最初は空白の画面しか表示されません。ジオフェンスを出たり入ったりすると、それに伴って携帯電話にローカル通知が表示されるはずです。
  5. アプリケーションを実物のデバイスにデプロイする前に、領域に対するデバイスの出入りをシミュレーションしたい場合は、「Debug/Location/Custom Location… (デバッグ/ロケーション/カスタム・ロケーション…)」の「iOS Simulator (iOS シミュレーター)」メニューを使用して、シミュレーターにカスタム・ロケーションを設定します。
  6. 以下の図に示すように、モバイル・アプリケーションにローカル通知がポップアップ表示されます。
  7. すべてが正常に機能していることを確認するために、Bluemix 側の MQ Light サービスがイベントを受信したことを確認します。それには、MQ Light サービスのコンソールを開きます。ダッシュボードの「Messages (メッセージ)」リストに、入出イベントが表示されるはずです。

Android アプリケーションを実行する

  1. Android バージョンのアプリケーションを実行するために、Android Studio を開いて、geofencing-sample/clientsdks/android プロジェクトをインポートします。
  2. geofence-demo モジュールに含まれている src/main/java/com/ibm/mf/geofence/demo/MapsActivity.java ファイルを開きます。
  3. SERVER_URL 定数の値を、環境に応じて変更します。
  4. アプリケーションを再ビルドします。これで、デバイスにインストールできる状態の APK が生成されます。

ジオフェンスを定義して保管する

ジオフェンスのそれぞれが、モニタリング対象の円形領域を表します。したがって、ジオフェンスは緯度と経度、およびその地点を中心とする円形領域の半径によって定義されます。Node.js アプリケーションには、ジオフェンスを保管、変更、削除するために必要な REST API がすべて揃っています。

ここでは、対象領域を一覧表示している既存の Web サイトとデータベースを利用するために、GeoJSON (地図データを対象とした JSON 標準) を使用します。GeoJSON フォーマットは、アプリケーション固有のプロパティーを追加できるようになっているので、このフォーマットを拡張することで、ジオフェンスの名前や説明などといった独自のカスタム・プロパティーを保管できます。

注意する点として、GeoJSON では現在のところ、円の概念を定義していないことがあります。円ではなく、地球上の特定の地点を表す Point の概念を使用し、radius をこのオブジェクトのプロパティーとして使用しています。

以下に、GeoJSON の Feature オブジェクトとして表現されたジオフェンスの例を示します。

{
   "type": "Feature",
   "geometry": {
      "type": "Point",
      "coordinates": [ 2.3488, 48.85341 ]
   },
   "properties":{
      "name": "Center of Paris",
      "description": "A geofence of 1 kilometer meter in the center of Paris",
      "radius": 1000
   }
}

GeoJSON は JSON フォーマットであることから、Bluemix 上にデプロイされた NoSQL Cloudant データベースにジオフェンスの構造体を直接保管できます。データを変換する必要はありません。

Cloudant データベースに保管される各オブジェクトには、自動的に新しい ID が割り当てられます。この ID を、それぞれのジオフェンスを識別する手段として利用できます。オブジェクト ID を使用することで、以下のように極めてシンプルな REST API になります。

エンドポイントHTTP メソッド説明
/geofencesGETすべてのジオフェンスを取得します。
/geofencesPOST1 つのジオフェンス (Feature) またはジオフェンスの集合 (FeatureCollection) を作成します。
/geofences/:idGET指定された ID のジオフェンスを取得します。
/geofences/:id PUT指定された ID のジオフェンスを更新します。
/geofences/:idDELETE指定された ID のジオフェンスを削除します。

GET REST verb の実装は、Node.js の Express Web フレームワークを使用して極めて簡潔なコード内で表現されています。

var router = express.Router();

var sanitize = function (doc) {
    doc.properties['@code'] = doc._id;
   ['_rev',  '_id'].forEach(function (val) {  delete doc[val];  });
   return doc;
};

router.get(function (req, res) {
   db.get(req.params.id, function (err, data) {
       if (err) {
           res.status(err.status || err.statusCode || 500).send(err);
       } else {
           res.json(sanitize(data));
       }
   });
})

db は Cloudant データベース・クライアントを表すという前提で、上記のコードはリクエスト・パラメーターに指定された id に従ってジオフェンスを取得し、JSON オブジェクト ID を表す _id 属性と Cloudant 内でのリビジョンを表す _rev 属性を削除してジオフェンス JSON オブジェクトをクリーンアップしてから、その JSON を返します。他の verb の実装も同じように単純です。

アプリケーション・ユーザー・インターフェースを使用する

このサンプル・アプリケーションは、地図上のジオフェンスを作成、更新、削除するために使用できる単純なユーザー・インターフェースも表示します。このユーザー・インターフェースに利用されているのは、AngularJS と、Leaflet というインタラクティブな地図を表示するためのオープンソース・パッケージです。

このサンプル・アプリケーションでは、Leaflet が提供する興味深い機能をいくつか利用しています。その 1 つとして、Leaflet では、複数の地図サーバー (このサンプル・アプリケーションでは OpenStreetMap を使用) からのデータを簡単に表示して、地図上に各種のジオフェンスを表示できるようになっていることがあります。

さらに、Leaflet のマーカーの概念によって、ジオフェンス編集機能も簡単に追加できるようになっています。この例の場合、マーカーを定義して、上記の図に示されている 5 つのハンドルをマーカーによって表わしています。これらのハンドルを使用したインタラクティブな操作によって、ジオフェンスを正確な位置に移動したり、円のサイズを変更したりできます。

Leaflet では、ジオフェンスのクラスターを定義することもできます。あまりにも多くジオフェンスが表示されてジオフェンスの区別がつきにくい場合は、特定のズーム・レベルで複数のジオフェンスをクラスターとして表現し、クラスターに含まれるジオフェンスの数を示すことができます。これにより、どのズーム・レベルでも地図が読みやすくなり、地図がマーカーで溢れることがなくなります。

モバイル側でジオフェンスをモニタリングする

理論上、特定の領域に対するデバイスの出入りは、クライアント・サイドで検出することも、デバイスの位置をサーバーに送信してサーバー・サイドで検出することもできます。ただし、ジオフェンスをモニタリングする上での重要な要素は、バッテリーを使い果たすことなくモニタリングを継続することなので、どちらも好ましい選択肢にはなりません。アプリケーションに、絶えずデバイスの位置情報を送信するよう求めることはできません。その場合、デバイスの GPS を起動しなければならなくなるため、バッテリーが消耗されるだけでなく、サーバー・サイドのソリューションで大量の計算が必要になります。

入出イベントの検出は、実際にはモバイル・オペレーティング・システム自体が行うため、モバイル・デバイスを使用してジオフェンスをモニタリングするほうが遥かに効率的です。iOS と Android にはそれぞれに固有のジオフェンス・モニタリング API があります。開発者はこれらの API を使用することで、一連の領域に対するデバイスの出入りをモニタリングできます。

iOS のソリューションも Android のソリューションも、バッテリー・フレンドリーな設計です。これらのソリューションでは、開発者がモニタリング対象の領域を登録して (iOS 上では最大 20 個の領域、Android 上では最大 100 個の領域を登録できます)、対象の領域に対して発生したデバイスの入出イベントの通知を受けられるようになっています。いずれのシステムにしても、モニタリングはバックグラウンドで行われるため、アプリケーションが実行されていなくてもモニタリングを続行できます。

これらのバッテリー・フレンドリーなモニタリング特性は、この記事で説明しているサンプル・アプリケーションのように、特別オファーによってユーザーを店内に勧誘するアプリケーションには理想的です。モニタリングによってバッテリーが大量に消費されるようであれば、ユーザーがアプリをアンインストールする羽目になってしまいます。

iOS 上でジオフェンスをモニタリングする

前述のとおり、iOS を使用する場合、開発者が 1 つのアプリケーションにつき登録できるモニタリング対象の領域は、最大で 20 個です。この数は、大半のアプリケーションにとっては物足りないことでしょう。これより多くの領域をサポートするためには、デバイス位置の変更に併せてモニター対象の領域を入れ替えることがソリューションになります。つまり、デバイスの位置が変わったことで遠くなった領域を削除し、近くなった領域を追加するということです。

このソリューションはどのように機能するのでしょうか?サンプル・アプリケーション内でメインの Swift クラスとなっている MFGeofencingManager は、シングルトン・パターンに従ってジオフェンスをモニタリングします。MFGeofencingManager は iOS SDK の CCLocationManager クラスを利用して、以下のような位置ベースのイベントをモニタリングします。

  • モニタリング対象領域への出入り
  • デバイス位置の大幅な変更

デバイスがモニタリング対象領域に入るか、そこから出ると、そのイベントが Node.js アプリケーションに送信されます。デバイスの位置が大幅に変更された場合は、iOS のロケーション・マネージャーがアプリケーションに大幅な位置の変更を通知します。この場合も、モニタリングはバッテリー・フレンドリーな方法を使用して行われます。この実装についての詳細は、MFGeofencingManager+CCLocationManagerDelegate.swift ファイルを参照してください。

大幅な位置の変更が検出された場合、MFGeofencingManager は以下の 2 つの処理を行います。

  • モニタリング対象のジオフェンスのリストを更新します。
  • ジオフェンスのリストをサーバー上に保管されているリストで更新する必要があるかどうかをチェックします。

ジオフェンスは、iOS Core Data を使用して保管されます。モニタリング対象のジオフェンスのリストを更新するには、Core Data 内に保管されたジオフェンス・レコードを、現在の位置からの距離を基準に昇順にソートします。その上で、同時にモニタリングする領域が 20 を超えないことを条件に、現在のモニタリング対象リストに対して追加または削除するジオフェンスをチェックします (詳細については、MFGeofencingManager+UpdateMonitoredGeofences.swift ファイルを参照してください)。

モニタリング対象のジオフェンスのリストはサーバー上で定義されているため、デバイスでは定期的にリストを更新する必要があります。ここで考慮しなければならない点がいくつかあります。まず、デバイスの数が増加しても、サーバーに対して十分な数の呼び出しを行えるように維持しなければなりません。したがって、同期のための呼び出しは 1 日あたり 1 回に制限する必要があります。また、データがダウンロードされる間、ユーザーを待機させないために、ダウンロードはバックグラウンドで行わなければなりません。それに対処するには、iOS の Background Transfer Service を使用できます。

Background Transfer Service により、オペレーティング・システムではダウンロード・プロセス全体をバックグラウンド・スレッド内で処理できるようになります。さらに、このサービスはアプリケーションにダウンロードの進捗状況も通知します。

Android 上でジオフェンスをモニタリングする

Android 側のシステムは非常に小規模ですが、バックグラウンドで実行するサービスを作成する際は、Android のほうが、柔軟性が高くなります。Android ソリューションでも MFGeofencingManager クラスを定義していますが、この場合は Java 内で定義されたバージョンです。

この MFGeofencingManager クラスはジオフェンスのリストを Android 上の SQL Lite データベースに保管します。この場合、ジオフェンスのモニタリングは Android のジオフェンシング API を使用して行われます (詳細については、このリンク先のジオフェンシング API リファレンスを参照してください)。

この API には iOS の API と同様の領域数の制約があり、ユーザー当たりのモニタリングできる領域の数は 100 に制限されています。したがって Android でも、iOS の場合に使用したようなソリューションを導入できなければなりません。

デバイス位置の大幅な変更に関する通知を設定するには、このリンク先のページで説明されている Android ロケーション・マネージャーを使用します。

ロケーション・マネージャーは、バッテリー・フレンドリーになるように構成することが重要です。このロケーション・マネージャーでは、複数のプロバイダーを組み合わせて使用してデバイスの位置情報を取得します。具体的には、携帯基地局や Wi-Fi から位置の変更を検出する NETWORK_PROVIDER と、アプリが他のアプリによって使用されているデータを取得できるようにする PASSIVE_PROVIDER という特殊なプロバイダーを使用します。通常、GPS ナビゲーション・アプリがデバイス上で実行されている場合、アプリはその位置データを利用しますが、アプリから GPS の精度を要求することはしません。

Android のバックグラウンド・サービスが実装するロジックは、iOS が実装するロジックと同じです。

  • ジオフェンシング API を listen し、入出イベントを検出すると、それを Node.js バックエンド・アプリケーションに通知します。
  • 位置の更新を listen して、モニタリング対象ジオフェンスのリストを更新する必要があるかどうかを判別します。

Android 内では、デバイスがオフにされると、モニタリング対象のジオフェンスのすべてが削除されます。この場合、Android SDK が専用ブロードキャスト・レシーバーを介してデバイスのリブート・イベントを listen し、リブート後に削除されたジオフェンスを再登録します。

まとめと次のステップ

この記事では、ジオフェンス・モニタリング・サービスを Bluemix 上でホストするにはどのようにするのか、そしてサーバー・サイドとクライアント・サイドの両方について、各種の要素をどのように考慮するのかを説明しました。この時点で、皆さんは「このソリューションはデバイス数の増加に伴ってスケーリングするだろうか」という疑問を抱いているかもしれません。

このサンプル・アプリは単なる概念検証であり、出発点に過ぎませんが、ソリューションのスケーラビリティーを改善するのは難しいことではありません。何よりもまず、Blumix 内では簡単に複数の Node.js アプリケーション・インスタンスを実行できます。この水平スケーリングは、Node.js アプリケーションのイベント処理機能の容量を拡大するのに役立ちます。並行して実行される Node.js アプリケーションの数が多ければ多いほど、システムで処理できる入出イベントの数が増えるからです。しかも、Node.js インスタンス間のロード・バランシングは、Bluemix が処理してくれます。

もう 1 つの注目すべき重要な点として、管理 API とイベント処理機能を同じレベルでスケーリングする必要がない点があります。具体的には、サーバーを呼び出すデバイスの数に対し、ジオフェンスを変更するのはほんの数人です。したがって、Node.js アプリケーションを複数のマイクロサービスに分割して、それぞれ独立してスケーリングしてモニタリングできるようにすることによっても、このソリューションを簡単に改善できます。

さらに、デバイス上のジオフェンス・リストの更新を改善する方法もいくつかあります。例えは単純な方法の 1 つは、デバイス呼び出しのたびにデータベースからジオフェンスのリストを取得しなくても済むように、このリストのインメモリー・キャッシュを用意することです。

MQ Light を使用すると、バッファーとして機能するスケーラビリティーの要素も提供されます。そのため、入出イベントの通知を使用するアプリケーションの残りの部分は、これらのイベントを独自のペースで使用できます。

この記事から明らかなように、モバイル・アプリケーションに新しい画期的な機会の数々をもたらすジオフェンシングの開発プロセスは、IBM Bluemix を使用することで大幅に単純化されます。


ダウンロード可能なリソース


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Mobile development, Cloud computing
ArticleID=1041179
ArticleTitle=Bluemix を使用してクラウド内にモバイル・ジオフェンシング・アプリを作成する
publish-date=01052017