LoginSignup
5
0

More than 1 year has passed since last update.

MapLibre GL Native for iOSを簡単に触ってみた

Last updated at Posted at 2022-12-19

MapLibre GLがiOSでも実装できると聞きましたので,今回はMapLibre GL Native for iOSを簡単に触ってみました.

参考サイト

MapTilerさんが MapLibre GL Native for iOS の チュートリアル を書いています.これを参考にしながら触ってみます.

環境

  • Xcode 14.2
  • Swift 5.7

今回はSwiftUIで実装していきます.

事前準備

Xcodeのプロジェクトの作成は省略します.

MapLibre GL Native for iOSを入れるために,パッケージをインストールします.

画面上部の「File」=>「Add Packages...」を選択します.

メニュー選択

右上の検索バーにMapLibre GLのGithub URL ( https://github.com/maplibre/maplibre-gl-native-distribution ) を入力します.その後,「maplibre-gl-native-distribution」を選択した状態で 「Add Package」 を押します.

インストール1

途中でmapboxのパッケージをインストールする画面が出てきます.これも「Add Package」を押します.

インストール1

左のサイドバーの「Package Dependencies」に「MapLibew GL Native」が表示されていれば,インストール完了です.

サイドバー

また,TARGETS => General => Frameworks, Libraries, and Embedded Content の中に「Mapbox」があるか確認してください.

TARGETS Frameworks

マップ表示の実装

マップを表示する部分を実装していきます.今回はSwiftUIで実装します.表示に関わるフォルダ構成は下記のとおりです(少し省略しています).

MGLMapView は,SwiftUIには対応しておらず,UIKitで定義する必要があります.SwiftUIに適用するために, MapLibreView.swiftMGLMapView の定義をしていきます.

Frameworks

MapLibreView.swift

UIKitでのみ対応しているライブラリをSwiftUIに適用するためには, UIViewRepresentable を継承してViewを定義します.まずは,全体のソースコードです.

API Keyは適切に管理してください.
.env ファイルを用いて管理する方法や, .plist ファイルを用いて管理する方法などが挙げられます.

MapLibreView.swift
import Mapbox
import MapKit
import SwiftUI

struct MapLibreView: UIViewRepresentable {
    
    func updateUIView(_ uiView: MGLMapView, context: Context) {
        
    }
    
    func makeUIView(context: Context) -> MGLMapView {
        let mapTilerAPIKey = {YOUR_MapTiler_APIKEY}
        let styleURL = URL(string: "https://api.maptiler.com/maps/basic-v2/style.json?key=\(mapTilerAPIKey)")
        let mapView = MGLMapView(frame: .zero, styleURL: styleURL)
        
        // Mapboxのロゴを消します.
        mapView.logoView.isHidden = true
        
        mapView.setCenter(
            CLLocationCoordinate2D(latitude: 35.6809591, longitude: 139.7673068),
            zoomLevel: 14.0,
            animated: false
        )
        
        mapView.delegate = context.coordinator
        
        return mapView
    }
    
    func makeCoordinator() -> MapLibreView.Coordinator {
        Coordinator(control: self)
    }
    
    class Coordinator: NSObject, MGLMapViewDelegate {
        var control: MapLibreView
        
        init(control: MapLibreView) {
            self.control = control
        }
        
        func mapViewDidFinishLoadingMap(_ mapView: MGLMapView) {
            // マップがロードされた後の処理を記載
        }
    }
}

makeUIView は,Viewが立ち上がるときにどういった処理をするのか定義します.今回は,マップ自体のスタイルの定義や,中心位置の設定などを記載しています.マップのスタイルは,MapTilerのベクタータイルを利用します.

updateUIView は,ビューが何かしらの更新をしたときにどういった処理をするのか定義します.今回は,特に何も処理をしないので空白です. UIViewRepresentable プロトコルに準拠する必要があるため,空白でも関数は定義する必要があります.

Coordinator クラスは,Viewの中でアクションが発生した場合にどういった処理をするのか定義します.わかりやすい例でいうと,ボタンをタップしたときの処理などは,この Coordinator クラスに定義します.

今回,Coordinator クラスでは,予めマップがロードされた後に実行される関数を書いていますが,中身は空の状態で定義しています.

ContentView.swift

ContentView.swift は,上記で作成した MapLibreViewbody の中に定義します.

ContentView.swift
import SwiftUI
import CoreData

struct ContentView: View {

    var body: some View {
        MapLibreView()
            .edgesIgnoringSafeArea(.all)
    }
    
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

.edgesIgnoringSafeArea(.all) で, MapLibreView をフル画面表示にします.

App.swift

一番最初に表示するビューを定義する App.swift(今回は MapLibreNativeSampleApp.swift)には ContentView を定義します.このファイル名は,一番最初にXcodeで作成したプロジェクト名が,そのまま反映されます.

MapLibreNativeSampleApp.swift
import SwiftUI

@main
struct MapLibreNativeSampleApp: App {

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

動作確認

この状態でエミュレータ or 実機で動作確認をすると,下記のように東京駅を中心としたMapTilerのベクトルマップが表示されます.

Frameworks

指定したポイントに画像を表示する

次に,指定した場所にポイントを示す画像を表示してみたいと思います.

画像の定義

画像を用意するにあたり,適当に作成した画像を,Xcode内の Assets に定義していきます.今回は PointIcon という名前で定義します.ちなみに,画像のサイズは 64px x 64px です.

Frameworks

本当はRetinaディスプレイ用に2x,3xも定義する必要がありますが,今回は1xのみ定義しています.

また,右のRender Asは Default に設定しておきます(赤枠の部分). Template image に設定すると,マップ上に表示される画像の色定義ができなくなります.

MapLibreView.swiftを編集する

Assetsの定義が完了したら, 地図上に画像アイコンを表示する処理を MapLibreView.swiftcreateMarker 関数で定義していきます.

この関数の中では,主に画像を表示する場所の定義( shapeSource ) と,画像を表示するレイヤーの定義( shapeLayer ) をしています.マップ上に表示する画像の定義は MGLStylesetImage で定義します.

MapLibreView.swift
func createMarker(_ mapView: MGLMapView, _ style: MGLStyle) {
    // ポイントの定義
    let point = MGLPointAnnotation()
    point.coordinate = CLLocationCoordinate2D(latitude: 35.6809591, longitude: 139.7673068)
    
    // ポイントのデータソース定義
    // 上記で定義したポイントをマップ上に表示するデータソースとして定義します
    let shapeSource = MGLShapeSource(identifier: "tokyo-station-source", shape: point)
    
    // シェイプレイヤーの定義
    // ポイントのデータソースをマップ上に表示するレイヤーに定義します
    let shapeLayer = MGLSymbolStyleLayer(identifier: "tokyo-station-style", source: shapeSource)

    // Assetsの画像をマップ表示用に定義
    if let image = UIImage(named: "PointIcon"){
        style.setImage(image, forName: "point-icon")
    }
    
    // マップ上に表示するレイヤーに,styleで設定した画像の名前を定義
    shapeLayer.iconImageName = NSExpression(forConstantValue: "point-icon")
    
    // スタイルにソースとレイヤーを追加
    style.addSource(shapeSource)
    style.addLayer(shapeLayer)
}


次に,MapLibreView.swift の中の Coordinator クラスを編集します.

今回は mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) 関数を定義しています.この関数は,マップのローディングが完了したときに呼び出される関数で, MGLMapViewMGLStyle を引数として受け取って処理をします.

関数の中身は,上記で定義した createMarker を呼び出しています.

MapLibreView.swift
class Coordinator: NSObject, MGLMapViewDelegate {
    var control: MapLibreView
    
    init(control: MapLibreView) {
        self.control = control
    }
    
    func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
        self.control.createMarker(mapView, style)
    }

}

動作確認

この状態で,エミュレータ or 実機で動作確認をすると,東京駅の部分に Assets て定義した画像が表示されます.

Frameworks

最後に

今回は,地図の表示と特定のポイントに画像を表示する処理を実装してみました.ライブラリがUIKitベースであるため,SwiftUIに適用させるためには工夫が必要ですが,そこまで難しくない実装で地図を表示することができました.

他にも,マップ上にLineStringを引いたり,Polygonを描画することもできます.GeoJSONを読み込んで表示する実装もできるそうなので,試してみたいと思います.

なお,私の環境ではMapLibre GLのライブラリをインストールしているのにもかかわらず,ソースコード内でMapLibreに付随しているMapboxライブラリが読み込まれない場合がありました.ただ,もう一度インストールをやり直すと,ライブラリの読み込みができました.

動作確認画面で表示している地図の著作権: © MapTiler © OpenStreetMap contributors

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0