@jacques_gordon/expo-mapbox-navigation 1.0.7 → 2.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.
Files changed (36) hide show
  1. package/ExpoMapboxNavigation.podspec +39 -0
  2. package/LICENSE +21 -0
  3. package/README.md +103 -209
  4. package/android/build.gradle +101 -39
  5. package/android/src/main/java/expo/modules/mapboxnavigation/ExpoMapboxNavigationModule.kt +81 -77
  6. package/android/src/main/java/expo/modules/mapboxnavigation/ExpoMapboxNavigationView.kt +260 -142
  7. package/app.plugin.js +216 -1
  8. package/build/index.d.ts +121 -2
  9. package/build/index.js +34 -3
  10. package/build/src/index.d.ts +121 -0
  11. package/build/src/index.js +39 -0
  12. package/package.json +37 -37
  13. package/plugin/src/index.js +216 -0
  14. package/src/index.tsx +162 -0
  15. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  16. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  17. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  18. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  19. package/android/.gradle/8.9/gc.properties +0 -0
  20. package/android/.gradle/9.2.0/checksums/checksums.lock +0 -0
  21. package/android/.gradle/9.2.0/fileChanges/last-build.bin +0 -0
  22. package/android/.gradle/9.2.0/fileHashes/fileHashes.bin +0 -0
  23. package/android/.gradle/9.2.0/fileHashes/fileHashes.lock +0 -0
  24. package/android/.gradle/9.2.0/gc.properties +0 -0
  25. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  26. package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  27. package/android/.gradle/vcs-1/gc.properties +0 -0
  28. package/build/MapboxNavigation.types.d.ts +0 -132
  29. package/build/MapboxNavigation.types.js +0 -2
  30. package/build/MapboxNavigationView.d.ts +0 -30
  31. package/build/MapboxNavigationView.js +0 -41
  32. package/expo-module.config.json +0 -9
  33. package/ios/ExpoMapboxNavigation.podspec +0 -25
  34. package/ios/ExpoMapboxNavigationModule.swift +0 -81
  35. package/ios/ExpoMapboxNavigationView.swift +0 -236
  36. package/plugin/index.js +0 -167
@@ -0,0 +1,39 @@
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 = 'ExpoMapboxNavigation'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.description = package['description']
10
+ s.license = package['license']
11
+ s.author = package['author']
12
+ s.homepage = package['homepage']
13
+ s.platforms = { :ios => '14.0' }
14
+ s.swift_version = '5.7'
15
+ s.source = { git: package['repository']['url'], tag: "v#{s.version}" }
16
+ s.static_framework = true
17
+
18
+ s.dependency 'ExpoModulesCore'
19
+
20
+ # ── iOS: Mapbox Navigation bundled as xcframework ──────────────────────────
21
+ # The Navigation SDK v3 for iOS does not support CocoaPods natively.
22
+ # xcframeworks are bundled directly. See README for how to rebuild them.
23
+ # ────────────────────────────────────────────────────────────────────────────
24
+ s.vendored_frameworks = 'ios/MapboxNavigationUIKit.xcframework',
25
+ 'ios/MapboxNavigationCore.xcframework',
26
+ 'ios/MapboxDirections.xcframework'
27
+
28
+ # Mapbox Maps SDK (via CocoaPods — available as of Maps SDK 11.x)
29
+ s.dependency 'MapboxMaps', '>= 11.11.0'
30
+
31
+ s.source_files = 'ios/**/*.{swift,m,mm}'
32
+
33
+ s.pod_target_xcconfig = {
34
+ 'DEFINES_MODULE' => 'YES',
35
+ # 16 KB page alignment for iOS (Apple Silicon + future-proof)
36
+ 'OTHER_LDFLAGS' => '-Wl,-dead_strip_dylibs',
37
+ 'SWIFT_COMPILATION_MODE' => 'wholemodule'
38
+ }
39
+ end
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Jacques Gordon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,276 +1,170 @@
1
1
  # @jacques_gordon/expo-mapbox-navigation
2
2
 
3
- Plugin Expo pour la navigation Mapbox **turn-by-turn**, compatible **Expo SDK 53** avec **Expo Dev Client**.
3
+ [![npm version](https://badge.fury.io/js/@jacques_gordon%2Fexpo-mapbox-navigation.svg)](https://www.npmjs.com/package/@jacques_gordon/expo-mapbox-navigation)
4
4
 
5
- Supporte **iOS** et **Android**, avec waypoints multiples, instructions vocales, reroutage automatique, restrictions de gabarit de véhicule et personnalisation de la carte.
5
+ Expo module for Mapbox Navigation SDK forked from [`@badatgil/expo-mapbox-navigation`](https://github.com/uju777/expo-mapbox-navigation) with the following fixes and improvements:
6
6
 
7
- > ⚠️ Nécessite **Expo Dev Client** — incompatible avec Expo Go.
8
-
9
- ---
10
-
11
- ## Fonctionnalités
12
-
13
- -Navigation turn-by-turn complète (iOS & Android)
14
- -Waypoints multiples
15
- - ✅ Instructions vocales
16
- - ✅ Reroutage automatique
17
- - ✅ Détection hors-route
18
- - ✅ Restrictions de gabarit de véhicule (hauteur / largeur)
19
- - ✅ Map Matching API (trajet explicite selon les coordonnées)
20
- - ✅ Routes alternatives
21
- - ✅ Style de carte personnalisable
22
- - ✅ Couche raster personnalisée
23
- - ✅ Multilangue
24
- - ✅ Compatible avec `@rnmapbox/maps`
7
+ | Change | Details |
8
+ |--------|---------|
9
+ | 🐛 **Fix #43** | Android crash: `NoSuchMethodError` for `CameraAnimationsUtils.calculateCameraAnimationHint` — caused by Mapbox Maps/Navigation SDK version mismatch. Fixed by pinning `mapbox-maps-android ≥ 11.11.0` and Navigation SDK `3.7.0`. |
10
+ | 🐛 **Fix #31** | Voice instructions always defaulted to imperial units. New `voiceUnits` prop (`"metric"` \| `"imperial"`) added. |
11
+ | ✅ **NDK 27** | Forced NDK `27.0.12077973` for full 16 KB page size compatibility (Android 15+ requirement). |
12
+ | ✅ **16 KB page size** | `jniLibs.useLegacyPackaging = false` + `ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON` — required for Google Play compliance from 2025 onwards. |
13
+ |**Expo SDK 53+** | Compatible with Expo SDK ≥ 53 and React Native 0.79+. |
14
+ |**Maps v11.11.0** | Minimum Mapbox Maps Android SDK enforced to 11.11.0 (config plugin validates this). |
25
15
 
26
16
  ---
27
17
 
28
18
  ## Installation
29
19
 
30
- ### 1. Installer `@rnmapbox/maps` (dépendance requise)
31
-
32
- Suivre les [instructions officielles de @rnmapbox/maps](https://rnmapbox.github.io/docs/install).
33
- La version recommandée est `11.11.0`. **Important : définir explicitement `RNMapboxMapsVersion`.**
34
-
35
- ### 2. Installer le package
36
-
37
20
  ```bash
38
- npm install @jacques_gordon/expo-mapbox-navigation
21
+ npx expo install @jacques_gordon/expo-mapbox-navigation @rnmapbox/maps
39
22
  ```
40
23
 
41
- Et additionnellement le package (parfois optionnelle)
24
+ ### Setup @rnmapbox/maps first
42
25
 
43
- ```bash
44
- npm install metro-cache-key
45
- ```
46
-
47
- ### 3. Configurer le plugin dans `app.json`
26
+ Follow the [full @rnmapbox/maps installation guide](https://rnmapbox.github.io/docs/install). Set `RNMapboxMapsVersion` to `11.11.0` or higher.
48
27
 
49
28
  ```json
50
- {
51
- "expo": {
52
- "plugins": [
53
- [
54
- "expo-build-properties",
55
- {
56
- "ios": {
57
- "useFrameworks": "static"
58
- }
59
- }
60
- ],
61
- [
62
- "@jacques_gordon/expo-mapbox-navigation",
63
- {
64
- "accessToken": "pk.eyJ1IjoiVk9UUkVfVE9LRU4iLCJhIjoiY...",
65
- "mapboxMapsVersion": "11.11.0",
66
- "androidColorOverrides": {
67
- "mapbox_main_maneuver_background_color": "#1E88E5"
68
- }
69
- }
70
- ]
71
- ]
72
- }
73
- }
29
+ "plugins": [
30
+ [
31
+ "@rnmapbox/maps",
32
+ {
33
+ "RNMapboxMapsImpl": "mapbox",
34
+ "RNMapboxMapsVersion": "11.11.0",
35
+ "RNMapboxMapsDownloadToken": "sk.your_secret_token"
36
+ }
37
+ ]
38
+ ]
74
39
  ```
75
40
 
76
- ### 4. Configurer les tokens secrets
77
-
78
- #### iOS — `~/.netrc`
41
+ ### Add this plugin
79
42
 
80
- ```
81
- machine api.mapbox.com
82
- login mapbox
83
- password sk.eyJ1IjoiVk9UUkVfVE9LRU5fU0VDUkVUIiwiYSI6Ii4uLiJ9...
43
+ ```json
44
+ "plugins": [
45
+ [
46
+ "@jacques_gordon/expo-mapbox-navigation",
47
+ {
48
+ "accessToken": "pk.your_public_token",
49
+ "mapboxMapsVersion": "11.11.0"
50
+ }
51
+ ]
52
+ ]
84
53
  ```
85
54
 
86
- #### Android `~/.gradle/gradle.properties`
55
+ > ⚠️ `mapboxMapsVersion` must match the version set in `@rnmapbox/maps`. Minimum: `11.11.0`.
87
56
 
88
- ```properties
89
- MAPBOX_DOWNLOADS_TOKEN=sk.eyJ1IjoiVk9UUkVfVE9LRU5fU0VDUkVUIiwiYSI6Ii4uLiJ9...
90
- ```
91
-
92
- ### 5. Prebuild + Dev Client
57
+ ### iOS: enable static frameworks
93
58
 
94
- ```bash
95
- npx expo prebuild --clean
96
- npx expo run:ios # ou run:android
59
+ ```json
60
+ "plugins": [
61
+ ["expo-build-properties", { "ios": { "useFrameworks": "static" } }]
62
+ ]
97
63
  ```
98
64
 
99
65
  ---
100
66
 
101
- ## Utilisation
102
-
103
- ### Exemple de base
67
+ ## Usage
104
68
 
105
69
  ```tsx
106
70
  import { MapboxNavigationView } from '@jacques_gordon/expo-mapbox-navigation';
107
71
 
108
- export default function NavigationScreen() {
72
+ export default function Navigation() {
109
73
  return (
110
74
  <MapboxNavigationView
111
75
  style={{ flex: 1 }}
112
76
  coordinates={[
113
- { latitude: 48.8566, longitude: 2.3522 }, // Paris — départ
114
- { latitude: 43.2965, longitude: 5.3698 }, // Marseille — destination
77
+ { latitude: 48.8566, longitude: 2.3522 }, // Paris
78
+ { latitude: 51.5074, longitude: -0.1278 }, // London
115
79
  ]}
116
- locale="fr"
117
- onFinalDestinationArrival={() => console.log('Arrivé !')}
118
- onCancelNavigation={() => navigation.goBack()}
80
+ voiceUnits="metric" // Fix for issue #31
81
+ language="fr"
82
+ navigationProfile="driving-traffic"
83
+ onArrival={() => console.log('Arrived!')}
84
+ onRoutesFailed={({ nativeEvent }) =>
85
+ console.error('Routes failed:', nativeEvent.message)
86
+ }
119
87
  />
120
88
  );
121
89
  }
122
90
  ```
123
91
 
124
- ### Exemple complet (compatible avec la page de navigation)
92
+ ---
125
93
 
126
- ```tsx
127
- import { MapboxNavigationView } from '@jacques_gordon/expo-mapbox-navigation';
94
+ ## Props
128
95
 
129
- export default function NavigationScreen({ navigation, reservation, currentPosition }) {
130
- const coordinates = [
131
- currentPosition, // départ (position actuelle)
132
- { latitude: 45.7640, longitude: 4.8357 }, // Lyon waypoint intermédiaire
133
- reservation.address_to_lat_long, // destination finale
134
- ];
135
-
136
- return (
137
- <MapboxNavigationView
138
- style={{ flex: 1 }}
139
- coordinates={coordinates}
140
- locale="fr"
141
- vehicleMaxHeight={5.0}
142
- vehicleMaxWidth={2.5}
143
- showsEndOfRouteFeedback
144
- onRouteProgressChanged={async (event) => {
145
- const { distanceRemaining, durationRemaining, distanceTraveled, fractionTraveled } =
146
- event.nativeEvent;
147
-
148
- // Notifier le client que le chauffeur approche
149
- if (distanceRemaining <= 60) {
150
- AXIOS_POST('reservations/livetracking/drivernear', { reservation });
151
- }
152
-
153
- const eta = new Date(Date.now() + durationRemaining * 1000);
154
- dispatch(setNavigationData({ eta, distanceRemaining, durationRemaining }));
155
- }}
156
- onWaypointArrival={(event) => {
157
- console.log('Waypoint atteint !', event.nativeEvent);
158
- }}
159
- onFinalDestinationArrival={async () => {
160
- await playSound(SOUNDS.ROAD_RECALCULATE);
161
- showToast({ toast_type: 'validation', title: 'Arrivée', body: 'Destination atteinte !' });
162
- }}
163
- onCancelNavigation={() => navigation.goBack()}
164
- onRouteChanged={() => console.log('Reroutage en cours...')}
165
- onUserOffRoute={() => console.log('Hors route !')}
166
- onRoutesLoaded={() => console.log('Routes chargées')}
167
- />
168
- );
169
- }
170
- ```
96
+ | Prop | Type | Default | Description |
97
+ |------|------|---------|-------------|
98
+ | `coordinates` | `Coordinate[]` | required | Route waypoints. Min 2 items. |
99
+ | `waypointIndices` | `number[]` | all points | Which coordinates are waypoints. |
100
+ | `language` | `string` | device locale | BCP-47 locale (e.g. `"fr"`, `"en-US"`). |
101
+ | `voiceUnits` | `"metric" \| "imperial"` | auto | **Fix #31** — Voice/distance units. |
102
+ | `navigationProfile` | `string` | `"driving-traffic"` | Mapbox routing profile. |
103
+ | `excludeTypes` | `string[]` | — | Road types to avoid. |
104
+ | `mapStyle` | `string` | Mapbox Navigation Day | Map style URL. |
105
+ | `mute` | `boolean` | `false` | Silence voice instructions. |
106
+ | `maxHeight` | `number` | — | Max vehicle height (m). |
107
+ | `maxWidth` | `number` | — | Max vehicle width (m). |
108
+ | `useMapMatching` | `boolean` | `false` | Use Map Matching API. |
109
+ | `customRasterTileUrl` | `string` | — | Custom tile URL with `{x}/{y}/{z}`. |
110
+ | `customRasterAboveLayerId` | `string` | — | Layer ID to place custom raster above. |
171
111
 
172
112
  ---
173
113
 
174
- ## Props
114
+ ## Events
175
115
 
176
- ### Route
177
-
178
- | Prop | Type | Requis | Description |
179
- |------|------|--------|-------------|
180
- | `coordinates` | `Coordinate[]` | **Oui** | Tableau de `{latitude, longitude}`. Minimum 2 points. |
181
- | `waypointIndices` | `number[]` | Non | Indices des points considérés comme waypoints. Par défaut: tous. |
182
-
183
- ### Options de routing
184
-
185
- | Prop | Type | Défaut | Description |
186
- |------|------|--------|-------------|
187
- | `locale` | `string` | locale appareil | Langue des instructions. Ex: `"fr"`, `"en"`, `"de"` |
188
- | `routeProfile` | `string` | `"mapbox/driving-traffic"` | Profil de routing. Android: sans `"mapbox/"`. |
189
- | `routeExcludeList` | `string[]` | `[]` | Routes à exclure: `"toll"`, `"ferry"`, `"motorway"` |
190
- | `useRouteMatchingApi` | `boolean` | `false` | Utilise l'API Map Matching au lieu de l'API Directions |
191
- | `disableAlternativeRoutes` | `boolean` | `false` | Désactive les routes alternatives |
192
- | `mute` | `boolean` | `false` | Coupe le son de navigation au démarrage |
193
- | `vehicleMaxHeight` | `number` | — | Hauteur max du véhicule en mètres |
194
- | `vehicleMaxWidth` | `number` | — | Largeur max du véhicule en mètres |
195
-
196
- ### Personnalisation visuelle
197
-
198
- | Prop | Type | Défaut | Description |
199
- |------|------|--------|-------------|
200
- | `mapStyle` | `string` | style par défaut | URL du style Mapbox |
201
- | `customRasterSourceUrl` | `string` | — | URL template raster personnalisée (ex: OpenStreetMap) |
202
- | `placeCustomRasterLayerAbove` | `string` | — | ID du layer au-dessus duquel placer la couche raster |
203
- | `showsEndOfRouteFeedback` | `boolean` | `false` | Affiche l'UI de feedback à l'arrivée |
204
-
205
- ### Callbacks
206
-
207
- | Prop | Paramètres | Description |
208
- |------|-----------|-------------|
209
- | `onRouteProgressChanged` | `{ nativeEvent: RouteProgress }` | Progression sur la route (appelé fréquemment) |
210
- | `onWaypointArrival` | `{ nativeEvent: RouteProgress }` (Android only) | Arrivée à un waypoint intermédiaire |
211
- | `onFinalDestinationArrival` | — | Arrivée à la destination finale |
212
- | `onCancelNavigation` | — | Annulation de la navigation par l'utilisateur |
213
- | `onRouteChanged` | — | Route modifiée ou reroutage |
214
- | `onUserOffRoute` | — | L'utilisateur est sorti de la route |
215
- | `onRoutesLoaded` | — | Routes chargées et prêtes |
116
+ | Event | Payload | Description |
117
+ |-------|---------|-------------|
118
+ | `onRoutesReady` | `{ routeCount, distanceMeters, durationSeconds }` | Routes calculated. |
119
+ | `onRouteProgressChanged` | `{ distanceRemaining, durationRemaining, ... }` | Progress update. |
120
+ | `onArrival` | `{}` | User reached destination. |
121
+ | `onNavigationCancelled` | `{}` | User cancelled navigation. |
122
+ | `onNavigationFinished` | `{}` | Session ended normally. |
123
+ | `onRoutesFailed` | `{ message }` | Route calculation failed. |
216
124
 
217
125
  ---
218
126
 
219
- ## Types TypeScript
127
+ ## Android Color Overrides
220
128
 
221
- ```ts
222
- interface Coordinate {
223
- latitude: number;
224
- longitude: number;
225
- }
129
+ Customize the Navigation UI colors by overriding Mapbox resource values:
226
130
 
227
- interface RouteProgress {
228
- distanceRemaining: number; // mètres restants
229
- distanceTraveled: number; // mètres parcourus
230
- durationRemaining: number; // secondes restantes
231
- fractionTraveled: number; // 0.0 → 1.0
232
- }
131
+ ```json
132
+ ["@jacques_gordon/expo-mapbox-navigation", {
133
+ "accessToken": "pk.your_token",
134
+ "mapboxMapsVersion": "11.11.0",
135
+ "androidColorOverrides": {
136
+ "mapbox_main_maneuver_background_color": "#FF5500",
137
+ "mapbox_primary_route_color": "#0055FF"
138
+ }
139
+ }]
233
140
  ```
234
141
 
235
142
  ---
236
143
 
237
- ## Plugin `app.json` Options complètes
144
+ ## 16 KB Page Size Compatibility
238
145
 
239
- ```json
240
- [
241
- "@jacques_gordon/expo-mapbox-navigation",
242
- {
243
- "accessToken": "pk.eyJ1...",
244
- "mapboxMapsVersion": "11.11.0",
245
- "androidColorOverrides": {
246
- "mapbox_main_maneuver_background_color": "#1E88E5",
247
- "mapbox_sub_maneuver_background_color": "#1565C0",
248
- "mapbox_banner_background_color": "#FFFFFF"
249
- }
250
- }
251
- ]
252
- ```
146
+ Android 15 (API 35) requires all `.so` native libraries to be aligned to 16 KB boundaries for devices using 16 KB memory page sizes.
253
147
 
254
- ## Notes importantes
148
+ This package enforces:
149
+ - **NDK 27** (`27.0.12077973`) — the first NDK version with full 16 KB support
150
+ - **`jniLibs.useLegacyPackaging = false`** — prevents `.so` compression, enabling proper alignment
151
+ - **64-bit-only ABI filters** (`arm64-v8a`, `x86_64`) — 16 KB requirement applies to 64-bit only
255
152
 
256
- - Nécessite **Expo Dev Client** (Expo Go non supporté)
257
- - iOS minimum : **14.0**
258
- - Android minimum SDK : **24**
259
- - Le SDK Mapbox Navigation est propriétaire — facturation via votre compte Mapbox
260
- - Pour iOS, les `.xcframework` du SDK Mapbox Navigation doivent être compilés et inclus dans `ios/Frameworks/`
261
- (voir [instructions dans le README du repo source](https://github.com/uju777/expo-mapbox-navigation))
153
+ More info: [Android 16 KB page size guide](https://developer.android.com/guide/practices/page-sizes)
262
154
 
263
155
  ---
264
156
 
265
- ## Obtenir vos tokens Mapbox
157
+ ## Changelog
266
158
 
267
- 1. Créer un compte sur [mapbox.com](https://www.mapbox.com/)
268
- 2. Aller dans [Account > Tokens](https://account.mapbox.com/access-tokens/)
269
- 3. **Token public** (`pk.eyJ1...`) token par défaut ou nouveau token
270
- 4. **Token secret** (`sk.eyJ1...`) nouveau token avec le scope `Downloads:Read`
159
+ ### 2.0.1
160
+ - Fix #43: `CameraAnimationsUtils.calculateCameraAnimationHint` NoSuchMethodError on Android
161
+ - Fix #31: Add `voiceUnits` prop for metric/imperial voice instructions
162
+ - Force NDK 27 for 16 KB page size support
163
+ - Enforce Mapbox Maps Android ≥ 11.11.0
164
+ - Expo SDK 53 compatibility
271
165
 
272
166
  ---
273
167
 
274
- ## Licence
168
+ ## License
275
169
 
276
170
  MIT
@@ -2,53 +2,115 @@ apply plugin: 'com.android.library'
2
2
  apply plugin: 'kotlin-android'
3
3
  apply plugin: 'maven-publish'
4
4
 
5
- buildscript {
6
- def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
7
- if (expoModulesCorePlugin.exists()) {
8
- apply from: expoModulesCorePlugin
9
- applyKotlinExpoModulesCorePlugin()
10
- }
11
- }
5
+ // ─────────────────────────────────────────────────────────────────────────────
6
+ // Mapbox Navigation SDK version used by this module.
7
+ // Must be aligned with the Mapbox Maps SDK version used in @rnmapbox/maps.
8
+ // Minimum required: 3.x compatible with mapbox-maps-android 11.11.0
9
+ // ─────────────────────────────────────────────────────────────────────────────
10
+ def MAPBOX_NAVIGATION_VERSION = "3.7.0"
11
+
12
+ // Forces minimum Mapbox Maps Android version to 11.11.0 to ensure
13
+ // CameraAnimationsUtils.calculateCameraAnimationHint(...) is available (fixes #43)
14
+ def MAPBOX_MAPS_MIN_VERSION = "11.11.0"
15
+
16
+ // ─────────────────────────────────────────────────────────────────────────────
17
+ // NDK 27 — required for 16 KB page size compatibility (Android 15+)
18
+ // See: https://developer.android.com/guide/practices/page-sizes
19
+ // NDK 27 added full support for 16 KB page alignment via -DALIGN_16KB flag
20
+ // ─────────────────────────────────────────────────────────────────────────────
21
+ def REQUIRED_NDK_VERSION = "27.0.12077973"
12
22
 
13
23
  android {
14
- compileSdkVersion 34
15
- namespace "expo.modules.mapboxnavigation"
16
-
17
- defaultConfig {
18
- minSdkVersion 24
19
- targetSdkVersion 34
20
- }
21
-
22
- compileOptions {
23
- sourceCompatibility JavaVersion.VERSION_17
24
- targetCompatibility JavaVersion.VERSION_17
25
- }
26
-
27
- kotlinOptions {
28
- jvmTarget = "17"
29
- }
24
+ compileSdkVersion safeExtGet("compileSdkVersion", 35)
25
+ namespace "expo.modules.mapboxnavigation"
26
+
27
+ // Force NDK 27 for 16 KB page size compatibility
28
+ ndkVersion REQUIRED_NDK_VERSION
29
+
30
+ defaultConfig {
31
+ minSdkVersion safeExtGet("minSdkVersion", 24)
32
+ targetSdkVersion safeExtGet("targetSdkVersion", 35)
33
+
34
+ // ─────────────────────────────────────────────────────────────────
35
+ // 16 KB PAGE SIZE SUPPORT (Android 15 / API 35+)
36
+ // Required for Google Play compliance starting Feb 2025 (64-bit apps)
37
+ // This ensures native .so libraries are aligned to 16 KB boundaries.
38
+ // ─────────────────────────────────────────────────────────────────
39
+ externalNativeBuild {
40
+ cmake {
41
+ arguments "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
42
+ }
43
+ }
44
+
45
+ ndk {
46
+ // Only build for 64-bit ABIs — 16 KB page size requirement is 64-bit only
47
+ abiFilters "arm64-v8a", "x86_64"
48
+ }
49
+ }
50
+
51
+ compileOptions {
52
+ sourceCompatibility JavaVersion.VERSION_17
53
+ targetCompatibility JavaVersion.VERSION_17
54
+ }
55
+
56
+ kotlinOptions {
57
+ jvmTarget = JavaVersion.VERSION_17.majorVersion
58
+ }
59
+
60
+ packagingOptions {
61
+ // Ensure .so files are NOT compressed — required for 16 KB page size support
62
+ // Compressed .so files cannot be aligned in the APK
63
+ jniLibs {
64
+ useLegacyPackaging = false
65
+ }
66
+ }
67
+
68
+ buildFeatures {
69
+ buildConfig true
70
+ }
30
71
  }
31
72
 
32
73
  repositories {
33
- maven {
34
- url 'https://api.mapbox.com/downloads/v2/releases/maven'
35
- authentication {
36
- basic(BasicAuthentication)
37
- }
38
- credentials {
39
- username = "mapbox"
40
- password = project.properties['MAPBOX_DOWNLOADS_TOKEN'] ?: System.getenv("MAPBOX_DOWNLOADS_TOKEN") ?: ""
74
+ mavenCentral()
75
+ google()
76
+
77
+ // Mapbox Maven repository — requires a secret token (sk.*)
78
+ maven {
79
+ url 'https://api.mapbox.com/downloads/v2/releases/maven'
80
+ authentication {
81
+ basic(BasicAuthentication)
82
+ }
83
+ credentials {
84
+ username = 'mapbox'
85
+ password = project.hasProperty('MAPBOX_DOWNLOADS_TOKEN')
86
+ ? project.property('MAPBOX_DOWNLOADS_TOKEN')
87
+ : System.getenv('MAPBOX_DOWNLOADS_TOKEN') ?: ""
88
+ }
41
89
  }
42
- }
43
- google()
44
- mavenCentral()
45
90
  }
46
91
 
47
92
  dependencies {
48
- implementation project(':expo-modules-core')
49
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion()}"
93
+ implementation project(':expo-modules-core')
94
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${safeExtGet('kotlinVersion', '1.9.0')}"
95
+
96
+ // ─────────────────────────────────────────────────────────────────────────
97
+ // Mapbox Navigation SDK for Android
98
+ // Version pinned to 3.7.0 which ships with mapbox-maps-android 11.11.0+
99
+ // This resolves the NoSuchMethodError for calculateCameraAnimationHint (issue #43)
100
+ // ─────────────────────────────────────────────────────────────────────────
101
+ implementation "com.mapbox.navigation:android:${MAPBOX_NAVIGATION_VERSION}"
102
+
103
+ // Explicitly pin Mapbox Maps SDK to ≥ 11.11.0 to guarantee method compatibility
104
+ // Prevents gradle from resolving an older transitive version (issue #43 root cause)
105
+ implementation("com.mapbox.maps:android:${MAPBOX_MAPS_MIN_VERSION}") {
106
+ transitive = true
107
+ }
108
+
109
+ // Lifecycle support
110
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0'
111
+ implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0'
112
+ }
50
113
 
51
- // Mapbox Navigation SDK v3 + Drop-in UI
52
- api "com.mapbox.navigation:android:3.3.0"
53
- api "com.mapbox.navigation:ui-dropin:3.3.0"
114
+ def safeExtGet(prop, fallback) {
115
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
54
116
  }