@josuelmm/cordova-background-geolocation 4.2.3 → 4.5.2
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/.npmignore +11 -0
- package/CHANGELOG.md +261 -0
- package/README.md +306 -115
- package/android/CDVBackgroundGeolocation/src/main/java/com/marianhello/bgloc/cordova/ConfigMapper.java +34 -0
- package/android/CDVBackgroundGeolocation/src/main/java/com/tenforwardconsulting/bgloc/cordova/BackgroundGeolocationPlugin.java +61 -1
- package/android/common/src/main/AndroidManifest.xml +1 -1
- package/android/common/src/main/java/com/marianhello/bgloc/BootCompletedReceiver.java +20 -3
- package/android/common/src/main/java/com/marianhello/bgloc/Config.java +87 -1
- package/android/common/src/main/java/com/marianhello/bgloc/data/BackgroundLocation.java +94 -0
- package/android/common/src/main/java/com/marianhello/bgloc/data/ConfigJsonMapper.java +211 -0
- package/android/common/src/main/java/com/marianhello/bgloc/data/LocationTemplateFactory.java +6 -0
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteConfigurationContract.java +5 -1
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteConfigurationDAO.java +32 -1
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteLocationContract.java +12 -2
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteLocationDAO.java +33 -2
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteOpenHelper.java +15 -1
- package/android/common/src/main/java/com/marianhello/bgloc/provider/AbstractLocationProvider.java +48 -1
- package/android/common/src/main/java/com/marianhello/bgloc/provider/ActivityRecognitionLocationProvider.java +105 -6
- package/android/common/src/main/java/com/marianhello/bgloc/provider/DistanceFilterLocationProvider.java +336 -250
- package/android/common/src/main/java/com/marianhello/bgloc/provider/RawLocationProvider.java +69 -19
- package/android/common/src/main/java/com/marianhello/bgloc/service/LocationServiceImpl.java +246 -21
- package/android/common/src/main/java/com/marianhello/bgloc/service/LocationServiceProxy.java +5 -2
- package/android/common/src/main/java/com/marianhello/bgloc/sync/BatchManager.java +46 -13
- package/ios/CDVBackgroundGeolocation/CDVBackgroundGeolocation.m +23 -1
- package/ios/common/BackgroundGeolocation/MAURActivityLocationProvider.m +208 -70
- package/ios/common/BackgroundGeolocation/MAURBackgroundGeolocationFacade.m +132 -5
- package/ios/common/BackgroundGeolocation/MAURBackgroundSync.m +20 -0
- package/ios/common/BackgroundGeolocation/MAURConfig.h +7 -0
- package/ios/common/BackgroundGeolocation/MAURConfig.m +37 -2
- package/ios/common/BackgroundGeolocation/MAURConfigurationContract.h +3 -0
- package/ios/common/BackgroundGeolocation/MAURConfigurationContract.m +3 -1
- package/ios/common/BackgroundGeolocation/MAURDistanceFilterLocationProvider.m +10 -1
- package/ios/common/BackgroundGeolocation/MAURGeolocationOpenHelper.m +15 -1
- package/ios/common/BackgroundGeolocation/MAURLocation.h +12 -0
- package/ios/common/BackgroundGeolocation/MAURLocation.m +33 -4
- package/ios/common/BackgroundGeolocation/MAURLocationContract.h +4 -0
- package/ios/common/BackgroundGeolocation/MAURLocationContract.m +5 -1
- package/ios/common/BackgroundGeolocation/MAURLocationManager.m +19 -1
- package/ios/common/BackgroundGeolocation/MAURPostLocationTask.h +9 -0
- package/ios/common/BackgroundGeolocation/MAURPostLocationTask.m +59 -1
- package/ios/common/BackgroundGeolocation/MAURRawLocationProvider.m +10 -1
- package/ios/common/BackgroundGeolocation/MAURSQLiteConfigurationDAO.m +54 -4
- package/ios/common/BackgroundGeolocation/MAURSQLiteLocationDAO.h +12 -0
- package/ios/common/BackgroundGeolocation/MAURSQLiteLocationDAO.m +125 -5
- package/package.json +31 -1
- package/plugin.xml +3 -10
- package/www/BackgroundGeolocation.d.ts +143 -3
- package/www/BackgroundGeolocation.js +11 -4
- package/CLAUDE.md +0 -56
- package/HISTORY.md +0 -871
- package/android/CDVBackgroundGeolocation/src/test/java/com/marianhello/ConfigMapperTest.java +0 -220
- package/android/common/src/androidTest/java/com/marianhello/bgloc/BackgroundGeolocationFacadeTest.java +0 -45
- package/android/common/src/androidTest/java/com/marianhello/bgloc/BatchManagerTest.java +0 -570
- package/android/common/src/androidTest/java/com/marianhello/bgloc/ConfigTest.java +0 -76
- package/android/common/src/androidTest/java/com/marianhello/bgloc/ContentProviderLocationDAOTest.java +0 -437
- package/android/common/src/androidTest/java/com/marianhello/bgloc/DBLogReaderTest.java +0 -95
- package/android/common/src/androidTest/java/com/marianhello/bgloc/LocationContentProviderTest.java +0 -159
- package/android/common/src/androidTest/java/com/marianhello/bgloc/LocationServiceProxyTest.java +0 -161
- package/android/common/src/androidTest/java/com/marianhello/bgloc/LocationServiceTest.java +0 -247
- package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteConfigurationDAOTest.java +0 -200
- package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteLocationDAOTest.java +0 -457
- package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteLocationDAOThreadTest.java +0 -96
- package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteOpenHelperTest.java +0 -225
- package/android/common/src/androidTest/java/com/marianhello/bgloc/TestPluginDelegate.java +0 -46
- package/android/common/src/androidTest/java/com/marianhello/bgloc/TestResourceResolver.java +0 -14
- package/android/common/src/androidTest/java/com/marianhello/bgloc/provider/MockLocationProvider.java +0 -50
- package/android/common/src/androidTest/java/com/marianhello/bgloc/provider/TestLocationProviderFactory.java +0 -17
- package/android/common/src/androidTest/java/com/marianhello/bgloc/sqlite/SQLiteOpenHelper10.java +0 -92
- package/android/common/src/androidTest/java/com/marianhello/bgloc/test/LocationProviderTestCase.java +0 -107
- package/android/common/src/androidTest/java/com/marianhello/bgloc/test/TestConstants.java +0 -5
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/ArrayListLocationTemplateTest.java +0 -82
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/BackgroundLocationTest.java +0 -128
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/ConfigTest.java +0 -191
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/DBLogReaderTest.java +0 -37
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/HashMapLocationTemplateTest.java +0 -216
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/HttpPostServiceTest.java +0 -223
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/LocationTemplateFactoryTest.java +0 -50
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/PostLocationTaskTest.java +0 -180
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/TestHelper.java +0 -16
- package/ios/common/BackgroundGeolocation/SOMotionDetector/CHANGELOG.md +0 -2
- package/ios/common/BackgroundGeolocation/SOMotionDetector/LICENSE +0 -21
- package/ios/common/BackgroundGeolocation/SOMotionDetector/README.md +0 -135
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOLocationManager.h +0 -80
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOLocationManager.m +0 -147
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionActivity.h +0 -30
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionActivity.m +0 -42
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionDetector.h +0 -99
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionDetector.m +0 -327
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOStepDetector.h +0 -44
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOStepDetector.m +0 -94
- package/ios/common/BackgroundGeolocationTests/Info.plist +0 -24
- package/ios/common/BackgroundGeolocationTests/MAURBackgroundLocationTest.m +0 -185
- package/ios/common/BackgroundGeolocationTests/MAURConfigTest.m +0 -161
- package/ios/common/BackgroundGeolocationTests/MAURGeolocationOpenHelperTest.m +0 -102
- package/ios/common/BackgroundGeolocationTests/MAURLocationTest.m +0 -216
- package/ios/common/BackgroundGeolocationTests/MAURLocationUploaderTest.m +0 -55
- package/ios/common/BackgroundGeolocationTests/MAURLogReaderTest.m +0 -43
- package/ios/common/BackgroundGeolocationTests/MAURSQLiteConfigurationDAOTest.m +0 -102
- package/ios/common/BackgroundGeolocationTests/MAURSQLiteHelperTest.m +0 -41
- package/ios/common/BackgroundGeolocationTests/MAURSQLiteLocationDAOTests.m +0 -240
- package/ios/common/BackgroundGeolocationTests/MAURSQLiteLocationDAOThreadTest.m +0 -84
- package/ios/common/BackgroundGeolocationTests/MAURSQLiteOpenHelperTest.m +0 -144
- package/ios/common/scripts/xcode-refactor.js +0 -184
|
@@ -30,6 +30,15 @@
|
|
|
30
30
|
|
|
31
31
|
@property (nonatomic, weak) MAURConfig * _Nullable config;
|
|
32
32
|
@property (nonatomic, weak) id<MAURPostLocationTaskDelegate> _Nullable delegate;
|
|
33
|
+
/** v4.5.1 — pending driving events buffer owned by the facade; the task drains it onto the
|
|
34
|
+
* post-transform location so events fired without a simultaneous fix (provider change,
|
|
35
|
+
* sensor crash, phone usage) survive even if `locationTransform` returns a new instance.
|
|
36
|
+
* Weak ref: if the facade is gone, no flush — by design. */
|
|
37
|
+
@property (nonatomic, weak) NSMutableArray * _Nullable pendingDrivingEventsBuffer;
|
|
38
|
+
/** v4.5.1 — same idea for the battery snapshot block. The facade installs a block that the
|
|
39
|
+
* task invokes AFTER a successful transform, so even when `locationTransform` returns a
|
|
40
|
+
* fresh instance, battery/charging fields land on what actually gets POSTed. */
|
|
41
|
+
@property (nonatomic, copy) void (^ _Nullable attachBatterySnapshot)(MAURLocation * _Nonnull);
|
|
33
42
|
|
|
34
43
|
- (void) add:(MAURLocation * _Nonnull)location;
|
|
35
44
|
- (void) start;
|
|
@@ -83,11 +83,63 @@ static MAURLocationTransform s_locationTransform = nil;
|
|
|
83
83
|
MAURLocation *location = inLocation;
|
|
84
84
|
|
|
85
85
|
if (locationTransform != nil) {
|
|
86
|
+
// v4.5.1 — snapshot v4.3+ fields BEFORE transform so they survive a transform
|
|
87
|
+
// that returns a brand new MAURLocation instance (otherwise events/battery would
|
|
88
|
+
// be lost en route to SQLite / backend).
|
|
89
|
+
NSMutableArray *rawEvents = inLocation.drivingEvents;
|
|
90
|
+
NSNumber *rawBattery = inLocation.batteryLevel;
|
|
91
|
+
NSNumber *rawCharging = inLocation.isCharging;
|
|
92
|
+
|
|
86
93
|
location = locationTransform(location);
|
|
87
94
|
|
|
88
95
|
if (location == nil) {
|
|
89
96
|
return;
|
|
90
97
|
}
|
|
98
|
+
|
|
99
|
+
// v4.5.1 — re-attach fields the transform may have dropped. When the transform
|
|
100
|
+
// produced a NEW instance (`location != inLocation`), MERGE rawEvents into the new
|
|
101
|
+
// instance's array instead of overwriting — same semantics as Android
|
|
102
|
+
// `LocationServiceImpl.onLocation` re-attach. If the transform returned the same
|
|
103
|
+
// instance (mutated in place) the rawEvents are already there.
|
|
104
|
+
if (location != inLocation) {
|
|
105
|
+
if (rawEvents != nil && [rawEvents count] > 0) {
|
|
106
|
+
if (location.drivingEvents == nil) {
|
|
107
|
+
location.drivingEvents = [rawEvents mutableCopy];
|
|
108
|
+
} else {
|
|
109
|
+
[location.drivingEvents addObjectsFromArray:rawEvents];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (location.batteryLevel == nil) location.batteryLevel = rawBattery;
|
|
113
|
+
if (location.isCharging == nil) location.isCharging = rawCharging;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// v4.5.1 — drain pending driving events ONTO the post-transform location. Previously
|
|
118
|
+
// the facade drained them BEFORE [postLocationTask add:], so a transform that returned
|
|
119
|
+
// nil silently lost every buffered event. Now: if transform succeeded we're guaranteed
|
|
120
|
+
// `location != nil` here and the buffer is drained safely.
|
|
121
|
+
NSMutableArray *pendingBuffer = self.pendingDrivingEventsBuffer;
|
|
122
|
+
if (pendingBuffer != nil) {
|
|
123
|
+
@synchronized (pendingBuffer) {
|
|
124
|
+
if ([pendingBuffer count] > 0) {
|
|
125
|
+
NSTimeInterval nowMs = [[NSDate date] timeIntervalSince1970] * 1000.0;
|
|
126
|
+
if (location.drivingEvents == nil) location.drivingEvents = [NSMutableArray array];
|
|
127
|
+
for (NSDictionary *ev in pendingBuffer) {
|
|
128
|
+
NSNumber *t = ev[@"time"];
|
|
129
|
+
NSTimeInterval evMs = t != nil ? [t doubleValue] : nowMs;
|
|
130
|
+
if (nowMs - evMs <= 60000.0) {
|
|
131
|
+
[location.drivingEvents addObject:ev];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
[pendingBuffer removeAllObjects];
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// v4.5.1 — stamp battery snapshot AFTER transform so it lands on the POSTed instance
|
|
139
|
+
// even if the transform created a new one.
|
|
140
|
+
void (^attachBattery)(MAURLocation *) = self.attachBatterySnapshot;
|
|
141
|
+
if (attachBattery != nil) {
|
|
142
|
+
attachBattery(location);
|
|
91
143
|
}
|
|
92
144
|
|
|
93
145
|
// v3.5 Phase 4: mock location policy. Detection already exists in MAURLocation.simulated.
|
|
@@ -255,7 +307,8 @@ static MAURLocationTransform s_locationTransform = nil;
|
|
|
255
307
|
return YES;
|
|
256
308
|
}
|
|
257
309
|
|
|
258
|
-
|
|
310
|
+
// v4.4.1: guard against outError == NULL (defensive — current callers pass &error).
|
|
311
|
+
if (outError == NULL || *outError == nil) {
|
|
259
312
|
DDLogDebug(@"%@ Server error while posting locations responseCode: %ld", TAG, (long)statusCode);
|
|
260
313
|
} else {
|
|
261
314
|
DDLogError(@"%@ Error while posting locations %@", TAG, [*outError localizedDescription]);
|
|
@@ -269,6 +322,11 @@ static MAURLocationTransform s_locationTransform = nil;
|
|
|
269
322
|
if (![self.config syncEnabled] || ![self.config hasValidSyncUrl]) {
|
|
270
323
|
return;
|
|
271
324
|
}
|
|
325
|
+
// v4.5.1 — rescue rows stuck in SyncPending from a previous upload that never completed
|
|
326
|
+
// (app/process killed mid-flight). Anything older than 15 min is safe to revert to
|
|
327
|
+
// PostPending; rows younger than that may still be uploading on a background NSURLSession.
|
|
328
|
+
NSTimeInterval staleCutoff = [[NSDate date] timeIntervalSince1970] - (15 * 60);
|
|
329
|
+
[[MAURSQLiteLocationDAO sharedInstance] restoreStaleSyncLocationsOlderThan:staleCutoff error:nil];
|
|
272
330
|
// For sync (batch) only static queryParams placeholders apply; per-location templating
|
|
273
331
|
// belongs in real-time post (httpMode="single" + httpMethod=GET) instead.
|
|
274
332
|
NSString *resolvedSyncUrl = [MAURUrlTemplateResolver resolve:self.config.syncUrl location:nil queryParams:self.config.queryParams];
|
|
@@ -118,11 +118,20 @@ static NSString * const Domain = @"com.marianhello";
|
|
|
118
118
|
- (void) onDestroy {
|
|
119
119
|
DDLogInfo(@"Destroying %@ ", TAG);
|
|
120
120
|
[self onStop:nil];
|
|
121
|
+
|
|
122
|
+
// v4.5.2: MAURLocationManager is a singleton shared with the other providers.
|
|
123
|
+
// Release our delegate slot so a later provider swap does not leave this
|
|
124
|
+
// (already destroyed) instance as the active delegate.
|
|
125
|
+
if (locationManager != nil && locationManager.delegate == self) {
|
|
126
|
+
locationManager.delegate = nil;
|
|
127
|
+
}
|
|
121
128
|
}
|
|
122
129
|
|
|
123
130
|
- (void) dealloc
|
|
124
131
|
{
|
|
125
|
-
|
|
132
|
+
if (locationManager != nil && locationManager.delegate == self) {
|
|
133
|
+
locationManager.delegate = nil;
|
|
134
|
+
}
|
|
126
135
|
}
|
|
127
136
|
|
|
128
137
|
@end
|
|
@@ -88,7 +88,8 @@
|
|
|
88
88
|
@COMMA_SEP @CC_COLUMN_NAME_PAUSE_LOCATION_UPDATES
|
|
89
89
|
@COMMA_SEP @CC_COLUMN_NAME_TEMPLATE
|
|
90
90
|
@COMMA_SEP @CC_COLUMN_NAME_LAST_UPDATED_AT
|
|
91
|
-
@
|
|
91
|
+
@COMMA_SEP @CC_COLUMN_NAME_CONFIG_JSON
|
|
92
|
+
@") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,DateTime('now'),?)";
|
|
92
93
|
|
|
93
94
|
[queue inDatabase:^(FMDatabase *database) {
|
|
94
95
|
success = [database executeUpdate:sql,
|
|
@@ -119,7 +120,9 @@
|
|
|
119
120
|
[config hasSaveBatteryOnBackground] ? config._saveBatteryOnBackground : @CC_COLUMN_NAME_NULLABLE,
|
|
120
121
|
[config hasMaxLocations] ? config.maxLocations : @CC_COLUMN_NAME_NULLABLE,
|
|
121
122
|
[config hasPauseLocationUpdates] ? config._pauseLocationUpdates : @CC_COLUMN_NAME_NULLABLE,
|
|
122
|
-
(templateString != nil) ? templateString : @CC_COLUMN_NAME_NULLABLE
|
|
123
|
+
(templateString != nil) ? templateString : @CC_COLUMN_NAME_NULLABLE,
|
|
124
|
+
// v4.5: full Config as JSON for paridad con Android
|
|
125
|
+
[self serializeConfigToJson:config]
|
|
123
126
|
];
|
|
124
127
|
|
|
125
128
|
if (success) {
|
|
@@ -165,6 +168,7 @@
|
|
|
165
168
|
@COMMA_SEP @CC_COLUMN_NAME_MAX_LOCATIONS
|
|
166
169
|
@COMMA_SEP @CC_COLUMN_NAME_PAUSE_LOCATION_UPDATES
|
|
167
170
|
@COMMA_SEP @CC_COLUMN_NAME_TEMPLATE
|
|
171
|
+
@COMMA_SEP @CC_COLUMN_NAME_CONFIG_JSON
|
|
168
172
|
@" FROM " @CC_TABLE_NAME @" WHERE " @CC_COLUMN_NAME_ID @" = 1";
|
|
169
173
|
|
|
170
174
|
[queue inDatabase:^(FMDatabase *database) {
|
|
@@ -231,14 +235,60 @@
|
|
|
231
235
|
config._template = [NSJSONSerialization JSONObjectWithData:jsonTemplate options:0 error:nil];
|
|
232
236
|
}
|
|
233
237
|
}
|
|
238
|
+
// v4.5: rehydrate post-3.2 keys from config_json blob (paridad Android).
|
|
239
|
+
// Index 28 is the new column. Strict NULL check (no NULLHACK sentinel for JSON column).
|
|
240
|
+
if (![rs columnIndexIsNull:28]) {
|
|
241
|
+
NSString *jsonString = [rs stringForColumnIndex:28];
|
|
242
|
+
if (jsonString != nil && jsonString.length > 0) {
|
|
243
|
+
[self applyConfigJson:jsonString to:config];
|
|
244
|
+
}
|
|
245
|
+
}
|
|
234
246
|
}
|
|
235
|
-
|
|
247
|
+
|
|
236
248
|
[rs close];
|
|
237
249
|
}];
|
|
238
|
-
|
|
250
|
+
|
|
239
251
|
return config;
|
|
240
252
|
}
|
|
241
253
|
|
|
254
|
+
// v4.5: serialize all post-3.2 keys to JSON for storage. Mirrors Android ConfigJsonMapper.
|
|
255
|
+
- (NSString*) serializeConfigToJson:(MAURConfig*)config
|
|
256
|
+
{
|
|
257
|
+
NSMutableDictionary *j = [NSMutableDictionary dictionary];
|
|
258
|
+
if (config.httpMethod != nil) j[@"httpMethod"] = config.httpMethod;
|
|
259
|
+
if (config.syncHttpMethod != nil) j[@"syncHttpMethod"] = config.syncHttpMethod;
|
|
260
|
+
if (config.httpMode != nil) j[@"httpMode"] = config.httpMode;
|
|
261
|
+
if (config.syncMode != nil) j[@"syncMode"] = config.syncMode;
|
|
262
|
+
if (config.queryParams != nil) j[@"queryParams"] = config.queryParams;
|
|
263
|
+
if (config.heartbeatInterval != nil) j[@"heartbeatInterval"] = config.heartbeatInterval;
|
|
264
|
+
if (config.mockLocationPolicy != nil) j[@"mockLocationPolicy"] = config.mockLocationPolicy;
|
|
265
|
+
if (config.drivingEvents != nil) j[@"drivingEvents"] = config.drivingEvents;
|
|
266
|
+
if (config.includeBattery != nil) j[@"includeBattery"] = config.includeBattery;
|
|
267
|
+
if (config._showsBackgroundLocationIndicator != nil) j[@"showsBackgroundLocationIndicator"] = config._showsBackgroundLocationIndicator;
|
|
268
|
+
NSError *err = nil;
|
|
269
|
+
NSData *data = [NSJSONSerialization dataWithJSONObject:j options:0 error:&err];
|
|
270
|
+
if (err != nil || data == nil) return @"";
|
|
271
|
+
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
- (void) applyConfigJson:(NSString*)jsonString to:(MAURConfig*)config
|
|
275
|
+
{
|
|
276
|
+
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
|
277
|
+
NSError *err = nil;
|
|
278
|
+
NSDictionary *j = [NSJSONSerialization JSONObjectWithData:data options:0 error:&err];
|
|
279
|
+
if (err != nil || ![j isKindOfClass:[NSDictionary class]]) return;
|
|
280
|
+
if (j[@"httpMethod"]) config.httpMethod = j[@"httpMethod"];
|
|
281
|
+
if (j[@"syncHttpMethod"]) config.syncHttpMethod = j[@"syncHttpMethod"];
|
|
282
|
+
if (j[@"httpMode"]) config.httpMode = j[@"httpMode"];
|
|
283
|
+
if (j[@"syncMode"]) config.syncMode = j[@"syncMode"];
|
|
284
|
+
if ([j[@"queryParams"] isKindOfClass:[NSDictionary class]]) config.queryParams = [j[@"queryParams"] mutableCopy];
|
|
285
|
+
if (j[@"heartbeatInterval"]) config.heartbeatInterval = j[@"heartbeatInterval"];
|
|
286
|
+
if (j[@"mockLocationPolicy"]) config.mockLocationPolicy = j[@"mockLocationPolicy"];
|
|
287
|
+
if ([j[@"drivingEvents"] isKindOfClass:[NSDictionary class]]) config.drivingEvents = j[@"drivingEvents"];
|
|
288
|
+
if (j[@"includeBattery"] != nil) config.includeBattery = j[@"includeBattery"];
|
|
289
|
+
if (j[@"showsBackgroundLocationIndicator"] != nil) config._showsBackgroundLocationIndicator = j[@"showsBackgroundLocationIndicator"];
|
|
290
|
+
}
|
|
291
|
+
|
|
242
292
|
- (BOOL) clearDatabase
|
|
243
293
|
{
|
|
244
294
|
__block BOOL success;
|
|
@@ -28,6 +28,18 @@
|
|
|
28
28
|
- (BOOL) deleteAllLocations:(NSError * __autoreleasing *)outError;
|
|
29
29
|
/** Mark all locations pending sync (PostPending) as deleted. Clears the sync queue without sending. */
|
|
30
30
|
- (BOOL) deletePendingSyncLocations:(NSError * __autoreleasing *)outError;
|
|
31
|
+
/** v4.5.1 — soft-delete only sync-pending rows whose `recorded_at` is <= cutoff (UNIX seconds).
|
|
32
|
+
* Used after a successful background-sync POST so locations persisted DURING the upload (race
|
|
33
|
+
* window) are NOT incorrectly marked deleted. */
|
|
34
|
+
- (BOOL) deleteSyncedLocationsBefore:(NSTimeInterval)cutoff error:(NSError * __autoreleasing *)outError;
|
|
35
|
+
/** v4.5.1 — undo the in-flight SyncPending state when the upload failed. SyncPending → PostPending
|
|
36
|
+
* so the next sync window re-tries them. Without this, a network failure during background-sync
|
|
37
|
+
* would silently drop every pending location. */
|
|
38
|
+
- (BOOL) restoreFailedSyncLocations:(NSError * __autoreleasing *)outError;
|
|
39
|
+
/** v4.5.1 — recover SyncPending rows that got stuck (app/process killed between getLocationsForSync
|
|
40
|
+
* and the upload's success/failure callback). Rows whose `recorded_at` is older than `cutoff`
|
|
41
|
+
* (UNIX seconds) are restored to PostPending so they get retried. Call before each sync window. */
|
|
42
|
+
- (BOOL) restoreStaleSyncLocationsOlderThan:(NSTimeInterval)cutoff error:(NSError * __autoreleasing *)outError;
|
|
31
43
|
- (BOOL) clearDatabase;
|
|
32
44
|
- (NSString*) getDatabaseName;
|
|
33
45
|
- (NSString*) getDatabasePath;
|
|
@@ -94,9 +94,17 @@
|
|
|
94
94
|
}
|
|
95
95
|
[rs close];
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
// v4.5.1 FIX (CRITICAL): mark the rows we just selected as SyncPending — NOT Deleted.
|
|
98
|
+
// The previous code UPDATEd the WHOLE table to Deleted before the upload had even started,
|
|
99
|
+
// losing every fix on HTTP failure / network drop. Now:
|
|
100
|
+
// PostPending → SyncPending (in-flight, do not re-include)
|
|
101
|
+
// on success in the network task: SyncPending → Deleted (deleteSyncedLocationsBefore:)
|
|
102
|
+
// on failure in the network task: SyncPending → PostPending (restoreFailedSyncLocations)
|
|
103
|
+
NSString *upd = @"UPDATE " @LC_TABLE_NAME @" SET " @LC_COLUMN_NAME_STATUS @" = ? WHERE " @LC_COLUMN_NAME_STATUS @" = ?";
|
|
104
|
+
if (![database executeUpdate:upd,
|
|
105
|
+
[NSString stringWithFormat:@"%ld", MAURLocationSyncPending],
|
|
106
|
+
[NSString stringWithFormat:@"%ld", MAURLocationPostPending]]) {
|
|
107
|
+
NSLog(@"Marking PostPending → SyncPending failed code: %d: message: %@", [database lastErrorCode], [database lastErrorMessage]);
|
|
100
108
|
}
|
|
101
109
|
}];
|
|
102
110
|
|
|
@@ -139,7 +147,18 @@
|
|
|
139
147
|
@COMMA_SEP @LC_COLUMN_NAME_LOCATION_PROVIDER
|
|
140
148
|
@COMMA_SEP @LC_COLUMN_NAME_STATUS
|
|
141
149
|
@COMMA_SEP @LC_COLUMN_NAME_RECORDED_AT
|
|
142
|
-
@
|
|
150
|
+
@COMMA_SEP @LC_COLUMN_NAME_EVENTS_JSON
|
|
151
|
+
@COMMA_SEP @LC_COLUMN_NAME_BATTERY_LEVEL
|
|
152
|
+
@COMMA_SEP @LC_COLUMN_NAME_IS_CHARGING
|
|
153
|
+
@") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
|
|
154
|
+
|
|
155
|
+
// v4.5: serialize driving events array to JSON for SQLite storage.
|
|
156
|
+
NSString *eventsJson = nil;
|
|
157
|
+
if (location.drivingEvents != nil && [location.drivingEvents count] > 0) {
|
|
158
|
+
NSError *jerr = nil;
|
|
159
|
+
NSData *jd = [NSJSONSerialization dataWithJSONObject:location.drivingEvents options:0 error:&jerr];
|
|
160
|
+
if (jd != nil) eventsJson = [[NSString alloc] initWithData:jd encoding:NSUTF8StringEncoding];
|
|
161
|
+
}
|
|
143
162
|
|
|
144
163
|
BOOL success = [database executeUpdate:sql,
|
|
145
164
|
[NSNumber numberWithDouble:[location.time timeIntervalSince1970]],
|
|
@@ -152,7 +171,10 @@
|
|
|
152
171
|
location.provider ?: [NSNull null],
|
|
153
172
|
location.locationProvider ?: [NSNull null],
|
|
154
173
|
location.isValid == YES ? @(1) : @(0),
|
|
155
|
-
recordedAt
|
|
174
|
+
recordedAt,
|
|
175
|
+
eventsJson ?: [NSNull null],
|
|
176
|
+
location.batteryLevel ?: [NSNull null],
|
|
177
|
+
location.isCharging ?: [NSNull null]
|
|
156
178
|
];
|
|
157
179
|
|
|
158
180
|
if (success) {
|
|
@@ -223,8 +245,19 @@
|
|
|
223
245
|
@COMMA_SEP @LC_COLUMN_NAME_LOCATION_PROVIDER @EQ_BIND
|
|
224
246
|
@COMMA_SEP @LC_COLUMN_NAME_STATUS @EQ_BIND
|
|
225
247
|
@COMMA_SEP @LC_COLUMN_NAME_RECORDED_AT @EQ_BIND
|
|
248
|
+
@COMMA_SEP @LC_COLUMN_NAME_EVENTS_JSON @EQ_BIND
|
|
249
|
+
@COMMA_SEP @LC_COLUMN_NAME_BATTERY_LEVEL @EQ_BIND
|
|
250
|
+
@COMMA_SEP @LC_COLUMN_NAME_IS_CHARGING @EQ_BIND
|
|
226
251
|
@" WHERE " @LC_COLUMN_NAME_ID @EQ_BIND;
|
|
227
252
|
|
|
253
|
+
// v4.5.1: serialize events for UPDATE path so old values don't bleed onto new locations
|
|
254
|
+
NSString *eventsJsonForUpdate = nil;
|
|
255
|
+
if (location.drivingEvents != nil && [location.drivingEvents count] > 0) {
|
|
256
|
+
NSError *jerr = nil;
|
|
257
|
+
NSData *jd = [NSJSONSerialization dataWithJSONObject:location.drivingEvents options:0 error:&jerr];
|
|
258
|
+
if (jd != nil) eventsJsonForUpdate = [[NSString alloc] initWithData:jd encoding:NSUTF8StringEncoding];
|
|
259
|
+
}
|
|
260
|
+
|
|
228
261
|
BOOL success = [database executeUpdate:sql,
|
|
229
262
|
[NSNumber numberWithDouble:[location.time timeIntervalSince1970]],
|
|
230
263
|
location.accuracy,
|
|
@@ -237,6 +270,9 @@
|
|
|
237
270
|
location.locationProvider ?: [NSNull null],
|
|
238
271
|
location.isValid == YES ? @(1) : @(0),
|
|
239
272
|
recordedAt,
|
|
273
|
+
eventsJsonForUpdate ?: [NSNull null],
|
|
274
|
+
location.batteryLevel ?: [NSNull null],
|
|
275
|
+
location.isCharging ?: [NSNull null],
|
|
240
276
|
locationId
|
|
241
277
|
];
|
|
242
278
|
|
|
@@ -304,6 +340,77 @@
|
|
|
304
340
|
return success;
|
|
305
341
|
}
|
|
306
342
|
|
|
343
|
+
- (BOOL) deleteSyncedLocationsBefore:(NSTimeInterval)cutoff error:(NSError * __autoreleasing *)outError
|
|
344
|
+
{
|
|
345
|
+
__block BOOL success = YES;
|
|
346
|
+
// v4.5.1 — operate on SyncPending (the rows the network task is/was uploading), not on
|
|
347
|
+
// PostPending (those are still queued for real-time POST and must NOT be touched).
|
|
348
|
+
NSString *sql = @"UPDATE " @LC_TABLE_NAME
|
|
349
|
+
@" SET " @LC_COLUMN_NAME_STATUS @" = ? "
|
|
350
|
+
@" WHERE " @LC_COLUMN_NAME_STATUS @" = ? AND " @LC_COLUMN_NAME_RECORDED_AT @" <= ?";
|
|
351
|
+
[queue inDatabase:^(FMDatabase *database) {
|
|
352
|
+
if (![database executeUpdate:sql,
|
|
353
|
+
@(MAURLocationDeleted),
|
|
354
|
+
@(MAURLocationSyncPending),
|
|
355
|
+
@(cutoff)]) {
|
|
356
|
+
int errorCode = [database lastErrorCode];
|
|
357
|
+
NSString *errorMessage = [database lastErrorMessage];
|
|
358
|
+
NSLog(@"deleteSyncedLocationsBefore failed code: %d: message: %@", errorCode, errorMessage);
|
|
359
|
+
if (outError != NULL) {
|
|
360
|
+
*outError = [NSError errorWithDomain:Domain code:errorCode userInfo:@{ NSLocalizedDescriptionKey: errorMessage ?: @"" }];
|
|
361
|
+
}
|
|
362
|
+
success = NO;
|
|
363
|
+
}
|
|
364
|
+
}];
|
|
365
|
+
return success;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
- (BOOL) restoreStaleSyncLocationsOlderThan:(NSTimeInterval)cutoff error:(NSError * __autoreleasing *)outError
|
|
369
|
+
{
|
|
370
|
+
// v4.5.1 — rows left as SyncPending because the previous sync's task was killed
|
|
371
|
+
// (app suspended mid-upload, OS process death, manual kill) never reach their
|
|
372
|
+
// success/failure callback. Call at the start of each sync window to rescue them.
|
|
373
|
+
__block BOOL success = YES;
|
|
374
|
+
NSString *sql = @"UPDATE " @LC_TABLE_NAME
|
|
375
|
+
@" SET " @LC_COLUMN_NAME_STATUS @" = ? "
|
|
376
|
+
@" WHERE " @LC_COLUMN_NAME_STATUS @" = ? AND " @LC_COLUMN_NAME_RECORDED_AT @" < ?";
|
|
377
|
+
[queue inDatabase:^(FMDatabase *database) {
|
|
378
|
+
if (![database executeUpdate:sql,
|
|
379
|
+
@(MAURLocationPostPending),
|
|
380
|
+
@(MAURLocationSyncPending),
|
|
381
|
+
@(cutoff)]) {
|
|
382
|
+
int errorCode = [database lastErrorCode];
|
|
383
|
+
NSString *errorMessage = [database lastErrorMessage];
|
|
384
|
+
NSLog(@"restoreStaleSyncLocations failed code: %d: message: %@", errorCode, errorMessage);
|
|
385
|
+
if (outError != NULL) {
|
|
386
|
+
*outError = [NSError errorWithDomain:Domain code:errorCode userInfo:@{ NSLocalizedDescriptionKey: errorMessage ?: @"" }];
|
|
387
|
+
}
|
|
388
|
+
success = NO;
|
|
389
|
+
}
|
|
390
|
+
}];
|
|
391
|
+
return success;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
- (BOOL) restoreFailedSyncLocations:(NSError * __autoreleasing *)outError
|
|
395
|
+
{
|
|
396
|
+
// v4.5.1 — undo the in-flight transition: SyncPending → PostPending so the next sync window
|
|
397
|
+
// (or real-time post) re-tries them.
|
|
398
|
+
__block BOOL success = YES;
|
|
399
|
+
NSString *sql = @"UPDATE " @LC_TABLE_NAME @" SET " @LC_COLUMN_NAME_STATUS @" = ? WHERE " @LC_COLUMN_NAME_STATUS @" = ?";
|
|
400
|
+
[queue inDatabase:^(FMDatabase *database) {
|
|
401
|
+
if (![database executeUpdate:sql, @(MAURLocationPostPending), @(MAURLocationSyncPending)]) {
|
|
402
|
+
int errorCode = [database lastErrorCode];
|
|
403
|
+
NSString *errorMessage = [database lastErrorMessage];
|
|
404
|
+
NSLog(@"restoreFailedSyncLocations failed code: %d: message: %@", errorCode, errorMessage);
|
|
405
|
+
if (outError != NULL) {
|
|
406
|
+
*outError = [NSError errorWithDomain:Domain code:errorCode userInfo:@{ NSLocalizedDescriptionKey: errorMessage ?: @"" }];
|
|
407
|
+
}
|
|
408
|
+
success = NO;
|
|
409
|
+
}
|
|
410
|
+
}];
|
|
411
|
+
return success;
|
|
412
|
+
}
|
|
413
|
+
|
|
307
414
|
- (BOOL) deletePendingSyncLocations:(NSError * __autoreleasing *)outError
|
|
308
415
|
{
|
|
309
416
|
__block BOOL success = YES;
|
|
@@ -368,6 +475,9 @@
|
|
|
368
475
|
@COMMA_SEP @LC_COLUMN_NAME_LOCATION_PROVIDER
|
|
369
476
|
@COMMA_SEP @LC_COLUMN_NAME_STATUS
|
|
370
477
|
@COMMA_SEP @LC_COLUMN_NAME_RECORDED_AT
|
|
478
|
+
@COMMA_SEP @LC_COLUMN_NAME_EVENTS_JSON
|
|
479
|
+
@COMMA_SEP @LC_COLUMN_NAME_BATTERY_LEVEL
|
|
480
|
+
@COMMA_SEP @LC_COLUMN_NAME_IS_CHARGING
|
|
371
481
|
@" FROM " @LC_TABLE_NAME;
|
|
372
482
|
}
|
|
373
483
|
|
|
@@ -387,6 +497,16 @@
|
|
|
387
497
|
location.isValid = [rs intForColumnIndex:10] == 1 ? YES : NO;
|
|
388
498
|
NSTimeInterval recordedAt = [rs longForColumnIndex:11];
|
|
389
499
|
location.recordedAt = [NSDate dateWithTimeIntervalSince1970:recordedAt];
|
|
500
|
+
// v4.5: events / battery / charging
|
|
501
|
+
NSString *eventsJson = [rs stringForColumnIndex:12];
|
|
502
|
+
if (eventsJson != nil && eventsJson.length > 0) {
|
|
503
|
+
NSError *jerr = nil;
|
|
504
|
+
id parsed = [NSJSONSerialization JSONObjectWithData:[eventsJson dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&jerr];
|
|
505
|
+
if ([parsed isKindOfClass:[NSMutableArray class]]) location.drivingEvents = parsed;
|
|
506
|
+
else if ([parsed isKindOfClass:[NSArray class]]) location.drivingEvents = [parsed mutableCopy];
|
|
507
|
+
}
|
|
508
|
+
if (![rs columnIndexIsNull:13]) location.batteryLevel = @([rs intForColumnIndex:13]);
|
|
509
|
+
if (![rs columnIndexIsNull:14]) location.isCharging = @([rs intForColumnIndex:14] == 1);
|
|
390
510
|
return location;
|
|
391
511
|
}
|
|
392
512
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@josuelmm/cordova-background-geolocation",
|
|
3
|
-
"version": "4.2
|
|
3
|
+
"version": "4.5.2",
|
|
4
4
|
"description": "Cordova Background Geolocation (fork actualizado)",
|
|
5
5
|
"main": "./www/BackgroundGeolocation.js",
|
|
6
6
|
"types": "./www/BackgroundGeolocation.d.ts",
|
|
@@ -109,6 +109,36 @@
|
|
|
109
109
|
"cordova": ">=10.0.0",
|
|
110
110
|
"cordova-android": ">=12.0.0",
|
|
111
111
|
"cordova-ios": ">=6.2.0"
|
|
112
|
+
},
|
|
113
|
+
"4.2.4": {
|
|
114
|
+
"cordova": ">=10.0.0",
|
|
115
|
+
"cordova-android": ">=12.0.0",
|
|
116
|
+
"cordova-ios": ">=6.2.0"
|
|
117
|
+
},
|
|
118
|
+
"4.3.0": {
|
|
119
|
+
"cordova": ">=10.0.0",
|
|
120
|
+
"cordova-android": ">=12.0.0",
|
|
121
|
+
"cordova-ios": ">=6.2.0"
|
|
122
|
+
},
|
|
123
|
+
"4.4.0": {
|
|
124
|
+
"cordova": ">=10.0.0",
|
|
125
|
+
"cordova-android": ">=12.0.0",
|
|
126
|
+
"cordova-ios": ">=6.2.0"
|
|
127
|
+
},
|
|
128
|
+
"4.4.1": {
|
|
129
|
+
"cordova": ">=10.0.0",
|
|
130
|
+
"cordova-android": ">=12.0.0",
|
|
131
|
+
"cordova-ios": ">=6.2.0"
|
|
132
|
+
},
|
|
133
|
+
"4.5.0": {
|
|
134
|
+
"cordova": ">=10.0.0",
|
|
135
|
+
"cordova-android": ">=12.0.0",
|
|
136
|
+
"cordova-ios": ">=6.2.0"
|
|
137
|
+
},
|
|
138
|
+
"4.5.1": {
|
|
139
|
+
"cordova": ">=10.0.0",
|
|
140
|
+
"cordova-android": ">=12.0.0",
|
|
141
|
+
"cordova-ios": ">=6.2.0"
|
|
112
142
|
}
|
|
113
143
|
}
|
|
114
144
|
},
|
package/plugin.xml
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
|
|
3
3
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
4
4
|
id="cordova-background-geolocation"
|
|
5
|
-
version="4.2
|
|
5
|
+
version="4.5.2">
|
|
6
6
|
<name>cordova-background-geolocation</name>
|
|
7
7
|
<description>Cordova Background Geolocation Plugin</description>
|
|
8
8
|
<license>Apache-2.0</license>
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
<source-file src="android/common/src/main/java/com/marianhello/bgloc/data/BackgroundActivity.java" target-dir="src/com/marianhello/bgloc/data" />
|
|
60
60
|
<source-file src="android/common/src/main/java/com/marianhello/bgloc/data/BackgroundLocation.java" target-dir="src/com/marianhello/bgloc/data" />
|
|
61
61
|
<source-file src="android/common/src/main/java/com/marianhello/bgloc/data/ConfigurationDAO.java" target-dir="src/com/marianhello/bgloc/data" />
|
|
62
|
+
<source-file src="android/common/src/main/java/com/marianhello/bgloc/data/ConfigJsonMapper.java" target-dir="src/com/marianhello/bgloc/data" />
|
|
62
63
|
<source-file src="android/common/src/main/java/com/marianhello/bgloc/data/DAOFactory.java" target-dir="src/com/marianhello/bgloc/data" />
|
|
63
64
|
<source-file src="android/common/src/main/java/com/marianhello/bgloc/data/HashMapLocationTemplate.java" target-dir="src/com/marianhello/bgloc/data" />
|
|
64
65
|
<source-file src="android/common/src/main/java/com/marianhello/bgloc/data/LocationDAO.java" target-dir="src/com/marianhello/bgloc/data" />
|
|
@@ -196,7 +197,7 @@
|
|
|
196
197
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
197
198
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
198
199
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
|
|
199
|
-
<uses-
|
|
200
|
+
<uses-feature android:name="android.hardware.location" android:required="false" />
|
|
200
201
|
</config-file>
|
|
201
202
|
<config-file target="res/xml/config.xml" parent="/*">
|
|
202
203
|
<feature name="BackgroundGeolocation">
|
|
@@ -353,14 +354,6 @@
|
|
|
353
354
|
<source-file src="ios/common/BackgroundGeolocation/MAURUncaughtExceptionLogger.m" />
|
|
354
355
|
<header-file src="ios/common/BackgroundGeolocation/Reachability.h" />
|
|
355
356
|
<source-file src="ios/common/BackgroundGeolocation/Reachability.m" />
|
|
356
|
-
<header-file src="ios/common/BackgroundGeolocation/SOMotionDetector/SOLocationManager.h" />
|
|
357
|
-
<source-file src="ios/common/BackgroundGeolocation/SOMotionDetector/SOLocationManager.m" />
|
|
358
|
-
<header-file src="ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionActivity.h" />
|
|
359
|
-
<source-file src="ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionActivity.m" />
|
|
360
|
-
<header-file src="ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionDetector.h" />
|
|
361
|
-
<source-file src="ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionDetector.m" />
|
|
362
|
-
<header-file src="ios/common/BackgroundGeolocation/SOMotionDetector/SOStepDetector.h" />
|
|
363
|
-
<source-file src="ios/common/BackgroundGeolocation/SOMotionDetector/SOStepDetector.m" />
|
|
364
357
|
<header-file src="ios/common/BackgroundGeolocation/SQLQueryBuilder/ext/NSString+ZIMString.h" />
|
|
365
358
|
<source-file src="ios/common/BackgroundGeolocation/SQLQueryBuilder/ext/NSString+ZIMString.m" />
|
|
366
359
|
<header-file src="ios/common/BackgroundGeolocation/SQLQueryBuilder/sql/ZIMSqlDataManipulationCommand.h" />
|