Xamarin.Forms (Android) で Map を使って現在地を取得し、ピンを追加する

# はじめに

以下のものを準備
- Visual Studio 2022
- Google アカウント

[Notification Hubs の時](https://zenn.dev/moimoi_kohei/articles/cbef4b3929b33d) と同様、Android のエミュレータを使用で進めることにした。

# 全体像
Xamarin.Androidで地図を使う際、[Xamarin.Forms.Map](https://docs.microsoft.com/ja-jp/xamarin/xamarin-forms/user-interface/map/) をコントローラとして制御を行い、地図自体は Google Map の API を使って表示する事になるみたい（おそらく）。

# 実装
1. マップの追加
2. ボタンを押して現在地を取得
3. マップ上にピンを追加

## マップの追加
こちらの公式Docsを参考に進める。https://docs.microsoft.com/ja-jp/xamarin/xamarin-forms/user-interface/map/setup
### Nu Get
共有プロジェクトを右クリックして、全プロジェクトにインストール
- Xamarin.Forms.Maps (ver. 5.0.0.2196) 

### MainAvctivity.csに追加
```
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
Xamarin.FormsMaps.Init(this, savedInstanceState); // ← この行を追加
LoadApplication(new App());
```

### Google Map API キーを取得
こちらの公式Docsを参考に進めていく。https://docs.microsoft.com/ja-jp/xamarin/android/platform/maps-and-location/maps/obtaining-a-google-maps-api-key?tabs=windows

### AndroidManifest.xml の に以下を追加

```<application>``` ブロック内に以下を追加
```
<meta-data android:name="com.google.android.geo.API_KEY" android:value="PASTE-YOUR-API-KEY-HERE" />
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
<uses-library android:name="org.apache.http.legacy" android:required="false" />
```

以下の ```<uses-permission>``` も追加
```
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

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

### MainPage.xaml を以下のように修正
```<maps:Map x:Name="map>```を挿入して起動することで地図が見えるようになる。```xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps"```を追加しておくことも忘れてはいけない。
```
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps"
             x:Class="PushDemoAndroid.MainPage">

    <StackLayout>
        <Frame BackgroundColor="#2196F3" Padding="24" CornerRadius="0">
            <Label Text="Welcome to Xamarin.Forms!" HorizontalTextAlignment="Center" TextColor="White" FontSize="36"/>
        </Frame>
        <maps:Map x:Name="map" />
    </StackLayout>

</ContentPage>
```

## ボタンを押して現在地を取得

上のコードの中で、``` <Button Text="現在地周辺を検索"  HorizontalOptions="Start" Clicked="CurrentLocationButton_Clicked"/>``` のボタンを押すと、```<CurrentLocationButton_Clicked>```の関数が呼び出されるようにしている。

### MainPage.xaml にボタンを追加
``` <StackLayout> ``` ブロックの中に以下を追記する。

```
<Button Text="現在地周辺を検索"  HorizontalOptions="Start" Clicked="CurrentLocationButton_Clicked"/>
        <Label x:Name="GPSlabel" HorizontalOptions="Center" TextColor="Black"/>
```

### MainPage.xaml.cs にて関数を宣言

```
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Essentials;
using Xamarin.Forms.Maps;
…
private async void CurrentLocationButton_Clicked(object sender, EventArgs e)
{
    try
    {
        var request = new GeolocationRequest(GeolocationAccuracy.Medium);
        var location = await Geolocation.GetLocationAsync(request);

        if (location != null)
        {
            GPSlabel.Text = $"{location.Latitude},{location.Longitude}";
            // enable IsShowingUser (built-in button to get the current location)
            map.IsShowingUser = true;
            // move the map to current location
            Position position = new Position(Convert.ToDouble(location.Latitude), Convert.ToDouble(location.Longitude));
            MapSpan mapSpan = new MapSpan(position, 0.01, 0.01);
            map.MoveToRegion(mapSpan);
        }
    }
    catch (Exception)
    {

    }
}
```

アプリを起動すると、「現在地の取得許可」というポップアップが出るので、確認して許可する。その後、```<Label x:Name="GPSlabel" HorizontalOptions="Center" TextColor="Black"/>```に緯度経度が画面上で反映され、現在地に画面が移動することを確認できる。もしも、エミュレータを使用していれば、現在地は [Googleplex](https://ja.wikipedia.org/wiki/Googleplex) にセットされているはずだ。

## マップ上にピンを追加

MainPage.xaml.csの中の```map.MoveToRegion(mapSpan);```の後に、以下を追加

```
map.MoveToRegion(mapSpan);
// Add Pin
AddPin();
```

### MainPage.xaml.cs にて関数を実装

今回はピンを立てれるかどうかのお試しなので、ピンを立てる際に必要な情報を関数内で設定しているが、当たり前だがこのあたりの情報は引数渡しが望ましい。
```
private void AddPin()
{
    Pin pin = new Pin
    {
        Label = "Santa Cruz",
        Address = "The city with a boardwalk",
        Type = PinType.Place,
        Position = new Position(37.42056167283825, -122.08411115979173)
    };
    map.Pins.Add(pin);
}

```

追加した後にアプリを実行すると、指定した場所にピンが立っていることが確認できる。追加したピンは```map.clear()```により削除することができる。デモ動画は次号にて、まとめて掲載する予定。
ちなみに、もし、ピンのデザインを工夫したいのであれば、[こちら](https://docs.microsoft.com/ja-jp/xamarin/xamarin-forms/app-fundamentals/custom-renderer/map-pin) の公式Docsも参考になるかと思うが、今回は割愛。