react-native-pointr 9.1.0 → 9.3.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 (78) hide show
  1. package/API_REFERENCE.md +887 -0
  2. package/CHANGELOG.md +35 -0
  3. package/EXTENDING.md +419 -0
  4. package/README.md +221 -117
  5. package/WAYFINDING_EVENTS.md +243 -0
  6. package/android/build.gradle +3 -16
  7. package/android/src/main/java/com/pointr/PTRCoreExtensions.kt +126 -0
  8. package/android/src/main/java/com/pointr/PTRMapWidgetCommandType.kt +3 -1
  9. package/android/src/main/java/com/pointr/PTRMapWidgetManager.kt +160 -11
  10. package/android/src/main/java/com/pointr/PointrModule.kt +106 -3
  11. package/example/pointr_rn_demo/.bundle/config +2 -0
  12. package/example/pointr_rn_demo/.eslintrc.js +4 -0
  13. package/example/pointr_rn_demo/.prettierrc.js +5 -0
  14. package/example/pointr_rn_demo/.watchmanconfig +1 -0
  15. package/example/pointr_rn_demo/App.tsx +323 -0
  16. package/example/pointr_rn_demo/Gemfile +16 -0
  17. package/example/pointr_rn_demo/Gemfile.lock +111 -0
  18. package/example/pointr_rn_demo/README.md +188 -0
  19. package/example/pointr_rn_demo/__tests__/App.test.tsx +13 -0
  20. package/example/pointr_rn_demo/android/app/build.gradle +119 -0
  21. package/example/pointr_rn_demo/android/app/debug.keystore +0 -0
  22. package/example/pointr_rn_demo/android/app/proguard-rules.pro +10 -0
  23. package/example/pointr_rn_demo/android/app/src/main/AndroidManifest.xml +27 -0
  24. package/example/pointr_rn_demo/android/app/src/main/java/com/pointr_rn_demo/MainActivity.kt +22 -0
  25. package/example/pointr_rn_demo/android/app/src/main/java/com/pointr_rn_demo/MainApplication.kt +27 -0
  26. package/example/pointr_rn_demo/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
  27. package/example/pointr_rn_demo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  28. package/example/pointr_rn_demo/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  29. package/example/pointr_rn_demo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  30. package/example/pointr_rn_demo/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  31. package/example/pointr_rn_demo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  32. package/example/pointr_rn_demo/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  33. package/example/pointr_rn_demo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  34. package/example/pointr_rn_demo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  35. package/example/pointr_rn_demo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  36. package/example/pointr_rn_demo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  37. package/example/pointr_rn_demo/android/app/src/main/res/values/strings.xml +3 -0
  38. package/example/pointr_rn_demo/android/app/src/main/res/values/styles.xml +9 -0
  39. package/example/pointr_rn_demo/android/build.gradle +32 -0
  40. package/example/pointr_rn_demo/android/gradle.properties +44 -0
  41. package/example/pointr_rn_demo/android/settings.gradle +6 -0
  42. package/example/pointr_rn_demo/app.json +4 -0
  43. package/example/pointr_rn_demo/babel.config.js +3 -0
  44. package/example/pointr_rn_demo/index.js +16 -0
  45. package/example/pointr_rn_demo/ios/.xcode.env +11 -0
  46. package/example/pointr_rn_demo/ios/Podfile +40 -0
  47. package/example/pointr_rn_demo/ios/Podfile.lock +2767 -0
  48. package/example/pointr_rn_demo/ios/pointr_rn_demo/AppDelegate.swift +48 -0
  49. package/example/pointr_rn_demo/ios/pointr_rn_demo/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
  50. package/example/pointr_rn_demo/ios/pointr_rn_demo/Images.xcassets/Contents.json +6 -0
  51. package/example/pointr_rn_demo/ios/pointr_rn_demo/Info.plist +63 -0
  52. package/example/pointr_rn_demo/ios/pointr_rn_demo/LaunchScreen.storyboard +47 -0
  53. package/example/pointr_rn_demo/ios/pointr_rn_demo/PrivacyInfo.xcprivacy +37 -0
  54. package/example/pointr_rn_demo/ios/pointr_rn_demo.xcodeproj/project.pbxproj +496 -0
  55. package/example/pointr_rn_demo/ios/pointr_rn_demo.xcodeproj/xcshareddata/xcschemes/pointr_rn_demo.xcscheme +88 -0
  56. package/example/pointr_rn_demo/ios/pointr_rn_demo.xcworkspace/contents.xcworkspacedata +10 -0
  57. package/example/pointr_rn_demo/jest.config.js +3 -0
  58. package/example/pointr_rn_demo/metro.config.js +22 -0
  59. package/example/pointr_rn_demo/package-lock.json +11747 -0
  60. package/example/pointr_rn_demo/package.json +46 -0
  61. package/example/pointr_rn_demo/prepare-demo-distribution.sh +103 -0
  62. package/example/pointr_rn_demo/tsconfig.json +5 -0
  63. package/ios/PTRMapWidgetContainerView.swift +59 -7
  64. package/ios/PTRMapWidgetManager-Bridging.m +65 -1
  65. package/ios/PTRMapWidgetManager.swift +185 -144
  66. package/ios/PTRNativeLibrary-Bridging.m +4 -0
  67. package/ios/PTRNativeLibrary.swift +244 -18
  68. package/package.json +16 -2
  69. package/prepare-distribution.sh +84 -0
  70. package/react-native-pointr.podspec +1 -1
  71. package/src/PTRCommand.ts +34 -1
  72. package/src/PTRMapWidgetUtils.ts +105 -5
  73. package/src/PTRPoiManager.ts +20 -0
  74. package/src/index.tsx +40 -1
  75. package/src/types/PTRGeometry.ts +70 -0
  76. package/src/types/PTRPoi.ts +49 -0
  77. package/src/types/PTRPosition.ts +22 -0
  78. package/src/types/PTRWayfindingEvent.ts +18 -0
@@ -0,0 +1,887 @@
1
+ # React Native Pointr - API Reference
2
+
3
+ > **Platform Compatibility:** This API reference is identical for both Android and iOS platforms. All methods, parameters, and behaviors are consistent across platforms.
4
+
5
+ ## Table of Contents
6
+ - [Native Module API](#native-module-api)
7
+ - [Map Widget Component](#map-widget-component)
8
+ - [Command Types](#command-types)
9
+ - [Utility Functions](#utility-functions)
10
+ - [Event Listeners](#event-listeners)
11
+
12
+ ---
13
+
14
+ ## Native Module API
15
+
16
+ ### `PTRNativePointrLibrary`
17
+
18
+ The main native module for interacting with the Pointr SDK.
19
+
20
+ #### Methods
21
+
22
+ ##### `initialize(clientId, licenseKey, baseUrl, logLevel)`
23
+
24
+ Initializes the Pointr SDK with credentials.
25
+
26
+ **Parameters:**
27
+ - `clientId` (string): Your Pointr client identifier
28
+ - `licenseKey` (string): Your Pointr license key
29
+ - `baseUrl` (string): The Pointr cloud base URL
30
+ - `logLevel` (number): Log level (0-4)
31
+ - `0`: Verbose
32
+ - `1`: Debug
33
+ - `2`: Info
34
+ - `3`: Warning
35
+ - `4`: Error
36
+
37
+ **Example:**
38
+ ```typescript
39
+ import { NativeModules } from 'react-native';
40
+
41
+ NativeModules.PTRNativePointrLibrary.initialize(
42
+ "client-id",
43
+ "license-key",
44
+ "https://your-instance.pointr.cloud",
45
+ 3
46
+ );
47
+ ```
48
+
49
+ ---
50
+
51
+ ##### `start(callback)`
52
+
53
+ Starts the Pointr SDK.
54
+
55
+ **Parameters:**
56
+ - `callback` (function): Callback function that receives the Pointr state as a string
57
+
58
+ **Example:**
59
+ ```typescript
60
+ NativeModules.PTRNativePointrLibrary.start((state: string) => {
61
+ console.log(`Pointr state: ${state}`);
62
+ });
63
+ ```
64
+
65
+ **Possible States:**
66
+ - `"running"` - SDK is running successfully
67
+ - `"failed registration"` - Registration failed
68
+ - `"failed validation"` - Validation failed
69
+ - `"failed invalid deep link url"` - Invalid deep link URL
70
+ - `"failed no internet"` - No internet connection
71
+ - `"off"` - SDK is off
72
+
73
+ ---
74
+
75
+ ##### `stop()`
76
+
77
+ Stops the Pointr SDK.
78
+
79
+ **Example:**
80
+ ```typescript
81
+ NativeModules.PTRNativePointrLibrary.stop();
82
+ ```
83
+
84
+ ---
85
+
86
+ ##### `requestPermissions()`
87
+
88
+ Requests necessary permissions (location, bluetooth, etc.).
89
+
90
+ **Example:**
91
+ ```typescript
92
+ NativeModules.PTRNativePointrLibrary.requestPermissions();
93
+ ```
94
+
95
+ ---
96
+
97
+ ##### `shouldRequestPermissionsAtStartup(shouldRequest)`
98
+
99
+ Sets whether permissions should be requested automatically at startup.
100
+
101
+ **Parameters:**
102
+ - `shouldRequest` (boolean): True to request permissions automatically
103
+
104
+ **Example:**
105
+ ```typescript
106
+ NativeModules.PTRNativePointrLibrary.shouldRequestPermissionsAtStartup(true);
107
+ ```
108
+
109
+ ---
110
+
111
+ ##### `getCurrentLocation(callback)`
112
+
113
+ Gets the current calculated position.
114
+
115
+ **Parameters:**
116
+ - `callback` (function): Callback function that receives location data or null
117
+
118
+ **Example:**
119
+ ```typescript
120
+ NativeModules.PTRNativePointrLibrary.getCurrentLocation((location) => {
121
+ if (location) {
122
+ console.log('Site:', location.siteExternalIdentifier);
123
+ console.log('Building:', location.buildingExternalIdentifier);
124
+ console.log('Level:', location.levelIndex);
125
+ console.log('Coordinates:', location.latitude, location.longitude);
126
+ }
127
+ });
128
+ ```
129
+
130
+ **Location Object:**
131
+ - `siteInternalIdentifier` (string)
132
+ - `siteExternalIdentifier` (string)
133
+ - `buildingInternalIdentifier` (string)
134
+ - `buildingExternalIdentifier` (string)
135
+ - `levelIndex` (number)
136
+ - `latitude` (number)
137
+ - `longitude` (number)
138
+ - `accuracy` (number)
139
+ - `heading` (number) - Only present if heading accuracy is high
140
+
141
+ ---
142
+
143
+ ##### `isMyCarMarked(callback)`
144
+
145
+ Checks if a "My Car" location has been saved.
146
+
147
+ **Parameters:**
148
+ - `callback` (function): Callback with no arguments if marked, error message if not
149
+
150
+ **Example:**
151
+ ```typescript
152
+ NativeModules.PTRNativePointrLibrary.isMyCarMarked((error) => {
153
+ if (!error) {
154
+ console.log('My car location is marked');
155
+ } else {
156
+ console.log('No saved location:', error);
157
+ }
158
+ });
159
+ ```
160
+
161
+ ---
162
+
163
+ ##### `setPointrMapWidgetConfiguration(configJson)`
164
+
165
+ Sets the map widget configuration.
166
+
167
+ **Parameters:**
168
+ - `configJson` (string): JSON string with configuration options
169
+
170
+ **Example:**
171
+ ```typescript
172
+ NativeModules.PTRNativePointrLibrary.setPointrMapWidgetConfiguration(
173
+ JSON.stringify({
174
+ isExitButtonEnabled: false,
175
+ isCompassEnabled: true,
176
+ isSearchBarEnabled: true,
177
+ isLevelSelectorEnabled: true,
178
+ isMyCarButtonEnabled: true
179
+ })
180
+ );
181
+ ```
182
+
183
+ **Configuration Options:**
184
+ - `isExitButtonEnabled` (boolean): Show/hide exit button
185
+ - `isCompassEnabled` (boolean): Show/hide compass
186
+ - `isSearchBarEnabled` (boolean): Show/hide search bar
187
+ - `isLevelSelectorEnabled` (boolean): Show/hide level selector
188
+ - `isMyCarButtonEnabled` (boolean): Show/hide my car button
189
+ - `isRouteFooterViewEnabled` (boolean): Show/hide route footer
190
+
191
+ ---
192
+
193
+ ##### `getPois(siteId)`
194
+
195
+ Retrieves all Points of Interest (POIs) for a specific site.
196
+
197
+ **Parameters:**
198
+ - `siteId` (string): Site external identifier
199
+
200
+ **Returns:** Promise<PTRPoi[]> - Array of POI objects
201
+
202
+ **Example:**
203
+ ```typescript
204
+ import { getPois } from 'react-native-pointr';
205
+
206
+ try {
207
+ const pois = await getPois('site-external-id');
208
+ console.log(`Found ${pois.length} POIs`);
209
+
210
+ pois.forEach(poi => {
211
+ console.log(`${poi.name} (${poi.typeCode})`);
212
+ console.log(` Location: ${poi.position.lat}, ${poi.position.lon}`);
213
+ console.log(` Level: ${poi.position.lvl}`);
214
+ });
215
+ } catch (error) {
216
+ console.error('Failed to get POIs:', error);
217
+ }
218
+ ```
219
+
220
+ **POI Object Structure:**
221
+ ```typescript
222
+ interface PTRPoi {
223
+ identifier: string; // Internal ID
224
+ externalIdentifier: string; // External ID
225
+ name: string; // Display name
226
+ typeCode: string; // POI type code
227
+ position: PTRPosition; // Geographic position
228
+ geometry: PTRGeometry; // Shape data
229
+ attributes: PTRPoiAttributes; // Metadata
230
+ }
231
+
232
+ interface PTRPosition {
233
+ lat: number; // Latitude
234
+ lon: number; // Longitude
235
+ isValid: boolean; // Position validity
236
+ sid: string; // Site ID
237
+ bid: string; // Building ID
238
+ lvl: number; // Level index
239
+ }
240
+
241
+ interface PTRPoiAttributes {
242
+ logo?: string; // Logo URL
243
+ images?: string[]; // Image URLs
244
+ description?: string; // Description text
245
+ extra?: Record<string, any>; // Custom data
246
+ [key: string]: any; // Other attributes
247
+ }
248
+ ```
249
+
250
+ ---
251
+
252
+ ## Map Widget Component
253
+
254
+ ### `PTRMapWidget`
255
+
256
+ A native UI component that displays the Pointr map.
257
+
258
+ **Props:**
259
+ - `style` (ViewStyle): Component styling
260
+ - `onMapWidgetDidEndLoading` (function): Callback when map finishes loading with a command
261
+ - `ref` (ref): Reference to the component for sending commands
262
+
263
+ **Example:**
264
+ ```typescript
265
+ import { requireNativeComponent } from 'react-native';
266
+
267
+ interface PTRMapWidgetProps {
268
+ style?: any;
269
+ onMapWidgetDidEndLoading?: (event: NativeSyntheticEvent<any>) => void;
270
+ }
271
+
272
+ const PTRMapWidget = requireNativeComponent<PTRMapWidgetProps>('PTRMapWidget');
273
+
274
+ function MyComponent() {
275
+ const ref = useRef(null);
276
+
277
+ const handleLoadingComplete = (event) => {
278
+ const { command, siteExternalIdentifier, error } = event.nativeEvent;
279
+ console.log('Map loaded:', command, siteExternalIdentifier, error);
280
+ };
281
+
282
+ return (
283
+ <PTRMapWidget
284
+ ref={ref}
285
+ style={{ flex: 1 }}
286
+ onMapWidgetDidEndLoading={handleLoadingComplete}
287
+ />
288
+ );
289
+ }
290
+ ```
291
+
292
+ ---
293
+
294
+ ## Command Types
295
+
296
+ ### `PTRCommandType`
297
+
298
+ Enum of supported command types.
299
+
300
+ ```typescript
301
+ enum PTRCommandType {
302
+ SITE = "site",
303
+ BUILDING = "building",
304
+ LEVEL = "level",
305
+ POI = "poi",
306
+ PATH = "path",
307
+ STATIC_PATH = "staticPath",
308
+ MARK_MY_CAR_LEVEL = "markMyCarForLevel",
309
+ MARK_MY_CAR_SITE = "markMyCarForSite",
310
+ SHOW_MY_CAR_SITE = "showMyCarForSite",
311
+ START_AND_FOCUS = "startAndFocus"
312
+ }
313
+ ```
314
+
315
+ ---
316
+
317
+ ### Command Classes
318
+
319
+ #### `PTRSiteCommand`
320
+
321
+ Shows a specific site on the map.
322
+
323
+ **Constructor:**
324
+ ```typescript
325
+ new PTRSiteCommand(site: string)
326
+ ```
327
+
328
+ **Parameters:**
329
+ - `site` (string): Site external identifier
330
+
331
+ **Example:**
332
+ ```typescript
333
+ import { PTRSiteCommand } from 'react-native-pointr/src/PTRCommand';
334
+ import { showMapWidget } from 'react-native-pointr/src/PTRMapWidgetUtils';
335
+
336
+ const command = new PTRSiteCommand("site-external-id");
337
+ showMapWidget(reactTag, command);
338
+ ```
339
+
340
+ ---
341
+
342
+ #### `PTRBuildingCommand`
343
+
344
+ Shows a specific building within a site.
345
+
346
+ **Constructor:**
347
+ ```typescript
348
+ new PTRBuildingCommand(site: string, building: string)
349
+ ```
350
+
351
+ **Parameters:**
352
+ - `site` (string): Site external identifier
353
+ - `building` (string): Building external identifier
354
+
355
+ **Example:**
356
+ ```typescript
357
+ const command = new PTRBuildingCommand("site-id", "building-id");
358
+ showMapWidget(reactTag, command);
359
+ ```
360
+
361
+ ---
362
+
363
+ #### `PTRLevelCommand`
364
+
365
+ Shows a specific level within a building.
366
+
367
+ **Constructor:**
368
+ ```typescript
369
+ new PTRLevelCommand(site: string, building: string, level: number)
370
+ ```
371
+
372
+ **Parameters:**
373
+ - `site` (string): Site external identifier
374
+ - `building` (string): Building external identifier
375
+ - `level` (number): Level index
376
+
377
+ **Example:**
378
+ ```typescript
379
+ const command = new PTRLevelCommand("site-id", "building-id", 1);
380
+ showMapWidget(reactTag, command);
381
+ ```
382
+
383
+ ---
384
+
385
+ #### `PTRPoiCommand`
386
+
387
+ Shows and focuses on a specific POI (Point of Interest).
388
+
389
+ **Constructor:**
390
+ ```typescript
391
+ new PTRPoiCommand(site: string, poi: string)
392
+ ```
393
+
394
+ **Parameters:**
395
+ - `site` (string): Site external identifier
396
+ - `poi` (string): POI external identifier or name
397
+
398
+ **Example:**
399
+ ```typescript
400
+ const command = new PTRPoiCommand("site-id", "Lobby");
401
+ showMapWidget(reactTag, command);
402
+ ```
403
+
404
+ ---
405
+
406
+ #### `PTRPathCommand`
407
+
408
+ Shows navigation path from current location to a POI.
409
+
410
+ **Constructor:**
411
+ ```typescript
412
+ new PTRPathCommand(site: string, poi: string)
413
+ ```
414
+
415
+ **Parameters:**
416
+ - `site` (string): Site external identifier
417
+ - `poi` (string): Destination POI external identifier
418
+
419
+ **Example:**
420
+ ```typescript
421
+ const command = new PTRPathCommand("site-id", "Lobby");
422
+ showMapWidget(reactTag, command);
423
+ ```
424
+
425
+ ---
426
+
427
+ #### `PTRStaticPathCommand`
428
+
429
+ Shows a static path between two POIs.
430
+
431
+ **Constructor:**
432
+ ```typescript
433
+ new PTRStaticPathCommand(site: string, fromPoi: string, toPoi: string)
434
+ ```
435
+
436
+ **Parameters:**
437
+ - `site` (string): Site external identifier
438
+ - `fromPoi` (string): Starting POI external identifier
439
+ - `toPoi` (string): Destination POI external identifier
440
+
441
+ **Example:**
442
+ ```typescript
443
+ const command = new PTRStaticPathCommand("site-id", "Lobby", "Cafeteria");
444
+ showMapWidget(reactTag, command);
445
+ ```
446
+
447
+ ---
448
+
449
+ #### `PTRMarkMyCarLevelCommand`
450
+
451
+ Marks "My Car" location on a specific level.
452
+
453
+ **Constructor:**
454
+ ```typescript
455
+ new PTRMarkMyCarLevelCommand(
456
+ site: string,
457
+ building: string,
458
+ level: number,
459
+ shouldShowPopup?: boolean,
460
+ animationType?: number
461
+ )
462
+ ```
463
+
464
+ **Parameters:**
465
+ - `site` (string): Site external identifier
466
+ - `building` (string): Building external identifier
467
+ - `level` (number): Level index
468
+ - `shouldShowPopup` (boolean): Show popup after marking (default: true)
469
+ - `animationType` (number): Animation type (default: 1)
470
+ - `0`: None
471
+ - `1`: Standard
472
+ - `2`: Fly over
473
+
474
+ **Example:**
475
+ ```typescript
476
+ const command = new PTRMarkMyCarLevelCommand("site-id", "building-id", 1, true, 1);
477
+ showMapWidget(reactTag, command);
478
+ ```
479
+
480
+ ---
481
+
482
+ #### `PTRMarkMyCarSiteCommand`
483
+
484
+ Marks "My Car" location at the current position within a site.
485
+
486
+ **Constructor:**
487
+ ```typescript
488
+ new PTRMarkMyCarSiteCommand(
489
+ site: string,
490
+ shouldShowPopup?: boolean,
491
+ animationType?: number
492
+ )
493
+ ```
494
+
495
+ **Parameters:**
496
+ - `site` (string): Site external identifier
497
+ - `shouldShowPopup` (boolean): Show popup after marking (default: true)
498
+ - `animationType` (number): Animation type (default: 1)
499
+
500
+ **Example:**
501
+ ```typescript
502
+ const command = new PTRMarkMyCarSiteCommand("site-id", true, 1);
503
+ showMapWidget(reactTag, command);
504
+ ```
505
+
506
+ ---
507
+
508
+ #### `PTRShowMyCarSiteCommand`
509
+
510
+ Shows the saved "My Car" location.
511
+
512
+ **Constructor:**
513
+ ```typescript
514
+ new PTRShowMyCarSiteCommand(
515
+ site: string,
516
+ shouldShowPopup?: boolean,
517
+ animationType?: number
518
+ )
519
+ ```
520
+
521
+ **Parameters:**
522
+ - `site` (string): Site external identifier
523
+ - `shouldShowPopup` (boolean): Show popup (default: true)
524
+ - `animationType` (number): Animation type (default: 1)
525
+
526
+ **Example:**
527
+ ```typescript
528
+ const command = new PTRShowMyCarSiteCommand("site-id", true, 1);
529
+ showMapWidget(reactTag, command);
530
+ ```
531
+
532
+ ---
533
+
534
+ #### `PTRStartAndFocusCommand`
535
+
536
+ Initializes the SDK and focuses on a location in a single command.
537
+
538
+ **Constructor:**
539
+ ```typescript
540
+ new PTRStartAndFocusCommand(
541
+ clientId: string,
542
+ licenseKey: string,
543
+ baseUrl: string,
544
+ logLevel: number,
545
+ command: PTRSiteCommand | PTRBuildingCommand | PTRLevelCommand | PTRPoiCommand
546
+ )
547
+ ```
548
+
549
+ **Parameters:**
550
+ - `clientId` (string): Client identifier
551
+ - `licenseKey` (string): License key
552
+ - `baseUrl` (string): Base URL
553
+ - `logLevel` (number): Log level (0-4)
554
+ - `command` (PTRCommand): Focus command to execute after initialization
555
+
556
+ **Example:**
557
+ ```typescript
558
+ const focusCommand = new PTRSiteCommand("site-id");
559
+ const command = new PTRStartAndFocusCommand(
560
+ "client-id",
561
+ "license-key",
562
+ "https://your-instance.pointr.cloud",
563
+ 3,
564
+ focusCommand
565
+ );
566
+ showMapWidget(reactTag, command);
567
+ ```
568
+
569
+ ---
570
+
571
+ ## Utility Functions
572
+
573
+ ### `showMapWidget(reactTag, command)`
574
+
575
+ Sends a command to the map widget.
576
+
577
+ **Parameters:**
578
+ - `reactTag` (number): The native view tag obtained from `findNodeHandle()`
579
+ - `command` (PTRCommand | PTRStartAndFocusCommand): The command to execute
580
+
581
+ **Example:**
582
+ ```typescript
583
+ import { findNodeHandle } from 'react-native';
584
+ import { showMapWidget } from 'react-native-pointr/src/PTRMapWidgetUtils';
585
+ import { PTRSiteCommand } from 'react-native-pointr/src/PTRCommand';
586
+
587
+ const showSite = () => {
588
+ const reactTag = findNodeHandle(mapWidgetRef.current);
589
+ if (reactTag) {
590
+ const command = new PTRSiteCommand("site-id");
591
+ showMapWidget(reactTag, command);
592
+ }
593
+ };
594
+ ```
595
+
596
+ ---
597
+
598
+ ## Event Listeners
599
+
600
+ ### Position Manager Events
601
+
602
+ Subscribe to position updates using the native event emitter.
603
+
604
+ **Events:**
605
+ - `OnPositionManagerCalculatedLocation`: Fired when a new position is calculated
606
+ - `OnBuildingClicked`: Fired when a building is tapped on the map
607
+ - `OnSiteClicked`: Fired when a site is tapped on the map
608
+ - `OnGeofenceEvent`: Fired when a geofence enter/exit event occurs
609
+
610
+ **Example:**
611
+ ```typescript
612
+ import { NativeEventEmitter, NativeModules } from 'react-native';
613
+
614
+ const PTREventEmitter = NativeModules.PTRNativePointrLibrary;
615
+ const eventEmitter = new NativeEventEmitter(PTREventEmitter);
616
+
617
+ // Listen to position updates
618
+ const subscription = eventEmitter.addListener(
619
+ 'OnPositionManagerCalculatedLocation',
620
+ (location) => {
621
+ console.log('New position:', location);
622
+ }
623
+ );
624
+
625
+ // Listen to building clicks
626
+ const buildingSubscription = eventEmitter.addListener(
627
+ 'OnBuildingClicked',
628
+ (building) => {
629
+ console.log('Building clicked:', building);
630
+ }
631
+ );
632
+
633
+ // Listen to geofence events
634
+ const geofenceSubscription = eventEmitter.addListener(
635
+ 'OnGeofenceEvent',
636
+ (geofenceEvent) => {
637
+ console.log('Geofence event:', geofenceEvent);
638
+ }
639
+ );
640
+
641
+ // Clean up
642
+ subscription.remove();
643
+ buildingSubscription.remove();
644
+ geofenceSubscription.remove();
645
+ ```
646
+
647
+ ---
648
+
649
+ ### Geofence Events
650
+
651
+ The `OnGeofenceEvent` is fired when the user enters or exits a geofence area. This feature requires the Pointr SDK to be running and geofence listeners are automatically registered when calling `start()`.
652
+
653
+ **Event Structure:**
654
+ ```typescript
655
+ {
656
+ eventType: 'enter' | 'exit', // Event type
657
+ timestamp?: number, // Unix timestamp in milliseconds (iOS only)
658
+ geofence: {
659
+ id: string, // Internal geofence ID
660
+ externalId: string, // External geofence ID
661
+ name: string, // Geofence name
662
+ geofenceType: 'beacon' | 'gps', // Type of geofence
663
+ position: {
664
+ latitude: number, // Geofence latitude
665
+ longitude: number // Geofence longitude
666
+ }
667
+ },
668
+ geofenceNotification?: { // Optional notification data
669
+ id: string,
670
+ message: string,
671
+ timestamp: number // Unix timestamp in milliseconds (Android)
672
+ // or milliseconds (iOS)
673
+ }
674
+ }
675
+ ```
676
+
677
+ **Platform Differences:**
678
+ - iOS: Includes `timestamp` field at the root level with milliseconds since epoch
679
+ - Android: Timestamp only available in `geofenceNotification` object
680
+ - Both platforms support beacon and GPS geofence types
681
+
682
+ **Example:**
683
+ ```typescript
684
+ import React, { useEffect } from 'react';
685
+ import { NativeEventEmitter, NativeModules } from 'react-native';
686
+
687
+ function GeofenceMonitor() {
688
+ useEffect(() => {
689
+ const eventEmitter = new NativeEventEmitter(
690
+ NativeModules.PTRNativePointrLibrary
691
+ );
692
+
693
+ const geofenceSubscription = eventEmitter.addListener(
694
+ 'OnGeofenceEvent',
695
+ (geofenceEvent) => {
696
+ console.log(`Geofence ${geofenceEvent.eventType}: ${geofenceEvent.geofence.name}`);
697
+ console.log(`Type: ${geofenceEvent.geofence.geofenceType}`);
698
+ console.log(`Location: ${geofenceEvent.geofence.position.latitude}, ${geofenceEvent.geofence.position.longitude}`);
699
+
700
+ if (geofenceEvent.geofenceNotification) {
701
+ console.log(`Notification: ${geofenceEvent.geofenceNotification.message}`);
702
+ }
703
+
704
+ if (geofenceEvent.timestamp) {
705
+ console.log(`Timestamp: ${new Date(geofenceEvent.timestamp).toISOString()}`);
706
+ }
707
+ }
708
+ );
709
+
710
+ return () => {
711
+ geofenceSubscription.remove();
712
+ };
713
+ }, []);
714
+
715
+ return null;
716
+ }
717
+ ```
718
+
719
+ ---
720
+
721
+ ### Map Widget Load Events
722
+
723
+ The `onMapWidgetDidEndLoading` prop receives events when commands complete.
724
+
725
+ **Event Object:**
726
+ ```typescript
727
+ {
728
+ command: string, // Command type that was executed
729
+ siteExternalIdentifier?: string,
730
+ buildingExternalIdentifier?: string,
731
+ levelIndex?: number,
732
+ poiExternalIdentifier?: string,
733
+ error?: string // Error message if command failed
734
+ }
735
+ ```
736
+
737
+ **Example:**
738
+ ```typescript
739
+ const handleMapWidgetDidEndLoading = (event) => {
740
+ const { command, siteExternalIdentifier, error } = event.nativeEvent;
741
+
742
+ if (error) {
743
+ console.error(`Command ${command} failed:`, error);
744
+ } else {
745
+ console.log(`Command ${command} completed for site:`, siteExternalIdentifier);
746
+ }
747
+ };
748
+
749
+ <PTRMapWidget
750
+ ref={ref}
751
+ onMapWidgetDidEndLoading={handleMapWidgetDidEndLoading}
752
+ />
753
+ ```
754
+
755
+ ---
756
+
757
+ ## Complete Example
758
+
759
+ ```typescript
760
+ import React, { useRef, useEffect } from 'react';
761
+ import {
762
+ requireNativeComponent,
763
+ findNodeHandle,
764
+ NativeModules,
765
+ NativeEventEmitter,
766
+ View
767
+ } from 'react-native';
768
+ import {
769
+ PTRSiteCommand,
770
+ showMapWidget,
771
+ getPois,
772
+ type PTRPoi
773
+ } from 'react-native-pointr';
774
+
775
+ const PTRMapWidget = requireNativeComponent('PTRMapWidget');
776
+
777
+ function PointrMapExample() {
778
+ const mapRef = useRef(null);
779
+
780
+ useEffect(() => {
781
+ // Initialize SDK
782
+ NativeModules.PTRNativePointrLibrary.initialize(
783
+ "client-id",
784
+ "license-key",
785
+ "https://your-instance.pointr.cloud",
786
+ 3
787
+ );
788
+
789
+ // Start SDK
790
+ NativeModules.PTRNativePointrLibrary.start((state) => {
791
+ console.log('Pointr state:', state);
792
+
793
+ if (state === 'running') {
794
+ // Show site when SDK is running
795
+ const reactTag = findNodeHandle(mapRef.current);
796
+ if (reactTag) {
797
+ const command = new PTRSiteCommand("site-id");
798
+ showMapWidget(reactTag, command);
799
+ }
800
+
801
+ // Fetch POIs for the site
802
+ fetchPOIs();
803
+ }
804
+ });
805
+
806
+ // Listen to position updates
807
+ const eventEmitter = new NativeEventEmitter(
808
+ NativeModules.PTRNativePointrLibrary
809
+ );
810
+ const subscription = eventEmitter.addListener(
811
+ 'OnPositionManagerCalculatedLocation',
812
+ (location) => {
813
+ console.log('Position update:', location);
814
+ }
815
+ );
816
+
817
+ // Listen to geofence events
818
+ const geofenceSubscription = eventEmitter.addListener(
819
+ 'OnGeofenceEvent',
820
+ (event) => {
821
+ console.log(`Geofence ${event.eventType}: ${event.geofence.name}`);
822
+ }
823
+ );
824
+
825
+ return () => {
826
+ subscription.remove();
827
+ geofenceSubscription.remove();
828
+ NativeModules.PTRNativePointrLibrary.stop();
829
+ };
830
+ }, []);
831
+
832
+ const fetchPOIs = async () => {
833
+ try {
834
+ const pois: PTRPoi[] = await getPois('site-id');
835
+ console.log(`Found ${pois.length} POIs`);
836
+ pois.forEach(poi => {
837
+ console.log(`${poi.name} at level ${poi.position.lvl}`);
838
+ });
839
+ } catch (error) {
840
+ console.error('Failed to fetch POIs:', error);
841
+ }
842
+ };
843
+
844
+ const handleMapLoaded = (event) => {
845
+ const { command, error } = event.nativeEvent;
846
+ console.log('Map command completed:', command, error);
847
+ };
848
+
849
+ return (
850
+ <View style={{ flex: 1 }}>
851
+ <PTRMapWidget
852
+ ref={mapRef}
853
+ style={{ flex: 1 }}
854
+ onMapWidgetDidEndLoading={handleMapLoaded}
855
+ />
856
+ </View>
857
+ );
858
+ }
859
+
860
+ export default PointrMapExample;
861
+ ```
862
+
863
+ ---
864
+
865
+ ## Error Handling
866
+
867
+ ### Common Errors
868
+
869
+ - **"Pointr is not initialized"**: Call `initialize()` before other methods
870
+ - **"Pointr is not running"**: Call `start()` and wait for "running" state
871
+ - **"Failed to find node handle for ref"**: Ensure ref is properly attached to component
872
+ - **"No saved location"**: User hasn't marked a "My Car" location yet
873
+
874
+ ### Best Practices
875
+
876
+ 1. Always check the Pointr state before executing commands
877
+ 2. Handle errors in callbacks and event handlers
878
+ 3. Clean up event listeners when component unmounts
879
+ 4. Use `findNodeHandle()` to get the correct native view tag
880
+ 5. Initialize SDK before rendering the map widget
881
+ 6. Request permissions before starting SDK if needed
882
+
883
+ ---
884
+
885
+ ## License
886
+
887
+ See the LICENSE file in the package root.