react-native-pointr 9.2.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 -4
  7. package/android/src/main/java/com/pointr/PTRCoreExtensions.kt +126 -0
  8. package/android/src/main/java/com/pointr/PTRMapWidgetCommandType.kt +2 -1
  9. package/android/src/main/java/com/pointr/PTRMapWidgetManager.kt +73 -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 +56 -5
  64. package/ios/PTRMapWidgetManager-Bridging.m +7 -0
  65. package/ios/PTRMapWidgetManager.swift +28 -0
  66. package/ios/PTRNativeLibrary-Bridging.m +4 -0
  67. package/ios/PTRNativeLibrary.swift +208 -2
  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 +13 -0
  72. package/src/PTRMapWidgetUtils.ts +10 -1
  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
package/CHANGELOG.md CHANGED
@@ -4,6 +4,41 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [9.3.1] - 2026-01-07
8
+
9
+ ### Added
10
+ - **POI Management API**: New `getPois(siteId)` method to retrieve all Points of Interest for a specific site
11
+ - **Geofence Events**: Added `OnGeofenceEvent` listener for geofence enter/exit notifications
12
+ - Supports both beacon and GPS geofence types
13
+ - Includes position data and optional notification messages
14
+ - Available on both iOS and Android platforms
15
+ - **TypeScript Types**: Complete type definitions for better IDE support
16
+ - `PTRPoi` - Point of Interest data structure
17
+ - `PTRPosition` - Geographic position with site/building/level info
18
+ - `PTRGeometry` - Geometry types (Point, Polygon, LineString, Circle, etc.)
19
+ - `PTRWayfindingEvent` - Wayfinding navigation events
20
+ - `PTRPoiAttributes` - POI metadata and attributes
21
+ - **Module Exports**: Enhanced ES6 module exports
22
+ - Named exports for all commands, types, and utilities
23
+ - Default export maintains backward compatibility
24
+ - Tree-shaking support for optimized bundle sizes
25
+ - **POI Manager**: New `PTRPoiManager` utility module for POI operations
26
+ - **Platform Extensions**: Native extensions for iOS and Android
27
+ - iOS: `PTRFeature`, `PTRPosition` dictionary conversions
28
+ - Android: `PTRCoreExtensions` with Kotlin extension methods
29
+ - Distribution preparation script (`prepare-distribution.sh`) for creating clean, distributable package archives
30
+ - `prepare-dist` npm script for easy package distribution preparation
31
+ - Automated cleanup of build artifacts, git history, and development files during distribution
32
+
33
+ ### Changed
34
+ - **Event Listeners**: Geofence manager listeners now registered in `start()` and removed in `stop()`
35
+ - **Module Structure**: Migrated from CommonJS to ES6 module exports
36
+ - **iOS Implementation**: Improved Swift code organization and type safety
37
+ - **Android Implementation**: Enhanced Kotlin code with extension methods
38
+
39
+ ### Fixed
40
+ - None.
41
+
7
42
  ## [8.16.1]
8
43
 
9
44
  ## Updates
package/EXTENDING.md ADDED
@@ -0,0 +1,419 @@
1
+ # Extending react-native-pointr Package
2
+
3
+ This guide demonstrates how to extend the functionality of the `react-native-pointr` package by adding new features. We'll use implementing a `getPois` function as an example to show the complete process of adding new functionality.
4
+
5
+ ## Overview
6
+
7
+ Extending the package involves three main steps:
8
+
9
+ 1. **Add native code** - Implement the functionality in both iOS (Swift/Objective-C) and Android (Kotlin/Java)
10
+ 2. **Create TypeScript interfaces** - Define types and interfaces for the new functionality
11
+ 3. **Expose to JavaScript** - Make the functionality accessible from React Native
12
+
13
+ ## Example: Adding getPois Functionality
14
+
15
+ This example shows how to add a function that retrieves all Points of Interest (POIs) for a specific site.
16
+
17
+ ### Step 1: Add Native Implementation
18
+
19
+ #### iOS Implementation
20
+
21
+ **File: `ios/PTRNativePointrLibrary.swift`**
22
+
23
+ Add the following method to your native iOS module:
24
+
25
+ ```swift
26
+ @objc(getPois:resolver:rejecter:)
27
+ func getPois(_ siteId: String,
28
+ resolver resolve: @escaping RCTPromiseResolveBlock,
29
+ rejecter reject: @escaping RCTPromiseRejectBlock) {
30
+
31
+ // Ensure Pointr SDK is initialized
32
+ guard let site = Pointr.shared.getSite(withExternalIdentifier: siteId) else {
33
+ reject("ERROR", "Site not found: \(siteId)", nil)
34
+ return
35
+ }
36
+
37
+ // Get all POIs for the site
38
+ let pois = site.getAllPois()
39
+
40
+ // Convert POIs to dictionary format
41
+ let poisData = pois.map { poi -> [String: Any] in
42
+ return [
43
+ "id": poi.externalIdentifier,
44
+ "name": poi.name ?? "",
45
+ "buildingId": poi.building?.externalIdentifier ?? "",
46
+ "levelIndex": poi.level?.index ?? 0,
47
+ "category": poi.category ?? "",
48
+ "latitude": poi.coordinate.latitude,
49
+ "longitude": poi.coordinate.longitude
50
+ ]
51
+ }
52
+
53
+ resolve(poisData)
54
+ }
55
+ ```
56
+
57
+ **File: `ios/PTRNativePointrLibrary.m`**
58
+
59
+ Add the method declaration to the bridge:
60
+
61
+ ```objective-c
62
+ RCT_EXTERN_METHOD(getPois:(NSString *)siteId
63
+ resolver:(RCTPromiseResolveBlock)resolve
64
+ rejecter:(RCTPromiseRejectBlock)reject)
65
+ ```
66
+
67
+ #### Android Implementation
68
+
69
+ **File: `android/src/main/java/com/reactnativepointr/PTRNativePointrLibraryModule.kt`**
70
+
71
+ Add the following method to your native Android module:
72
+
73
+ ```kotlin
74
+ @ReactMethod
75
+ fun getPois(siteId: String, promise: Promise) {
76
+ try {
77
+ // Ensure Pointr SDK is initialized
78
+ val site = Pointr.getSite(siteId)
79
+
80
+ if (site == null) {
81
+ promise.reject("ERROR", "Site not found: $siteId")
82
+ return
83
+ }
84
+
85
+ // Get all POIs for the site
86
+ val pois = site.getAllPois()
87
+
88
+ // Convert POIs to WritableArray
89
+ val poisArray = Arguments.createArray()
90
+
91
+ pois.forEach { poi ->
92
+ val poiMap = Arguments.createMap().apply {
93
+ putString("id", poi.externalIdentifier)
94
+ putString("name", poi.name ?: "")
95
+ putString("buildingId", poi.building?.externalIdentifier ?: "")
96
+ putInt("levelIndex", poi.level?.index ?: 0)
97
+ putString("category", poi.category ?: "")
98
+ putDouble("latitude", poi.coordinate.latitude)
99
+ putDouble("longitude", poi.coordinate.longitude)
100
+ }
101
+ poisArray.pushMap(poiMap)
102
+ }
103
+
104
+ promise.resolve(poisArray)
105
+
106
+ } catch (e: Exception) {
107
+ promise.reject("ERROR", "Failed to get POIs: ${e.message}", e)
108
+ }
109
+ }
110
+ ```
111
+
112
+ ### Step 2: Create TypeScript Interfaces
113
+
114
+ **File: `src/types/PTRPoi.ts`**
115
+
116
+ Create a new file to define the POI type:
117
+
118
+ ```typescript
119
+ /**
120
+ * Point of Interest (POI) data structure
121
+ */
122
+ export interface PTRPoi {
123
+ /** Unique identifier for the POI */
124
+ id: string;
125
+
126
+ /** Display name of the POI */
127
+ name: string;
128
+
129
+ /** Building identifier where the POI is located */
130
+ buildingId: string;
131
+
132
+ /** Level/floor index where the POI is located */
133
+ levelIndex: number;
134
+
135
+ /** Category or type of the POI */
136
+ category: string;
137
+
138
+ /** Latitude coordinate */
139
+ latitude: number;
140
+
141
+ /** Longitude coordinate */
142
+ longitude: number;
143
+ }
144
+ ```
145
+
146
+ ### Step 3: Create JavaScript Wrapper
147
+
148
+ **File: `src/PTRNativePointrLibrary.ts`**
149
+
150
+ Create a wrapper function that provides a clean API:
151
+
152
+ ```typescript
153
+ import { NativeModules } from 'react-native';
154
+ import { PTRPoi } from './types/PTRPoi';
155
+
156
+ const { PTRNativePointrLibrary } = NativeModules;
157
+
158
+ /**
159
+ * Get all Points of Interest (POIs) for a specific site
160
+ * @param siteId - The external identifier of the site
161
+ * @returns Promise that resolves with an array of POIs
162
+ * @throws Error if the site is not found or if the operation fails
163
+ */
164
+ export async function getPois(siteId: string): Promise<PTRPoi[]> {
165
+ try {
166
+ const pois = await PTRNativePointrLibrary.getPois(siteId);
167
+ return pois as PTRPoi[];
168
+ } catch (error) {
169
+ console.error('Failed to get POIs:', error);
170
+ throw error;
171
+ }
172
+ }
173
+ ```
174
+
175
+ ### Step 4: Export the New Functionality
176
+
177
+ **File: `src/index.ts`**
178
+
179
+ Export the new functions and types from the main entry point:
180
+
181
+ ```typescript
182
+ // Existing exports
183
+ export * from './PTRCommand';
184
+ export * from './PTRMapWidgetUtils';
185
+
186
+ // New exports
187
+ export { getPois } from './PTRNativePointrLibrary';
188
+ export type { PTRPoi } from './types/PTRPoi';
189
+ ```
190
+
191
+ ### Step 5: Usage Example
192
+
193
+ Now you can use the new functionality in your React Native app:
194
+
195
+ ```typescript
196
+ import React, { useState, useEffect } from 'react';
197
+ import { View, Text, FlatList, ActivityIndicator } from 'react-native';
198
+ import { getPois, PTRPoi } from 'react-native-pointr';
199
+
200
+ function PoiListScreen() {
201
+ const [pois, setPois] = useState<PTRPoi[]>([]);
202
+ const [loading, setLoading] = useState(true);
203
+ const [error, setError] = useState<string | null>(null);
204
+
205
+ useEffect(() => {
206
+ loadPois();
207
+ }, []);
208
+
209
+ const loadPois = async () => {
210
+ try {
211
+ setLoading(true);
212
+ const siteId = 'your-site-id';
213
+ const poisData = await getPois(siteId);
214
+ setPois(poisData);
215
+ setError(null);
216
+ } catch (err) {
217
+ setError(err instanceof Error ? err.message : 'Failed to load POIs');
218
+ console.error('Error loading POIs:', err);
219
+ } finally {
220
+ setLoading(false);
221
+ }
222
+ };
223
+
224
+ if (loading) {
225
+ return (
226
+ <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
227
+ <ActivityIndicator size="large" />
228
+ <Text>Loading POIs...</Text>
229
+ </View>
230
+ );
231
+ }
232
+
233
+ if (error) {
234
+ return (
235
+ <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
236
+ <Text style={{ color: 'red' }}>Error: {error}</Text>
237
+ </View>
238
+ );
239
+ }
240
+
241
+ return (
242
+ <FlatList
243
+ data={pois}
244
+ keyExtractor={(item) => item.id}
245
+ renderItem={({ item }) => (
246
+ <View style={{ padding: 16, borderBottomWidth: 1, borderColor: '#ccc' }}>
247
+ <Text style={{ fontSize: 18, fontWeight: 'bold' }}>{item.name}</Text>
248
+ <Text>Category: {item.category}</Text>
249
+ <Text>Building: {item.buildingId}</Text>
250
+ <Text>Level: {item.levelIndex}</Text>
251
+ <Text>
252
+ Location: {item.latitude.toFixed(6)}, {item.longitude.toFixed(6)}
253
+ </Text>
254
+ </View>
255
+ )}
256
+ />
257
+ );
258
+ }
259
+
260
+ export default PoiListScreen;
261
+ ```
262
+
263
+ ## Best Practices for Extensions
264
+
265
+ ### 1. Type Safety
266
+
267
+ Always define TypeScript interfaces for data structures:
268
+
269
+ ```typescript
270
+ export interface PTRCustomData {
271
+ id: string;
272
+ value: any;
273
+ // Add proper types
274
+ }
275
+ ```
276
+
277
+ ### 2. Error Handling
278
+
279
+ Implement comprehensive error handling in both native and JavaScript code:
280
+
281
+ ```typescript
282
+ try {
283
+ const result = await nativeModule.someMethod();
284
+ return result;
285
+ } catch (error) {
286
+ console.error('Operation failed:', error);
287
+ throw new Error(`Failed to execute: ${error.message}`);
288
+ }
289
+ ```
290
+
291
+ ### 3. Promise-based APIs
292
+
293
+ Use Promises for asynchronous operations to provide a consistent API:
294
+
295
+ ```swift
296
+ // iOS
297
+ @objc(someAsyncMethod:resolver:rejecter:)
298
+ func someAsyncMethod(_ param: String,
299
+ resolver resolve: @escaping RCTPromiseResolveBlock,
300
+ rejecter reject: @escaping RCTPromiseRejectBlock) {
301
+ // Implementation
302
+ }
303
+ ```
304
+
305
+ ```kotlin
306
+ // Android
307
+ @ReactMethod
308
+ fun someAsyncMethod(param: String, promise: Promise) {
309
+ // Implementation
310
+ }
311
+ ```
312
+
313
+ ### 4. Documentation
314
+
315
+ Document all new functionality with JSDoc comments:
316
+
317
+ ```typescript
318
+ /**
319
+ * Description of what the function does
320
+ * @param paramName - Description of the parameter
321
+ * @returns Description of what is returned
322
+ * @throws Description of potential errors
323
+ * @example
324
+ * ```typescript
325
+ * const result = await someFunction('value');
326
+ * ```
327
+ */
328
+ export async function someFunction(paramName: string): Promise<ResultType> {
329
+ // Implementation
330
+ }
331
+ ```
332
+
333
+ ### 5. Testing
334
+
335
+ Create test cases for new functionality:
336
+
337
+ ```typescript
338
+ import { getPois } from 'react-native-pointr';
339
+
340
+ describe('getPois', () => {
341
+ it('should return an array of POIs', async () => {
342
+ const pois = await getPois('test-site-id');
343
+ expect(Array.isArray(pois)).toBe(true);
344
+ expect(pois.length).toBeGreaterThan(0);
345
+ });
346
+
347
+ it('should throw error for invalid site', async () => {
348
+ await expect(getPois('invalid-site')).rejects.toThrow();
349
+ });
350
+ });
351
+ ```
352
+
353
+ ### 6. Platform Consistency
354
+
355
+ Ensure both iOS and Android implementations return the same data structure:
356
+
357
+ ```typescript
358
+ // Both platforms should return identical structure
359
+ {
360
+ id: string;
361
+ name: string;
362
+ // Same fields with same types
363
+ }
364
+ ```
365
+
366
+ ## Adding Event Listeners
367
+
368
+ For continuous data streams or callbacks, use event emitters:
369
+
370
+ ### Native Side (iOS)
371
+
372
+ ```swift
373
+ @objc
374
+ func sendEvent(_ name: String, body: Any) {
375
+ sendEvent(withName: name, body: body)
376
+ }
377
+
378
+ override func supportedEvents() -> [String]! {
379
+ return ["onLocationUpdate", "onPoiEnter"]
380
+ }
381
+ ```
382
+
383
+ ### Native Side (Android)
384
+
385
+ ```kotlin
386
+ private fun sendEvent(eventName: String, params: WritableMap?) {
387
+ reactContext
388
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
389
+ .emit(eventName, params)
390
+ }
391
+ ```
392
+
393
+ ### JavaScript Side
394
+
395
+ ```typescript
396
+ import { NativeEventEmitter, NativeModules } from 'react-native';
397
+
398
+ const { PTRNativePointrLibrary } = NativeModules;
399
+ const eventEmitter = new NativeEventEmitter(PTRNativePointrLibrary);
400
+
401
+ export function subscribeToLocationUpdates(
402
+ callback: (location: PTRLocation) => void
403
+ ): () => void {
404
+ const subscription = eventEmitter.addListener('onLocationUpdate', callback);
405
+ return () => subscription.remove();
406
+ }
407
+ ```
408
+
409
+ ## Conclusion
410
+
411
+ Extending the `react-native-pointr` package follows a consistent pattern:
412
+
413
+ 1. Implement native functionality on both platforms
414
+ 2. Define TypeScript types
415
+ 3. Create JavaScript wrappers
416
+ 4. Export from the package
417
+ 5. Document and test
418
+
419
+ This approach ensures a maintainable, type-safe, and platform-consistent API for your React Native application.