react-native-geofence-manager 0.1.0-beta.12 → 0.1.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 +16 -0
- package/android/src/main/java/com/geofencemanager/GeofenceBroadcastReceiver.kt +60 -14
- package/android/src/main/java/com/geofencemanager/GeofenceHeadlessTaskService.kt +26 -5
- package/android/src/main/java/com/geofencemanager/GeofenceManagerModule.kt +43 -7
- package/lib/module/geofenceDebugLog.js +22 -0
- package/lib/module/geofenceDebugLog.js.map +1 -0
- package/lib/module/index.js +49 -7
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/geofenceDebugLog.d.ts +3 -0
- package/lib/typescript/src/geofenceDebugLog.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/geofenceDebugLog.ts +28 -0
- package/src/index.tsx +49 -7
package/README.md
CHANGED
|
@@ -115,6 +115,22 @@ Para geofences confiáveis é necessário **localização** (fina ou aproximada)
|
|
|
115
115
|
|
|
116
116
|
---
|
|
117
117
|
|
|
118
|
+
## Depuração (logs)
|
|
119
|
+
|
|
120
|
+
A lib emite logs em cada etapa para localizar falhas (SDK nativo + JS).
|
|
121
|
+
|
|
122
|
+
**Android (Logcat)** — filtre pela tag:
|
|
123
|
+
|
|
124
|
+
```text
|
|
125
|
+
adb logcat -s GeofenceManager
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Você verá, entre outros: inicialização do módulo, `addGeofences` (sucesso/falha do Play Services), `BroadcastReceiver` (transição, foreground vs headless), `HeadlessTaskService` e erros de reflexão.
|
|
129
|
+
|
|
130
|
+
**JavaScript** — mensagens com prefixo `[GeofenceManager]` no console (Metro) e também no Logcat como `ReactNativeJS` ao rodar no dispositivo.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
118
134
|
## App de exemplo
|
|
119
135
|
|
|
120
136
|
Na raiz do repositório:
|
|
@@ -4,6 +4,7 @@ import android.content.BroadcastReceiver
|
|
|
4
4
|
import android.content.Context
|
|
5
5
|
import android.content.Intent
|
|
6
6
|
import android.os.Build
|
|
7
|
+
import android.util.Log
|
|
7
8
|
import android.os.Handler
|
|
8
9
|
import android.os.Looper
|
|
9
10
|
import com.facebook.react.HeadlessJsTaskService
|
|
@@ -16,36 +17,71 @@ import com.google.android.gms.location.GeofencingEvent
|
|
|
16
17
|
|
|
17
18
|
class GeofenceBroadcastReceiver : BroadcastReceiver() {
|
|
18
19
|
|
|
20
|
+
companion object {
|
|
21
|
+
private const val TAG = "GeofenceManager"
|
|
22
|
+
}
|
|
23
|
+
|
|
19
24
|
override fun onReceive(context: Context?, intent: Intent?) {
|
|
20
|
-
|
|
21
|
-
if (intent
|
|
25
|
+
Log.i(TAG, "BroadcastReceiver.onReceive: invoked action=${intent?.action}")
|
|
26
|
+
if (context == null || intent == null) {
|
|
27
|
+
Log.w(TAG, "BroadcastReceiver.onReceive: abort — null context or intent")
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
if (intent.action != GeofenceManagerModule.GEOFENCE_ACTION) {
|
|
31
|
+
Log.w(TAG, "BroadcastReceiver.onReceive: wrong action, expected ${GeofenceManagerModule.GEOFENCE_ACTION}")
|
|
32
|
+
return
|
|
33
|
+
}
|
|
22
34
|
|
|
23
|
-
val geofencingEvent = GeofencingEvent.fromIntent(intent)
|
|
24
|
-
if (geofencingEvent
|
|
35
|
+
val geofencingEvent = GeofencingEvent.fromIntent(intent)
|
|
36
|
+
if (geofencingEvent == null) {
|
|
37
|
+
Log.e(TAG, "BroadcastReceiver.onReceive: GeofencingEvent.fromIntent returned null")
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
if (geofencingEvent.hasError()) {
|
|
41
|
+
Log.e(TAG, "BroadcastReceiver.onReceive: Geofencing error code=${geofencingEvent.errorCode}")
|
|
42
|
+
return
|
|
43
|
+
}
|
|
25
44
|
|
|
26
|
-
if (GeofenceManagerModule.isWithinGracePeriod(context))
|
|
45
|
+
if (GeofenceManagerModule.isWithinGracePeriod(context)) {
|
|
46
|
+
Log.i(TAG, "BroadcastReceiver.onReceive: skipped — within grace period after addGeofences")
|
|
47
|
+
return
|
|
48
|
+
}
|
|
27
49
|
|
|
28
50
|
val transition = geofencingEvent.geofenceTransition
|
|
29
51
|
val eventName = when (transition) {
|
|
30
52
|
Geofence.GEOFENCE_TRANSITION_ENTER -> "enter"
|
|
31
53
|
Geofence.GEOFENCE_TRANSITION_EXIT -> "exit"
|
|
32
54
|
Geofence.GEOFENCE_TRANSITION_DWELL -> "dwell"
|
|
33
|
-
else ->
|
|
55
|
+
else -> {
|
|
56
|
+
Log.w(TAG, "BroadcastReceiver.onReceive: unknown transition=$transition")
|
|
57
|
+
return
|
|
58
|
+
}
|
|
34
59
|
}
|
|
60
|
+
Log.i(TAG, "BroadcastReceiver.onReceive: transition=$eventName")
|
|
35
61
|
|
|
36
|
-
val triggeringGeofences = geofencingEvent.triggeringGeofences
|
|
37
|
-
if (triggeringGeofences.isEmpty())
|
|
62
|
+
val triggeringGeofences = geofencingEvent.triggeringGeofences
|
|
63
|
+
if (triggeringGeofences == null || triggeringGeofences.isEmpty()) {
|
|
64
|
+
Log.w(TAG, "BroadcastReceiver.onReceive: no triggering geofences")
|
|
65
|
+
return
|
|
66
|
+
}
|
|
38
67
|
|
|
39
68
|
val reactContext = GeofenceManagerModule.reactContextRef
|
|
40
69
|
val timestamp = System.currentTimeMillis().toDouble()
|
|
41
70
|
val isForeground = reactContext != null && reactContext.hasActiveReactInstance()
|
|
71
|
+
Log.i(
|
|
72
|
+
TAG,
|
|
73
|
+
"BroadcastReceiver.onReceive: ids=${triggeringGeofences.map { it.requestId }} isForeground=$isForeground hasReactContextRef=${reactContext != null}"
|
|
74
|
+
)
|
|
42
75
|
|
|
43
76
|
if (isForeground) {
|
|
44
77
|
val ctx = reactContext!!
|
|
45
78
|
val geofenceIds = triggeringGeofences.map { it.requestId }
|
|
46
79
|
val eventNameForRunnable = eventName
|
|
47
80
|
Handler(Looper.getMainLooper()).postDelayed({
|
|
48
|
-
if (!ctx.hasActiveReactInstance())
|
|
81
|
+
if (!ctx.hasActiveReactInstance()) {
|
|
82
|
+
Log.w(TAG, "BroadcastReceiver: foreground path — React instance gone after delay, skipping emit")
|
|
83
|
+
return@postDelayed
|
|
84
|
+
}
|
|
49
85
|
try {
|
|
50
86
|
val emitter = ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
51
87
|
for (geofenceId in geofenceIds) {
|
|
@@ -61,13 +97,17 @@ class GeofenceBroadcastReceiver : BroadcastReceiver() {
|
|
|
61
97
|
putDouble("radius", it.radius.toDouble())
|
|
62
98
|
}
|
|
63
99
|
}
|
|
100
|
+
Log.i(TAG, "BroadcastReceiver: emitting onGeofenceTransition id=$geofenceId event=$eventNameForRunnable")
|
|
64
101
|
emitter.emit("onGeofenceTransition", params)
|
|
65
102
|
}
|
|
66
|
-
} catch (
|
|
103
|
+
} catch (e: Exception) {
|
|
104
|
+
Log.e(TAG, "BroadcastReceiver: emit to JS failed", e)
|
|
105
|
+
}
|
|
67
106
|
}, 50)
|
|
68
107
|
return
|
|
69
108
|
}
|
|
70
109
|
|
|
110
|
+
Log.i(TAG, "BroadcastReceiver: background/headless path — starting GeofenceHeadlessTaskService")
|
|
71
111
|
val appContext = context.applicationContext
|
|
72
112
|
HeadlessJsTaskService.acquireWakeLockNow(appContext)
|
|
73
113
|
for (geofence in triggeringGeofences) {
|
|
@@ -76,10 +116,16 @@ class GeofenceBroadcastReceiver : BroadcastReceiver() {
|
|
|
76
116
|
putExtra(GeofenceHeadlessTaskService.EXTRA_EVENT, eventName)
|
|
77
117
|
putExtra(GeofenceHeadlessTaskService.EXTRA_TIMESTAMP, timestamp)
|
|
78
118
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
119
|
+
try {
|
|
120
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
121
|
+
appContext.startForegroundService(serviceIntent)
|
|
122
|
+
Log.i(TAG, "BroadcastReceiver: startForegroundService for id=${geofence.requestId}")
|
|
123
|
+
} else {
|
|
124
|
+
appContext.startService(serviceIntent)
|
|
125
|
+
Log.i(TAG, "BroadcastReceiver: startService for id=${geofence.requestId}")
|
|
126
|
+
}
|
|
127
|
+
} catch (e: Exception) {
|
|
128
|
+
Log.e(TAG, "BroadcastReceiver: failed to start headless service", e)
|
|
83
129
|
}
|
|
84
130
|
}
|
|
85
131
|
}
|
|
@@ -5,6 +5,7 @@ import android.app.NotificationChannel
|
|
|
5
5
|
import android.app.NotificationManager
|
|
6
6
|
import android.content.Intent
|
|
7
7
|
import android.os.Build
|
|
8
|
+
import android.util.Log
|
|
8
9
|
import com.facebook.react.HeadlessJsTaskService
|
|
9
10
|
import com.facebook.react.bridge.Arguments
|
|
10
11
|
import com.facebook.react.jstasks.HeadlessJsTaskConfig
|
|
@@ -18,13 +19,21 @@ class GeofenceHeadlessTaskService : HeadlessJsTaskService() {
|
|
|
18
19
|
* startForeground() é chamado para que o sistema inicie o serviço mesmo em background (dwell/exit).
|
|
19
20
|
*/
|
|
20
21
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
|
22
|
+
Log.i(TAG, "HeadlessTaskService.onStartCommand extras=${intent?.extras}")
|
|
21
23
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
22
24
|
ensureNotificationChannel()
|
|
23
25
|
val notification = buildNotification(intent)
|
|
24
26
|
startForeground(NOTIFICATION_ID, notification)
|
|
27
|
+
Log.d(TAG, "HeadlessTaskService: startForeground done")
|
|
28
|
+
}
|
|
29
|
+
val taskConfig = getTaskConfig(intent)
|
|
30
|
+
if (taskConfig == null) {
|
|
31
|
+
Log.e(TAG, "HeadlessTaskService: getTaskConfig returned null — check EXTRA_GEOFENCE_ID / EXTRA_EVENT")
|
|
32
|
+
return START_NOT_STICKY
|
|
25
33
|
}
|
|
26
|
-
val taskConfig = getTaskConfig(intent) ?: return START_NOT_STICKY
|
|
27
34
|
val ctx = reactContext
|
|
35
|
+
val hasInstance = ctx?.hasActiveReactInstance() == true
|
|
36
|
+
Log.i(TAG, "HeadlessTaskService: hasActiveReactInstance=$hasInstance")
|
|
28
37
|
if (ctx != null && !ctx.hasActiveReactInstance()) {
|
|
29
38
|
HeadlessJsTaskService.acquireWakeLockNow(this)
|
|
30
39
|
try {
|
|
@@ -34,21 +43,32 @@ class GeofenceHeadlessTaskService : HeadlessJsTaskService() {
|
|
|
34
43
|
)
|
|
35
44
|
method.isAccessible = true
|
|
36
45
|
method.invoke(this, taskConfig)
|
|
37
|
-
|
|
46
|
+
Log.i(TAG, "HeadlessTaskService: createReactContextAndScheduleTask invoked OK")
|
|
47
|
+
} catch (e: Exception) {
|
|
48
|
+
Log.e(TAG, "HeadlessTaskService: reflection createReactContextAndScheduleTask failed", e)
|
|
38
49
|
return super.onStartCommand(intent, flags, startId)
|
|
39
50
|
}
|
|
40
51
|
return START_REDELIVER_INTENT
|
|
41
52
|
}
|
|
53
|
+
Log.i(TAG, "HeadlessTaskService: delegating to super.onStartCommand")
|
|
42
54
|
return super.onStartCommand(intent, flags, startId)
|
|
43
55
|
}
|
|
44
56
|
|
|
45
57
|
override fun getTaskConfig(intent: Intent?): HeadlessJsTaskConfig? {
|
|
46
|
-
if (intent == null)
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
if (intent == null) {
|
|
59
|
+
Log.w(TAG, "getTaskConfig: null intent")
|
|
60
|
+
return null
|
|
61
|
+
}
|
|
62
|
+
val geofenceId = intent.getStringExtra(EXTRA_GEOFENCE_ID)
|
|
63
|
+
val event = intent.getStringExtra(EXTRA_EVENT)
|
|
64
|
+
if (geofenceId == null || event == null) {
|
|
65
|
+
Log.e(TAG, "getTaskConfig: missing geofenceId or event (id=$geofenceId event=$event)")
|
|
66
|
+
return null
|
|
67
|
+
}
|
|
49
68
|
val timestamp = intent.getDoubleExtra(EXTRA_TIMESTAMP, 0.0)
|
|
50
69
|
|
|
51
70
|
val details = GeofenceManagerModule.getGeofenceDetails(this, geofenceId)
|
|
71
|
+
Log.i(TAG, "getTaskConfig: task=${GeofenceManagerModule.GEOFENCE_HEADLESS_TASK_NAME} id=$geofenceId event=$event")
|
|
52
72
|
val data = Arguments.createMap().apply {
|
|
53
73
|
putString("geofenceId", geofenceId)
|
|
54
74
|
putString("event", event)
|
|
@@ -90,6 +110,7 @@ class GeofenceHeadlessTaskService : HeadlessJsTaskService() {
|
|
|
90
110
|
}
|
|
91
111
|
|
|
92
112
|
companion object {
|
|
113
|
+
private const val TAG = "GeofenceManager"
|
|
93
114
|
private const val CHANNEL_ID = "geofence_manager_channel"
|
|
94
115
|
private const val NOTIFICATION_ID = 9001
|
|
95
116
|
const val EXTRA_GEOFENCE_ID = "geofenceId"
|
|
@@ -5,6 +5,7 @@ import android.content.ComponentName
|
|
|
5
5
|
import android.content.Context
|
|
6
6
|
import android.content.Intent
|
|
7
7
|
import android.content.SharedPreferences
|
|
8
|
+
import android.util.Log
|
|
8
9
|
import com.facebook.react.bridge.Promise
|
|
9
10
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
10
11
|
import com.facebook.react.bridge.ReadableArray
|
|
@@ -20,6 +21,7 @@ class GeofenceManagerModule(reactContext: ReactApplicationContext) :
|
|
|
20
21
|
NativeGeofenceManagerSpec(reactContext) {
|
|
21
22
|
|
|
22
23
|
companion object {
|
|
24
|
+
private const val TAG = "GeofenceManager"
|
|
23
25
|
const val NAME = "GeofenceManager"
|
|
24
26
|
const val GEOFENCE_ACTION = "com.geofencemanager.GEOFENCE_TRANSITION"
|
|
25
27
|
const val GEOFENCE_HEADLESS_TASK_NAME = "GeofenceManagerTransition"
|
|
@@ -70,7 +72,9 @@ class GeofenceManagerModule(reactContext: ReactApplicationContext) :
|
|
|
70
72
|
geofenceDetailsMap[d.id] = d
|
|
71
73
|
d.name?.let { geofenceNames[d.id] = it }
|
|
72
74
|
}
|
|
73
|
-
} catch (
|
|
75
|
+
} catch (e: Exception) {
|
|
76
|
+
Log.w(TAG, "loadDetailsFromPrefs failed", e)
|
|
77
|
+
}
|
|
74
78
|
}
|
|
75
79
|
}
|
|
76
80
|
|
|
@@ -84,11 +88,15 @@ class GeofenceManagerModule(reactContext: ReactApplicationContext) :
|
|
|
84
88
|
}
|
|
85
89
|
|
|
86
90
|
init {
|
|
91
|
+
Log.i(TAG, "Module init: package=${reactContext.packageName} hasActivity=${reactContext.currentActivity != null}")
|
|
87
92
|
// Só guardar o contexto que tem Activity (tela principal). O contexto da headless task
|
|
88
93
|
// não tem currentActivity; se o armazenarmos, os eventos em foreground (dwell/exit)
|
|
89
94
|
// seriam emitidos para ele e o listener registrado na tela nunca receberia.
|
|
90
95
|
if (reactContext.currentActivity != null) {
|
|
91
96
|
GeofenceManagerModule.reactContextRef = reactContext
|
|
97
|
+
Log.i(TAG, "Module init: reactContextRef set (foreground JS will receive DeviceEventEmitter events)")
|
|
98
|
+
} else {
|
|
99
|
+
Log.w(TAG, "Module init: no currentActivity — reactContextRef NOT updated (normal for some init paths)")
|
|
92
100
|
}
|
|
93
101
|
}
|
|
94
102
|
|
|
@@ -98,7 +106,11 @@ class GeofenceManagerModule(reactContext: ReactApplicationContext) :
|
|
|
98
106
|
private var geofencePendingIntent: PendingIntent? = null
|
|
99
107
|
|
|
100
108
|
private fun getPendingIntent(): PendingIntent {
|
|
101
|
-
geofencePendingIntent?.let {
|
|
109
|
+
geofencePendingIntent?.let {
|
|
110
|
+
Log.d(TAG, "getPendingIntent: reusing existing PendingIntent")
|
|
111
|
+
return it
|
|
112
|
+
}
|
|
113
|
+
Log.i(TAG, "getPendingIntent: creating new PendingIntent -> GeofenceBroadcastReceiver action=$GEOFENCE_ACTION")
|
|
102
114
|
val intent = Intent(applicationContext, GeofenceBroadcastReceiver::class.java).apply {
|
|
103
115
|
action = GEOFENCE_ACTION
|
|
104
116
|
setPackage(applicationContext.packageName)
|
|
@@ -116,11 +128,20 @@ class GeofenceManagerModule(reactContext: ReactApplicationContext) :
|
|
|
116
128
|
override fun getName(): String = NAME
|
|
117
129
|
|
|
118
130
|
override fun addGeofences(geofences: ReadableArray, promise: Promise) {
|
|
131
|
+
Log.i(TAG, "addGeofences: start, arraySize=${geofences.size()}")
|
|
119
132
|
try {
|
|
120
133
|
val list = mutableListOf<Geofence>()
|
|
121
134
|
for (i in 0 until geofences.size()) {
|
|
122
|
-
val item
|
|
123
|
-
|
|
135
|
+
val item = geofences.getMap(i)
|
|
136
|
+
if (item == null) {
|
|
137
|
+
Log.w(TAG, "addGeofences: index $i skipped (null map)")
|
|
138
|
+
continue
|
|
139
|
+
}
|
|
140
|
+
val id = item.getString("id")
|
|
141
|
+
if (id == null) {
|
|
142
|
+
Log.w(TAG, "addGeofences: index $i skipped (missing id)")
|
|
143
|
+
continue
|
|
144
|
+
}
|
|
124
145
|
val name = if (item.hasKey("name")) item.getString("name") else null
|
|
125
146
|
val lat = item.getDouble("latitude")
|
|
126
147
|
val lng = item.getDouble("longitude")
|
|
@@ -140,8 +161,10 @@ class GeofenceManagerModule(reactContext: ReactApplicationContext) :
|
|
|
140
161
|
)
|
|
141
162
|
.build()
|
|
142
163
|
)
|
|
164
|
+
Log.i(TAG, "addGeofences: parsed geofence id=$id lat=$lat lng=$lng radius=$radius")
|
|
143
165
|
}
|
|
144
166
|
if (list.isEmpty()) {
|
|
167
|
+
Log.e(TAG, "addGeofences: no valid geofences — resolving false (check id/latitude/longitude)")
|
|
145
168
|
promise.resolve(false)
|
|
146
169
|
return
|
|
147
170
|
}
|
|
@@ -150,15 +173,21 @@ class GeofenceManagerModule(reactContext: ReactApplicationContext) :
|
|
|
150
173
|
.setInitialTrigger(0)
|
|
151
174
|
.addGeofences(list)
|
|
152
175
|
.build()
|
|
176
|
+
Log.i(TAG, "addGeofences: calling GeofencingClient.addGeofences count=${list.size}")
|
|
153
177
|
geofencingClient.addGeofences(request, getPendingIntent())
|
|
154
178
|
.addOnSuccessListener {
|
|
155
179
|
getPrefs(applicationContext).edit()
|
|
156
180
|
.putLong(PREFS_KEY_LAST_ADD_AT, System.currentTimeMillis())
|
|
157
181
|
.apply()
|
|
182
|
+
Log.i(TAG, "addGeofences: SUCCESS — geofences registered with Play Services")
|
|
158
183
|
promise.resolve(true)
|
|
159
184
|
}
|
|
160
|
-
.addOnFailureListener {
|
|
185
|
+
.addOnFailureListener { e ->
|
|
186
|
+
Log.e(TAG, "addGeofences: FAILURE — ${e.message}", e)
|
|
187
|
+
promise.resolve(false)
|
|
188
|
+
}
|
|
161
189
|
} catch (e: Exception) {
|
|
190
|
+
Log.e(TAG, "addGeofences: exception", e)
|
|
162
191
|
promise.reject(e)
|
|
163
192
|
}
|
|
164
193
|
}
|
|
@@ -180,13 +209,20 @@ class GeofenceManagerModule(reactContext: ReactApplicationContext) :
|
|
|
180
209
|
}
|
|
181
210
|
|
|
182
211
|
override fun removeAllGeofences(promise: Promise) {
|
|
212
|
+
Log.i(TAG, "removeAllGeofences: start")
|
|
183
213
|
synchronized(GeofenceManagerModule.geofenceNames) {
|
|
184
214
|
GeofenceManagerModule.geofenceNames.clear()
|
|
185
215
|
GeofenceManagerModule.geofenceDetailsMap.clear()
|
|
186
216
|
}
|
|
187
217
|
getPrefs(applicationContext).edit().remove(PREFS_KEY_DETAILS).apply()
|
|
188
218
|
geofencingClient.removeGeofences(getPendingIntent())
|
|
189
|
-
.addOnSuccessListener {
|
|
190
|
-
|
|
219
|
+
.addOnSuccessListener {
|
|
220
|
+
Log.i(TAG, "removeAllGeofences: SUCCESS")
|
|
221
|
+
promise.resolve(true)
|
|
222
|
+
}
|
|
223
|
+
.addOnFailureListener { e ->
|
|
224
|
+
Log.e(TAG, "removeAllGeofences: FAILURE — ${e.message}", e)
|
|
225
|
+
promise.resolve(false)
|
|
226
|
+
}
|
|
191
227
|
}
|
|
192
228
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Logs de diagnóstico da lib. Aparecem no Metro e no Logcat (Android) com filtro "GeofenceManager".
|
|
5
|
+
*/
|
|
6
|
+
const TAG = '[GeofenceManager]';
|
|
7
|
+
function safeStringify(data) {
|
|
8
|
+
try {
|
|
9
|
+
return JSON.stringify(data);
|
|
10
|
+
} catch {
|
|
11
|
+
return String(data);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function geofenceDebugLog(step, data) {
|
|
15
|
+
const line = data !== undefined ? `${TAG} ${step} ${safeStringify(data)}` : `${TAG} ${step}`;
|
|
16
|
+
console.log(line);
|
|
17
|
+
}
|
|
18
|
+
export function geofenceDebugWarn(step, data) {
|
|
19
|
+
const line = data !== undefined ? `${TAG} ${step} ${safeStringify(data)}` : `${TAG} ${step}`;
|
|
20
|
+
console.warn(line);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=geofenceDebugLog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["TAG","safeStringify","data","JSON","stringify","String","geofenceDebugLog","step","line","undefined","console","log","geofenceDebugWarn","warn"],"sourceRoot":"..\\..\\src","sources":["geofenceDebugLog.ts"],"mappings":";;AAAA;AACA;AACA;AACA,MAAMA,GAAG,GAAG,mBAAmB;AAE/B,SAASC,aAAaA,CAACC,IAAa,EAAU;EAC5C,IAAI;IACF,OAAOC,IAAI,CAACC,SAAS,CAACF,IAAI,CAAC;EAC7B,CAAC,CAAC,MAAM;IACN,OAAOG,MAAM,CAACH,IAAI,CAAC;EACrB;AACF;AAEA,OAAO,SAASI,gBAAgBA,CAACC,IAAY,EAAEL,IAAc,EAAQ;EACnE,MAAMM,IAAI,GACRN,IAAI,KAAKO,SAAS,GACd,GAAGT,GAAG,IAAIO,IAAI,IAAIN,aAAa,CAACC,IAAI,CAAC,EAAE,GACvC,GAAGF,GAAG,IAAIO,IAAI,EAAE;EACtBG,OAAO,CAACC,GAAG,CAACH,IAAI,CAAC;AACnB;AAEA,OAAO,SAASI,iBAAiBA,CAACL,IAAY,EAAEL,IAAc,EAAQ;EACpE,MAAMM,IAAI,GACRN,IAAI,KAAKO,SAAS,GACd,GAAGT,GAAG,IAAIO,IAAI,IAAIN,aAAa,CAACC,IAAI,CAAC,EAAE,GACvC,GAAGF,GAAG,IAAIO,IAAI,EAAE;EACtBG,OAAO,CAACG,IAAI,CAACL,IAAI,CAAC;AACpB","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -2,13 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
import { AppRegistry, DeviceEventEmitter } from 'react-native';
|
|
4
4
|
import NativeGeofenceManager from "./NativeGeofenceManager.js";
|
|
5
|
+
import { geofenceDebugLog, geofenceDebugWarn } from "./geofenceDebugLog.js";
|
|
5
6
|
const EVENT_NAME = 'onGeofenceTransition';
|
|
6
7
|
|
|
7
8
|
/** Nome da headless task para eventos de geofence (app morto/background). Deve ser usado com registerGeofenceHeadlessTask no index do app. */
|
|
8
9
|
export const GEOFENCE_HEADLESS_TASK_NAME = 'GeofenceManagerTransition';
|
|
9
10
|
export function addGeofenceEventListener(callback) {
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
geofenceDebugLog('JS: addGeofenceEventListener — registering listener', {
|
|
12
|
+
eventName: EVENT_NAME
|
|
13
|
+
});
|
|
14
|
+
const subscription = DeviceEventEmitter.addListener(EVENT_NAME, payload => {
|
|
15
|
+
geofenceDebugLog('JS: addGeofenceEventListener — event received', payload);
|
|
16
|
+
callback(payload);
|
|
17
|
+
});
|
|
18
|
+
return () => {
|
|
19
|
+
geofenceDebugLog('JS: addGeofenceEventListener — unsubscribed');
|
|
20
|
+
subscription.remove();
|
|
21
|
+
};
|
|
12
22
|
}
|
|
13
23
|
export function onGeofenceEvent(callback) {
|
|
14
24
|
return addGeofenceEventListener(callback);
|
|
@@ -32,13 +42,45 @@ export function onGeofenceEvent(callback) {
|
|
|
32
42
|
* AppRegistry.registerComponent(appName, () => App);
|
|
33
43
|
*/
|
|
34
44
|
export function registerGeofenceHeadlessTask(callback) {
|
|
35
|
-
|
|
45
|
+
geofenceDebugLog('JS: registerGeofenceHeadlessTask — registering', {
|
|
46
|
+
taskName: GEOFENCE_HEADLESS_TASK_NAME
|
|
47
|
+
});
|
|
48
|
+
AppRegistry.registerHeadlessTask(GEOFENCE_HEADLESS_TASK_NAME, () => data => {
|
|
49
|
+
geofenceDebugLog('JS: headless task invoked', data);
|
|
50
|
+
return Promise.resolve(callback(data));
|
|
51
|
+
});
|
|
36
52
|
}
|
|
37
|
-
const addGeofences = geofences => {
|
|
38
|
-
|
|
53
|
+
const addGeofences = async geofences => {
|
|
54
|
+
geofenceDebugLog('JS: addGeofences — calling native', {
|
|
55
|
+
count: geofences.length,
|
|
56
|
+
ids: geofences.map(g => g.id)
|
|
57
|
+
});
|
|
58
|
+
try {
|
|
59
|
+
const ok = await NativeGeofenceManager.addGeofences(geofences);
|
|
60
|
+
geofenceDebugLog('JS: addGeofences — native result', {
|
|
61
|
+
success: ok
|
|
62
|
+
});
|
|
63
|
+
if (!ok) {
|
|
64
|
+
geofenceDebugWarn('JS: addGeofences — native returned false (empty list, Geofencing API failure, or permissions)');
|
|
65
|
+
}
|
|
66
|
+
return ok;
|
|
67
|
+
} catch (e) {
|
|
68
|
+
geofenceDebugWarn('JS: addGeofences — threw (TurboModule missing or bridge error)', e);
|
|
69
|
+
throw e;
|
|
70
|
+
}
|
|
39
71
|
};
|
|
40
|
-
const removeAllGeofences = () => {
|
|
41
|
-
|
|
72
|
+
const removeAllGeofences = async () => {
|
|
73
|
+
geofenceDebugLog('JS: removeAllGeofences — calling native');
|
|
74
|
+
try {
|
|
75
|
+
const ok = await NativeGeofenceManager.removeAllGeofences();
|
|
76
|
+
geofenceDebugLog('JS: removeAllGeofences — native result', {
|
|
77
|
+
success: ok
|
|
78
|
+
});
|
|
79
|
+
return ok;
|
|
80
|
+
} catch (e) {
|
|
81
|
+
geofenceDebugWarn('JS: removeAllGeofences — threw', e);
|
|
82
|
+
throw e;
|
|
83
|
+
}
|
|
42
84
|
};
|
|
43
85
|
export { addGeofences, removeAllGeofences };
|
|
44
86
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["AppRegistry","DeviceEventEmitter","NativeGeofenceManager","EVENT_NAME","GEOFENCE_HEADLESS_TASK_NAME","addGeofenceEventListener","callback","subscription","addListener","payload","remove","onGeofenceEvent","registerGeofenceHeadlessTask","registerHeadlessTask","data","Promise","resolve","addGeofences","geofences","removeAllGeofences"],"sourceRoot":"..\\..\\src","sources":["index.tsx"],"mappings":";;AAAA,SACEA,WAAW,EACXC,kBAAkB,QAEb,cAAc;AACrB,OAAOC,qBAAqB,MAAM,4BAAyB;
|
|
1
|
+
{"version":3,"names":["AppRegistry","DeviceEventEmitter","NativeGeofenceManager","geofenceDebugLog","geofenceDebugWarn","EVENT_NAME","GEOFENCE_HEADLESS_TASK_NAME","addGeofenceEventListener","callback","eventName","subscription","addListener","payload","remove","onGeofenceEvent","registerGeofenceHeadlessTask","taskName","registerHeadlessTask","data","Promise","resolve","addGeofences","geofences","count","length","ids","map","g","id","ok","success","e","removeAllGeofences"],"sourceRoot":"..\\..\\src","sources":["index.tsx"],"mappings":";;AAAA,SACEA,WAAW,EACXC,kBAAkB,QAEb,cAAc;AACrB,OAAOC,qBAAqB,MAAM,4BAAyB;AAC3D,SAASC,gBAAgB,EAAEC,iBAAiB,QAAQ,uBAAoB;AASxE,MAAMC,UAAU,GAAG,sBAAsB;;AAEzC;AACA,OAAO,MAAMC,2BAA2B,GAAG,2BAA2B;AAEtE,OAAO,SAASC,wBAAwBA,CACtCC,QAAwC,EAC5B;EACZL,gBAAgB,CAAC,qDAAqD,EAAE;IACtEM,SAAS,EAAEJ;EACb,CAAC,CAAC;EACF,MAAMK,YAA+B,GAAGT,kBAAkB,CAACU,WAAW,CACpEN,UAAU,EACTO,OAAgB,IAAK;IACpBT,gBAAgB,CAAC,+CAA+C,EAAES,OAAO,CAAC;IAC1EJ,QAAQ,CAACI,OAAwB,CAAC;EACpC,CACF,CAAC;EACD,OAAO,MAAM;IACXT,gBAAgB,CAAC,6CAA6C,CAAC;IAC/DO,YAAY,CAACG,MAAM,CAAC,CAAC;EACvB,CAAC;AACH;AAEA,OAAO,SAASC,eAAeA,CAC7BN,QAAwC,EAC5B;EACZ,OAAOD,wBAAwB,CAACC,QAAQ,CAAC;AAC3C;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASO,4BAA4BA,CAC1CP,QAAwC,EAClC;EACNL,gBAAgB,CAAC,gDAAgD,EAAE;IACjEa,QAAQ,EAAEV;EACZ,CAAC,CAAC;EACFN,WAAW,CAACiB,oBAAoB,CAC9BX,2BAA2B,EAC3B,MAAOY,IAAa,IAAK;IACvBf,gBAAgB,CAAC,2BAA2B,EAAEe,IAAI,CAAC;IACnD,OAAOC,OAAO,CAACC,OAAO,CAACZ,QAAQ,CAACU,IAAqB,CAAC,CAAC;EACzD,CACF,CAAC;AACH;AAEA,MAAMG,YAAY,GAAG,MACnBC,SAA0B,IACL;EACrBnB,gBAAgB,CAAC,mCAAmC,EAAE;IACpDoB,KAAK,EAAED,SAAS,CAACE,MAAM;IACvBC,GAAG,EAAEH,SAAS,CAACI,GAAG,CAAEC,CAAC,IAAKA,CAAC,CAACC,EAAE;EAChC,CAAC,CAAC;EACF,IAAI;IACF,MAAMC,EAAE,GAAG,MAAM3B,qBAAqB,CAACmB,YAAY,CAACC,SAAS,CAAC;IAC9DnB,gBAAgB,CAAC,kCAAkC,EAAE;MAAE2B,OAAO,EAAED;IAAG,CAAC,CAAC;IACrE,IAAI,CAACA,EAAE,EAAE;MACPzB,iBAAiB,CACf,+FACF,CAAC;IACH;IACA,OAAOyB,EAAE;EACX,CAAC,CAAC,OAAOE,CAAC,EAAE;IACV3B,iBAAiB,CAAC,gEAAgE,EAAE2B,CAAC,CAAC;IACtF,MAAMA,CAAC;EACT;AACF,CAAC;AAED,MAAMC,kBAAkB,GAAG,MAAAA,CAAA,KAA8B;EACvD7B,gBAAgB,CAAC,yCAAyC,CAAC;EAC3D,IAAI;IACF,MAAM0B,EAAE,GAAG,MAAM3B,qBAAqB,CAAC8B,kBAAkB,CAAC,CAAC;IAC3D7B,gBAAgB,CAAC,wCAAwC,EAAE;MAAE2B,OAAO,EAAED;IAAG,CAAC,CAAC;IAC3E,OAAOA,EAAE;EACX,CAAC,CAAC,OAAOE,CAAC,EAAE;IACV3B,iBAAiB,CAAC,gCAAgC,EAAE2B,CAAC,CAAC;IACtD,MAAMA,CAAC;EACT;AACF,CAAC;AAED,SAASV,YAAY,EAAEW,kBAAkB","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geofenceDebugLog.d.ts","sourceRoot":"","sources":["../../../src/geofenceDebugLog.ts"],"names":[],"mappings":"AAaA,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAMnE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAMpE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEnE,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,aAAa,GACd,MAAM,gBAAgB,CAAC;AAIxB,8IAA8I;AAC9I,eAAO,MAAM,2BAA2B,8BAA8B,CAAC;AAEvE,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,GACvC,MAAM,IAAI,CAeZ;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,GACvC,MAAM,IAAI,CAEZ;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,GACvC,IAAI,CAWN;AAED,QAAA,MAAM,YAAY,GAChB,WAAW,aAAa,EAAE,KACzB,OAAO,CAAC,OAAO,CAkBjB,CAAC;AAEF,QAAA,MAAM,kBAAkB,QAAa,OAAO,CAAC,OAAO,CAUnD,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logs de diagnóstico da lib. Aparecem no Metro e no Logcat (Android) com filtro "GeofenceManager".
|
|
3
|
+
*/
|
|
4
|
+
const TAG = '[GeofenceManager]';
|
|
5
|
+
|
|
6
|
+
function safeStringify(data: unknown): string {
|
|
7
|
+
try {
|
|
8
|
+
return JSON.stringify(data);
|
|
9
|
+
} catch {
|
|
10
|
+
return String(data);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function geofenceDebugLog(step: string, data?: unknown): void {
|
|
15
|
+
const line =
|
|
16
|
+
data !== undefined
|
|
17
|
+
? `${TAG} ${step} ${safeStringify(data)}`
|
|
18
|
+
: `${TAG} ${step}`;
|
|
19
|
+
console.log(line);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function geofenceDebugWarn(step: string, data?: unknown): void {
|
|
23
|
+
const line =
|
|
24
|
+
data !== undefined
|
|
25
|
+
? `${TAG} ${step} ${safeStringify(data)}`
|
|
26
|
+
: `${TAG} ${step}`;
|
|
27
|
+
console.warn(line);
|
|
28
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
type EventSubscription,
|
|
5
5
|
} from 'react-native';
|
|
6
6
|
import NativeGeofenceManager from './NativeGeofenceManager';
|
|
7
|
+
import { geofenceDebugLog, geofenceDebugWarn } from './geofenceDebugLog';
|
|
7
8
|
import type { GeofenceEvent, GeofenceModel } from './models/index';
|
|
8
9
|
|
|
9
10
|
export type {
|
|
@@ -20,11 +21,20 @@ export const GEOFENCE_HEADLESS_TASK_NAME = 'GeofenceManagerTransition';
|
|
|
20
21
|
export function addGeofenceEventListener(
|
|
21
22
|
callback: (event: GeofenceEvent) => void
|
|
22
23
|
): () => void {
|
|
24
|
+
geofenceDebugLog('JS: addGeofenceEventListener — registering listener', {
|
|
25
|
+
eventName: EVENT_NAME,
|
|
26
|
+
});
|
|
23
27
|
const subscription: EventSubscription = DeviceEventEmitter.addListener(
|
|
24
28
|
EVENT_NAME,
|
|
25
|
-
(payload: unknown) =>
|
|
29
|
+
(payload: unknown) => {
|
|
30
|
+
geofenceDebugLog('JS: addGeofenceEventListener — event received', payload);
|
|
31
|
+
callback(payload as GeofenceEvent);
|
|
32
|
+
}
|
|
26
33
|
);
|
|
27
|
-
return () =>
|
|
34
|
+
return () => {
|
|
35
|
+
geofenceDebugLog('JS: addGeofenceEventListener — unsubscribed');
|
|
36
|
+
subscription.remove();
|
|
37
|
+
};
|
|
28
38
|
}
|
|
29
39
|
|
|
30
40
|
export function onGeofenceEvent(
|
|
@@ -53,18 +63,50 @@ export function onGeofenceEvent(
|
|
|
53
63
|
export function registerGeofenceHeadlessTask(
|
|
54
64
|
callback: (event: GeofenceEvent) => void
|
|
55
65
|
): void {
|
|
66
|
+
geofenceDebugLog('JS: registerGeofenceHeadlessTask — registering', {
|
|
67
|
+
taskName: GEOFENCE_HEADLESS_TASK_NAME,
|
|
68
|
+
});
|
|
56
69
|
AppRegistry.registerHeadlessTask(
|
|
57
70
|
GEOFENCE_HEADLESS_TASK_NAME,
|
|
58
|
-
() => (data: unknown) =>
|
|
71
|
+
() => (data: unknown) => {
|
|
72
|
+
geofenceDebugLog('JS: headless task invoked', data);
|
|
73
|
+
return Promise.resolve(callback(data as GeofenceEvent));
|
|
74
|
+
}
|
|
59
75
|
);
|
|
60
76
|
}
|
|
61
77
|
|
|
62
|
-
const addGeofences = (
|
|
63
|
-
|
|
78
|
+
const addGeofences = async (
|
|
79
|
+
geofences: GeofenceModel[]
|
|
80
|
+
): Promise<boolean> => {
|
|
81
|
+
geofenceDebugLog('JS: addGeofences — calling native', {
|
|
82
|
+
count: geofences.length,
|
|
83
|
+
ids: geofences.map((g) => g.id),
|
|
84
|
+
});
|
|
85
|
+
try {
|
|
86
|
+
const ok = await NativeGeofenceManager.addGeofences(geofences);
|
|
87
|
+
geofenceDebugLog('JS: addGeofences — native result', { success: ok });
|
|
88
|
+
if (!ok) {
|
|
89
|
+
geofenceDebugWarn(
|
|
90
|
+
'JS: addGeofences — native returned false (empty list, Geofencing API failure, or permissions)'
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
return ok;
|
|
94
|
+
} catch (e) {
|
|
95
|
+
geofenceDebugWarn('JS: addGeofences — threw (TurboModule missing or bridge error)', e);
|
|
96
|
+
throw e;
|
|
97
|
+
}
|
|
64
98
|
};
|
|
65
99
|
|
|
66
|
-
const removeAllGeofences = (): Promise<boolean> => {
|
|
67
|
-
|
|
100
|
+
const removeAllGeofences = async (): Promise<boolean> => {
|
|
101
|
+
geofenceDebugLog('JS: removeAllGeofences — calling native');
|
|
102
|
+
try {
|
|
103
|
+
const ok = await NativeGeofenceManager.removeAllGeofences();
|
|
104
|
+
geofenceDebugLog('JS: removeAllGeofences — native result', { success: ok });
|
|
105
|
+
return ok;
|
|
106
|
+
} catch (e) {
|
|
107
|
+
geofenceDebugWarn('JS: removeAllGeofences — threw', e);
|
|
108
|
+
throw e;
|
|
109
|
+
}
|
|
68
110
|
};
|
|
69
111
|
|
|
70
112
|
export { addGeofences, removeAllGeofences };
|