【kotlin / osmdroid】Androidスマートフォンに国土地理院地図を表示する

各地の里山のような知名度のない山に登る際、登山地図は発売されておらず、またGoogle Mapでは徒歩道の情報がありません(いつか徒歩道も含まれるような気はします)。

徒歩道の把握のためには国土地理院地図が必携なので、電子地図の勉強も兼ねて国土地理院地図を表示するAndroidアプリケーションを作成してみることにしました。

地図ライブラリ

Androidの地図ライブラリのなかで最も一般的であり、開発に関わる情報量が多いのはやはりGoogle Maps Platformかと思います。
ただGoogle Maps Platformsは従量課金制となってしまい、少ないアクセス数では使用料がかからないものの、一定アクセス数を超えると課金されてしまうので恐ろしくて使えません。

Googleプロダクトが使えないとなるとオープンソースから探すことになり、つぎにメジャーなライブラリはOpen Street MapベースのMapboxになります。しかしながら、これもGoogle Maps Platformより安価とはいえ一定数のアクセスで有料となっています。
商用アプリケーションでも採用例が多く開発の情報量も見込めることからMapboxで開発してみようかとも思いましたが、Access Tokenを取得しなければならない点で少し気が重くなります。

それでは第三の選択肢ということで、情報量は少ないもののフリーで利用できそう、かつ現在もアップデートが続いているという条件に当てはまるosmdroidを使って地図アプリのベースを作ってみたいと思います。

開発環境の準備

osmdroidの環境については同プロジェクトのGitHubにしっかり書かれています。

github.com

ただドキュメントまで手が回っていないのか、javaサンプルコード通りに作ろうとするとDeprecatedの警告が出たりするので、その点を変更しています。

build.gradle

repositories {
        mavenCentral()
}

dependencies {
    implementation 'org.osmdroid:osmdroid-android:6.1.2'
    implementation "androidx.preference:preference-ktx:1.1.0"
}

osmdroidの最新版は2019/09/28時点で、"6.1.2"です。
osmdroidのサンプルコードでは"PreferenceManager"を使用していますが、これはAPI Level 29で非推奨となるため"AndroidX Preference Library"を使用します。

AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

"INTERNET"と"ACCESS_NETWORK_STATE"は国土地理院地図にアクセスするために使用します。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    <view android:layout_width="0dp" android:layout_height="0dp" class="org.osmdroid.views.MapView"
          id="@+id/view"
          app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
          app:layout_constraintStart_toStartOf="parent"
          app:layout_constraintEnd_toEndOf="parent" android:id="@+id/mapview"/>
</androidx.constraintlayout.widget.ConstraintLayout>

レイアウトは"constraintlayout"を使用していますが、"LinearLayout"でもなんでもかまいません。

MainActivity.kt

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.preference.PreferenceManager
import org.osmdroid.config.Configuration
import org.osmdroid.tileprovider.tilesource.XYTileSource
import org.osmdroid.util.GeoPoint
import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.ScaleBarOverlay

class MainActivity : AppCompatActivity() {

    private lateinit var mapView: MapView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Configuration.getInstance().load(applicationContext, PreferenceManager.getDefaultSharedPreferences(applicationContext))
        setContentView(R.layout.activity_main)

        mapView = findViewById(R.id.mapview)
        val tileSource = XYTileSource("GSI Map", 5, 18, 256, ".png", arrayOf("https://cyberjapandata.gsi.go.jp/xyz/std/"))
        mapView.setTileSource(tileSource)
        mapView.setMultiTouchControls(true)

        // 地図センター位置
        val mapController = mapView.controller
        mapController.setZoom(15.0) // ズームレベル 15
        mapController.setCenter(GeoPoint(35.658581,  139.745433))  // 東京タワー
    }

    override fun onPause() {
        super.onPause()
        mapView.onPause()
    }

    override fun onResume() {
        super.onResume()
        mapView.onResume()
    }
}

XYTileSourceで国土地理院の標準地図を指定します。
コンストラクタ

XYTileSource(String aName, int aZoomMinLevel, int aZoomMaxLevel, int aTileSizePixels, String aImageFilenameEnding, String[] aBaseUrl)

に対し、標準地図のズームレベル "5 - 18"、タイルのピクセル "256 * 256"、拡張子 "png"を設定しています。

現在は東京タワーをセンターに表示しているので、GPS取得位置をセンターにするよう変更していく予定です。

blog.misatowater.com