Capacitor の Google Maps 代替案が必要な場合、現実的な選択肢は3つあります:公式 @capacitor/google-maps プラグインを使い制限内で対応するか、MapLibre GL JS や Leaflet などの JavaScript ライブラリを使用して WebView 内でマップを描画するか、あるいは別の SDK ベースのネイティブマッププラグインを使用するかです。Capgo は独自のマップ描画プラグインを提供していないため、このガイドでは各オプションを中立的に比較し、どのマップとも相性の良い Capgo プラグイン(ナビゲーションの引き継ぎ、ジオコーディング、バックグラウンド位置情報)を紹介します。
なぜ開発者は @capacitor/google-maps 以外の選択肢を検討するのか
公式プラグイン(Capacitor 8 用のバージョン 8)は、iOS と Android ではネイティブの Google Maps SDK を、Web では Google Maps JavaScript API を埋め込みます。動作はしますが、以下の点が繰り返し問題になります。
全プラットフォームで課金が有効な Google Cloud アカウント
このプラグインを使用するには、Android、iOS、Web のすべてで、課金が有効な Google Cloud アカウントに紐付いた API キーが必要です。ネイティブモバイルでのマップロードに対する Google の料金体系は比較的余裕がありますが、それでも課金設定を行い、キーをプラットフォームごとに制限し、クォータを監視する必要があります。Web でのマップロードや Places、Directions などのサービスは、無料枠を超えると従量課金されます。2025 年に料金モデルが変わっているため、導入前に Google Maps Platform の最新の料金ページを確認してください。
Android ではマップが WebView の背後に描画される
iOS ではマップビューが WebView のスクロールビュー内に配置されます。Android では WebView 全体の下にレンダリングされ、プラグインがそれを追従させるように <capacitor-google-map> 要素を移動させます。その上にあるすべてのレイヤーは透明でなければなりません:
/* Required on Android with @capacitor/google-maps */
html,
body,
ion-content,
ion-content::part(background) {
background: transparent !important;
--background: transparent;
}
これが「マップが真っ白になる」という問題の最大の原因です。また、HTML がネイティブビューの上に重なるため、カスタムオーバーレイ、モーダル、ページ遷移の実装も難しくなります。
マーカーは追加・削除はできるが、更新はできない
API には addMarker, addMarkers, removeMarker と removeMarkersがありますが、 updateMarker車両の位置をリアルタイムで表示する場合、更新のたびに要素の削除と追加を繰り返す必要があり、画面のちらつきやブリッジ通信のコストが発生します。
ネイティブではスタイルと機能に制限あり
例えば、以下のようなWebのみ対応のオプションもあります: mapId クラウドベースのスタイリング、および region と languageマーカー、クラスタリング、ポリライン、ポリゴン、円、タイルオーバーレイ、カメラ制御、クリックリスナーなどが利用可能です。ただし、全プラットフォームでデータ駆動型のスタイリングやヒートマップ、3Dビルディングを同様に実現しようとすると、制限に直面することになります。
選択肢の概要
| オプション | レンダリング | API のキーが必要 | タイルソース | 最適な用途 |
|---|---|---|---|---|
@capacitor/google-maps |
ネイティブ SDK(Android、iOS)、WebではJS | はい、課金有効 | Googleのデータとネイティブパフォーマンスを求めるアプリ | |
| MapLibre GL JS | WebView内のWebGL | タイルプロバイダーに依存 | 任意のベクトルタイルソース、セルフホスト可能 | カスタムスタイルの地図、オフライン寄り、ベンダーロックインなし |
| Leaflet | WebView内のDOMとcanvas | タイルプロバイダーに依存 | ラスタタイル(OSMベースなど) | シンプルな地図、軽量なbundle、豊富なプラグイン |
| WebView内のGoogle Maps JS API | GoogleのJSレンダラー | はい | 全プラットフォームで同じGoogleの見た目、JS機能をフル搭載 | |
| Native MapLibreまたはMapboxプラグイン | Native SDK | 用途による | 任意 / Mapbox | 大量のデータ、長時間セッション、ネイティブジェスチャー |
唯一の正解はありません。データ量、スタイリングの要件、および特定のベンダーへの依存度によって最適な選択肢は変わります。
案1: WebViewでのMapLibre GL JS
MapLibre GL JSはMapbox GL JS v1のオープンソースフォークです。WebGLでベクトルタイルを描画し、WKWebViewやAndroid System WebViewでもスムーズに動作します。Googleのデータが不要であれば、最も柔軟な選択肢となります。
bun add maplibre-gl
import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
const map = new maplibregl.Map({
container: 'map',
style: 'https://your-tile-provider.example.com/styles/streets/style.json',
center: [2.3522, 48.8566], // [lng, lat]
zoom: 12,
});
map.addControl(new maplibregl.NavigationControl(), 'top-right');
// A marker you can move without remove/add
const courier = new maplibregl.Marker({ color: '#1d4ed8' })
.setLngLat([2.35, 48.85])
.addTo(map);
export function moveCourier(lng: number, lat: number) {
courier.setLngLat([lng, lat]);
}
GeoJSONレイヤー、データ駆動型スタイリング、ルートラインをファーストクラスでサポート:
map.on('load', () => {
map.addSource('route', {
type: 'geojson',
data: {
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: [
[2.3522, 48.8566],
[2.3376, 48.8606],
[2.2945, 48.8584],
],
},
},
});
map.addLayer({
id: 'route-line',
type: 'line',
source: 'route',
paint: { 'line-color': '#2563eb', 'line-width': 5 },
});
});
注意点:
- タイルソースが必要です。商用のベクトルタイルホストを利用するか、OpenStreetMapのデータから生成したタイルをセルフホストする選択肢があります。なお、OpenStreetMapのパブリックタイルサーバーには利用ポリシーがあり、アプリからの大量のトラフィックは許可されていません。
- タイルプロバイダーが規定するクレジット表記(attribution)は必ず表示してください。
- プレーンなWeb code なので、ブラウザプレビューでも同じマップが動作し、開発をスピードアップできます。
案2: Leaflet
Leafletは軽量で成熟したライブラリです。数百個程度のマーカー、ラスタタイル、シンプルなインタラクションを伴うマップに適しています。
bun add leaflet
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
const map = L.map('map').setView([48.8566, 2.3522], 13);
L.tileLayer('https://tiles.example.com/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap contributors',
}).addTo(map);
L.marker([48.8584, 2.2945]).addTo(map).bindPopup('Eiffel Tower');
バンドルされたアプリでは、Leafletのデフォルトのマーカーアイコンのパスが壊れがちです。アイコン画像をインポートしてオプションを設定するか、 L.Icon.Default 独自のアイコンを使用してください。 L.divIcon.
案3: WebViewでのGoogle Maps JavaScript API
Googleのデータや見た目は必要だが、マップを他のHTML要素と同じように扱いたい場合は、ネイティブのSDKではなく、WebView内でMaps JavaScript APIをロードしてください。ネイティブ特有の滑らかさは多少損なわれ、マップのロードごとにWebの課金が発生しますが、マップIDによるクラウドスタイリングや高度なマーカー、データレイヤーなど、JSのAPIをフルに活用できます。
HTTPリファラーを使用してWebキーを制限してください。iOSでは、Capacitorはアプリを capacitor://localhost から提供し、Androidでは https://localhostから提供するため、それらのオリジンをキーの制限に追加して両方の動作を確認してください。
案4: 他のSDKで作られたネイティブプラグイン
コミュニティには、MapLibre NativeやMapbox SDKをラップしたNative wrapperが存在します。これらは、あらゆるタイルソースにおいてNativeなジェスチャーとパフォーマンスを提供します。選定の際は、Capacitor 8をサポートしているか、最新のリリースがあるか、iOS(最新のCapacitor 8 iOSプロジェクトのデフォルト)でSwift Package Managerをサポートしているか、そして必要なオーバーレイタイプをカバーしているかを確認してください。Nativeマッププラグインは、公式プラグインと同様のレイヤー構成のトレードオフがあります。マップはNative viewとして扱われるため、HTMLはそれを避けるようにレイアウトする必要があります。
@capacitor/google-maps を選ぶべきケース
- Googleのベースマップ、Places、およびStreet Viewのデータが必要です。
- マップはスクロールコンテンツ内の小さなカードではなく、フルスクリーンのビューとして使用します。
- マーカーの移動には、削除と追加を繰り返すか、更新頻度が低い方法でも問題ありません。
継続して使用する場合は、CSSで透明度を設定し、 <capacitor-google-map> 要素に明示的なサイズを指定して、 destroy() ページを離れる際に呼び出し、 skipLibCheck: true における tsconfig.json プラグインのREADMEの指示に従って設定してください。
あらゆる地図と相性の良いプラグイン
地図の描画方法は様々ですが、これらの Capgo プラグインは、WebViewベースの地図では不可能なネイティブ機能を提供します。
ターンバイターンナビゲーションを任せる
ナビゲーション機能の構築はそれ自体が大きなプロジェクトです。多くのアプリでは、ユーザーが普段使っているナビアプリを起動する手法をとっています。 @capgo/capacitor-launch-navigator Apple Maps、Google Maps、Wazeなど、多くのサービスに対応しています:
import { LaunchNavigator, TransportMode } from '@capgo/capacitor-launch-navigator';
await LaunchNavigator.navigate({
destination: [48.8584, 2.2945], // [lat, lng]
options: { transportMode: TransportMode.DRIVING },
});
Webサービス不要のジオコーディング
@capgo/capacitor-nativegeocoder iOSとAndroidのプラットフォーム標準のジオコーダーを使用するため、デバイス上でGoogle APIキーを用意する必要はありません:
import { NativeGeocoder } from '@capgo/capacitor-nativegeocoder';
const { addresses } = await NativeGeocoder.reverseGeocode({
latitude: 48.8584,
longitude: 2.2945,
maxResults: 1,
});
console.log(addresses[0]?.thoroughfare, addresses[0]?.locality);
const result = await NativeGeocoder.forwardGeocode({
addressString: '5 Avenue Anatole France, Paris',
maxResults: 1,
});
console.log(result.addresses[0]?.latitude, result.addresses[0]?.longitude);
Web環境では、プラグインはGoogleの API を使用するため、 apiKey オプションが追加されました。
バックグラウンドでもユーザーの位置を表示
フォアグラウンドでの「現在地(青いドット)」表示には、 @capacitor/geolocation これだけで十分です。アプリがバックグラウンドの状態でも追跡を継続したり、特定の場所に進入した際にイベントをトリガーしたりするには、 @capgo/background-geolocationを使用し、選択した地図に座標を渡してください。
Capacitor でのマップ関連トラブルシューティング
公式プラグインを使用した場合、Androidで地図が空白になる。 親要素の透明度が設定されていない。Chrome DevToolsで以下を確認してください: chrome://inspect 「 <html> 」と地図要素の間の
背景色がないか。 地図要素の高さが0になっている。地図コンテナには固有のサイズがないため、明示的な高さを設定するか、親要素に固定の高さを指定してflexレイアウトを使用してください。
AndroidでWebGLマップがぼやける、または動作が重い。 デバイスのSystem WebViewが最新か確認し、レイヤー数を減らしてください。ルート変更のたびにマップを作り直さず、一度作成したものを再利用しましょう。
リリースビルドでタイルが読み込まれない。 Content Security Policyとネットワークセキュリティ設定を確認し、タイルホストがHTTPSであることを確かめてください。
タイルスタイルのURLを変更するとマップが壊れる。 スタイルとタイルのURLは単なるJavaScriptの設定です。既存ユーザー向けのプロバイダー切り替えは、次の条件で可能です: Capgo Live Updatesアプリストアリリースなしで、ネイティブの code に変更がない限り。
判断方法
- フルスクリーンマップでGoogleのデータとネイティブのパフォーマンスが必要なら、そのまま使い続ける。
@capacitor/google-maps. - カスタムスタイリング、Googleの課金が不要、HTMLのように動くマップが必要な場合:MapLibre GL JS。
- マーカーを数個置くだけのシンプルなマップが必要なら:Leaflet。
- スクロール可能なレイアウトでGoogle Mapsの見た目を実現したい場合:WebView内でGoogle Maps JS API を使用します。
どれを選んでも、早めに低スペックのAndroid端末でテストしてください。ネイティブの構成要素をさらに探すには、以下をご覧ください: Capgo プラグインディレクトリ.