207 Tech Blog

テクノロジーで物流を変える 207 (ニーマルナナ) 株式会社のテックブログ

React NativeでMapboxを使っているはなし

前回の記事ではMapboxを導入した経緯について書きましたが、今回は技術的な面について書こうと思います。

最近GoogleMapからMapboxへ移行し、ちょっとしたハマりどころ等があったので、社内への共有ドキュメント兼備忘録として書いておきます。

なお、TODOCUサポーターはReact Nativeで開発しているため、Mapbox Maps SDK for React Native (以下、 react-native-mapbox-gl ) を利用していて、主にこのライブラリを中心に書きます。

インストール

react-native-mapbox-glの導入方法は公式のドキュメントに従えば特に詰まることなく導入できるはずなので、細かい所の説明は省きます。*1

github.com

クラッシュレートの増加と修正

1ヶ月ほどインストール手順通りの内容で運用していましたが、本番環境で EXC_BAD_ACCESS が頻繁に発生していました。*2

7/19週からクラッシュが大幅に増加して下がっている図
リリースした週(7/19)からクラッシュが大幅に増加し、9/6週で改善

Gitterを見てみると、 iOS SDKのアップデートが解決できる という投稿があったため *3 、こちらを参考にしてTODOCUサポーターでもiOS SDKのバージョンを指定しています。

react-native-mapbox-gl は Mapbox SDKのバージョンを指定できるように作られており、記事執筆時点でのデフォルトバージョンは v5.8.0を利用しているようでした。

アップデート方法はドキュメントにも記載がある通り、 Podfileに $ReactNativeMapboxGLIOSVersion = '~> 6.3' を書くだけですが、ドキュメントにも記載があるとおり、iOS SDKのv6からはSDKをダウンロードするためにアクセストークンが必要になっています。
Mapboxの管理画面からアクセストークンを作り、ホームディレクトリに ~/. netrcとしてファイルを置くだけです。

管理画面からaccess tokenの設定をしている画像
管理画面からaccess tokenの設定

TODOCUサポーターはiOSのビルドにEASを利用しているため、EASビルド時にアクセストークンを設定しておく必要がありますが、EASビルドのnpm hooks~/.netrc ファイルを生成することで解決しました。
アクセストークンの中身は、Expoの管理画面からSecretとして登録しています。

地図上での工夫とTODOCUサポーターで使っているコード

TODOCUサポーターのスクリーンショット
TODOCUサポーターのスクリーンショット

TODOCUサポーターは配達を補助するアプリで、配達する各荷物ごとにマーカーを地図上に表示しています。
荷物には時間指定がある場合があり、地図上でわかりやすくなるように工夫する必要があります。
例えば、以下のような処理を行っています。

  1. 複数のマーカーが重なっている時に、時間指定が早い時間のマーカー(荷物)を優先して表示する*4
  2. マーカーの上に開始時間を表示する

上記の実現方法について、実際のコード(一部)を使って簡単に説明します。

マーカーの実装は下記のようになっています。

  • feature collection (実際には動的に生成しています / GeoJSON )
{
  type: 'FeatureCollection',
  features: [{
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [0, 0], // long,lat
    },
    properties: {
      icon: 'icon-0', // MapboxGL.Images で読み込んだ画像
      text: '9',
      priority: '100',
    },
  }],
}
  • 実装
<MapboxGL.ShapeSource
  id="productsSource"
  shape={featureCollection}
  onPress={handlePressMarker}
>
  <MapboxGL.SymbolLayer
    id="productsPointLayer"
    sourceID="productsSource"
    minZoomLevel={1}
    style={{
      iconImage: ['get', 'icon'], // 画像の選択
      iconSize: 0.25,
      iconAllowOverlap: true,
      symbolZOrder: 'auto', // 以下のsymbolSortKeyで表示順を変えるために指定
      symbolSortKey: ['to-number', ['get', 'priority']],
      textField: ['get', 'text'], // マーカー上に表示する文字の取得
      iconAnchor: 'bottom', // マーカー画像の基準点
      textSize: 20,
      textRadialOffset: 5,
      textColor: 'white',
      textTranslate: [0, -44], // マーカー上の文字位置
      textFont: ['DIN Offc Pro Bold'],
      textAllowOverlap: true,
      textTranslateAnchor: 'viewport',
    }}
  />
</MapboxGL.ShapeSource>

マーカーの表示優先度を制御する方法はコードコメントに書いてますが、symbolZOrder で制御できます。
各Featureの properties.priority が高いほどz-indexも大きくなります。
この設定で "時間指定が早い時間を優先して表示する" のを実現しています。

おわりに

最後に、207ではソフトウェアエンジニアやGISに興味がある方などを募集しています! ちょっと興味あるなと思った方はぜひ以下のリンクからチラ見おねがいします!!

www.notion.so

*1:Expo SDK41で導入されたplugin機能を使えば、expo ejectしなくてもreact-native-mapbox-glが使えるようになったみたいです。

*2:Sentryで検知

*3:gitterはreact-native-mapbox-glのREADMEからリンクされていました

*4:厳密には時間指定枠という概念が存在し、時間指定枠の若いほうを優先して表示しています。