Wikitude開発入門(Android編)[PR]

GrapeCity Garage Wikitude開発入門(Android編)[PR]

WikitudeでカンタンAndroid向けAR開発。ブラウザーでデバッグ可能[PR]

2016年7月13日

位置情報を含むレストラン検索の「ホットペッパーAPI」を活用したAndroid向けモバイルARアプリを作成。Wikitudeを使えば、使い慣れたテキストエディターで開発し、ブラウザーで手軽にデバッグできる。

デジタルアドバンテージ 一色 政彦
  • このエントリーをはてなブックマークに追加

 前回は、「WikitudeではどのようなAR機能を開発できるのか」を示したうえで、Wikitudeを採用したiOS向けのモバイルARアプリの開発を試してみた。その際に分かったように、Wikitude開発のメイン作業はARchitect Worldの構築であり、これはAndroidアプリの開発でも変わらない。つまり、iOS向けにARchitect Worldが開発できたのなら、ARアプリ開発という意味では、Android向けアプリも大きな問題なく「開発できる」と考えてよい。

 ということで今回は、前回より実践的な内容を目指し、

  • 前半:Android向けWikitude SDK(JavaScript API)開発のポイント
  • 後半:Wikitude開発時の効率的なデバッグ手法

を示す。前回同様、ポイント紹介のみで、チュートリアルのような開発手順の説明はしないので、あらかじめご了承いただきたい。また前提条件として、前々回と前回の記事をすでに読了しており、Wikitude開発に関してはある程度の基礎知識がすでにあるものとして説明を進める。

1. Android向けWikitude SDK(JavaScript API)開発のポイント

 まずは、今回開発するサンプルアプリについて紹介しよう。

1.1 サンプルアプリの内容

 今回のサンプルアプリの内容は、

周囲500m以内に存在する最寄りのレストランの名称(最大10件)とそのレストランまでの距離情報が、その地点の方向・場所にポップアップ表示される

というものだ。

 身の回りの360度をぐるりとカメラでかざしながら適切なレストランを直観的に探せる。行きたいレストランに向かって歩き出せば距離の値がどんどん小さくなっていくので、近づいているか離れているかがARで見える化されるというわけだ。なお今回のサンプルは、基本的に前回のサンプルアプリを拡張したものとなっており、今回はより現実的に利用しやすいように以下のような新機能をさらに作り込んだ。

  • 間引き表示機能: 数多くのレストランが見付かった場合は、最寄りの10件に絞り込む
  • ずらし表示機能: ARタグ(=ポップアップするバルーンUIで、コードでは「Marker」と表現)が完全に重ならないようにする(一部は重なることがある)
  • 近い順表示機能: 距離が近いものほど最前面に表示されて、内容が読める
  • 遠いものも見える化機能: ARタグをタップすると一時的に最前面に表示できる

 図1は、本稿のサンプルアプリを実際に使っているときの画面例である。

図1 サンプルアプリの実行例: 距離がより遠いために、重なりの奥にあるARタグをタップする

距離がより遠いために、重なりの奥にあるARタグをタップする

図1 サンプルアプリの実行例: そのARタグは一時的に最前面に表示されて(この例では「ほむら庵 池袋東口」)、内容が見えるようになる

そのARタグは一時的に最前面に表示されて(この例では「ほむら庵 池袋東口」)、内容が見えるようになる

図1 サンプルアプリの実行例

 このサンプルを開発するための技術選択ポイントは下記の2点となる。

  • Android向けWikitude SDK(JavaScript API)を使用し、ロケーションベースのARを採用する
  • ホットペッパーのWeb APIで「レストラン検索の位置情報」を活用する(JSONP形式で取得したデータはある程度、キャッシュする)

 実際の開発内容を説明する前に、その開発環境を準備しておこう。

1.2 開発環境の準備

 Android開発なので、Android StudioMacもしくはWindows)を使用する。また、開発言語はAndroidアプリ開発の標準であるJava(+JavaScript)を用いる。本サンプルでは、有償のWikitudeライセンスを借りて開発してみたので、スクリーン上への「Trial」表示はなくなっている(無料のトライアルライセンスでも問題なく本稿の開発は行える)。

 全ての手順を示すと記事が長くなってしまうので、以下ではWikitude+Android Studio環境を構築するためのポイントのみを示す(一部の説明は、前回のXcodeと同じである)。なお、Android Studioは先にインストールしておいてほしい(Android Studio環境の構築方法についての説明は割愛する)。

Wikitude SDKのダウンロード

 下記のリンク先にアクセスして[Android]用のWikitude SDKをダウンロードする。なお初回アクセス時は、アカウント作成(無料)が促されるので、流れに沿って作成する。

無償トライアルライセンスキーの入手

 下記のリンク先の説明に従って無償のライセンスキーを取得する。

1.3 Wikitudeアプリ開発のひな型コードの作成

 次に、Android StudioでAndroidアプリのプロジェクトを作成する。

 プロジェクト作成時に表示されるウィザードでは図2のように指定した。今回はアクティビティテンプレートとして「Empty Activity」を選択している。

図2 Android Studioでプロジェクトを新規作成する際のオプション指定例
図2 Android Studioでプロジェクトを新規作成する際のオプション指定例(1)
図2 Android Studioでプロジェクトを新規作成する際のオプション指定例(2)
図2 Android Studioでプロジェクトを新規作成する際のオプション指定例(3)
図2 Android Studioでプロジェクトを新規作成する際のオプション指定例

 あとは、このプロジェクトにWikitude SDK(wikitudesdk.aarファイル)を追加する。この手順は公式サイトやCodeZineのPR記事(下記のリンク先)で分かりやすく説明されているので、そちらを参考にしてほしい。

 この手順に従うと、図3のようなフォルダー&ファイル構成になったはずだ。

図3 ひな型コードのフォルダー&ファイル構成
図3 ひな型コードのフォルダー&ファイル構成

テスト関連のフォルダーは本稿では使わないので削除してよい。

 本稿のサンプルでは下記の2つのフォルダーが存在するが、これらがWikitude SDK関連のものになる。

  • app/src/main/assets/ArchitectWorldフォルダー: JavaScript APIを用いたARchitect World。最初、中身は空になっている。JavaScript APIを使用したアプリは、このフォルダー内で作り込んでいく
  • app/libsフォルダー: Android Architect SDK API

 図4にAndroid版Wikitude SDK(JavaScript API)のアーキテクチャを示す。上記の2つのフォルダーは、この構成図に示す2つのAPIとマッチしている。

図4 Android版Wikitude SDK(JavaScript API)のアーキテクチャ

前回のiOS版と構成内容はほぼ同じだ。

 ARchitect WorldをロードするビューコンポーネントであるARchitectViewは、ARビュー画面に対応するアクティビティ内で使われている。参考までに、ARchitect Worldをロードしている箇所のコードを抜き出して掲載しておく。

Java
/** Wikitudeのライセンスキーを定数として定義。*/
// TODO: 実際に取得した正しいWikitudeのアクセスキーに変更してください。
protected static final String WIKITUDE_SDK_KEY = @"<ライセンスキーを書き直してください!>";

/** ARchitect WorldとなるHTMLファイルのURLを定数として定義。*/
protected static final String MAIN_ARCHITECT_WORLD_URL = "ArchitectWorld/index.html";

……中略……

/**
* [アクティビティのライフサイクル]アクティビティが作成される時に呼び出されます。
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  ……中略……
  
  // ARビュー用のレイアウト("\app\src\main\res\layout\activity_main.xml")を設定します。
  setContentView(R.layout.activity_main);
  ……中略……
  
  // ライフサイクル通知などに対するARchitectViewを設定します。
  this.architectView = (ArchitectView) this.findViewById(R.id.architectView);
  
  // SDKキーと必要な機能(ジオロケーションと2D画像トラッキング)を指定します。
  final StartupConfiguration config = new StartupConfiguration(
      WIKITUDE_SDK_KEY,
      StartupConfiguration.Features.Geo | StartupConfiguration.Features.Tracking2D,
      StartupConfiguration.CameraPosition.DEFAULT);
  
  // ARchitectViewのライフサイクルメソッド「onCreate」を呼び出す必要があります。
  try {
    this.architectView.onCreate(config);
  } catch (RuntimeException rex) {
    ……中略……
  }
  ……中略……
}

/**
* [アクティビティのライフサイクル]アクティビティが作成&表示完了した直後に呼び出されます。
*/
@Override
protected void onPostCreate(Bundle savedInstanceState) {
  super.onPostCreate(savedInstanceState);
  
  if (this.architectView != null) {
    
    // architectViewのライフサイクルメソッド「onPostCreate」を呼び出す必要があります。
    this.architectView.onPostCreate();
    
    try {
      // ARchitect World(=HTMLファイル)を、メインコンポーネントであるARchitectViewにロードします。
      // Android向けでは、HTMLファイル内に「<script src="architect://architect.js"></script>」を必ず記載する必要があります。
      this.architectView.load(MAIN_ARCHITECT_WORLD_URL); 
      
    } catch (IOException e1) {
      ……中略……
    }
  }
}
リスト1 ARchitect Worldをロードしている箇所のコードの抜粋(app/src/main/java/isshiki/mywikitudeappforandroid/MainActivity.java)

 Android Architect SDK APIを用いたアクティビティの開発は、ちょっとしたパラメーター調整などはあるものの、ほとんどの場合では定型のコードとなるので、初学者はざっと流れを理解しておくだけで十分だ。本稿では解説を割愛するが、流れを理解する助けになるように、本稿のサンプルアプリのコードには、しつこいくらい詳しい説明(日本語)をコメントとして入れているので、そちらを参照してほしい。

 ARchitect Worldへ位置変更を通知しているのは、LocationListener実装クラスのonLocationChangedメソッドである(リスト2)。

Java
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  ……中略……
  
  //  位置情報のリスナーを登録します。全ての位置情報更新はここで処理され、ここから本アプリ内で一元的に位置情報を管理するプロバイダー「locationProvider」に引き渡されます。
  this.locationListener = new LocationListener() {
    
    ……中略……
    
    @Override
    public void onLocationChanged(final Location location) {
      // LocationProviderが、位置情報の更新をこのメソッドに伝達します。ここではARchitectViewに位置情報を引き渡すことで、ARchitect Worldの位置情報を更新します。
      if (location != null) {
        // アプリ内のどこかで位置情報が必要になる場合に備えて、最新(=前回)の位置情報を保存しておきます。
        MainActivity.this.lastKnownLocaton = location;
        if (MainActivity.this.architectView != null) {
          
          // ARchitectViewの位置情報を更新します。
          MainActivity.this.architectView.setLocation(
            location.getLatitude(),   // 緯度
            location.getLongitude(),  // 経度
            0.0,                      // 高度(m)。本来なら↓のようにすべきですが、常に「0.0」にすることで、POIの位置を調整しやすくしています。
            //(location.hasAltitude() ? location.getAltitude() : UNKNOWN_ALTITUDE),  // 高度(m)。高度として「UNKNOWN_ALTITUDE」値が使われると、ARchitect Worldでは現在のユーザーの高度情報で代用されます。
            (location.hasAccuracy() ? location.getAccuracy() : 20)  // 精度(m)。精度は、10m以内だと高い、11~35mなら普通、35m以上なら低いと判断してください。
          );
        }
      }
    }
  };
  
  // 位置情報を収集するために使うLocationProviderに、位置情報リスナー(locationListener)を指定してインスタンスを生成・取得します。
  this.locationProvider = getLocationProvider(this.locationListener);
  
  ……中略……
}
リスト2 ARchitect Worldへ位置変更を通知している箇所のコードの抜粋(app/src/main/java/isshiki/mywikitudeappforandroid/MainActivity.java)

 LocationProviderは位置情報関連の処理をまとめるためのAndroid向け実装戦略パターンで、そのサンプル実装がILocationProviderインターフェースとLocationProviderクラスとしてSDKサンプルに同梱されている。本稿では、それらをそのまま活用している。

1.4 ARchitect Worldの実装内容

 ここまで来たら、あとはARchitect WorldをHTML+CSS+JavaScriptで自由に実装していくだけだ。Android Studioはネイティブ開発では必要であるが、ARchitect World開発では必要最低限の使用で済む。ここからは基本的に使い慣れたテキストエディターを中心に使って開発を進めればよい。

位置変更時の処理

 ネイティブ側(前掲のリスト2)のMainActivity.this.architectView.setLocationメソッドの実行により、JavaScript側(リスト3)のAR.context.onLocationChangedにセットされたJavaScript関数が呼び出される。本稿のサンプルでは、リスト3に示すWorld.locationChanged関数が呼び出される。

JavaScript
// ARchitect World(=AR体験)の実装
var World = {
  ……中略……
  
  // ロケーションを更新します。Androidネイティブ環境でarchitectView.setLocationメソッドが呼び出されるたびに、この関数は呼び出されます。iOSではネイティブサービスのstartUpdatingLocationメソッドを呼び出すとここが呼び出されるようです(ドキュメント無し)。
  locationChanged: function (lat, lon, alt, acc) {
    
    if (World.changingLocationDisplay) return;
    World.changingLocationDisplay = true;
    
    // World.initiallyLoadedDataフラグを確認して、初回起動時にのみPOIデータをロードする処理を実行します。
    if (!World.initiallyLoadedData) {
      // 緯度・経度などを指定してrequestPOIsFromWebAPI関数を呼び出し、現在地周辺のPOIデータを取得し、ARタグを作成します。
      World.requestPOIsFromWebAPI(lat, lon, alt, acc);
      World.initiallyLoadedData = true;  // 最後にフラグを「読み込み済み」(=true)に設定します。
      
    } else {
      // 緯度・経度などを指定してupdatePOIs関数を呼び出し、現在地周辺のPOIデータを更新し、ARタグを作成します。
      World.updatePOIs(lat, lon, alt, acc);
    }
    
    // テスト表示用(iボタンをタップすると表示される状態メッセージをセットします)。
    World.updateStatusMessage(World.markerList.length + "件、緯度・経度:" + lat + ", " + lon);
    //alert("緯度・経度:" + lat + ", " + lon);
    
    World.changingLocationDisplay = false;
  },
  
  ……中略……
};

/*
  ロケーションが変更された時の処理を実行する関数をセットします。
*/
AR.context.onLocationChanged = World.locationChanged;
リスト3 位置変更時のARchitect World側処理のコード抜粋(/ArchitectWorld/js/mainlogic.js)

 初回ロード時は、World.requestPOIsFromWebAPI関数を呼び出してホットペッパーWeb APIからレストラン情報を取得している(詳細後述)。それ以降の位置情報更新時は、World.updatePOIs関数を呼び出して位置表示用ARタグの内容を更新したり、必要があればもう一度Web APIにアクセスしてレストラン情報を取得し直したりしている。

Web APIからの情報取得

 Web APIを呼び出す方法は、通常のWeb開発での方法と変わらない。本稿のサンプルではリスト4に示すとおり、jQueryを用いて処理している(参考:「jQuery: JSON形式のWeb APIにアクセスするには?($.getJSON)」)。ホットペッパーWeb APIを使うには、「リクルートWEBサービス」でキーを取得する必要がある。

JavaScript
var World = {
  
  // TODO: 適切な「リクルートWEBサービス(ホットペッパー)」のキーを指定してください。
  webApiKeyID: '<キーを書き直してください! 例:abc01234567890de>',
  
  ……中略……
  
  // 指定された地点における全てのPOIデータをロードします。
  requestPOIsFromWebAPI: function (centerPointLatitude, centerPointLongitude, centerPointAltitude, centerPointAccuracy) {
    
    ……中略……
    
    // cachedDataオブジェクトは、cacheddata.jsに固定的に定義しておいたレストランのPOIデータです。
    // 本サンプルでは、ここで「ホットペッパー」のWeb APIから動的にレストランデータを取得しています。
    
    // 以下では、「ホットペッパー」のWeb APIから動的にレストランデータを取得して、それをPOIデータに加工して表示しています。
    cachedData = [];  // 新しく検索し直すので、全てのデータをクリアしています。
    var params = {
      keyid: World.webApiKeyID,
      format: 'jsonp',
      callback: '&callback=?',           // jQueryにより「?」にはコールバック関数名が自動セットされます。
      latitude: centerPointLatitude,
      longitude: centerPointLongitude,
      range: 3,                         // 中心点からの検索範囲(半径)。1:300m、2:500m、3:1000m(初期値)、4:2000m、5:3000m
      hit_per_page: 100,                // 1回のMAXは100件。100件ずつ何ページも読み取り、最終的に上記に検索範囲にある全てを読み込みます。
      offset_page: 1                    // 1ページ目から取得していきます。
    };
    var loadPOIsFromWebApi = function() {
      var url = 'http://webservice.recruit.co.jp/hotpepper/gourmet/v1/?' + 
        'key=' + params.keyid + 
        '&lat=' + params.latitude + 
        '&lng=' + params.longitude + 
        '&range=' + params.range +
        '&count=' + params.hit_per_page +
        '&start=' + ((params.hit_per_page * (params.offset_page - 1)) + 1) +
        '&format=' + params.format + 
        params.callback;
      $.getJSON(url) 
      .done(function(json) {
        var total_hit_count = parseInt(json.results.results_returned);
        if (total_hit_count > 0) {
          for (var n in json.results.shop) {
            cachedData.push({
              "id":        (json.results.shop[n].id),
              "name":      (json.results.shop[n].name),
              "latitude":  parseFloat(json.results.shop[n].lat),
              "longitude": parseFloat(json.results.shop[n].lng),
            });  // 再ロードをできるだけ抑折するために、少し広めのレストランJSONデータをcachedData変数に保持しておきます。
          }
          if ((params.hit_per_page * params.offset_page) < total_hit_count) {
            params.offset_page++;
            loadPOIsFromWebApi();  // さらに次のページのデータを読み込む(再帰呼び出し)
          } else {
            World.loadPOIsFromCachedData(centerPointLatitude, centerPointLongitude, centerPointAltitude, centerPointAccuracy, false);  // これ以上、データは読み込まない。
          }
        } else {
          if (params.offset_page == 1) {
            World.updateStatusMessage("0件(レストランが見付かりません!)、緯度・経度:" + lat + ", " + lon);
          } else {
            World.loadPOIsFromCachedData(centerPointLatitude, centerPointLongitude, centerPointAltitude, centerPointAccuracy, false);  // これ以上、データは読み込まない。
          }
        }
      });
    };
    loadPOIsFromWebApi();
  },
  
  ……中略……
};
リスト4 jQueryを用いたWeb APIからの情報取得処理のコード抜粋(/ArchitectWorld/js/mainlogic.js)

 本稿のサンプルでは、World.loadPOIsFromCachedData関数で最終的なPOI(Point Of Interest:注目座標点)データを作成してARタグを表示している。その実装内容については前回のリスト2で示したコードと似ているので、ここでは説明を割愛する(詳しく知りたい場合は、サンプルコードをダウンロードして確認してほしい)。

 なお、今回のARchitect Worldの実装で前回と根本的に異なるのは、前回は「ローカル変数」として定義していたJSONデータが、今回は「JSONP形式のWeb API」で取得することになった点ぐらいだ。もちろんそれ以外にも、アプリとしての機能性向上や、処理内容に合わせて関数名を変更したりはしているが、Wikitude開発を理解するうえでの本質部分ではない。よって前回の説明が理解できたのなら、今回も基本構造は変わっていないので、処理の流れを丁寧に読めば理解できるはずだ。

 ちなみにWeb APIは、本稿のようにJavaScriptのARchitect World側ではなく、ネイティブ側で呼び出して取得したデータをARchitect Worldに引き渡すことも可能である。しかしネイティブ側で処理してしまうと、iOSとAndroidで処理を共有できないというデメリットがあるので、基本的にはJavaScript側に実装するのがオススメだ。

1.5 Wikitude開発に役立つドキュメント類(Android編)

 以上で開発は完了だ。Web APIを利用したAR開発の感触をつかんでいただけただろうか。

 Android向けARアプリ開発方法のまとめとして、開発時に参考となる各種ドキュメント類について箇条書きでまとめておく(ヘルプドキュメントはSDKにも同梱されており、下記のフォルダー内に存在する)。

○ Web上でのみ提供されている公式チュートリアル
○ 「/Reference/Android Architect SDK API」フォルダー

 Androidネイティブ部分の開発には基本的にJava言語を使う必要がある。よって公式のJava開発用のAPIリファレンスも示しておこう。

○ 「/Reference/JavaScript API」フォルダー

 ちなみにJavaScript APIではなくAndroidネイティブAPIを使う場合は、

を参照する必要がある。

2. Wikitude開発時の効率的なデバッグ手法

 以上、Wikitude開発の基礎を説明した。あとは実践あるのみだが、効率的に開発を進めていくうえで、適切なデバッグ手段を選択するのは重要である。Wikitudeにはさまざまなデバッグ方法が用意されており、ケースバイケースで使い分けて開発していくことになる。

 本連載の最後に、このデバッグ手法について簡単に紹介する。なおデバッグ手法は、iOSとAndroidで大きな違いはなく、以下の説明はどちらでも共通する話として読んでほしい(差異がある部分はその都度、説明する)。

2.1 ARchitectView&ネイティブ回り(Android/iOS Architect SDK API)の開発とデバッグ

 これは通常のiOS/Android開発と変わらない。カメラを使う必要があるので、基本的には実機デバッグとなる。iOS開発であればXcodeのデバッガー、Android開発であればAndroid Studioのデバッガーを用いて、ブレークポイントを設定したり、例外の内容を把握したりできる。これについては説明不要だろう。

2.2 ARchitect World(JavaScript API)回りの開発とデバッグ

 これには、実機デバッグだけでなく、ブラウザーデバッグが行えるのがWikitudeの特長である。

 まずは実機デバッグの方法について見ていこう。

2.3 ARchitect Worldを実機デバッグするための2つの手法

 ARchitect Worldを実機でデバッグするには、大きく分けて下記の2つの手段が使える。

  • 1alert表示とログ出力
  • 2開発者ツール

 それぞれ簡単に説明していこう。

1alert表示とログ出力

 原始的なデバッグ手段としては、JavaScriptのalert関数を使うことが考えられる(リスト5)。もちろんARchitect Worldでもこれは実現可能で、1回限りでちょっとだけ値をチェックしたい場合などで役立つだろう。

JavaScript
var World = {
  ……中略……
  locationChanged: function (lat, lon, alt, acc) {
    alert("緯度・経度:" + lat + ", " + lon);
  },
  ……中略……
};
リスト5 JavaScriptのalert関数による原始的なデバッグ(app/src/main/assets/ArchitectWorld/js/mainlogic.js)

 ただ、alert関数ではダイアログが表示されてしまい、処理内容を検証したい場所が増えれば増えるほどデバッグがしにくくなる。そういう状況では、WikitudeのJavaScript APIが提供しているAR.loggerクラスが役立つ(リスト6)。

JavaScript
var World = {
  ……中略……
  locationChanged: function (lat, lon, alt, acc) {
    AR.logger.info("緯度・経度:" + lat + ", " + lon);
  },
  ……中略……
};
リスト6 WikitudeのAR.loggerクラスによるログ出力(app/src/main/assets/ArchitectWorld/js/mainlogic.js)

 上記の例ではinfoメソッドにメッセージを指定して呼び出しているが、AR.loggerクラスには下記の4種類のログ出力用メソッドが提供されている。

  • debugメソッド: コンソールに「デバッグ」メッセージを出力する
  • errorメソッド: コンソールに「エラー」メッセージを出力する
  • infoメソッド: コンソールに「情報」メッセージを出力する
  • warningメソッド: コンソールに「警告」メッセージを出力する

 これらのログ出力は「ADE」(ARchitect Desktop Environment)により、実機端末上で確認できる。ADEを表示するには、Wikitudeのデバッグモードをアクティブにする必要がある。これには、ARchitect Worldの実体となるメインHTMLファイルの<body>タグに、onLoad="javascript:AR.logger.activateDebugMode();"属性を指定するだけである(リスト7)。なお、ADEの実体であるade.jsファイルがSDKに同梱されているので(/Tools/ADE/ade.js)、これをあらかじめARchitect World配下のフォルダー内に含めておく必要がある。

HTML
<!DOCTYPE html>
<html>

<head>
  ……中略……
  <!-- ADE(ARchitect Desktop Environment)ライブラリをインポートします。 -->
  <script src="js/ade.js"></script>
  
  ……中略……
</head>

<!--<body>-->
<body onLoad="javascript:AR.logger.activateDebugMode();"><!--⇒ログ出力を有効にするには、onLoad属性付きのこちらを有効にしてください。-->
  ……中略……
</body>
</html>
リスト7 ARchitect Worldの実体となるメインHTMLファイル内で、Wikitudeのデバッグモードをアクティブ化(app/src/main/assets/ArchitectWorld/index.html)

 ADEが有効な状態でWikitudeアプリを実機で実行すれば、図5のようにしてログメッセージを確認できる。実機での動作を細かく検証したいときに大変役立つ機能である。

図5 実機でのログメッセージの確認(ADE): 右下のオレンジ色の三角をタップ

右下のオレンジ色の三角をタップ

図5 実機でのログメッセージの確認(ADE): [Error]/[Warning]/[Info]/[Debug]ボタンをオン/オフすると、その対象のログメッセージを閲覧できる

[Error]/[Warning]/[Info]/[Debug]ボタンをオン/オフすると、その対象のログメッセージを閲覧できる

図5 実機でのログメッセージの確認(ADE)
2開発者ツール

 実機デバッグが必要な場面において、大半のケースではログ出力ができれば何とかなるだろう。しかし、JavaScriptコードをステップ実行したり、ARオブジェクトのHTML内容やオブジェクト内容を確認したりして、ログ出力よりももっと細かいデバッグ作業が必要となるケースもある。そのような場合には、iOSであればSafariの[Web インスペクタ](開発者ツール)、AndroidであればChromeの[デベロッパー ツール](DevToolos)を用いてデバッグすることが可能だ。図6は実際に[Web インスペクタ]を使ってデバッグしている例である。

図6 [Web インスペクタ]を使ってデバッグしている例(iPhone実機上のARchitect Worldをデバッグ)

 開発者ツールによるデバッグには、モバイルWebアプリをデスクトップからリモートデバッグする通常の手段がそのまま使える。Wikitude特有の手法ではないので、ここでは説明を割愛する。詳しくは、各公式リファレンス「SafariでiOSリモートデバッグ」/「ChromeでAndroidリモートデバッグ」(いずれも英語)を参照してほしい。

 実機デバッグに続いて、ローカルでのブラウザーデバッグについて見ていこう。

2.4 ARchitect Worldをローカルでブラウザーデバッグ

 ARchitect Worldを実機でデバッグするのは、アプリが完成に近づいて、実際の状態をテストしたいときには確かに有効だ。しかし通常の開発段階で、わざわざ実機にアプリをデプロイしてデバッグするのでは手間が掛かりすぎる。このような作業コストの問題を回避するための手段がWikitudeにより提供されている。これが先ほども登場したADE(ARchitect Desktop Environment)である。

 これを試すのは簡単である。前掲のリスト6のようにADEをインポートしてデバッグモードを有効にした状態で、HTMLファイル(本稿ではapp/src/main/assets/ArchitectWorld/index.html)をダブルクリックするなどして、任意の使い慣れたブラウザーに表示するだけだ。表示されたら前掲の図5にあったように右下のオレンジ色の三角をタップすると、ADEのデバッグ画面が表示される。図7のように緯度・経度を指定して位置情報の変更通知を手動で発行したり、ARchitect World内のオブジェクトをツリー表示したりできる。また、上部のタブを[ADE]から[Logger]に切り替えることで、ローカルでもログ出力を確認できる。

図7 ADEを用いたローカルでのブラウザーデバッグ: 緯度・経度を入力して[Apply and Save]ボタンをクリックすると、変更通知の手動発行とともに、ブラウザーに緯度・経度を保存できる(=再利用可能)

緯度・経度を入力して[Apply and Save]ボタンをクリックすると、変更通知の手動発行とともに、ブラウザーに緯度・経度を保存できる(=再利用可能)

図7 ADEを用いたローカルでのブラウザーデバッグ: [onClick]リンクをクリックすることでクリック動作を手動でシミュレーションできる

[onClick]リンクをクリックすることでクリック動作を手動でシミュレーションできる

図7 ADEを用いたローカルでのブラウザーデバッグ

 さらに、Chromeなどの[デベロッパー ツール]と組み合わせることで、JavaScriptの挙動をステップ実行するなど細かなデバッグが可能だ。多様なデバッグ作業ができるので、手間のかかる実機端末でのデバッグを行う前に、まずはローカル環境でブラウザーデバッグができないかを試すべきだ。

図8 ADEと[デベロッパー ツール]を組み合わせて細かなデバッグ

 何よりARchitect Worldの開発は、挙動の重いIDE(Android StudioやXcode)を全く触らずにできるのが本当に便利だ。好きなテキストエディターを使って、JavaScriptコードを書いていくだけで開発を進められる。実際に本稿のサンプル作成でも、ほとんどテキストエディターで開発した。いったんネイティブ回りの実装さえ完成すれば、あとは開発が楽になるので、本稿が提供するサンプルなどをうまく使ってネイティブ開発部分をできるだけ手軽に済ませて、さまざまなモバイルAR開発にチャレンジしていただけると筆者としてうれしい。

3. まとめ - さらに開発を進めたいと思った方へ

 以上、3回にわたってWikitudeによるロケーションベースのモバイルARアプリの開発を紹介した。本稿で紹介したのは、Wikitude開発のほんの一部であり、他にも多種多様な開発が可能である。興味がある方は、本連載の次には下記のオンラインドキュメントに進んでみてほしい。

 Wikitude開発で壁にぶつかった場合は、英語ではあるが下記のサイトも利用するとよい。

1. 拡張現実(AR)とは? モバイルARを実現するテクノロジーと開発ライブラリ[PR]

ARの概要と特徴、利用モデルを図と動画で初歩から解説。主な開発ライブラリと、その一つであるWikitudeを紹介し、AR開発で使える「位置情報データ&API」も紹介する。

2. iPhone向け拡張現実アプリの開発に挑戦してみた(Wikitude活用)[PR]

モバイルARアプリ開発に初挑戦! 位置情報を含むオープンデータの「バス停位置情報」と、ARライブラリの「Wikitude」を活用したら、拡張現実に対応した有用なiOSアプリが簡単に開発できた。

3. 【現在、表示中】≫ WikitudeでカンタンAndroid向けAR開発。ブラウザーでデバッグ可能[PR]

位置情報を含むレストラン検索の「ホットペッパーAPI」を活用したAndroid向けモバイルARアプリを作成。Wikitudeを使えば、使い慣れたテキストエディターで開発し、ブラウザーで手軽にデバッグできる。

4. AR(拡張現実)開発を始めよう! 複数ターゲットの認識と、距離・角度の把握(Wikitude活用、iOS編)[PR]

2人の相性を写真から診断するアプリを、画像認識型ARで開発。ターゲット写真を認識してARオブジェクトを表示し、2枚のターゲット間の距離と角度が一定の条件内になれば診断を開始する仕組みだ。

5. 身の回りの3D物体を認識して、そこにAR(拡張現実)オブジェクトを表示する方法(Wikitude活用、Android編)[PR]

市販のドレッシングボトルを映せばレシピが提案されるアプリを、物体認識型ARで開発。物体ターゲットを認識すると、その物体空間に合わせてARオブジェクトを表示し、それをタップするとレシピページにジャンプする。

サイトからのお知らせ

Twitterでつぶやこう!