Androidから,Google Maps Engine APIを使う例です.なお,マップの中身を取得することはできなかったため,実用上はあまり意味がないです orz
AndroidからMaps Engine APIを使う
マイマップはGoogle Maps Engine Liteに統合されるらしいという話があります.
それで,このMaps Engine LiteをAndroidから扱えないか,参照できないかということで,調べてみました.
なお最後に書いていますが,結局マップの中身を取得することはできなかったため,このページの内容は実用上はあまり意味がないです.orz
APIの利用登録
APIを使う時の認証の話は,
Installed Application Authentication - Google Maps Engine API
に書かれています.基本的にはこれに従うことにします.
ただAndroidなので,端末に設定されているアカウントをAccountManager経由で使うということで,色々と違ってきます.
APIの利用登録ですが,
Google API Console
から,利用するアプリの署名とパッケージ名を登録して下さい.
Mapsなど他のAPIを使う場合と同じなので特に説明しませんが,ポイントは
- Servicesで「Google Maps Engine API」をONにする
- API Accessで登録しますが,必ず「Authorized API Access(OAuth 2.0)」で登録する.「Installed application」-「Android」です.Google Maps APIなどと同じ調子で「Simple API Access」に登録すると,駄目です
ぐらいだと思います.
ライブラリの準備
素直に
Google APIs Client Library for Java
を使うことにします.
試した時点の最新版,
- google-api-java-client-1.17.0-rc.zip
を使いました.
ダウンロードしたzipを展開すると色々jarがありますが,自分のアプリのプロジェクトに以下のファイルを追加しました.
libsに入れて,ビルドパスに追加したファイル
commons-codec-1.3.jar
commons-logging-1.1.1.jar
google-api-client-1.17.0-rc.jar
google-api-client-android-1.17.0-rc.jar
google-http-client-1.17.0-rc.jar
google-http-client-android-1.17.0-rc.jar
google-http-client-gson-1.17.0-rc.jar
google-oauth-client-1.17.0-rc.jar
gson-2.1.jar
httpclient-4.0.1.jar
httpcore-4.0.1.jar
jsr305-1.3.9.jar
なお,commons-codec-1.3.jarはgoogle-api-java-clientに同梱されていないので,
http://repo.maven.apache.org/maven2/commons-codec/commons-codec/1.3/commons-codec-1.3.jar
からダウンロードしました.
このあたりの依存関係の情報は,google-api-java-clientのzipを展開した中身の
dependencies/google-api-client-android-dependencies.html
に書かれています.
Google Play Services APIの追加も必要です.Google Maps Android API v2を使うときと同じですが,google-play-services_lib のライブラリプロジェクトを参照する設定にして下さい.
AndroidのAccountManagerを認証に使う場合の参考資料は,
また,Maps Engine API固有の処理についてですが,Fusion Tablesなど他のAPIは,インターフェイスのラッパーライブラリが用意されていて,
からダウンロードできます.しかしMaps Engineのものは無かったので,自前で実装します.
ソースコード
mapsパスを呼び出して,mapId指定でmapのメタデータを取得する例です.logcatに出力します.
tasks-android-sampleのソースを元に,改造したものです.
MainAct.java
package
com.kamoland.gapitest.tasks;
import
com.google.android.gms.common.GooglePlayServicesUtil;
import
com.google.api.client.extensions.android.http.AndroidHttp;
import
com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import
com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
import
com.google.api.client.http.GenericUrl;
import
com.google.api.client.http.HttpRequest;
import
com.google.api.client.http.HttpRequestFactory;
import
com.google.api.client.http.HttpResponse;
import
com.google.api.client.http.HttpTransport;
import
android.accounts.AccountManager;
import
android.app.Activity;
import
android.content.Context;
import
android.content.Intent;
import
android.content.SharedPreferences;
import
android.os.Bundle;
import
android.util.Log;
import
java.io.BufferedReader;
import
java.io.IOException;
import
java.io.InputStreamReader;
import
java.util.Collections;
public
class
MainAct extends
Activity {
private
static
final
String PREF_ACCOUNT_NAME = "accountName"
;
private
static
final
int
REQUEST_GOOGLE_PLAY_SERVICES = 0;
private
static
final
int
REQUEST_AUTHORIZATION = 1;
private
static
final
int
REQUEST_ACCOUNT_PICKER = 2;
private
GoogleAccountCredential credential;
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
credential = GoogleAccountCredential
.usingOAuth2(this
,Collections.singleton(
"https://www.googleapis.com/auth/mapsengine.readonly"
));
// "https://www.googleapis.com/auth/mapsengine")); // read and write
SharedPreferences settings = getPreferences(Context.MODE_PRIVATE);
credential.setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null
));
}
@Override
protected
void
onResume() {
super
.onResume();
if
(checkGooglePlayServicesAvailable()) {
haveGooglePlayServices();
}
}
@Override
protected
void
onActivityResult(int
requestCode, int
resultCode, Intent data) {
super
.onActivityResult(requestCode, resultCode, data);
if
(requestCode == REQUEST_GOOGLE_PLAY_SERVICES) {
if
(resultCode == Activity.RESULT_OK) {
haveGooglePlayServices();
} else
{
checkGooglePlayServicesAvailable();
}
} else
if
(requestCode == REQUEST_AUTHORIZATION) {
if
(resultCode == Activity.RESULT_OK) {
} else
{
chooseAccount();
}
} else
if
(requestCode == REQUEST_ACCOUNT_PICKER) {
if
(resultCode == Activity.RESULT_OK && data != null
&& data.getExtras() != null
) {
String accountName = data.getExtras().getString(AccountManager.KEY_ACCOUNT_NAME);
if
(accountName != null
) {
credential.setSelectedAccountName(accountName);
SharedPreferences.Editor editor = getPreferences(Context.MODE_PRIVATE).edit();
editor.putString(PREF_ACCOUNT_NAME, accountName);
editor.commit();
}
}
}
}
private
boolean
checkGooglePlayServicesAvailable() {
final
int
connectionStatusCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this
);
if
(GooglePlayServicesUtil.isUserRecoverableError(connectionStatusCode)) {
runOnUiThread(new
Runnable() {
@Override
public
void
run() {
GooglePlayServicesUtil.getErrorDialog(connectionStatusCode,
MainAct.this
, REQUEST_GOOGLE_PLAY_SERVICES).show();
}
});
return
false
;
}
return
true
;
}
private
void
haveGooglePlayServices() {
if
(credential.getSelectedAccountName() == null
) {
chooseAccount();
} else
{
mapEngineRequest();
}
}
private
void
chooseAccount() {
startActivityForResult(credential.newChooseAccountIntent(),
REQUEST_ACCOUNT_PICKER);
}
private
void
mapEngineRequest() {
final
String mapId = "z8XxNtJBE8Uw.kJn9Fyq397d8"
;
(new
Thread() {
@Override
public
void
run() {
try
{
HttpTransport httpTransport = AndroidHttp.newCompatibleTransport();
HttpRequestFactory factory = httpTransport.createRequestFactory(credential);
HttpRequest request = factory.buildGetRequest(new
GenericUrl(
"https://www.googleapis.com/mapsengine/v1/maps/"
+ mapId
));
HttpResponse response = request.execute();
BufferedReader reader = new
BufferedReader(
new
InputStreamReader(response.getContent()));
for
(String line = null
; (line = reader.readLine()) != null
;) {
log(line);
}
} catch
(UserRecoverableAuthIOException uraex) {
startActivityForResult(
uraex.getIntent(),
MainAct.REQUEST_AUTHORIZATION);
} catch
(IOException ex) {
throw
new
RuntimeException(ex);
}
}
}).start();
}
private
static
void
log(String mes) {
Log.d("**GApiTest"
, mes);
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kamoland.gapitest.tasks"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-sdk
android:minSdkVersion="5" android:targetSdkVersion="9" />
<application android:label="GAPI Test">
<activity
android:name=".MainAct" android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
AccountManagerを使っているので,minSdkVersionは5にしています.
これだけの実装で,使用するアカウントの選択ダイアログや,Maps Engineの権限確認のダイアログが表示されて,動きます.
実行結果
ログに以下の内容が出力されれば成功です.Android 2.3.3以上で確認しました.
10-21 09:44:00.322: D/**GApiTest(9834): {
10-21 09:44:00.322: D/**GApiTest(9834): "id": "z8XxNtJBE8Uw.kJn9Fyq397d8",
10-21 09:44:00.322: D/**GApiTest(9834): "name": "大阪城の地図",
10-21 09:44:00.322: D/**GApiTest(9834): "description": "大阪城です",
10-21 09:44:00.322: D/**GApiTest(9834): "versions": []
10-21 09:44:00.322: D/**GApiTest(9834): }
mapIdは,Web版のMaps Engine Liteで「共有」を押したときに出力されるURL
https://mapsengine.google.com/map/edit?mid=z8XxNtJBE8Uw.kJn9Fyq397d8
のmidが対応しています.
このマップはテスト用に,誰でも閲覧できるという設定にしています.
しかしマップの中身は...
で,マップのメタデータは取得できたのですが,それだけでは嬉しくないのデス...
Maps Engine APIの仕様によると,マップの中身を取得するには,
tableIdを指定してfeaturesを取得する
必要がありそうですが,Liteの制限なのかよくわかりませんが,tableIdを知るすべがなさそうです.
...手詰まりになってしまいました.
ちなみに,中身のKMLを,Maps Engine以外の方法で直接取得する方法を試された方もいるようですが,
現在はMaps Engine自体がKML出力機能を持っているため,中止されたようです.
(;´Д`)