MapFragmentを使ってみた

2013-03-24T00:00:00+00:00 Android Java

タイトル通り。今更ながらMapFragmentを使ってGoogle MapsをAndroidアプリ上に表示させてみた

インストール

Google Play Serviceが必要になる。Android Package Manager?で入れておく。で自分の場合はAndroid SDKが/opt/androidにあるので/opt/android/extras/google/google_play_services/libproject/google-play-services_libをEclipseのライブラリプロジェクトとしてインポートする

これがどうも「ファイル」->「インポート」で出来なかったので、「ファイル」->「新規」から「Android Project from Existing Code」からインポート処理をする。でどうやらこれが必要な理由としてcom.google.android.gcm.Rっていうクラスが必要なのだけど、これがこのプロジェクトしか入ってないので必要っぽい

Google Maps APIのAPI Keyを取得する

https://code.google.com/apis/console から

  • Servicesで「Google Maps Android API v2」をonにする
  • API Accessにて「Create new Android Key」でAPI Keyを取得する

1は問題無いけど2ではキーストアのフィンガープリントが必要なので

keytool -list -v -keystore debug.keystore

で出力されたSHA1なフィンガープリントをコピーして「フィンガープリント内容;パッケージ名」
でAPI Access時に指定して取得。ちなみにデバッグ用(Eclipseでやる場合)のキーストアは$HOME/.android/debug.keystoreっぽい。Windowsは知らん

これで準備完了、あとはコードを書くだけ

AndroidManifest.xml

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="sample.test"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" />

    <permission android:name="sample.test.permission.MAPS_RECEIVE" android:protectionLevel="signature" />
    <uses-permission android:name="sample.test.permission.MAPS_RECEIVE" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <uses-feature android:glEsVersion="0x00020000" android:required="true" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">

        <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="Google Maps APIのAPI Key" />

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

com.google.android.maps.v2.API_KEYが必要なくらいであとはパーミッションとかちょこちょこな事が必要なくらい

res/layout/main.xml

<?xml version="1.0" ?>
<fragment
    class="com.google.android.gms.maps.SupportMapFragment"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/map"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

古い端末で実検証したのでcom.google.android.gms.maps.SupportMapFragmentを使ってますが、新しめな場合はcom.google.android.gms.maps.MapFragmentでいいのかも

MainActivity.java

package sample.test;

import java.util.ArrayList;
import java.util.List;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.PolygonOptions;
import com.google.android.gms.maps.model.PolylineOptions;

import android.app.AlertDialog;
import android.graphics.Color;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;

public class MainActivity extends FragmentActivity {

    private static final String TAG = "MainActivity";

    private GoogleMap map;

    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.main);

        map = ((SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
        map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
        map.setMyLocationEnabled(true);
        map.setTrafficEnabled(true);

        map.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
            @Override
            public void onInfoWindowClick(Marker marker) {
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);

                builder
                    .setMessage(marker.getTitle())
                    .create()
                    .show();
            }
        });

        map.setOnMyLocationChangeListener(new GoogleMap.OnMyLocationChangeListener() {
            @Override
            public void onMyLocationChange(Location loc) {
                LatLng pos1 = new LatLng(loc.getLatitude(), loc.getLongitude());

                // 東京スカイツリー
                LatLng pos2 = new LatLng(35.7105827, 139.81148759999996);

                MarkerOptions marker1 = new MarkerOptions();
                marker1
                    .position(pos2)
                    .title("タイトル")
                    .snippet("スニペット");

                map.addMarker(marker1);

                PolylineOptions marker2 = new PolylineOptions();
                marker2
                    .add(pos1, pos2)
                    .color(Color.argb(80, 255, 0, 0))
                    .geodesic(true);

                map.addPolyline(marker2);

                int blueColor = Color.argb(80, 0, 0, 255);

                CircleOptions marker3 = new CircleOptions();
                marker3
                    .fillColor(blueColor)
                    .strokeWidth(0)
                    .center(pos2)
                    .radius(100);

                // 以下のmarker4と位置がかぶる。一応見え無くもないけど
                map.addCircle(marker3);

                // GeoHashを使って近傍エリアを取得するだけ (APIはAndroidパッケージには含まれてない)
                String geoCode = GeoHash.encode(pos2.latitude, pos2.longitude, 5);
                List<String> geoCodes = GeoHash.neighbor(geoCode);
                List<LatLng> positions = new ArrayList<LatLng>(geoCodes.size());

                for (String code : geoCodes) {
                    double[] latlng = GeoHash.decode(code);

                    positions.add(new LatLng(latlng[0], latlng[1]));
                }

                PolygonOptions marker4 = new PolygonOptions();
                marker4
                    .addAll(positions)
                    .strokeWidth(0)
                    .fillColor(blueColor);

                map.addPolygon(marker4);

                map.moveCamera(
                    CameraUpdateFactory.newCameraPosition(
                        new CameraPosition.Builder()
                            .target(pos2)
                            .zoom(10f)
                            .build()
                    )
                );

                map.setOnMyLocationChangeListener(null);
            }
        });
    }
}

でおおまかな動作概要

ソースに書いてる通り現在地と東京スカイツリーをPolylineで線を繋ぐ。で東京スカイツリーにマーカーを設置している

でちょいとズームしてマーカーをタップする

で出た吹き出しもタップすると

これがGoogleMap.OnInfoWindowClickListenerな模様。まぁ上で出てるけど、円なマーカーも付けてる。で最後にPolygonなマーカー

な感じでマーカーをつけれたりする

んまぁあとは以下に記載している参考サイトを見る+公式ドキュメントに書いているのでそれ読めば良いかと

参考: http://dev.classmethod.jp/smartphone/android/android-tips-25-google-maps-android-api-v2

yuidocでアンダースコア(アンダーバー)を使うと消える件