Amazon Location Service のマップをクライアントサイドで表示してみた

2021.06.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは!DA(データアナリティクス)事業本部 インテグレーション部の大高です。

Amazon Location Serviceでは、マップリソースを作成することで、クライアントアプリケーションで地図を表示することができます。

下記のドキュメントによると、

To add a map to your application, you must first create a map resource and select one of available map providers and styles. You can then use the resource with popular open-source map SDKs, such as MapLibre GL and Tangram, to display the map in your application.

と記載されており、一般的なオープンソースの地図表示用ライブラリが利用できるようです。一方で今回は初めてなので、まずはドキュメントを読みながら地図表示を試してみたいと思います。

やりたいこと

まずは「Amazon Location Serviceの地図をブラウザで表示したい!」それだけの想いです。

前提と事前準備

前提条件として下記のドキュメントに記載のとおり「map」リソースが作成されている必要があります。今回は検証環境に既にexplore.mapという名前の「map」が存在していたので、これを利用します。

また、リソースへのリクエストについてはCognitoを利用した認証設定が必要になります。今回は地図表示をするためにこの設定が必要となるので、下記のドキュメントに従ってIDプールを作成します。

手順としてはドキュメントに記載の通りなのですが、作成時のポイントとしては以下になります。

  • 「認証されていない ID に対してアクセスを有効にする」にチェックを入れて作成
  • 「Identify the IAM roles to use with your new identity pool」の画面が表示される
    • 「詳細を表示」をクリックする
    • 「ロールの概要」の「IAM ロール」プルダウンで「新しい IAM ロールの作成」を選択
      • 下の方の「Your unauthenticated identities would like access to Cognito.」であることに注意
    • 「ポリシードキュメントを表示」をクリックして「編集」リンクをクリック
      • ブラウザの高さがある程度ないと隠れて見えないので注意
    • ポリシードキュメントは、サンプルと同様に以下のように記載する
      • Resourceの箇所は自分のMapリソースに合わせる(今回はexplore.mapのARN)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "MapsReadOnly",
      "Effect": "Allow",
      "Action": [
        "geo:GetMapStyleDescriptor",
        "geo:GetMapGlyphs",
        "geo:GetMapSprites",
        "geo:GetMapTile"
      ],
      "Resource": "arn:aws:geo:ap-northeast-1:XXXXXXXXXXXX:map/explore.map"
    }
  ]
}

なお、ドキュメントにも記載されているとおり、セキュリティを考慮して不必要なリソースへのアクセスは許可しないように十分留意してください。

今回は簡単な検証のために認証されていないIDに対してもアクセスを有効化していますが、本番利用の際には用途にあわせて適切なポリシー設定を行う必要があります。

地図表示を試してみる

では、準備ができたのでさくっと地図表示をしたいと思います。が、ドキュメントのチュートリアルをみた感じでは1からすべてを作るのは少々大変そうです。

一方で、ありがたいことにGitHubにサンプルアプリケーションが公開されているとのことなので、こちらをベースにして試してみたいと思います。

サンプルの準備

以下を実行してリポジトリをCloneします。

$ git clone https://github.com/aws-samples/amazon-location-samples.git

中には色々なサンプルがあり、大きくは「Mapbox」、「MapLibre」、「Tangram」を利用したサンプルがあるようです。このうち、index.htmlファイルだけしかない、一番簡単そうな「mapbox-gl-js」を試してみましょう。

<Identity Pool ID>に「Cognito Identity Pool ID」、<Map name>に「マップ名」を指定すれば良さそうです。事前に準備したCognitoのIDプールのID(ap-northeast-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXのようなID)とexplore.mapを指定して書き換えてみます。

amazon-location-samples/mapbox-gl-js/index.html

<!-- Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -->
<!-- SPDX-License-Identifier: MIT-0 -->
<html>
  <head>
    <link
      href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css"
      rel="stylesheet"
    />
    <style>
      body {
        margin: 0;
      }

      #map {
        height: 100vh;
      }
    </style>
  </head>

  <body>
    <div id="map" />
    <script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
    <script src="https://sdk.amazonaws.com/js/aws-sdk-2.784.0.min.js"></script>
    <script src="https://unpkg.com/@aws-amplify/core@3.7.0/dist/aws-amplify-core.min.js"></script>
    <script>
      // use Signer from @aws-amplify/core
      const { Signer } = window.aws_amplify_core;

      // configuration
      // Cognito Identity Pool ID
      const identityPoolId = "<Identity Pool ID>";
      // Amazon Location Service Map Name
      const mapName = "<Map name>";

      // extract the region from the Identity Pool ID
      AWS.config.region = identityPoolId.split(":")[0];

      // instantiate a credential provider
      const credentials = new AWS.CognitoIdentityCredentials({
        IdentityPoolId: identityPoolId,
      });

      /**
       * Sign requests made by Mapbox GL using AWS SigV4.
       */
      function transformRequest(url, resourceType) {
        if (resourceType === "Style" && !url.includes("://")) {
          // resolve to an AWS URL
          url = `https://maps.geo.${AWS.config.region}.amazonaws.com/maps/v0/maps/${url}/style-descriptor`;
        }

        if (url.includes("amazonaws.com")) {
          // only sign AWS requests (with the signature as part of the query string)
          return {
            url: Signer.signUrl(url, {
              access_key: credentials.accessKeyId,
              secret_key: credentials.secretAccessKey,
              session_token: credentials.sessionToken,
            }),
          };
        }

        // don't sign
        return { url };
      }

      /**
       * Initialize a map.
       */
      async function initializeMap() {
        // load credentials and set them up to refresh
        await credentials.getPromise();

        // actually initialize the map
        const map = new mapboxgl.Map({
          container: "map",
          center: [-123.1187, 49.2819], // initial map centerpoint
          zoom: 10, // initial map zoom
          style: mapName,
          transformRequest,
        });

        map.addControl(new mapboxgl.NavigationControl(), "top-left");
      }

      initializeMap();
    </script>
  </body>
</html>

ブラウザで確認してみる

書き換えたらhtmlファイルをChromeで開いてみましょう。以下のように地図が表示されたら成功です!(※うまく表示されなかった場合は、Chromeの開発者ツールでエラー原因を確認していくと解決できるかと思います)

秋葉原近辺はこのような感じですね。

まとめ

以上、Amazon Location Service のマップをクライアントサイドで表示してみました。

今回試したサンプルコードを見ると、肝になるのは transformRequest のあたりのようです。これを踏襲すれば他の地図表示ライブラリでもうまく表示できそうですね。できればOpenLayersLeafletあたりでも試してみたいと思います。

どなたかのお役に立てば幸いです。それでは!