capacitor-google-navigation 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CapacitorGoogleNavigation.podspec +18 -0
- package/Package.swift +28 -0
- package/README.md +486 -0
- package/android/build.gradle +59 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/attributeai/navigation/GoogleNavigation.java +152 -0
- package/android/src/main/java/com/attributeai/navigation/GoogleNavigationPlugin.java +87 -0
- package/android/src/main/java/com/attributeai/navigation/NavigationFragment.java +74 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +123 -0
- package/dist/esm/definitions.d.ts +45 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +24 -0
- package/dist/esm/web.js +16 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +30 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +33 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/GoogleNavigationPlugin/GoogleNavigation.swift +110 -0
- package/ios/Sources/GoogleNavigationPlugin/GoogleNavigationPlugin.swift +69 -0
- package/ios/Tests/GoogleNavigationPluginTests/GoogleNavigationTests.swift +15 -0
- package/package.json +80 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'CapacitorGoogleNavigation'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.license = package['license']
|
|
10
|
+
s.homepage = package['repository']['url']
|
|
11
|
+
s.author = package['author']
|
|
12
|
+
s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
|
|
13
|
+
s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
|
|
14
|
+
s.ios.deployment_target = '15.0'
|
|
15
|
+
s.dependency 'Capacitor'
|
|
16
|
+
s.dependency 'GoogleNavigation', '~> 9.0'
|
|
17
|
+
s.swift_version = '5.1'
|
|
18
|
+
end
|
package/Package.swift
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// swift-tools-version: 5.9
|
|
2
|
+
import PackageDescription
|
|
3
|
+
|
|
4
|
+
let package = Package(
|
|
5
|
+
name: "CapacitorGoogleNavigation",
|
|
6
|
+
platforms: [.iOS(.v15)],
|
|
7
|
+
products: [
|
|
8
|
+
.library(
|
|
9
|
+
name: "CapacitorGoogleNavigation",
|
|
10
|
+
targets: ["GoogleNavigationPlugin"])
|
|
11
|
+
],
|
|
12
|
+
dependencies: [
|
|
13
|
+
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0")
|
|
14
|
+
],
|
|
15
|
+
targets: [
|
|
16
|
+
.target(
|
|
17
|
+
name: "GoogleNavigationPlugin",
|
|
18
|
+
dependencies: [
|
|
19
|
+
.product(name: "Capacitor", package: "capacitor-swift-pm"),
|
|
20
|
+
.product(name: "Cordova", package: "capacitor-swift-pm")
|
|
21
|
+
],
|
|
22
|
+
path: "ios/Sources/GoogleNavigationPlugin"),
|
|
23
|
+
.testTarget(
|
|
24
|
+
name: "GoogleNavigationPluginTests",
|
|
25
|
+
dependencies: ["GoogleNavigationPlugin"],
|
|
26
|
+
path: "ios/Tests/GoogleNavigationPluginTests")
|
|
27
|
+
]
|
|
28
|
+
)
|
package/README.md
ADDED
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
# capacitor-google-navigation
|
|
2
|
+
|
|
3
|
+
A Capacitor 8 plugin for Google Navigation SDK — turn-by-turn navigation inside your iOS and Android app.
|
|
4
|
+
|
|
5
|
+
> **Native only.** This plugin has no web implementation. It must be run on a physical or emulated iOS/Android device.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
### Google Cloud Console
|
|
12
|
+
|
|
13
|
+
1. Open or create a project at [console.cloud.google.com](https://console.cloud.google.com)
|
|
14
|
+
2. Enable the **Navigation SDK** API
|
|
15
|
+
3. Enable **billing** on your project
|
|
16
|
+
4. Create an API key under **APIs & Services → Credentials**
|
|
17
|
+
|
|
18
|
+
### iOS
|
|
19
|
+
|
|
20
|
+
- iOS 15.0+
|
|
21
|
+
- Xcode 14+
|
|
22
|
+
- CocoaPods — **Swift Package Manager is not supported** (Google Navigation SDK has no SPM distribution)
|
|
23
|
+
|
|
24
|
+
### Android
|
|
25
|
+
|
|
26
|
+
- Android API 24 (Android 7.0)+
|
|
27
|
+
- Google Play Services on the device
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install capacitor-google-navigation
|
|
35
|
+
npx cap sync
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## iOS Setup
|
|
41
|
+
|
|
42
|
+
### 1. Install pods
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
cd ios/App
|
|
46
|
+
pod install
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The `GoogleNavigation ~> 9.0` pod is declared in the plugin's podspec and is pulled in automatically.
|
|
50
|
+
|
|
51
|
+
### 2. Add location permissions to `Info.plist`
|
|
52
|
+
|
|
53
|
+
```xml
|
|
54
|
+
<key>NSLocationWhenInUseUsageDescription</key>
|
|
55
|
+
<string>This app uses your location for turn-by-turn navigation.</string>
|
|
56
|
+
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
|
57
|
+
<string>This app uses your location for navigation, including in the background.</string>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 3. Register your API key in `AppDelegate.swift`
|
|
61
|
+
|
|
62
|
+
The iOS SDK requires the key to be provided before any map or navigator is created.
|
|
63
|
+
|
|
64
|
+
```swift
|
|
65
|
+
import UIKit
|
|
66
|
+
import Capacitor
|
|
67
|
+
import GoogleNavigation
|
|
68
|
+
|
|
69
|
+
@UIApplicationMain
|
|
70
|
+
class AppDelegate: UIResponder, UIApplicationDelegate {
|
|
71
|
+
|
|
72
|
+
func application(
|
|
73
|
+
_ application: UIApplication,
|
|
74
|
+
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
|
75
|
+
) -> Bool {
|
|
76
|
+
GMSServices.provideAPIKey("YOUR_IOS_API_KEY")
|
|
77
|
+
return true
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
> You can also pass the key via `GoogleNavigation.initialize({ apiKey })` at runtime — the plugin calls `GMSServices.provideAPIKey()` for you. Either approach works; calling it in `AppDelegate` is the earlier-initialization option.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Android Setup
|
|
87
|
+
|
|
88
|
+
### 1. Add the API key and permissions to `android/app/src/main/AndroidManifest.xml`
|
|
89
|
+
|
|
90
|
+
```xml
|
|
91
|
+
<manifest>
|
|
92
|
+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
|
93
|
+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
|
94
|
+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
95
|
+
|
|
96
|
+
<application>
|
|
97
|
+
<!-- Required: Navigation SDK reads this at startup -->
|
|
98
|
+
<meta-data
|
|
99
|
+
android:name="com.google.android.geo.API_KEY"
|
|
100
|
+
android:value="YOUR_ANDROID_API_KEY" />
|
|
101
|
+
</application>
|
|
102
|
+
</manifest>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
> **Important:** On Android the Navigation SDK reads the API key from `AndroidManifest.xml` — not from the `apiKey` parameter passed to `initialize()`. The `apiKey` parameter is used on iOS only.
|
|
106
|
+
|
|
107
|
+
### 2. Request location permission at runtime
|
|
108
|
+
|
|
109
|
+
The plugin does not request permissions itself. You must request `ACCESS_FINE_LOCATION` before calling `initialize()`. In an Ionic React app use `@capacitor/geolocation` or the browser Permissions API:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { Geolocation } from '@capacitor/geolocation';
|
|
113
|
+
|
|
114
|
+
await Geolocation.requestPermissions();
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## How it works
|
|
120
|
+
|
|
121
|
+
Calling `showNavigationView({ show: true })` presents a **full-screen native navigation UI** on top of your app. Your Ionic/web UI stays alive underneath. Calling `showNavigationView({ show: false })` dismisses the native view and restores your app UI.
|
|
122
|
+
|
|
123
|
+
**Call order:**
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
initialize()
|
|
127
|
+
↓ fires onNavigationReady when SDK is ready
|
|
128
|
+
showNavigationView({ show: true })
|
|
129
|
+
↓ presents native map full-screen
|
|
130
|
+
startNavigation({ lat, lng, travelMode })
|
|
131
|
+
↓ sets destination, begins guidance
|
|
132
|
+
↓ fires onArrival when user arrives
|
|
133
|
+
↓ fires onRouteChanged on recalculation
|
|
134
|
+
stopNavigation()
|
|
135
|
+
↓ ends guidance, clears destination
|
|
136
|
+
showNavigationView({ show: false })
|
|
137
|
+
↓ dismisses native map, restores app UI
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Usage — Ionic React
|
|
143
|
+
|
|
144
|
+
### 1. Create a `useGoogleNavigation` hook
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
// src/hooks/useGoogleNavigation.ts
|
|
148
|
+
import { useEffect, useRef, useCallback } from 'react';
|
|
149
|
+
import { GoogleNavigation } from 'capacitor-google-navigation';
|
|
150
|
+
import type { PluginListenerHandle } from 'capacitor-google-navigation';
|
|
151
|
+
|
|
152
|
+
interface UseNavigationOptions {
|
|
153
|
+
apiKey: string;
|
|
154
|
+
onArrival?: (event: any) => void;
|
|
155
|
+
onRouteChanged?: () => void;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function useGoogleNavigation({ apiKey, onArrival, onRouteChanged }: UseNavigationOptions) {
|
|
159
|
+
const listeners = useRef<PluginListenerHandle[]>([]);
|
|
160
|
+
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
const setup = async () => {
|
|
163
|
+
const readyHandle = await GoogleNavigation.addListener('onNavigationReady', () => {
|
|
164
|
+
console.log('Navigation SDK ready');
|
|
165
|
+
});
|
|
166
|
+
listeners.current.push(readyHandle);
|
|
167
|
+
|
|
168
|
+
if (onArrival) {
|
|
169
|
+
const h = await GoogleNavigation.addListener('onArrival', onArrival);
|
|
170
|
+
listeners.current.push(h);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (onRouteChanged) {
|
|
174
|
+
const h = await GoogleNavigation.addListener('onRouteChanged', onRouteChanged);
|
|
175
|
+
listeners.current.push(h);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
await GoogleNavigation.initialize({ apiKey });
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
setup().catch(console.error);
|
|
182
|
+
|
|
183
|
+
return () => {
|
|
184
|
+
listeners.current.forEach(h => h.remove());
|
|
185
|
+
listeners.current = [];
|
|
186
|
+
};
|
|
187
|
+
}, [apiKey]);
|
|
188
|
+
|
|
189
|
+
const navigate = useCallback(async (
|
|
190
|
+
latitude: number,
|
|
191
|
+
longitude: number,
|
|
192
|
+
travelMode: 'DRIVING' | 'WALKING' | 'CYCLING' | 'TWO_WHEELER' = 'DRIVING',
|
|
193
|
+
) => {
|
|
194
|
+
await GoogleNavigation.showNavigationView({ show: true });
|
|
195
|
+
await GoogleNavigation.startNavigation({
|
|
196
|
+
destinationLatitude: latitude,
|
|
197
|
+
destinationLongitude: longitude,
|
|
198
|
+
travelMode,
|
|
199
|
+
});
|
|
200
|
+
}, []);
|
|
201
|
+
|
|
202
|
+
const stop = useCallback(async () => {
|
|
203
|
+
await GoogleNavigation.stopNavigation();
|
|
204
|
+
await GoogleNavigation.showNavigationView({ show: false });
|
|
205
|
+
}, []);
|
|
206
|
+
|
|
207
|
+
return { navigate, stop };
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### 2. Use the hook in a page
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
// src/pages/NavigationPage.tsx
|
|
215
|
+
import React from 'react';
|
|
216
|
+
import {
|
|
217
|
+
IonPage,
|
|
218
|
+
IonHeader,
|
|
219
|
+
IonToolbar,
|
|
220
|
+
IonTitle,
|
|
221
|
+
IonContent,
|
|
222
|
+
IonButton,
|
|
223
|
+
IonAlert,
|
|
224
|
+
} from '@ionic/react';
|
|
225
|
+
import { useGoogleNavigation } from '../hooks/useGoogleNavigation';
|
|
226
|
+
|
|
227
|
+
const NavigationPage: React.FC = () => {
|
|
228
|
+
const [showArrival, setShowArrival] = React.useState(false);
|
|
229
|
+
|
|
230
|
+
const { navigate, stop } = useGoogleNavigation({
|
|
231
|
+
apiKey: import.meta.env.VITE_GOOGLE_NAV_API_KEY as string,
|
|
232
|
+
onArrival: () => setShowArrival(true),
|
|
233
|
+
onRouteChanged: () => console.log('Route recalculated'),
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
return (
|
|
237
|
+
<IonPage>
|
|
238
|
+
<IonHeader>
|
|
239
|
+
<IonToolbar>
|
|
240
|
+
<IonTitle>Navigation</IonTitle>
|
|
241
|
+
</IonToolbar>
|
|
242
|
+
</IonHeader>
|
|
243
|
+
|
|
244
|
+
<IonContent className="ion-padding">
|
|
245
|
+
<IonButton
|
|
246
|
+
expand="block"
|
|
247
|
+
onClick={() => navigate(37.7749, -122.4194, 'DRIVING')}
|
|
248
|
+
>
|
|
249
|
+
Navigate to San Francisco
|
|
250
|
+
</IonButton>
|
|
251
|
+
|
|
252
|
+
<IonButton expand="block" color="medium" onClick={() => navigate(34.0522, -118.2437, 'WALKING')}>
|
|
253
|
+
Walk to Los Angeles
|
|
254
|
+
</IonButton>
|
|
255
|
+
|
|
256
|
+
<IonButton expand="block" color="danger" onClick={stop}>
|
|
257
|
+
Stop Navigation
|
|
258
|
+
</IonButton>
|
|
259
|
+
</IonContent>
|
|
260
|
+
|
|
261
|
+
<IonAlert
|
|
262
|
+
isOpen={showArrival}
|
|
263
|
+
header="Arrived!"
|
|
264
|
+
message="You have reached your destination."
|
|
265
|
+
buttons={['OK']}
|
|
266
|
+
onDidDismiss={() => setShowArrival(false)}
|
|
267
|
+
/>
|
|
268
|
+
</IonPage>
|
|
269
|
+
);
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
export default NavigationPage;
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### 3. Store your API key in `.env`
|
|
276
|
+
|
|
277
|
+
Create a `.env` file in your app root (never commit this):
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
VITE_GOOGLE_NAV_API_KEY=AIzaSy...
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Usage — Vanilla TypeScript / JavaScript
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
import { GoogleNavigation } from 'capacitor-google-navigation';
|
|
289
|
+
|
|
290
|
+
// 1. Attach event listeners first
|
|
291
|
+
const readyHandle = await GoogleNavigation.addListener('onNavigationReady', () => {
|
|
292
|
+
console.log('SDK ready');
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const arrivalHandle = await GoogleNavigation.addListener('onArrival', (event) => {
|
|
296
|
+
console.log('Arrived:', event);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
const routeHandle = await GoogleNavigation.addListener('onRouteChanged', () => {
|
|
300
|
+
console.log('Route recalculated');
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// 2. Initialize the SDK (fires onNavigationReady when done)
|
|
304
|
+
await GoogleNavigation.initialize({ apiKey: 'YOUR_API_KEY' });
|
|
305
|
+
|
|
306
|
+
// 3. Show the native navigation view
|
|
307
|
+
await GoogleNavigation.showNavigationView({ show: true });
|
|
308
|
+
|
|
309
|
+
// 4. Start navigation
|
|
310
|
+
await GoogleNavigation.startNavigation({
|
|
311
|
+
destinationLatitude: 37.7749,
|
|
312
|
+
destinationLongitude: -122.4194,
|
|
313
|
+
travelMode: 'DRIVING', // DRIVING | WALKING | CYCLING | TWO_WHEELER
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// 5. Stop guidance and dismiss
|
|
317
|
+
await GoogleNavigation.stopNavigation();
|
|
318
|
+
await GoogleNavigation.showNavigationView({ show: false });
|
|
319
|
+
|
|
320
|
+
// 6. Clean up
|
|
321
|
+
await readyHandle.remove();
|
|
322
|
+
await arrivalHandle.remove();
|
|
323
|
+
await routeHandle.remove();
|
|
324
|
+
// or:
|
|
325
|
+
await GoogleNavigation.removeAllListeners();
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## API
|
|
331
|
+
|
|
332
|
+
<!-- docgen-api -->
|
|
333
|
+
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
|
|
334
|
+
|
|
335
|
+
### initialize(...)
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
initialize(options: { apiKey: string; }) => Promise<{ success: boolean; }>
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
Initialize the Navigation SDK with API key
|
|
342
|
+
|
|
343
|
+
| Param | Type |
|
|
344
|
+
| ------------- | -------------------------------- |
|
|
345
|
+
| **`options`** | <code>{ apiKey: string; }</code> |
|
|
346
|
+
|
|
347
|
+
**Returns:** <code>Promise<{ success: boolean; }></code>
|
|
348
|
+
|
|
349
|
+
--------------------
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
### startNavigation(...)
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
startNavigation(options: { destinationLatitude: number; destinationLongitude: number; travelMode?: 'DRIVING' | 'WALKING' | 'CYCLING' | 'TWO_WHEELER'; }) => Promise<{ success: boolean; }>
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Start navigation to a destination
|
|
359
|
+
|
|
360
|
+
| Param | Type |
|
|
361
|
+
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
362
|
+
| **`options`** | <code>{ destinationLatitude: number; destinationLongitude: number; travelMode?: 'DRIVING' \| 'WALKING' \| 'CYCLING' \| 'TWO_WHEELER'; }</code> |
|
|
363
|
+
|
|
364
|
+
**Returns:** <code>Promise<{ success: boolean; }></code>
|
|
365
|
+
|
|
366
|
+
--------------------
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
### stopNavigation()
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
stopNavigation() => Promise<{ success: boolean; }>
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
Stop navigation
|
|
376
|
+
|
|
377
|
+
**Returns:** <code>Promise<{ success: boolean; }></code>
|
|
378
|
+
|
|
379
|
+
--------------------
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
### showNavigationView(...)
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
showNavigationView(options: { show: boolean; }) => Promise<{ success: boolean; }>
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
Show/hide navigation view
|
|
389
|
+
|
|
390
|
+
| Param | Type |
|
|
391
|
+
| ------------- | -------------------------------- |
|
|
392
|
+
| **`options`** | <code>{ show: boolean; }</code> |
|
|
393
|
+
|
|
394
|
+
**Returns:** <code>Promise<{ success: boolean; }></code>
|
|
395
|
+
|
|
396
|
+
--------------------
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
### addListener(...)
|
|
400
|
+
|
|
401
|
+
```typescript
|
|
402
|
+
addListener(eventName: 'onArrival' | 'onRouteChanged' | 'onNavigationReady', listenerFunc: (event: any) => void) => Promise<PluginListenerHandle>
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Add listener for navigation events
|
|
406
|
+
|
|
407
|
+
| Param | Type |
|
|
408
|
+
| ------------------ | ----------------------------------------------------------------- |
|
|
409
|
+
| **`eventName`** | <code>'onArrival' \| 'onRouteChanged' \| 'onNavigationReady'</code> |
|
|
410
|
+
| **`listenerFunc`** | <code>(event: any) => void</code> |
|
|
411
|
+
|
|
412
|
+
**Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code>
|
|
413
|
+
|
|
414
|
+
--------------------
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
### removeAllListeners()
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
removeAllListeners() => Promise<void>
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Remove all listeners
|
|
424
|
+
|
|
425
|
+
--------------------
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
### Interfaces
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
#### PluginListenerHandle
|
|
432
|
+
|
|
433
|
+
| Prop | Type |
|
|
434
|
+
| ------------ | ----------------------------------------- |
|
|
435
|
+
| **`remove`** | <code>() => Promise<void></code> |
|
|
436
|
+
|
|
437
|
+
<!-- docgen-api-end -->
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## Events
|
|
442
|
+
|
|
443
|
+
| Event | Payload | Fired when |
|
|
444
|
+
|-------|---------|-----------|
|
|
445
|
+
| `onNavigationReady` | `{}` | SDK has initialized and the navigator is available |
|
|
446
|
+
| `onArrival` | `{ latitude, longitude, title }` | User arrives at the destination waypoint |
|
|
447
|
+
| `onRouteChanged` | `{}` | The route is recalculated (traffic, missed turn, etc.) |
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## Platform notes
|
|
452
|
+
|
|
453
|
+
| Feature | iOS | Android |
|
|
454
|
+
|---------|-----|---------|
|
|
455
|
+
| Turn-by-turn guidance | ✅ | ✅ |
|
|
456
|
+
| Full-screen native UI | ✅ | ✅ |
|
|
457
|
+
| `onArrival` event | ✅ | ✅ |
|
|
458
|
+
| `onRouteChanged` event | ✅ | ✅ |
|
|
459
|
+
| API key via `initialize()` | ✅ | ⚠️ Manifest only |
|
|
460
|
+
| Web | ❌ | ❌ |
|
|
461
|
+
| Swift Package Manager | ❌ | — |
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## Troubleshooting
|
|
466
|
+
|
|
467
|
+
**`showNavigationView` must be called before `startNavigation`**
|
|
468
|
+
The navigator instance is only available after the native navigation view is presented. Calling `startNavigation` without first calling `showNavigationView({ show: true })` will return an error.
|
|
469
|
+
|
|
470
|
+
**Blank map on Android**
|
|
471
|
+
All `NavigationView` lifecycle events must be delegated — the plugin handles this via `NavigationFragment`. If you see a blank map, check that your `Activity` extends `AppCompatActivity` (Capacitor does this by default).
|
|
472
|
+
|
|
473
|
+
**`initialize()` fails on Android**
|
|
474
|
+
The Android Navigation SDK validates the API key from `AndroidManifest.xml`. Ensure the key is present and the Navigation SDK is enabled in your Google Cloud project with billing active.
|
|
475
|
+
|
|
476
|
+
**iOS — "This app has attempted to access privacy-sensitive data"**
|
|
477
|
+
Add both `NSLocationWhenInUseUsageDescription` and `NSLocationAlwaysAndWhenInUseUsageDescription` to `Info.plist` before calling `initialize()`.
|
|
478
|
+
|
|
479
|
+
**CocoaPods not found / pod install fails**
|
|
480
|
+
Make sure CocoaPods is installed (`sudo gem install cocoapods`) and run `npx cap sync` before `pod install`.
|
|
481
|
+
|
|
482
|
+
---
|
|
483
|
+
|
|
484
|
+
## License
|
|
485
|
+
|
|
486
|
+
MIT
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
ext {
|
|
2
|
+
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
|
|
3
|
+
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
|
|
4
|
+
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
|
|
5
|
+
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
buildscript {
|
|
9
|
+
repositories {
|
|
10
|
+
google()
|
|
11
|
+
mavenCentral()
|
|
12
|
+
}
|
|
13
|
+
dependencies {
|
|
14
|
+
classpath 'com.android.tools.build:gradle:8.13.0'
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
apply plugin: 'com.android.library'
|
|
19
|
+
|
|
20
|
+
android {
|
|
21
|
+
namespace = "com.attributeai.navigation"
|
|
22
|
+
compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
|
|
23
|
+
defaultConfig {
|
|
24
|
+
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
|
|
25
|
+
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
|
|
26
|
+
versionCode 1
|
|
27
|
+
versionName "1.0"
|
|
28
|
+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
29
|
+
}
|
|
30
|
+
buildTypes {
|
|
31
|
+
release {
|
|
32
|
+
minifyEnabled false
|
|
33
|
+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
lintOptions {
|
|
37
|
+
abortOnError = false
|
|
38
|
+
}
|
|
39
|
+
compileOptions {
|
|
40
|
+
sourceCompatibility JavaVersion.VERSION_21
|
|
41
|
+
targetCompatibility JavaVersion.VERSION_21
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
repositories {
|
|
46
|
+
google()
|
|
47
|
+
mavenCentral()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
dependencies {
|
|
52
|
+
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
53
|
+
implementation project(':capacitor-android')
|
|
54
|
+
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
55
|
+
implementation 'com.google.android.libraries.navigation:navigation:6.0.0'
|
|
56
|
+
testImplementation "junit:junit:$junitVersion"
|
|
57
|
+
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
58
|
+
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
|
59
|
+
}
|