@maplibre/maplibre-react-native 10.0.0-beta.13 → 10.0.0-beta.14
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/README.md +9 -11
- package/android/src/main/java/org/maplibre/reactnative/components/camera/MLRNCamera.java +37 -48
- package/android/src/main/java/org/maplibre/reactnative/components/location/LocationComponentManager.java +16 -9
- package/app.plugin.js +1 -1
- package/ios/MLRN/MLRNCamera.m +6 -7
- package/lib/commonjs/components/Camera.js +109 -60
- package/lib/commonjs/components/Camera.js.map +1 -1
- package/lib/commonjs/components/MapView.js +6 -6
- package/lib/commonjs/modules/offline/OfflineManager.js +8 -8
- package/lib/commonjs/plugin/withMapLibre.js +149 -0
- package/lib/commonjs/plugin/withMapLibre.js.map +1 -0
- package/lib/module/components/Camera.js +111 -62
- package/lib/module/components/Camera.js.map +1 -1
- package/lib/module/components/MapView.js +6 -6
- package/lib/module/modules/offline/OfflineManager.js +8 -8
- package/lib/module/plugin/withMapLibre.js +140 -0
- package/lib/module/plugin/withMapLibre.js.map +1 -0
- package/lib/typescript/commonjs/src/components/Camera.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/modules/offline/OfflineManager.d.ts +8 -8
- package/{plugin/build → lib/typescript/commonjs/src/plugin}/withMapLibre.d.ts +1 -0
- package/lib/typescript/commonjs/src/plugin/withMapLibre.d.ts.map +1 -0
- package/lib/typescript/module/src/components/Camera.d.ts.map +1 -1
- package/lib/typescript/module/src/modules/offline/OfflineManager.d.ts +8 -8
- package/lib/typescript/module/src/plugin/withMapLibre.d.ts +13 -0
- package/lib/typescript/module/src/plugin/withMapLibre.d.ts.map +1 -0
- package/package.json +8 -10
- package/src/components/Camera.tsx +151 -73
- package/src/components/MapView.tsx +6 -6
- package/src/modules/offline/OfflineManager.ts +8 -8
- package/src/plugin/withMapLibre.ts +181 -0
- package/lib/typescript/commonjs/jest.config.d.ts +0 -2
- package/lib/typescript/commonjs/jest.config.d.ts.map +0 -1
- package/lib/typescript/module/jest.config.d.ts +0 -2
- package/lib/typescript/module/jest.config.d.ts.map +0 -1
- package/plugin/build/withMapLibre.js +0 -148
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { point } from "@turf/helpers";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
forwardRef,
|
|
4
|
+
memo,
|
|
5
|
+
useEffect,
|
|
6
|
+
useImperativeHandle,
|
|
7
|
+
useMemo,
|
|
8
|
+
useState,
|
|
9
|
+
} from "react";
|
|
10
|
+
import { Platform, requireNativeComponent, type ViewProps } from "react-native";
|
|
4
11
|
|
|
5
12
|
import { CameraModes } from "../MLRNModule";
|
|
6
13
|
import { useNativeRef } from "../hooks/useNativeRef";
|
|
@@ -47,54 +54,62 @@ function makeNativeCameraStop(stop?: CameraStop): NativeCameraStop | undefined {
|
|
|
47
54
|
return undefined;
|
|
48
55
|
}
|
|
49
56
|
|
|
50
|
-
const
|
|
57
|
+
const newNativeStop: NativeCameraStop = {};
|
|
51
58
|
|
|
52
59
|
if (stop.animationDuration !== undefined) {
|
|
53
|
-
|
|
60
|
+
newNativeStop.duration = stop.animationDuration;
|
|
54
61
|
}
|
|
55
62
|
if (stop.animationMode !== undefined) {
|
|
56
|
-
|
|
63
|
+
newNativeStop.mode = getNativeCameraMode(stop.animationMode);
|
|
57
64
|
}
|
|
58
65
|
if (stop.centerCoordinate) {
|
|
59
|
-
|
|
66
|
+
newNativeStop.centerCoordinate = JSON.stringify(
|
|
67
|
+
point(stop.centerCoordinate),
|
|
68
|
+
);
|
|
60
69
|
}
|
|
61
70
|
if (stop.heading !== undefined) {
|
|
62
|
-
|
|
71
|
+
newNativeStop.heading = stop.heading;
|
|
63
72
|
}
|
|
64
73
|
if (stop.pitch !== undefined) {
|
|
65
|
-
|
|
74
|
+
newNativeStop.pitch = stop.pitch;
|
|
66
75
|
}
|
|
67
76
|
if (stop.zoomLevel !== undefined) {
|
|
68
|
-
|
|
77
|
+
newNativeStop.zoom = stop.zoomLevel;
|
|
69
78
|
}
|
|
70
79
|
|
|
71
80
|
if (stop.bounds && stop.bounds.ne && stop.bounds.sw) {
|
|
72
81
|
const { ne, sw } = stop.bounds;
|
|
73
|
-
|
|
82
|
+
newNativeStop.bounds = makeNativeBounds(ne, sw);
|
|
74
83
|
}
|
|
75
84
|
|
|
76
85
|
const paddingTop = stop.padding?.paddingTop ?? stop.bounds?.paddingTop;
|
|
77
86
|
if (paddingTop !== undefined) {
|
|
78
|
-
|
|
87
|
+
newNativeStop.paddingTop = paddingTop;
|
|
79
88
|
}
|
|
80
89
|
|
|
81
90
|
const paddingRight = stop.padding?.paddingRight ?? stop.bounds?.paddingRight;
|
|
82
91
|
if (paddingRight !== undefined) {
|
|
83
|
-
|
|
92
|
+
newNativeStop.paddingRight = paddingRight;
|
|
84
93
|
}
|
|
85
94
|
|
|
86
95
|
const paddingBottom =
|
|
87
96
|
stop.padding?.paddingBottom ?? stop.bounds?.paddingBottom;
|
|
88
97
|
if (paddingBottom !== undefined) {
|
|
89
|
-
|
|
98
|
+
newNativeStop.paddingBottom = paddingBottom;
|
|
90
99
|
}
|
|
91
100
|
|
|
92
101
|
const paddingLeft = stop.padding?.paddingLeft ?? stop.bounds?.paddingLeft;
|
|
93
102
|
if (paddingLeft !== undefined) {
|
|
94
|
-
|
|
103
|
+
newNativeStop.paddingLeft = paddingLeft;
|
|
95
104
|
}
|
|
96
105
|
|
|
97
|
-
|
|
106
|
+
if (newNativeStop.centerCoordinate && newNativeStop.bounds) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
"Create a camera stop with bounds and centerCoordinate – this is not possible.",
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return newNativeStop;
|
|
98
113
|
}
|
|
99
114
|
|
|
100
115
|
export interface CameraRef {
|
|
@@ -269,44 +284,11 @@ export const Camera = memo(
|
|
|
269
284
|
}: CameraProps,
|
|
270
285
|
ref,
|
|
271
286
|
) => {
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
const nativeStop = useMemo(() => {
|
|
275
|
-
return makeNativeCameraStop({
|
|
276
|
-
animationDuration,
|
|
277
|
-
animationMode,
|
|
278
|
-
bounds,
|
|
279
|
-
centerCoordinate,
|
|
280
|
-
heading,
|
|
281
|
-
padding,
|
|
282
|
-
pitch,
|
|
283
|
-
zoomLevel,
|
|
284
|
-
});
|
|
285
|
-
}, [
|
|
286
|
-
animationDuration,
|
|
287
|
-
animationMode,
|
|
288
|
-
bounds,
|
|
289
|
-
centerCoordinate,
|
|
290
|
-
heading,
|
|
291
|
-
padding,
|
|
292
|
-
pitch,
|
|
293
|
-
zoomLevel,
|
|
294
|
-
]);
|
|
295
|
-
|
|
296
|
-
const nativeDefaultStop = useMemo(() => {
|
|
297
|
-
return makeNativeCameraStop(defaultSettings);
|
|
298
|
-
}, [defaultSettings]);
|
|
299
|
-
|
|
300
|
-
const nativeMaxBounds = useMemo(() => {
|
|
301
|
-
if (!maxBounds?.ne || !maxBounds?.sw) {
|
|
302
|
-
return undefined;
|
|
303
|
-
}
|
|
304
|
-
return makeNativeBounds(maxBounds.ne, maxBounds.sw);
|
|
305
|
-
}, [maxBounds]);
|
|
287
|
+
const nativeCameraRef = useNativeRef<NativeCameraProps>();
|
|
306
288
|
|
|
307
289
|
const setCamera = (config: CameraStop | CameraStops = {}): void => {
|
|
308
290
|
if ("stops" in config) {
|
|
309
|
-
|
|
291
|
+
nativeCameraRef.current?.setNativeProps({
|
|
310
292
|
stop: {
|
|
311
293
|
stops: config.stops
|
|
312
294
|
.map((stopItem) => makeNativeCameraStop(stopItem))
|
|
@@ -314,10 +296,10 @@ export const Camera = memo(
|
|
|
314
296
|
},
|
|
315
297
|
});
|
|
316
298
|
} else {
|
|
317
|
-
const
|
|
299
|
+
const stop = makeNativeCameraStop(config);
|
|
318
300
|
|
|
319
|
-
if (
|
|
320
|
-
|
|
301
|
+
if (stop) {
|
|
302
|
+
nativeCameraRef.current?.setNativeProps({ stop });
|
|
321
303
|
}
|
|
322
304
|
}
|
|
323
305
|
};
|
|
@@ -399,10 +381,10 @@ export const Camera = memo(
|
|
|
399
381
|
* cameraRef.current?.fitBounds([lng, lat], [lng, lat], [verticalPadding, horizontalPadding], 1000)
|
|
400
382
|
* cameraRef.current?.fitBounds([lng, lat], [lng, lat], [top, right, bottom, left], 1000)
|
|
401
383
|
*
|
|
402
|
-
* @param {Array<
|
|
403
|
-
* @param {Array<
|
|
404
|
-
* @param {
|
|
405
|
-
* @param {
|
|
384
|
+
* @param {Array<number>} ne - North east coordinate of bound
|
|
385
|
+
* @param {Array<number>} sw - South west coordinate of bound
|
|
386
|
+
* @param {number|Array<number>|undefined} padding - Padding for the bounds
|
|
387
|
+
* @param {number=} animationDuration - Duration of camera animation
|
|
406
388
|
* @return {void}
|
|
407
389
|
*/
|
|
408
390
|
fitBounds,
|
|
@@ -413,8 +395,8 @@ export const Camera = memo(
|
|
|
413
395
|
* cameraRef.current?.flyTo([lng, lat])
|
|
414
396
|
* cameraRef.current?.flyTo([lng, lat], 12000)
|
|
415
397
|
*
|
|
416
|
-
* @param {Array<
|
|
417
|
-
* @param {
|
|
398
|
+
* @param {Array<number>} coordinates - Coordinates that map camera will jump to
|
|
399
|
+
* @param {number=} animationDuration - Duration of camera animation
|
|
418
400
|
* @return {void}
|
|
419
401
|
*/
|
|
420
402
|
flyTo,
|
|
@@ -425,8 +407,8 @@ export const Camera = memo(
|
|
|
425
407
|
* cameraRef.current?.moveTo([lng, lat], 200) // eases camera to new location based on duration
|
|
426
408
|
* cameraRef.current?.moveTo([lng, lat]) // snaps camera to new location without any easing
|
|
427
409
|
*
|
|
428
|
-
* @param {Array<
|
|
429
|
-
* @param {
|
|
410
|
+
* @param {Array<number>} coordinates - Coordinates that map camera will move too
|
|
411
|
+
* @param {number=} animationDuration - Duration of camera animation
|
|
430
412
|
* @return {void}
|
|
431
413
|
*/
|
|
432
414
|
moveTo,
|
|
@@ -437,8 +419,8 @@ export const Camera = memo(
|
|
|
437
419
|
* cameraRef.current?.zoomTo(16)
|
|
438
420
|
* cameraRef.current?.zoomTo(16, 100)
|
|
439
421
|
*
|
|
440
|
-
* @param {
|
|
441
|
-
* @param {
|
|
422
|
+
* @param {number} zoomLevel - Zoom level that the map camera will animate too
|
|
423
|
+
* @param {number=} animationDuration - Duration of camera animation
|
|
442
424
|
* @return {void}
|
|
443
425
|
*/
|
|
444
426
|
zoomTo,
|
|
@@ -465,20 +447,116 @@ export const Camera = memo(
|
|
|
465
447
|
}),
|
|
466
448
|
);
|
|
467
449
|
|
|
450
|
+
const followProps = useMemo(() => {
|
|
451
|
+
return {
|
|
452
|
+
followUserMode,
|
|
453
|
+
followPitch: followPitch ?? pitch,
|
|
454
|
+
followHeading: followHeading ?? heading,
|
|
455
|
+
followZoomLevel: followZoomLevel ?? zoomLevel,
|
|
456
|
+
};
|
|
457
|
+
}, [
|
|
458
|
+
followUserMode,
|
|
459
|
+
followPitch,
|
|
460
|
+
pitch,
|
|
461
|
+
followHeading,
|
|
462
|
+
heading,
|
|
463
|
+
followZoomLevel,
|
|
464
|
+
zoomLevel,
|
|
465
|
+
]);
|
|
466
|
+
|
|
467
|
+
useEffect(() => {
|
|
468
|
+
if (followUserLocation) {
|
|
469
|
+
if (Platform.OS === "android") {
|
|
470
|
+
nativeCameraRef.current?.setNativeProps({
|
|
471
|
+
...followProps,
|
|
472
|
+
followUserLocation,
|
|
473
|
+
});
|
|
474
|
+
} else {
|
|
475
|
+
nativeCameraRef.current?.setNativeProps({
|
|
476
|
+
...followProps,
|
|
477
|
+
});
|
|
478
|
+
nativeCameraRef.current?.setNativeProps({
|
|
479
|
+
followUserLocation,
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
} else {
|
|
483
|
+
nativeCameraRef.current?.setNativeProps({
|
|
484
|
+
followUserLocation,
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
}, [followUserLocation, followProps]);
|
|
488
|
+
|
|
489
|
+
const nativeMaxBounds = useMemo(() => {
|
|
490
|
+
if (!maxBounds?.ne || !maxBounds?.sw) {
|
|
491
|
+
return undefined;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return makeNativeBounds(maxBounds.ne, maxBounds.sw);
|
|
495
|
+
}, [maxBounds]);
|
|
496
|
+
|
|
497
|
+
useEffect(() => {
|
|
498
|
+
if (!followUserLocation) {
|
|
499
|
+
nativeCameraRef.current?.setNativeProps({
|
|
500
|
+
maxBounds: nativeMaxBounds,
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
}, [followUserLocation, nativeMaxBounds]);
|
|
504
|
+
|
|
505
|
+
useEffect(() => {
|
|
506
|
+
if (!followUserLocation) {
|
|
507
|
+
nativeCameraRef.current?.setNativeProps({
|
|
508
|
+
minZoomLevel,
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
}, [followUserLocation, minZoomLevel]);
|
|
512
|
+
|
|
513
|
+
useEffect(() => {
|
|
514
|
+
if (!followUserLocation) {
|
|
515
|
+
nativeCameraRef.current?.setNativeProps({
|
|
516
|
+
maxZoomLevel,
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
}, [followUserLocation, maxZoomLevel]);
|
|
520
|
+
|
|
521
|
+
const nativeStop = useMemo(() => {
|
|
522
|
+
return makeNativeCameraStop({
|
|
523
|
+
animationDuration,
|
|
524
|
+
animationMode,
|
|
525
|
+
bounds,
|
|
526
|
+
centerCoordinate,
|
|
527
|
+
heading,
|
|
528
|
+
padding,
|
|
529
|
+
pitch,
|
|
530
|
+
zoomLevel,
|
|
531
|
+
});
|
|
532
|
+
}, [
|
|
533
|
+
animationDuration,
|
|
534
|
+
animationMode,
|
|
535
|
+
bounds,
|
|
536
|
+
centerCoordinate,
|
|
537
|
+
heading,
|
|
538
|
+
padding,
|
|
539
|
+
pitch,
|
|
540
|
+
zoomLevel,
|
|
541
|
+
]);
|
|
542
|
+
|
|
543
|
+
useEffect(() => {
|
|
544
|
+
if (!followUserLocation) {
|
|
545
|
+
nativeCameraRef.current?.setNativeProps({
|
|
546
|
+
stop: nativeStop,
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
}, [followUserLocation, nativeStop]);
|
|
550
|
+
|
|
551
|
+
const [nativeDefaultStop] = useState(
|
|
552
|
+
makeNativeCameraStop(defaultSettings),
|
|
553
|
+
);
|
|
554
|
+
|
|
468
555
|
return (
|
|
469
556
|
<MLRNCamera
|
|
470
557
|
testID="Camera"
|
|
471
|
-
ref={
|
|
472
|
-
stop={nativeStop}
|
|
558
|
+
ref={nativeCameraRef}
|
|
473
559
|
defaultStop={nativeDefaultStop}
|
|
474
|
-
maxBounds={nativeMaxBounds}
|
|
475
|
-
followUserLocation={followUserLocation}
|
|
476
|
-
followHeading={followHeading}
|
|
477
|
-
followPitch={followPitch}
|
|
478
|
-
followUserMode={followUserMode}
|
|
479
|
-
followZoomLevel={followZoomLevel}
|
|
480
|
-
maxZoomLevel={maxZoomLevel}
|
|
481
|
-
minZoomLevel={minZoomLevel}
|
|
482
560
|
onUserTrackingModeChange={onUserTrackingModeChange}
|
|
483
561
|
/>
|
|
484
562
|
);
|
|
@@ -355,8 +355,8 @@ export const MapView = memo(
|
|
|
355
355
|
queryRenderedFeaturesInRect,
|
|
356
356
|
/**
|
|
357
357
|
* Takes snapshot of map with current tiles and returns a URI to the image
|
|
358
|
-
* @param {
|
|
359
|
-
* @return {
|
|
358
|
+
* @param {boolean} writeToDisk If true will create a temp file, otherwise it is in base64
|
|
359
|
+
* @return {string}
|
|
360
360
|
*/
|
|
361
361
|
takeSnap,
|
|
362
362
|
/**
|
|
@@ -365,7 +365,7 @@ export const MapView = memo(
|
|
|
365
365
|
* @example
|
|
366
366
|
* const zoom = await this._map.getZoom();
|
|
367
367
|
*
|
|
368
|
-
* @return {
|
|
368
|
+
* @return {number}
|
|
369
369
|
*/
|
|
370
370
|
getZoom,
|
|
371
371
|
/**
|
|
@@ -374,7 +374,7 @@ export const MapView = memo(
|
|
|
374
374
|
* @example
|
|
375
375
|
* const center = await this._map.getCenter();
|
|
376
376
|
*
|
|
377
|
-
* @return {Array<
|
|
377
|
+
* @return {Array<number>} Coordinates
|
|
378
378
|
*/
|
|
379
379
|
getCenter,
|
|
380
380
|
/**
|
|
@@ -384,8 +384,8 @@ export const MapView = memo(
|
|
|
384
384
|
* await this._map.setSourceVisibility(false, 'composite', 'building')
|
|
385
385
|
*
|
|
386
386
|
* @param {boolean} visible - Visibility of the layers
|
|
387
|
-
* @param {
|
|
388
|
-
* @param {
|
|
387
|
+
* @param {string} sourceId - Identifier of the target source (e.g. 'composite')
|
|
388
|
+
* @param {string=} sourceLayerId - Identifier of the target source-layer (e.g. 'building')
|
|
389
389
|
*/
|
|
390
390
|
setSourceVisibility,
|
|
391
391
|
/**
|
|
@@ -109,7 +109,7 @@ class OfflineManager {
|
|
|
109
109
|
* @example
|
|
110
110
|
* await OfflineManager.invalidatePack('packName')
|
|
111
111
|
*
|
|
112
|
-
* @param {
|
|
112
|
+
* @param {string} name Name of the offline pack.
|
|
113
113
|
* @return {void}
|
|
114
114
|
*/
|
|
115
115
|
async invalidatePack(name: string): Promise<void> {
|
|
@@ -131,7 +131,7 @@ class OfflineManager {
|
|
|
131
131
|
* @example
|
|
132
132
|
* await OfflineManager.deletePack('packName')
|
|
133
133
|
*
|
|
134
|
-
* @param {
|
|
134
|
+
* @param {string} name Name of the offline pack.
|
|
135
135
|
* @return {void}
|
|
136
136
|
*/
|
|
137
137
|
async deletePack(name: string): Promise<void> {
|
|
@@ -185,7 +185,7 @@ class OfflineManager {
|
|
|
185
185
|
* @example
|
|
186
186
|
* await OfflineManager.setMaximumAmbientCacheSize(5000000);
|
|
187
187
|
*
|
|
188
|
-
* @param {
|
|
188
|
+
* @param {number} size Size of ambient cache.
|
|
189
189
|
* @return {void}
|
|
190
190
|
*/
|
|
191
191
|
async setMaximumAmbientCacheSize(size: number): Promise<void> {
|
|
@@ -228,7 +228,7 @@ class OfflineManager {
|
|
|
228
228
|
* @example
|
|
229
229
|
* const offlinePack = await OfflineManager.getPack();
|
|
230
230
|
*
|
|
231
|
-
* @param {
|
|
231
|
+
* @param {string} name Name of the offline pack.
|
|
232
232
|
* @return {OfflinePack}
|
|
233
233
|
*/
|
|
234
234
|
async getPack(name: string) {
|
|
@@ -242,7 +242,7 @@ class OfflineManager {
|
|
|
242
242
|
* @example
|
|
243
243
|
* await OfflineManager.mergeOfflineRegions(path);
|
|
244
244
|
*
|
|
245
|
-
* @param {
|
|
245
|
+
* @param {string} path Path to offline tile db on file system.
|
|
246
246
|
* @return {void}
|
|
247
247
|
*/
|
|
248
248
|
async mergeOfflineRegions(path: string): Promise<void> {
|
|
@@ -257,7 +257,7 @@ class OfflineManager {
|
|
|
257
257
|
* @example
|
|
258
258
|
* OfflineManager.setTileCountLimit(1000);
|
|
259
259
|
*
|
|
260
|
-
* @param {
|
|
260
|
+
* @param {number} limit Map tile limit count.
|
|
261
261
|
* @return {void}
|
|
262
262
|
*/
|
|
263
263
|
setTileCountLimit(limit: number): void {
|
|
@@ -271,7 +271,7 @@ class OfflineManager {
|
|
|
271
271
|
* @example
|
|
272
272
|
* OfflineManager.setProgressEventThrottle(500);
|
|
273
273
|
*
|
|
274
|
-
* @param {
|
|
274
|
+
* @param {number} throttleValue event throttle value in ms.
|
|
275
275
|
* @return {void}
|
|
276
276
|
*/
|
|
277
277
|
setProgressEventThrottle(throttleValue: number): void {
|
|
@@ -338,7 +338,7 @@ class OfflineManager {
|
|
|
338
338
|
* @example
|
|
339
339
|
* OfflineManager.unsubscribe('packName')
|
|
340
340
|
*
|
|
341
|
-
* @param {
|
|
341
|
+
* @param {string} packName Name of the offline pack.
|
|
342
342
|
* @return {void}
|
|
343
343
|
*/
|
|
344
344
|
unsubscribe(packName: string): void {
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ConfigPlugin,
|
|
3
|
+
createRunOncePlugin,
|
|
4
|
+
withDangerousMod,
|
|
5
|
+
withXcodeProject,
|
|
6
|
+
type XcodeProject,
|
|
7
|
+
} from "@expo/config-plugins";
|
|
8
|
+
import {
|
|
9
|
+
mergeContents,
|
|
10
|
+
removeGeneratedContents,
|
|
11
|
+
} from "@expo/config-plugins/build/utils/generateCode";
|
|
12
|
+
import { promises } from "node:fs";
|
|
13
|
+
import path from "node:path";
|
|
14
|
+
|
|
15
|
+
let pkg: { name: string; version?: string } = {
|
|
16
|
+
name: "@maplibre/maplibre-react-native",
|
|
17
|
+
};
|
|
18
|
+
try {
|
|
19
|
+
pkg = require("@maplibre/maplibre-react-native/package.json");
|
|
20
|
+
} catch {
|
|
21
|
+
// empty catch block
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type InstallerBlockName = "pre" | "post";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Dangerously adds the custom installer hooks to the Podfile.
|
|
28
|
+
* In the future this should be removed in favor of some custom hooks provided by Expo autolinking.
|
|
29
|
+
*
|
|
30
|
+
* https://github.com/maplibre/maplibre-react-native/blob/main/docs/guides/setup/iOS.md
|
|
31
|
+
*/
|
|
32
|
+
const withCocoaPodsInstallerBlocks: ConfigPlugin = (c) => {
|
|
33
|
+
return withDangerousMod(c, [
|
|
34
|
+
"ios",
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
36
|
+
async (config) => {
|
|
37
|
+
const file = path.join(config.modRequest.platformProjectRoot, "Podfile");
|
|
38
|
+
|
|
39
|
+
const contents = await promises.readFile(file, "utf8");
|
|
40
|
+
|
|
41
|
+
await promises.writeFile(
|
|
42
|
+
file,
|
|
43
|
+
applyCocoaPodsModifications(contents),
|
|
44
|
+
"utf-8",
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
return config;
|
|
48
|
+
},
|
|
49
|
+
]);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Only the post-install block is required, the post installer block is
|
|
53
|
+
// used for spm (swift package manager) which Expo doesn't currently support.
|
|
54
|
+
export function applyCocoaPodsModifications(contents: string): string {
|
|
55
|
+
// Ensure installer blocks exist
|
|
56
|
+
let src = addInstallerBlock(contents, "post");
|
|
57
|
+
src = addMapLibreInstallerBlock(src, "post");
|
|
58
|
+
|
|
59
|
+
return src;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function addInstallerBlock(
|
|
63
|
+
src: string,
|
|
64
|
+
blockName: InstallerBlockName,
|
|
65
|
+
): string {
|
|
66
|
+
const matchBlock = new RegExp(`${blockName}_install do \\|installer\\|`);
|
|
67
|
+
const tag = `${blockName}_installer`;
|
|
68
|
+
for (const line of src.split("\n")) {
|
|
69
|
+
const contents = line.trim();
|
|
70
|
+
// Ignore comments
|
|
71
|
+
if (!contents.startsWith("#")) {
|
|
72
|
+
// Prevent adding the block if it exists outside of comments.
|
|
73
|
+
if (contents.match(matchBlock)) {
|
|
74
|
+
// This helps to still allow revisions, since we enabled the block previously.
|
|
75
|
+
// Only continue if the generated block exists...
|
|
76
|
+
const modified = removeGeneratedContents(src, tag);
|
|
77
|
+
if (!modified) {
|
|
78
|
+
return src;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return mergeContents({
|
|
85
|
+
tag,
|
|
86
|
+
src,
|
|
87
|
+
newSrc: [` ${blockName}_install do |installer|`, " end"].join("\n"),
|
|
88
|
+
anchor: /use_react_native/,
|
|
89
|
+
// We can't go after the use_react_native block because it might have parameters, causing it to be multi-line (see react-native template).
|
|
90
|
+
offset: 0,
|
|
91
|
+
comment: "#",
|
|
92
|
+
}).contents;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function addMapLibreInstallerBlock(
|
|
96
|
+
src: string,
|
|
97
|
+
blockName: InstallerBlockName,
|
|
98
|
+
): string {
|
|
99
|
+
return mergeContents({
|
|
100
|
+
tag: `@maplibre/maplibre-react-native-${blockName}_installer`,
|
|
101
|
+
src,
|
|
102
|
+
newSrc: ` $MLRN.${blockName}_install(installer)`,
|
|
103
|
+
anchor: new RegExp(`${blockName}_install do \\|installer\\|`),
|
|
104
|
+
offset: 1,
|
|
105
|
+
comment: "#",
|
|
106
|
+
}).contents;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Exclude building for arm64 on simulator devices in the pbxproj project.
|
|
111
|
+
* Without this, production builds targeting simulators will fail.
|
|
112
|
+
*/
|
|
113
|
+
export function setExcludedArchitectures(project: XcodeProject): XcodeProject {
|
|
114
|
+
const configurations = project.pbxXCBuildConfigurationSection();
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
116
|
+
// @ts-ignore
|
|
117
|
+
for (const { name, buildSettings } of Object.values(configurations || {})) {
|
|
118
|
+
// Guessing that this is the best way to emulate Xcode.
|
|
119
|
+
// Using `project.addToBuildSettings` modifies too many targets.
|
|
120
|
+
if (
|
|
121
|
+
name === "Release" &&
|
|
122
|
+
typeof buildSettings?.PRODUCT_NAME !== "undefined"
|
|
123
|
+
) {
|
|
124
|
+
buildSettings['"EXCLUDED_ARCHS[sdk=iphonesimulator*]"'] = '"arm64"';
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return project;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const withoutSignatures: ConfigPlugin = (config) => {
|
|
131
|
+
const shellScript = `
|
|
132
|
+
echo "Remove signature files (Xcode workaround)";
|
|
133
|
+
rm -rf "$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature";
|
|
134
|
+
`;
|
|
135
|
+
return withXcodeProject(config, async (config) => {
|
|
136
|
+
const xcodeProject = config.modResults;
|
|
137
|
+
xcodeProject.addBuildPhase(
|
|
138
|
+
[],
|
|
139
|
+
"PBXShellScriptBuildPhase",
|
|
140
|
+
"Remove signature files (Xcode workaround)",
|
|
141
|
+
null,
|
|
142
|
+
{
|
|
143
|
+
shellPath: "/bin/sh",
|
|
144
|
+
shellScript,
|
|
145
|
+
},
|
|
146
|
+
);
|
|
147
|
+
return config;
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Set the Debug Information Format to DWARF with dSYM File during EAS Build for Managed App
|
|
153
|
+
* https://github.com/expo/eas-cli/issues/968
|
|
154
|
+
* // Set artifactPath in eas.json
|
|
155
|
+
* "ios": {
|
|
156
|
+
* "artifactPath": "ios/build/*"
|
|
157
|
+
* }
|
|
158
|
+
*/
|
|
159
|
+
const withDwarfDsym: ConfigPlugin = (config) => {
|
|
160
|
+
return withXcodeProject(config, async (config) => {
|
|
161
|
+
const xcodeProject = config.modResults;
|
|
162
|
+
xcodeProject.debugInformationFormat = "dwarf-with-dsym";
|
|
163
|
+
return config;
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const withExcludedSimulatorArchitectures: ConfigPlugin = (c) => {
|
|
168
|
+
return withXcodeProject(c, (config) => {
|
|
169
|
+
config.modResults = setExcludedArchitectures(config.modResults);
|
|
170
|
+
return config;
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const withMapLibre: ConfigPlugin = (config) => {
|
|
175
|
+
config = withoutSignatures(
|
|
176
|
+
withDwarfDsym(withExcludedSimulatorArchitectures(config)),
|
|
177
|
+
);
|
|
178
|
+
return withCocoaPodsInstallerBlocks(config);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export default createRunOncePlugin(withMapLibre, pkg.name, pkg.version);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"jest.config.d.ts","sourceRoot":"","sources":["../../../jest.config.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"jest.config.d.ts","sourceRoot":"","sources":["../../../jest.config.ts"],"names":[],"mappings":""}
|