react-native-geofence-manager 0.1.0-beta.11 → 0.1.0-beta.13
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 +173 -37
- package/android/src/main/AndroidManifest.xml +17 -16
- package/android/src/main/java/com/geofencemanager/GeofenceBroadcastReceiver.kt +133 -0
- package/android/src/main/java/com/geofencemanager/GeofenceHeadlessTaskService.kt +98 -141
- package/android/src/main/java/com/geofencemanager/GeofenceManagerModule.kt +187 -154
- package/ios/GeofenceManager.mm +21 -21
- package/lib/module/NativeGeofenceManager.js +1 -7
- package/lib/module/NativeGeofenceManager.js.map +1 -1
- package/lib/module/geofenceDebugLog.js +22 -0
- package/lib/module/geofenceDebugLog.js.map +1 -0
- package/lib/module/index.js +79 -35
- package/lib/module/index.js.map +1 -1
- package/lib/module/models/GeofenceEvent.js +4 -0
- package/lib/module/models/GeofenceEvent.js.map +1 -0
- package/lib/module/models/GeofenceEventType.js +2 -0
- package/lib/module/models/GeofenceEventType.js.map +1 -0
- package/lib/module/models/GeofenceModel.js +2 -0
- package/lib/module/models/GeofenceModel.js.map +1 -0
- package/lib/module/models/index.js +6 -0
- package/lib/module/models/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeGeofenceManager.d.ts +3 -16
- package/lib/typescript/src/NativeGeofenceManager.d.ts.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 +27 -26
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/models/GeofenceEvent.d.ts +11 -0
- package/lib/typescript/src/models/GeofenceEvent.d.ts.map +1 -0
- package/lib/typescript/src/models/GeofenceEventType.d.ts +2 -0
- package/lib/typescript/src/models/GeofenceEventType.d.ts.map +1 -0
- package/lib/typescript/src/models/GeofenceModel.d.ts +8 -0
- package/lib/typescript/src/models/GeofenceModel.d.ts.map +1 -0
- package/lib/typescript/src/models/index.d.ts +4 -0
- package/lib/typescript/src/models/index.d.ts.map +1 -0
- package/package.json +16 -15
- package/src/NativeGeofenceManager.ts +4 -29
- package/src/geofenceDebugLog.ts +28 -0
- package/src/index.tsx +99 -71
- package/src/models/GeofenceEvent.ts +11 -0
- package/src/models/GeofenceEventType.ts +1 -0
- package/src/models/GeofenceModel.ts +7 -0
- package/src/models/index.ts +3 -0
- package/android/src/main/java/com/geofencemanager/GeofenceReceiver.kt +0 -192
- package/android/src/main/java/com/geofencemanager/RegionManager.kt +0 -387
- package/lib/commonjs/NativeGeofenceManager.js +0 -15
- package/lib/commonjs/NativeGeofenceManager.js.map +0 -1
- package/lib/commonjs/index.js +0 -47
- package/lib/commonjs/index.js.map +0 -1
- package/lib/commonjs/package.json +0 -1
- package/react-native.config.js +0 -11
|
@@ -1,193 +1,226 @@
|
|
|
1
1
|
package com.geofencemanager
|
|
2
2
|
|
|
3
|
+
import android.app.PendingIntent
|
|
4
|
+
import android.content.ComponentName
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.content.Intent
|
|
7
|
+
import android.content.SharedPreferences
|
|
3
8
|
import android.util.Log
|
|
4
|
-
import com.facebook.react.bridge.Arguments
|
|
5
|
-
import com.facebook.react.bridge.LifecycleEventListener
|
|
6
9
|
import com.facebook.react.bridge.Promise
|
|
7
10
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
8
11
|
import com.facebook.react.bridge.ReadableArray
|
|
9
12
|
import com.facebook.react.bridge.ReadableMap
|
|
10
|
-
import com.
|
|
13
|
+
import com.google.android.gms.location.Geofence
|
|
14
|
+
import com.google.android.gms.location.GeofencingClient
|
|
15
|
+
import com.google.android.gms.location.GeofencingRequest
|
|
16
|
+
import com.google.android.gms.location.LocationServices
|
|
17
|
+
import org.json.JSONArray
|
|
18
|
+
import org.json.JSONObject
|
|
11
19
|
|
|
12
20
|
class GeofenceManagerModule(reactContext: ReactApplicationContext) :
|
|
13
|
-
NativeGeofenceManagerSpec(reactContext)
|
|
21
|
+
NativeGeofenceManagerSpec(reactContext) {
|
|
14
22
|
|
|
15
23
|
companion object {
|
|
24
|
+
private const val TAG = "GeofenceManager"
|
|
16
25
|
const val NAME = "GeofenceManager"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
const val GEOFENCE_ACTION = "com.geofencemanager.GEOFENCE_TRANSITION"
|
|
27
|
+
const val GEOFENCE_HEADLESS_TASK_NAME = "GeofenceManagerTransition"
|
|
28
|
+
private const val GEOFENCE_REQUEST_CODE = 12345
|
|
29
|
+
private const val PREFS_NAME = "GeofenceManagerPrefs"
|
|
30
|
+
private const val PREFS_KEY_DETAILS = "geofence_details"
|
|
31
|
+
private const val PREFS_KEY_LAST_ADD_AT = "geofence_last_add_at"
|
|
32
|
+
private const val GRACE_PERIOD_MS = 90_000L
|
|
33
|
+
|
|
34
|
+
fun isWithinGracePeriod(context: Context): Boolean {
|
|
35
|
+
val lastAdd = getPrefs(context).getLong(PREFS_KEY_LAST_ADD_AT, 0L)
|
|
36
|
+
if (lastAdd == 0L) return false
|
|
37
|
+
return System.currentTimeMillis() - lastAdd < GRACE_PERIOD_MS
|
|
38
|
+
}
|
|
20
39
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
40
|
+
@Volatile
|
|
41
|
+
var reactContextRef: ReactApplicationContext? = null
|
|
42
|
+
|
|
43
|
+
private val geofenceNames = mutableMapOf<String, String>()
|
|
44
|
+
private val geofenceDetailsMap = mutableMapOf<String, GeofenceDetails>()
|
|
45
|
+
|
|
46
|
+
data class GeofenceDetails(
|
|
47
|
+
val id: String,
|
|
48
|
+
val name: String?,
|
|
49
|
+
val latitude: Double,
|
|
50
|
+
val longitude: Double,
|
|
51
|
+
val radius: Float
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
private fun getPrefs(context: Context): SharedPreferences =
|
|
55
|
+
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
56
|
+
|
|
57
|
+
private fun loadDetailsFromPrefs(context: Context) {
|
|
58
|
+
synchronized(geofenceDetailsMap) {
|
|
59
|
+
if (geofenceDetailsMap.isNotEmpty()) return@synchronized
|
|
60
|
+
val json = getPrefs(context).getString(PREFS_KEY_DETAILS, null) ?: return@synchronized
|
|
61
|
+
try {
|
|
62
|
+
val arr = JSONArray(json)
|
|
63
|
+
for (i in 0 until arr.length()) {
|
|
64
|
+
val o = arr.getJSONObject(i)
|
|
65
|
+
val d = GeofenceDetails(
|
|
66
|
+
id = o.getString("id"),
|
|
67
|
+
name = if (o.has("name")) o.optString("name").takeIf { it.isNotEmpty() } else null,
|
|
68
|
+
latitude = o.getDouble("latitude"),
|
|
69
|
+
longitude = o.getDouble("longitude"),
|
|
70
|
+
radius = o.getDouble("radius").toFloat()
|
|
71
|
+
)
|
|
72
|
+
geofenceDetailsMap[d.id] = d
|
|
73
|
+
d.name?.let { geofenceNames[d.id] = it }
|
|
74
|
+
}
|
|
75
|
+
} catch (e: Exception) {
|
|
76
|
+
Log.w(TAG, "loadDetailsFromPrefs failed", e)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
29
80
|
|
|
30
|
-
|
|
81
|
+
fun getGeofenceName(id: String): String? = geofenceNames[id]
|
|
31
82
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
83
|
+
fun getGeofenceDetails(context: Context, id: String): GeofenceDetails? {
|
|
84
|
+
geofenceDetailsMap[id]?.let { return it }
|
|
85
|
+
loadDetailsFromPrefs(context)
|
|
86
|
+
return geofenceDetailsMap[id]
|
|
87
|
+
}
|
|
36
88
|
}
|
|
37
89
|
|
|
38
|
-
|
|
39
|
-
Log.
|
|
90
|
+
init {
|
|
91
|
+
Log.i(TAG, "Module init: package=${reactContext.packageName} hasActivity=${reactContext.currentActivity != null}")
|
|
92
|
+
// Só guardar o contexto que tem Activity (tela principal). O contexto da headless task
|
|
93
|
+
// não tem currentActivity; se o armazenarmos, os eventos em foreground (dwell/exit)
|
|
94
|
+
// seriam emitidos para ele e o listener registrado na tela nunca receberia.
|
|
95
|
+
if (reactContext.currentActivity != null) {
|
|
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)")
|
|
100
|
+
}
|
|
40
101
|
}
|
|
41
102
|
|
|
42
|
-
|
|
43
|
-
|
|
103
|
+
private val applicationContext: Context = reactContext.applicationContext
|
|
104
|
+
private val geofencingClient: GeofencingClient =
|
|
105
|
+
LocationServices.getGeofencingClient(applicationContext)
|
|
106
|
+
private var geofencePendingIntent: PendingIntent? = null
|
|
107
|
+
|
|
108
|
+
private fun getPendingIntent(): PendingIntent {
|
|
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")
|
|
114
|
+
val intent = Intent(applicationContext, GeofenceBroadcastReceiver::class.java).apply {
|
|
115
|
+
action = GEOFENCE_ACTION
|
|
116
|
+
setPackage(applicationContext.packageName)
|
|
117
|
+
component = ComponentName(applicationContext, GeofenceBroadcastReceiver::class.java)
|
|
118
|
+
}
|
|
119
|
+
geofencePendingIntent = PendingIntent.getBroadcast(
|
|
120
|
+
applicationContext,
|
|
121
|
+
GEOFENCE_REQUEST_CODE,
|
|
122
|
+
intent,
|
|
123
|
+
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
|
|
124
|
+
)
|
|
125
|
+
return geofencePendingIntent!!
|
|
44
126
|
}
|
|
45
127
|
|
|
46
|
-
override fun
|
|
47
|
-
Log.d(TAG, "════════════════════════════════════════")
|
|
48
|
-
Log.d(TAG, "▶️ START() CHAMADO")
|
|
49
|
-
Log.d(TAG, "════════════════════════════════════════")
|
|
50
|
-
Log.d(TAG, "📊 Parâmetros recebidos:")
|
|
51
|
-
Log.d(TAG, " └─ Quantidade de regiões: ${regions.size()}")
|
|
52
|
-
Log.d(TAG, " └─ Options: $options")
|
|
128
|
+
override fun getName(): String = NAME
|
|
53
129
|
|
|
130
|
+
override fun addGeofences(geofences: ReadableArray, promise: Promise) {
|
|
131
|
+
Log.i(TAG, "addGeofences: start, arraySize=${geofences.size()}")
|
|
54
132
|
try {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
133
|
+
val list = mutableListOf<Geofence>()
|
|
134
|
+
for (i in 0 until geofences.size()) {
|
|
135
|
+
val item: ReadableMap = geofences.getMap(i) ?: run {
|
|
136
|
+
Log.w(TAG, "addGeofences: index $i skipped (null map)")
|
|
137
|
+
continue
|
|
138
|
+
}
|
|
139
|
+
val id = item.getString("id") ?: run {
|
|
140
|
+
Log.w(TAG, "addGeofences: index $i skipped (missing id)")
|
|
141
|
+
continue
|
|
142
|
+
}
|
|
143
|
+
val name = if (item.hasKey("name")) item.getString("name") else null
|
|
144
|
+
val lat = item.getDouble("latitude")
|
|
145
|
+
val lng = item.getDouble("longitude")
|
|
146
|
+
val radius = if (item.hasKey("radius")) item.getDouble("radius").toFloat() else 100f
|
|
147
|
+
synchronized(GeofenceManagerModule.geofenceNames) {
|
|
148
|
+
if (name != null) GeofenceManagerModule.geofenceNames[id] = name
|
|
149
|
+
GeofenceManagerModule.geofenceDetailsMap[id] = GeofenceDetails(id, name, lat, lng, radius)
|
|
150
|
+
}
|
|
151
|
+
list.add(
|
|
152
|
+
Geofence.Builder()
|
|
153
|
+
.setRequestId(id)
|
|
154
|
+
.setCircularRegion(lat, lng, radius)
|
|
155
|
+
.setExpirationDuration(Geofence.NEVER_EXPIRE)
|
|
156
|
+
.setLoiteringDelay(30_000)
|
|
157
|
+
.setTransitionTypes(
|
|
158
|
+
Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT or Geofence.GEOFENCE_TRANSITION_DWELL
|
|
159
|
+
)
|
|
160
|
+
.build()
|
|
62
161
|
)
|
|
63
|
-
|
|
162
|
+
Log.i(TAG, "addGeofences: parsed geofence id=$id lat=$lat lng=$lng radius=$radius")
|
|
64
163
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
Log.d(TAG, "⚙️ Configurações:")
|
|
71
|
-
Log.d(TAG, " └─ dwellDelay: ${dwellDelay}ms")
|
|
72
|
-
Log.d(TAG, " └─ headlessTaskTimeout: ${headlessTaskTimeout}ms")
|
|
73
|
-
Log.d(TAG, "📍 Regiões parseadas: ${regionList.size}")
|
|
74
|
-
regionList.forEachIndexed { index, region ->
|
|
75
|
-
Log.d(TAG, " └─ [$index] id=${region.id}, name=${region.name}")
|
|
76
|
-
Log.d(TAG, " └─ lat=${region.latitude}, lng=${region.longitude}, radius=${region.radius}m")
|
|
164
|
+
if (list.isEmpty()) {
|
|
165
|
+
Log.e(TAG, "addGeofences: no valid geofences — resolving false (check id/latitude/longitude)")
|
|
166
|
+
promise.resolve(false)
|
|
167
|
+
return
|
|
77
168
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
169
|
+
saveDetailsToPrefs(applicationContext)
|
|
170
|
+
val request = GeofencingRequest.Builder()
|
|
171
|
+
.setInitialTrigger(0)
|
|
172
|
+
.addGeofences(list)
|
|
173
|
+
.build()
|
|
174
|
+
Log.i(TAG, "addGeofences: calling GeofencingClient.addGeofences count=${list.size}")
|
|
175
|
+
geofencingClient.addGeofences(request, getPendingIntent())
|
|
176
|
+
.addOnSuccessListener {
|
|
177
|
+
getPrefs(applicationContext).edit()
|
|
178
|
+
.putLong(PREFS_KEY_LAST_ADD_AT, System.currentTimeMillis())
|
|
179
|
+
.apply()
|
|
180
|
+
Log.i(TAG, "addGeofences: SUCCESS — geofences registered with Play Services")
|
|
181
|
+
promise.resolve(true)
|
|
182
|
+
}
|
|
183
|
+
.addOnFailureListener { e ->
|
|
184
|
+
Log.e(TAG, "addGeofences: FAILURE — ${e.message}", e)
|
|
185
|
+
promise.resolve(false)
|
|
94
186
|
}
|
|
95
|
-
)
|
|
96
187
|
} catch (e: Exception) {
|
|
97
|
-
Log.e(TAG, "
|
|
98
|
-
|
|
99
|
-
Log.e(TAG, " └─ StackTrace: ${e.stackTraceToString()}")
|
|
100
|
-
promise.reject("GEOFENCE_ERROR", e.message)
|
|
188
|
+
Log.e(TAG, "addGeofences: exception", e)
|
|
189
|
+
promise.reject(e)
|
|
101
190
|
}
|
|
102
191
|
}
|
|
103
192
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
promise.reject("GEOFENCE_ERROR", e.message)
|
|
193
|
+
private fun saveDetailsToPrefs(context: Context) {
|
|
194
|
+
synchronized(GeofenceManagerModule.geofenceDetailsMap) {
|
|
195
|
+
val arr = JSONArray()
|
|
196
|
+
GeofenceManagerModule.geofenceDetailsMap.values.forEach { d ->
|
|
197
|
+
arr.put(JSONObject().apply {
|
|
198
|
+
put("id", d.id)
|
|
199
|
+
put("name", d.name ?: "")
|
|
200
|
+
put("latitude", d.latitude)
|
|
201
|
+
put("longitude", d.longitude)
|
|
202
|
+
put("radius", d.radius.toDouble())
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
getPrefs(context).edit().putString(PREFS_KEY_DETAILS, arr.toString()).apply()
|
|
118
206
|
}
|
|
119
207
|
}
|
|
120
208
|
|
|
121
|
-
override fun
|
|
122
|
-
Log.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
val active = RegionManager.isActive(reactApplicationContext)
|
|
127
|
-
Log.d(TAG, "📊 Resultado: active=$active")
|
|
128
|
-
Log.d(TAG, "✅ IS_ACTIVE() SUCESSO - Promise resolvida")
|
|
129
|
-
promise.resolve(active)
|
|
130
|
-
} catch (e: Exception) {
|
|
131
|
-
Log.e(TAG, "💥 EXCEÇÃO em isActive():")
|
|
132
|
-
Log.e(TAG, " └─ Message: ${e.message}")
|
|
133
|
-
promise.reject("GEOFENCE_ERROR", e.message)
|
|
209
|
+
override fun removeAllGeofences(promise: Promise) {
|
|
210
|
+
Log.i(TAG, "removeAllGeofences: start")
|
|
211
|
+
synchronized(GeofenceManagerModule.geofenceNames) {
|
|
212
|
+
GeofenceManagerModule.geofenceNames.clear()
|
|
213
|
+
GeofenceManagerModule.geofenceDetailsMap.clear()
|
|
134
214
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
Log.d(TAG, "════════════════════════════════════════")
|
|
141
|
-
try {
|
|
142
|
-
val regions = RegionManager.getRegions(reactApplicationContext)
|
|
143
|
-
Log.d(TAG, "📊 Encontradas ${regions.size} região(ões) ativas")
|
|
144
|
-
|
|
145
|
-
val result: WritableArray = Arguments.createArray()
|
|
146
|
-
|
|
147
|
-
for (region in regions) {
|
|
148
|
-
Log.d(TAG, " └─ id=${region.id}, name=${region.name}")
|
|
149
|
-
Log.d(TAG, " └─ lat=${region.latitude}, lng=${region.longitude}, radius=${region.radius}m")
|
|
150
|
-
val map = Arguments.createMap().apply {
|
|
151
|
-
putString("id", region.id)
|
|
152
|
-
putString("name", region.name)
|
|
153
|
-
putString("data", region.data)
|
|
154
|
-
putDouble("latitude", region.latitude)
|
|
155
|
-
putDouble("longitude", region.longitude)
|
|
156
|
-
putDouble("radius", region.radius.toDouble())
|
|
157
|
-
}
|
|
158
|
-
result.pushMap(map)
|
|
215
|
+
getPrefs(applicationContext).edit().remove(PREFS_KEY_DETAILS).apply()
|
|
216
|
+
geofencingClient.removeGeofences(getPendingIntent())
|
|
217
|
+
.addOnSuccessListener {
|
|
218
|
+
Log.i(TAG, "removeAllGeofences: SUCCESS")
|
|
219
|
+
promise.resolve(true)
|
|
159
220
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
} catch (e: Exception) {
|
|
164
|
-
Log.e(TAG, "💥 EXCEÇÃO em getActiveRegions():")
|
|
165
|
-
Log.e(TAG, " └─ Message: ${e.message}")
|
|
166
|
-
promise.reject("GEOFENCE_ERROR", e.message)
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
private fun parseRegions(regions: ReadableArray): List<Region> {
|
|
171
|
-
Log.d(TAG, "🔧 parseRegions() - Parseando ${regions.size()} regiões...")
|
|
172
|
-
val list = mutableListOf<Region>()
|
|
173
|
-
for (i in 0 until regions.size()) {
|
|
174
|
-
val map = regions.getMap(i)
|
|
175
|
-
if (map == null) {
|
|
176
|
-
Log.w(TAG, " └─ [$i] IGNORADA - map é null")
|
|
177
|
-
continue
|
|
221
|
+
.addOnFailureListener { e ->
|
|
222
|
+
Log.e(TAG, "removeAllGeofences: FAILURE — ${e.message}", e)
|
|
223
|
+
promise.resolve(false)
|
|
178
224
|
}
|
|
179
|
-
val region = Region(
|
|
180
|
-
id = map.getString("id") ?: "region_$i",
|
|
181
|
-
name = map.getString("name") ?: "",
|
|
182
|
-
data = map.getString("data") ?: "",
|
|
183
|
-
latitude = map.getDouble("latitude"),
|
|
184
|
-
longitude = map.getDouble("longitude"),
|
|
185
|
-
radius = map.takeIf { it.hasKey("radius") }?.getDouble("radius")?.toFloat() ?: 100f
|
|
186
|
-
)
|
|
187
|
-
Log.d(TAG, " └─ [$i] OK - id=${region.id}")
|
|
188
|
-
list.add(region)
|
|
189
|
-
}
|
|
190
|
-
Log.d(TAG, "🔧 parseRegions() - Concluído: ${list.size} regiões válidas")
|
|
191
|
-
return list
|
|
192
225
|
}
|
|
193
226
|
}
|
package/ios/GeofenceManager.mm
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
#import "GeofenceManager.h"
|
|
2
|
-
|
|
3
|
-
@implementation GeofenceManager
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
{
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
return @
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
@end
|
|
1
|
+
#import "GeofenceManager.h"
|
|
2
|
+
|
|
3
|
+
@implementation GeofenceManager
|
|
4
|
+
|
|
5
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
6
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
7
|
+
{
|
|
8
|
+
return std::make_shared<facebook::react::NativeGeofenceManagerSpecJSI>(params);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
+ (NSString *)moduleName
|
|
12
|
+
{
|
|
13
|
+
return @"GeofenceManager";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
- (NSNumber *)multiply:(double)a b:(double)b
|
|
17
|
+
{
|
|
18
|
+
return @(a * b);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@end
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { TurboModuleRegistry } from 'react-native';
|
|
4
|
-
|
|
5
|
-
if (NativeModule) {
|
|
6
|
-
console.log('✅ react-native-geofence-manager: Native module linked successfully');
|
|
7
|
-
} else {
|
|
8
|
-
console.warn('❌ react-native-geofence-manager: Native module not found. Make sure you rebuilt the app after installing the package.');
|
|
9
|
-
}
|
|
10
|
-
export default NativeModule;
|
|
4
|
+
export default TurboModuleRegistry.getEnforcing('GeofenceManager');
|
|
11
5
|
//# sourceMappingURL=NativeGeofenceManager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["TurboModuleRegistry","
|
|
1
|
+
{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"..\\..\\src","sources":["NativeGeofenceManager.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAA0B,cAAc;AAQpE,eAAeA,mBAAmB,CAACC,YAAY,CAAO,iBAAiB,CAAC","ignoreList":[]}
|
|
@@ -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
|
@@ -1,42 +1,86 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
3
|
+
import { AppRegistry, DeviceEventEmitter } from 'react-native';
|
|
4
|
+
import NativeGeofenceManager from "./NativeGeofenceManager.js";
|
|
5
|
+
import { geofenceDebugLog, geofenceDebugWarn } from "./geofenceDebugLog.js";
|
|
6
|
+
const EVENT_NAME = 'onGeofenceTransition';
|
|
7
|
+
|
|
8
|
+
/** Nome da headless task para eventos de geofence (app morto/background). Deve ser usado com registerGeofenceHeadlessTask no index do app. */
|
|
9
|
+
export const GEOFENCE_HEADLESS_TASK_NAME = 'GeofenceManagerTransition';
|
|
10
|
+
export function addGeofenceEventListener(callback) {
|
|
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
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function onGeofenceEvent(callback) {
|
|
24
|
+
return addGeofenceEventListener(callback);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Registra o handler da headless task para quando o app é acordado por um evento de geofence
|
|
29
|
+
* (app morto ou em background). Deve ser chamado no index do app, antes de AppRegistry.registerComponent.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* // index.js
|
|
33
|
+
* import { AppRegistry } from 'react-native';
|
|
34
|
+
* import { registerGeofenceHeadlessTask } from 'react-native-geofence-manager';
|
|
35
|
+
* import App from './App';
|
|
36
|
+
* import { name as appName } from './app.json';
|
|
37
|
+
*
|
|
38
|
+
* registerGeofenceHeadlessTask((event) => {
|
|
39
|
+
* console.log('Geofence (headless):', event.geofenceId, event.event);
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* AppRegistry.registerComponent(appName, () => App);
|
|
43
|
+
*/
|
|
44
|
+
export function registerGeofenceHeadlessTask(callback) {
|
|
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
|
+
});
|
|
52
|
+
}
|
|
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
|
|
22
62
|
});
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
onExit: cb => emitter.addListener('onExit', cb),
|
|
26
|
-
onDwell: cb => emitter.addListener('onDwell', cb),
|
|
27
|
-
registerBackgroundHandler: handler => {
|
|
28
|
-
if (Platform.OS !== 'android') {
|
|
29
|
-
return;
|
|
63
|
+
if (!ok) {
|
|
64
|
+
geofenceDebugWarn('JS: addGeofences — native returned false (empty list, Geofencing API failure, or permissions)');
|
|
30
65
|
}
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
66
|
+
return ok;
|
|
67
|
+
} catch (e) {
|
|
68
|
+
geofenceDebugWarn('JS: addGeofences — threw (TurboModule missing or bridge error)', e);
|
|
69
|
+
throw e;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
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;
|
|
40
83
|
}
|
|
41
84
|
};
|
|
85
|
+
export { addGeofences, removeAllGeofences };
|
|
42
86
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
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,"names":[],"sourceRoot":"..\\..\\..\\src","sources":["models/GeofenceEvent.ts"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"..\\..\\..\\src","sources":["models/GeofenceEventType.ts"],"mappings":"","ignoreList":[]}
|