expo-gaode-map 1.0.5 → 1.0.7

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 (47) hide show
  1. package/README.en.md +320 -0
  2. package/README.md +2 -0
  3. package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapModule.kt +1 -298
  4. package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapViewModule.kt +126 -0
  5. package/android/src/main/java/expo/modules/gaodemap/overlays/CircleViewModule.kt +41 -0
  6. package/android/src/main/java/expo/modules/gaodemap/overlays/ClusterViewModule.kt +29 -0
  7. package/android/src/main/java/expo/modules/gaodemap/overlays/HeatMapViewModule.kt +27 -0
  8. package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerViewModule.kt +49 -0
  9. package/android/src/main/java/expo/modules/gaodemap/overlays/MultiPointViewModule.kt +21 -0
  10. package/android/src/main/java/expo/modules/gaodemap/overlays/PolygonViewModule.kt +37 -0
  11. package/android/src/main/java/expo/modules/gaodemap/overlays/PolylineView.kt +2 -0
  12. package/android/src/main/java/expo/modules/gaodemap/overlays/PolylineViewModule.kt +45 -0
  13. package/build/ExpoGaodeMapView.js +1 -1
  14. package/build/ExpoGaodeMapView.js.map +1 -1
  15. package/build/components/overlays/Cluster.d.ts.map +1 -1
  16. package/build/components/overlays/Cluster.js +1 -1
  17. package/build/components/overlays/Cluster.js.map +1 -1
  18. package/build/components/overlays/HeatMap.d.ts.map +1 -1
  19. package/build/components/overlays/HeatMap.js +1 -1
  20. package/build/components/overlays/HeatMap.js.map +1 -1
  21. package/build/components/overlays/MultiPoint.d.ts.map +1 -1
  22. package/build/components/overlays/MultiPoint.js +1 -1
  23. package/build/components/overlays/MultiPoint.js.map +1 -1
  24. package/docs/API.en.md +418 -0
  25. package/docs/API.md +31 -5
  26. package/docs/ARCHITECTURE.en.md +423 -0
  27. package/docs/ARCHITECTURE.md +2 -0
  28. package/docs/EXAMPLES.en.md +642 -0
  29. package/docs/EXAMPLES.md +2 -0
  30. package/docs/INITIALIZATION.en.md +346 -0
  31. package/docs/INITIALIZATION.md +2 -0
  32. package/expo-module.config.json +22 -2
  33. package/ios/ExpoGaodeMapModule.swift +0 -334
  34. package/ios/ExpoGaodeMapViewModule.swift +155 -0
  35. package/ios/modules/LocationManager.swift +4 -3
  36. package/ios/overlays/CircleViewModule.swift +31 -0
  37. package/ios/overlays/ClusterViewModule.swift +23 -0
  38. package/ios/overlays/HeatMapViewModule.swift +21 -0
  39. package/ios/overlays/MarkerViewModule.swift +55 -0
  40. package/ios/overlays/MultiPointViewModule.swift +15 -0
  41. package/ios/overlays/PolygonViewModule.swift +27 -0
  42. package/ios/overlays/PolylineViewModule.swift +39 -0
  43. package/package.json +1 -1
  44. package/src/ExpoGaodeMapView.tsx +1 -1
  45. package/src/components/overlays/Cluster.tsx +2 -1
  46. package/src/components/overlays/HeatMap.tsx +2 -1
  47. package/src/components/overlays/MultiPoint.tsx +2 -1
@@ -0,0 +1,642 @@
1
+ # Usage Examples
2
+
3
+ English | [简体中文](./EXAMPLES.md)
4
+
5
+ Complete usage examples and best practices.
6
+
7
+ > 📖 **Recommended Reading**: [Initialization Guide](./INITIALIZATION.en.md) - Detailed initialization process and permission handling
8
+
9
+ ## Table of Contents
10
+
11
+ - [Complete Application Example](#complete-application-example)
12
+ - [Basic Map Application](#basic-map-application)
13
+ - [Location Tracking Application](#location-tracking-application)
14
+ - [Overlay Examples](#overlay-examples)
15
+ - [Advanced Usage](#advanced-usage)
16
+
17
+ ## Complete Application Example
18
+
19
+ Complete example with permission management, error handling, and loading states:
20
+
21
+ ```tsx
22
+ import { useEffect, useState } from 'react';
23
+ import { View, Text, Alert, Linking, Platform } from 'react-native';
24
+ import {
25
+ MapView,
26
+ initSDK,
27
+ checkLocationPermission,
28
+ requestLocationPermission,
29
+ getCurrentLocation,
30
+ type LatLng,
31
+ } from 'expo-gaode-map';
32
+
33
+ export default function App() {
34
+ const [initialPosition, setInitialPosition] = useState<{
35
+ target: LatLng;
36
+ zoom: number;
37
+ } | null>(null);
38
+ const [error, setError] = useState<string | null>(null);
39
+
40
+ useEffect(() => {
41
+ const initialize = async () => {
42
+ try {
43
+ // 1. Initialize SDK
44
+ initSDK({
45
+ androidKey: 'your-android-api-key',
46
+ iosKey: 'your-ios-api-key',
47
+ });
48
+
49
+ // 2. Check permission
50
+ const status = await checkLocationPermission();
51
+
52
+ // 3. Request permission if needed
53
+ if (!status.granted) {
54
+ const result = await requestLocationPermission();
55
+
56
+ if (!result.granted) {
57
+ // Permission denied
58
+ setInitialPosition({
59
+ target: { latitude: 39.9, longitude: 116.4 },
60
+ zoom: 10
61
+ });
62
+
63
+ // Guide user to settings
64
+ if (!result.canAskAgain) {
65
+ Alert.alert(
66
+ 'Location Permission Required',
67
+ 'Please enable location permission in settings',
68
+ [
69
+ { text: 'Cancel' },
70
+ { text: 'Settings', onPress: () => {
71
+ if (Platform.OS === 'ios') {
72
+ Linking.openURL('app-settings:');
73
+ } else {
74
+ Linking.openSettings();
75
+ }
76
+ }}
77
+ ]
78
+ );
79
+ }
80
+ return;
81
+ }
82
+ }
83
+
84
+ // 4. Get location
85
+ const location = await getCurrentLocation();
86
+ setInitialPosition({
87
+ target: {
88
+ latitude: location.latitude,
89
+ longitude: location.longitude
90
+ },
91
+ zoom: 15
92
+ });
93
+
94
+ } catch (err) {
95
+ console.error('Initialization failed:', err);
96
+ setError('Initialization failed');
97
+ setInitialPosition({
98
+ target: { latitude: 39.9, longitude: 116.4 },
99
+ zoom: 10
100
+ });
101
+ }
102
+ };
103
+
104
+ initialize();
105
+ }, []);
106
+
107
+ // Loading state
108
+ if (!initialPosition && !error) {
109
+ return (
110
+ <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
111
+ <Text>Loading map...</Text>
112
+ </View>
113
+ );
114
+ }
115
+
116
+ // Error state
117
+ if (error) {
118
+ return (
119
+ <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
120
+ <Text>{error}</Text>
121
+ </View>
122
+ );
123
+ }
124
+
125
+ return (
126
+ <MapView
127
+ style={{ flex: 1 }}
128
+ initialCameraPosition={initialPosition!}
129
+ myLocationEnabled={true}
130
+ onLoad={() => console.log('Map loaded')}
131
+ />
132
+ );
133
+ }
134
+ ```
135
+
136
+ ## Basic Map Application
137
+
138
+ ```tsx
139
+ import React, { useRef, useEffect } from 'react';
140
+ import { View, StyleSheet, Button } from 'react-native';
141
+ import {
142
+ MapView,
143
+ initSDK,
144
+ Circle,
145
+ Marker,
146
+ Polyline,
147
+ Polygon,
148
+ type MapViewRef
149
+ } from 'expo-gaode-map';
150
+
151
+ export default function App() {
152
+ const mapRef = useRef<MapViewRef>(null);
153
+
154
+ useEffect(() => {
155
+ const initialize = async () => {
156
+ initSDK({
157
+ androidKey: 'your-android-api-key',
158
+ iosKey: 'your-ios-api-key',
159
+ });
160
+
161
+ // Check and request permission
162
+ const status = await checkLocationPermission();
163
+ if (!status.granted) {
164
+ await requestLocationPermission();
165
+ }
166
+ };
167
+
168
+ initialize();
169
+ }, []);
170
+
171
+ const handleMoveCamera = async () => {
172
+ await mapRef.current?.moveCamera(
173
+ {
174
+ target: { latitude: 40.0, longitude: 116.5 },
175
+ zoom: 15,
176
+ },
177
+ 1000
178
+ );
179
+ };
180
+
181
+ return (
182
+ <View style={styles.container}>
183
+ <MapView
184
+ ref={mapRef}
185
+ style={styles.map}
186
+ initialCameraPosition={{
187
+ target: { latitude: 39.9, longitude: 116.4 },
188
+ zoom: 10,
189
+ }}
190
+ myLocationEnabled={true}
191
+ followUserLocation={false}
192
+ trafficEnabled={true}
193
+ onMapPress={(e) => console.log('Map pressed', e)}
194
+ onLoad={() => console.log('Map loaded')}
195
+ >
196
+ {/* Circle overlay */}
197
+ <Circle
198
+ center={{ latitude: 39.9, longitude: 116.4 }}
199
+ radius={1000}
200
+ fillColor="#8800FF00"
201
+ strokeColor="#FFFF0000"
202
+ strokeWidth={2}
203
+ />
204
+
205
+ {/* Marker */}
206
+ <Marker
207
+ position={{ latitude: 39.95, longitude: 116.45 }}
208
+ title="This is a marker"
209
+ draggable={true}
210
+ />
211
+
212
+ {/* Polyline */}
213
+ <Polyline
214
+ points={[
215
+ { latitude: 39.9, longitude: 116.4 },
216
+ { latitude: 39.95, longitude: 116.45 },
217
+ { latitude: 40.0, longitude: 116.5 },
218
+ ]}
219
+ width={5}
220
+ color="#FF0000FF"
221
+ />
222
+
223
+ {/* Polygon */}
224
+ <Polygon
225
+ points={[
226
+ { latitude: 39.85, longitude: 116.35 },
227
+ { latitude: 39.85, longitude: 116.45 },
228
+ { latitude: 39.75, longitude: 116.40 },
229
+ ]}
230
+ fillColor="#880000FF"
231
+ strokeColor="#FFFF0000"
232
+ strokeWidth={2}
233
+ />
234
+ </MapView>
235
+
236
+ <View style={styles.controls}>
237
+ <Button title="Move Camera" onPress={handleMoveCamera} />
238
+ </View>
239
+ </View>
240
+ );
241
+ }
242
+
243
+ const styles = StyleSheet.create({
244
+ container: {
245
+ flex: 1,
246
+ },
247
+ map: {
248
+ flex: 1,
249
+ },
250
+ controls: {
251
+ position: 'absolute',
252
+ bottom: 20,
253
+ left: 20,
254
+ right: 20,
255
+ },
256
+ });
257
+ ```
258
+
259
+ ## Location Tracking Application
260
+
261
+ ```tsx
262
+ import React, { useEffect, useState } from 'react';
263
+ import { View, Text, Button, StyleSheet } from 'react-native';
264
+ import {
265
+ MapView,
266
+ initSDK,
267
+ configure,
268
+ start,
269
+ stop,
270
+ getCurrentLocation,
271
+ addLocationListener,
272
+ type Location,
273
+ } from 'expo-gaode-map';
274
+
275
+ export default function LocationApp() {
276
+ const [location, setLocation] = useState<Location | null>(null);
277
+ const [isTracking, setIsTracking] = useState(false);
278
+
279
+ useEffect(() => {
280
+ const initialize = async () => {
281
+ // Initialize SDK
282
+ initSDK({
283
+ androidKey: 'your-android-api-key',
284
+ iosKey: 'your-ios-api-key',
285
+ });
286
+
287
+ // Check and request permission
288
+ const status = await checkLocationPermission();
289
+ if (!status.granted) {
290
+ await requestLocationPermission();
291
+ }
292
+
293
+ // Configure location parameters
294
+ configure({
295
+ withReGeocode: true,
296
+ mode: 0,
297
+ interval: 2000,
298
+ });
299
+
300
+ // Listen to location updates
301
+ const subscription = addLocationListener((loc) => {
302
+ console.log('Location update:', loc);
303
+ setLocation(loc);
304
+ });
305
+
306
+ return () => subscription.remove();
307
+ };
308
+
309
+ initialize();
310
+ }, []);
311
+
312
+ const handleStartTracking = () => {
313
+ start();
314
+ setIsTracking(true);
315
+ };
316
+
317
+ const handleStopTracking = () => {
318
+ stop();
319
+ setIsTracking(false);
320
+ };
321
+
322
+ const handleGetLocation = async () => {
323
+ try {
324
+ const loc = await getCurrentLocation();
325
+ setLocation(loc);
326
+ } catch (error) {
327
+ console.error('Get location failed:', error);
328
+ }
329
+ };
330
+
331
+ return (
332
+ <View style={styles.container}>
333
+ <MapView
334
+ style={styles.map}
335
+ myLocationEnabled={true}
336
+ followUserLocation={isTracking}
337
+ initialCameraPosition={{
338
+ target: {
339
+ latitude: location?.latitude || 39.9,
340
+ longitude: location?.longitude || 116.4
341
+ },
342
+ zoom: 15,
343
+ }}
344
+ />
345
+
346
+ {location && (
347
+ <View style={styles.info}>
348
+ <Text style={styles.infoText}>
349
+ Latitude: {location.latitude.toFixed(6)}
350
+ </Text>
351
+ <Text style={styles.infoText}>
352
+ Longitude: {location.longitude.toFixed(6)}
353
+ </Text>
354
+ <Text style={styles.infoText}>
355
+ Accuracy: {location.accuracy.toFixed(2)} m
356
+ </Text>
357
+ {location.address && (
358
+ <Text style={styles.infoText}>
359
+ Address: {location.address}
360
+ </Text>
361
+ )}
362
+ </View>
363
+ )}
364
+
365
+ <View style={styles.controls}>
366
+ <Button
367
+ title="Get Location"
368
+ onPress={handleGetLocation}
369
+ />
370
+ <View style={{ height: 10 }} />
371
+ <Button
372
+ title={isTracking ? 'Stop Tracking' : 'Start Tracking'}
373
+ onPress={isTracking ? handleStopTracking : handleStartTracking}
374
+ color={isTracking ? '#FF3B30' : '#007AFF'}
375
+ />
376
+ </View>
377
+ </View>
378
+ );
379
+ }
380
+
381
+ const styles = StyleSheet.create({
382
+ container: {
383
+ flex: 1,
384
+ },
385
+ map: {
386
+ flex: 1,
387
+ },
388
+ info: {
389
+ position: 'absolute',
390
+ top: 50,
391
+ left: 20,
392
+ right: 20,
393
+ backgroundColor: 'white',
394
+ padding: 15,
395
+ borderRadius: 10,
396
+ shadowColor: '#000',
397
+ shadowOffset: { width: 0, height: 2 },
398
+ shadowOpacity: 0.25,
399
+ shadowRadius: 3.84,
400
+ elevation: 5,
401
+ },
402
+ infoText: {
403
+ fontSize: 14,
404
+ marginBottom: 5,
405
+ color: '#333',
406
+ },
407
+ controls: {
408
+ position: 'absolute',
409
+ bottom: 30,
410
+ left: 20,
411
+ right: 20,
412
+ },
413
+ });
414
+ ```
415
+
416
+ ## Overlay Examples
417
+
418
+ ### Circle
419
+
420
+ **Declarative usage:**
421
+ ```tsx
422
+ <MapView style={{ flex: 1 }}>
423
+ <Circle
424
+ center={{ latitude: 39.9, longitude: 116.4 }}
425
+ radius={1000}
426
+ fillColor="#8800FF00"
427
+ strokeColor="#FFFF0000"
428
+ strokeWidth={2}
429
+ onPress={() => console.log('Circle pressed')}
430
+ />
431
+ </MapView>
432
+ ```
433
+
434
+ **Imperative usage:**
435
+ ```tsx
436
+ const mapRef = useRef<MapViewRef>(null);
437
+
438
+ await mapRef.current?.addCircle('circle1', {
439
+ center: { latitude: 39.9, longitude: 116.4 },
440
+ radius: 1000,
441
+ fillColor: 0x8800FF00,
442
+ strokeColor: 0xFFFF0000,
443
+ strokeWidth: 2,
444
+ });
445
+
446
+ await mapRef.current?.updateCircle('circle1', {
447
+ radius: 2000,
448
+ });
449
+
450
+ await mapRef.current?.removeCircle('circle1');
451
+ ```
452
+
453
+ ### Marker
454
+
455
+ **Declarative usage:**
456
+ ```tsx
457
+ <MapView style={{ flex: 1 }}>
458
+ <Marker
459
+ position={{ latitude: 39.9, longitude: 116.4 }}
460
+ title="Title"
461
+ snippet="Description"
462
+ draggable={true}
463
+ onPress={() => console.log('Marker pressed')}
464
+ onDragEnd={(e) => console.log('Drag ended', e.nativeEvent)}
465
+ />
466
+ </MapView>
467
+ ```
468
+
469
+ **Imperative usage:**
470
+ ```tsx
471
+ await mapRef.current?.addMarker('marker1', {
472
+ position: { latitude: 39.9, longitude: 116.4 },
473
+ title: 'Title',
474
+ snippet: 'Description',
475
+ draggable: true,
476
+ });
477
+
478
+ await mapRef.current?.updateMarker('marker1', {
479
+ position: { latitude: 40.0, longitude: 116.5 },
480
+ });
481
+
482
+ await mapRef.current?.removeMarker('marker1');
483
+ ```
484
+
485
+ > **⚠️ Limitation**: Markers added via imperative API **do not support event callbacks** (onPress, onDragEnd, etc.). Use declarative `<Marker>` component for event handling.
486
+
487
+ ### Polyline
488
+
489
+ **Declarative usage - Normal polyline:**
490
+ ```tsx
491
+ <MapView style={{ flex: 1 }}>
492
+ <Polyline
493
+ points={[
494
+ { latitude: 39.9, longitude: 116.4 },
495
+ { latitude: 39.95, longitude: 116.45 },
496
+ { latitude: 40.0, longitude: 116.5 },
497
+ ]}
498
+ width={5}
499
+ color="#FFFF0000"
500
+ onPress={() => console.log('Polyline pressed')}
501
+ />
502
+ </MapView>
503
+ ```
504
+
505
+ **Declarative usage - Textured polyline:**
506
+ ```tsx
507
+ import { Image } from 'react-native';
508
+
509
+ const iconUri = Image.resolveAssetSource(require('./assets/arrow.png')).uri;
510
+
511
+ <MapView style={{ flex: 1 }}>
512
+ <Polyline
513
+ points={[
514
+ { latitude: 39.9, longitude: 116.4 },
515
+ { latitude: 39.95, longitude: 116.45 },
516
+ { latitude: 40.0, longitude: 116.5 },
517
+ ]}
518
+ width={20}
519
+ color="#FFFF0000"
520
+ texture={iconUri}
521
+ onPress={() => console.log('Textured polyline pressed')}
522
+ />
523
+ </MapView>
524
+ ```
525
+
526
+ > **Note**:
527
+ > - Color format uses ARGB (`#AARRGGBB`), e.g., `#FFFF0000` for opaque red
528
+ > - `texture` supports network images (http/https) and local files (file://)
529
+ > - Texture tiles along the polyline direction
530
+ > - Recommend larger `width` values (e.g., 20) for better texture display
531
+ > - **Segment Texture Limitation**: Single Polyline can only have one texture. For different textures on segments, create multiple Polyline components
532
+
533
+ ### Polygon
534
+
535
+ **Declarative usage:**
536
+ ```tsx
537
+ <MapView style={{ flex: 1 }}>
538
+ <Polygon
539
+ points={[
540
+ { latitude: 39.9, longitude: 116.3 },
541
+ { latitude: 39.9, longitude: 116.4 },
542
+ { latitude: 39.8, longitude: 116.4 },
543
+ ]}
544
+ fillColor="#8800FF00"
545
+ strokeColor="#FFFF0000"
546
+ strokeWidth={2}
547
+ onPress={() => console.log('Polygon pressed')}
548
+ />
549
+ </MapView>
550
+ ```
551
+
552
+ **Imperative usage:**
553
+ ```tsx
554
+ await mapRef.current?.addPolygon('polygon1', {
555
+ points: [
556
+ { latitude: 39.9, longitude: 116.3 },
557
+ { latitude: 39.9, longitude: 116.4 },
558
+ { latitude: 39.8, longitude: 116.4 },
559
+ ],
560
+ fillColor: 0x8800FF00,
561
+ strokeColor: 0xFFFF0000,
562
+ strokeWidth: 2,
563
+ });
564
+ ```
565
+
566
+ ## Advanced Usage
567
+
568
+ ### Custom Location Blue Dot
569
+
570
+ ```tsx
571
+ import { Image } from 'react-native';
572
+
573
+ const iconUri = Image.resolveAssetSource(require('./assets/location-icon.png')).uri;
574
+
575
+ <MapView
576
+ myLocationEnabled={true}
577
+ userLocationRepresentation={{
578
+ showsAccuracyRing: true,
579
+ fillColor: '#4285F4',
580
+ strokeColor: '#1967D2',
581
+ lineWidth: 2,
582
+ image: iconUri,
583
+ imageWidth: 40,
584
+ imageHeight: 40,
585
+ }}
586
+ />
587
+ ```
588
+
589
+ ### Batch Overlay Operations
590
+
591
+ ```tsx
592
+ const mapRef = useRef<MapViewRef>(null);
593
+
594
+ const addMultipleOverlays = async () => {
595
+ await mapRef.current?.addCircle('circle1', {
596
+ center: { latitude: 39.9, longitude: 116.4 },
597
+ radius: 1000,
598
+ fillColor: 0x8800FF00,
599
+ });
600
+
601
+ await mapRef.current?.addCircle('circle2', {
602
+ center: { latitude: 40.0, longitude: 116.5 },
603
+ radius: 500,
604
+ fillColor: 0x880000FF,
605
+ });
606
+
607
+ await mapRef.current?.addMarker('marker1', {
608
+ position: { latitude: 39.95, longitude: 116.45 },
609
+ title: 'Beijing',
610
+ });
611
+ };
612
+
613
+ const clearAll = async () => {
614
+ await mapRef.current?.removeCircle('circle1');
615
+ await mapRef.current?.removeCircle('circle2');
616
+ await mapRef.current?.removeMarker('marker1');
617
+ };
618
+ ```
619
+
620
+ ### Zoom Level Limits
621
+
622
+ ```tsx
623
+ <MapView
624
+ maxZoom={18}
625
+ minZoom={5}
626
+ initialCameraPosition={{
627
+ target: { latitude: 39.9, longitude: 116.4 },
628
+ zoom: 10,
629
+ }}
630
+ />
631
+ ```
632
+
633
+ ### Heading Updates (iOS)
634
+
635
+ ```tsx
636
+ import { startUpdatingHeading, stopUpdatingHeading } from 'expo-gaode-map';
637
+
638
+ // Start heading updates
639
+ startUpdatingHeading();
640
+
641
+ // Stop heading updates
642
+ stopUpdatingHeading();
package/docs/EXAMPLES.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # 使用示例
2
2
 
3
+ [English](./EXAMPLES.en.md) | 简体中文
4
+
3
5
  完整的使用示例和最佳实践。
4
6
 
5
7
  > 📖 **推荐阅读**: [初始化指南](./INITIALIZATION.md) - 详细的初始化流程和权限处理