@maplibre/maplibre-react-native 11.0.0-alpha.31 → 11.0.0-alpha.33
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 +1 -1
- package/android/src/main/java/org/maplibre/reactnative/MLRNPackage.kt +10 -12
- package/android/src/main/java/org/maplibre/reactnative/components/mapview/MLRNMapView.kt +9 -0
- package/android/src/main/java/org/maplibre/reactnative/components/mapview/MLRNMapViewManager.kt +5 -1
- package/android/src/main/java/org/maplibre/reactnative/modules/MLRNModule.java +6 -24
- package/android/src/main/java/org/maplibre/reactnative/modules/MLRNOfflineModule.kt +561 -0
- package/ios/components/map-view/MLRNMapView.h +1 -0
- package/ios/components/map-view/MLRNMapView.m +5 -0
- package/ios/components/map-view/MLRNMapViewComponentView.mm +4 -0
- package/ios/modules/mlrn/MLRNModule.m +0 -13
- package/ios/modules/offline/MLRNOfflineModule.h +4 -7
- package/ios/modules/offline/MLRNOfflineModule.mm +693 -0
- package/lib/commonjs/MLRNModule.js +1 -3
- package/lib/commonjs/MLRNModule.js.map +1 -1
- package/lib/commonjs/components/map-view/AndroidTextureMapViewNativeComponent.ts +1 -0
- package/lib/commonjs/components/map-view/MapView.js.map +1 -1
- package/lib/commonjs/components/map-view/MapViewNativeComponent.ts +1 -0
- package/lib/commonjs/index.js +0 -8
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/modules/offline/NativeOfflineModule.js +9 -0
- package/lib/commonjs/modules/offline/NativeOfflineModule.js.map +1 -0
- package/lib/commonjs/modules/offline/OfflineManager.js +124 -164
- package/lib/commonjs/modules/offline/OfflineManager.js.map +1 -1
- package/lib/commonjs/modules/offline/OfflinePack.js +15 -25
- package/lib/commonjs/modules/offline/OfflinePack.js.map +1 -1
- package/lib/module/MLRNModule.js +0 -1
- package/lib/module/MLRNModule.js.map +1 -1
- package/lib/module/components/map-view/AndroidTextureMapViewNativeComponent.ts +1 -0
- package/lib/module/components/map-view/MapView.js.map +1 -1
- package/lib/module/components/map-view/MapViewNativeComponent.ts +1 -0
- package/lib/module/index.js +0 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/modules/offline/NativeOfflineModule.js +5 -0
- package/lib/module/modules/offline/NativeOfflineModule.js.map +1 -0
- package/lib/module/modules/offline/OfflineManager.js +123 -163
- package/lib/module/modules/offline/OfflineManager.js.map +1 -1
- package/lib/module/modules/offline/OfflinePack.js +14 -25
- package/lib/module/modules/offline/OfflinePack.js.map +1 -1
- package/lib/typescript/commonjs/src/MLRNModule.d.ts +1 -6
- package/lib/typescript/commonjs/src/MLRNModule.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/map-view/AndroidTextureMapViewNativeComponent.d.ts +1 -0
- package/lib/typescript/commonjs/src/components/map-view/AndroidTextureMapViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/map-view/MapView.d.ts +6 -0
- package/lib/typescript/commonjs/src/components/map-view/MapView.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/map-view/MapViewNativeComponent.d.ts +1 -0
- package/lib/typescript/commonjs/src/components/map-view/MapViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +2 -5
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/modules/offline/NativeOfflineModule.d.ts +50 -0
- package/lib/typescript/commonjs/src/modules/offline/NativeOfflineModule.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/modules/offline/OfflineManager.d.ts +66 -69
- package/lib/typescript/commonjs/src/modules/offline/OfflineManager.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/modules/offline/OfflinePack.d.ts +11 -9
- package/lib/typescript/commonjs/src/modules/offline/OfflinePack.d.ts.map +1 -1
- package/lib/typescript/module/src/MLRNModule.d.ts +1 -6
- package/lib/typescript/module/src/MLRNModule.d.ts.map +1 -1
- package/lib/typescript/module/src/components/map-view/AndroidTextureMapViewNativeComponent.d.ts +1 -0
- package/lib/typescript/module/src/components/map-view/AndroidTextureMapViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/components/map-view/MapView.d.ts +6 -0
- package/lib/typescript/module/src/components/map-view/MapView.d.ts.map +1 -1
- package/lib/typescript/module/src/components/map-view/MapViewNativeComponent.d.ts +1 -0
- package/lib/typescript/module/src/components/map-view/MapViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +2 -5
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/modules/offline/NativeOfflineModule.d.ts +50 -0
- package/lib/typescript/module/src/modules/offline/NativeOfflineModule.d.ts.map +1 -0
- package/lib/typescript/module/src/modules/offline/OfflineManager.d.ts +66 -69
- package/lib/typescript/module/src/modules/offline/OfflineManager.d.ts.map +1 -1
- package/lib/typescript/module/src/modules/offline/OfflinePack.d.ts +11 -9
- package/lib/typescript/module/src/modules/offline/OfflinePack.d.ts.map +1 -1
- package/package.json +7 -3
- package/src/MLRNModule.ts +0 -8
- package/src/components/map-view/AndroidTextureMapViewNativeComponent.ts +1 -0
- package/src/components/map-view/MapView.tsx +7 -0
- package/src/components/map-view/MapViewNativeComponent.ts +1 -0
- package/src/index.ts +13 -5
- package/src/modules/offline/NativeOfflineModule.ts +63 -0
- package/src/modules/offline/OfflineManager.ts +174 -210
- package/src/modules/offline/OfflinePack.ts +22 -32
- package/android/src/main/java/org/maplibre/reactnative/modules/MLRNOfflineModule.java +0 -586
- package/ios/modules/offline/MLRNOfflineModule.m +0 -524
- package/lib/commonjs/modules/offline/OfflineCreatePackOptions.js +0 -37
- package/lib/commonjs/modules/offline/OfflineCreatePackOptions.js.map +0 -1
- package/lib/commonjs/utils/makeNativeBounds.js +0 -11
- package/lib/commonjs/utils/makeNativeBounds.js.map +0 -1
- package/lib/module/modules/offline/OfflineCreatePackOptions.js +0 -32
- package/lib/module/modules/offline/OfflineCreatePackOptions.js.map +0 -1
- package/lib/module/utils/makeNativeBounds.js +0 -7
- package/lib/module/utils/makeNativeBounds.js.map +0 -1
- package/lib/typescript/commonjs/src/modules/offline/OfflineCreatePackOptions.d.ts +0 -20
- package/lib/typescript/commonjs/src/modules/offline/OfflineCreatePackOptions.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/utils/makeNativeBounds.d.ts +0 -2
- package/lib/typescript/commonjs/src/utils/makeNativeBounds.d.ts.map +0 -1
- package/lib/typescript/module/src/modules/offline/OfflineCreatePackOptions.d.ts +0 -20
- package/lib/typescript/module/src/modules/offline/OfflineCreatePackOptions.d.ts.map +0 -1
- package/lib/typescript/module/src/utils/makeNativeBounds.d.ts +0 -2
- package/lib/typescript/module/src/utils/makeNativeBounds.d.ts.map +0 -1
- package/src/modules/offline/OfflineCreatePackOptions.ts +0 -53
- package/src/utils/makeNativeBounds.ts +0 -5
|
@@ -0,0 +1,693 @@
|
|
|
1
|
+
#import "MLRNOfflineModule.h"
|
|
2
|
+
#import "MLRNEvent.h"
|
|
3
|
+
#import "MLRNEventTypes.h"
|
|
4
|
+
#import "MLRNUtils.h"
|
|
5
|
+
|
|
6
|
+
#import <MapLibre/MapLibre.h>
|
|
7
|
+
|
|
8
|
+
static NSString *const MLRN_MIGRATION_KEY = @"migrationVersion";
|
|
9
|
+
static const NSInteger MLRN_MIGRATION_VERSION = 1;
|
|
10
|
+
|
|
11
|
+
@implementation MLRNOfflineModule {
|
|
12
|
+
NSUInteger lastPackState;
|
|
13
|
+
double lastPackTimestamp;
|
|
14
|
+
double eventThrottle;
|
|
15
|
+
NSMutableArray<RCTPromiseResolveBlock> *packRequestQueue;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
+ (NSString *)moduleName {
|
|
19
|
+
return @"MLRNOfflineModule";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
23
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params {
|
|
24
|
+
return std::make_shared<facebook::react::NativeOfflineModuleSpecJSI>(params);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
- (void)initialize {
|
|
28
|
+
[self runMigrations];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
- (instancetype)init {
|
|
32
|
+
if (self = [super init]) {
|
|
33
|
+
packRequestQueue = [NSMutableArray new];
|
|
34
|
+
eventThrottle = 300;
|
|
35
|
+
lastPackState = -1;
|
|
36
|
+
|
|
37
|
+
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
|
38
|
+
[defaultCenter addObserver:self
|
|
39
|
+
selector:@selector(offlinePackProgressDidChange:)
|
|
40
|
+
name:MLNOfflinePackProgressChangedNotification
|
|
41
|
+
object:nil];
|
|
42
|
+
[defaultCenter addObserver:self
|
|
43
|
+
selector:@selector(offlinePackDidReceiveError:)
|
|
44
|
+
name:MLNOfflinePackErrorNotification
|
|
45
|
+
object:nil];
|
|
46
|
+
[defaultCenter addObserver:self
|
|
47
|
+
selector:@selector(offlinePackDidReceiveMaxAllowedMapboxTiles:)
|
|
48
|
+
name:MLNOfflinePackMaximumMapboxTilesReachedNotification
|
|
49
|
+
object:nil];
|
|
50
|
+
|
|
51
|
+
[[MLNOfflineStorage sharedOfflineStorage] addObserver:self
|
|
52
|
+
forKeyPath:@"packs"
|
|
53
|
+
options:NSKeyValueObservingOptionInitial
|
|
54
|
+
context:NULL];
|
|
55
|
+
}
|
|
56
|
+
return self;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
- (void)dealloc {
|
|
60
|
+
[[MLNOfflineStorage sharedOfflineStorage] removeObserver:self forKeyPath:@"packs"];
|
|
61
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
- (void)observeValueForKeyPath:(NSString *)keyPath
|
|
65
|
+
ofObject:(id)object
|
|
66
|
+
change:(NSDictionary<NSKeyValueChangeKey, id> *)change
|
|
67
|
+
context:(void *)context {
|
|
68
|
+
if ([keyPath isEqualToString:@"state"] && [object isKindOfClass:[MLNOfflinePack class]]) {
|
|
69
|
+
MLNOfflinePack *pack = (MLNOfflinePack *)object;
|
|
70
|
+
[self observerStateForPack:pack context:context];
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (packRequestQueue.count == 0) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
NSArray<MLNOfflinePack *> *packs = [[MLNOfflineStorage sharedOfflineStorage] packs];
|
|
79
|
+
if (packs == nil) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
while (packRequestQueue.count > 0) {
|
|
84
|
+
RCTPromiseResolveBlock resolve = [packRequestQueue objectAtIndex:0];
|
|
85
|
+
resolve([self _convertPacksToJson:packs]);
|
|
86
|
+
[packRequestQueue removeObjectAtIndex:0];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
- (void)createPack:(JS::NativeOfflineModule::NativeOfflinePackCreateOptions &)options
|
|
91
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
92
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
93
|
+
NSString *styleURL = options.mapStyle();
|
|
94
|
+
|
|
95
|
+
auto boundsArray = options.bounds();
|
|
96
|
+
if (boundsArray.size() != 4) {
|
|
97
|
+
reject(@"createPack", @"Invalid bounds", nil);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
MLNCoordinateBounds bounds = [MLRNUtils fromReactBounds:@[
|
|
102
|
+
@(boundsArray[0]), @(boundsArray[1]), @(boundsArray[2]), @(boundsArray[3])
|
|
103
|
+
]];
|
|
104
|
+
|
|
105
|
+
id<MLNOfflineRegion> offlineRegion =
|
|
106
|
+
[[MLNTilePyramidOfflineRegion alloc] initWithStyleURL:[NSURL URLWithString:styleURL]
|
|
107
|
+
bounds:bounds
|
|
108
|
+
fromZoomLevel:options.minZoom()
|
|
109
|
+
toZoomLevel:options.maxZoom()];
|
|
110
|
+
|
|
111
|
+
NSString *metadataString = options.metadata();
|
|
112
|
+
|
|
113
|
+
NSMutableDictionary *contextDictionary = [NSMutableDictionary new];
|
|
114
|
+
contextDictionary[MLRN_MIGRATION_KEY] = @(MLRN_MIGRATION_VERSION);
|
|
115
|
+
contextDictionary[@"id"] = [[[NSUUID UUID] UUIDString] lowercaseString];
|
|
116
|
+
contextDictionary[@"metadata"] = metadataString;
|
|
117
|
+
|
|
118
|
+
NSString *contextString = [self _serializeDictionaryToJSON:contextDictionary];
|
|
119
|
+
NSError *archiveError = nil;
|
|
120
|
+
NSData *contextData = [NSKeyedArchiver archivedDataWithRootObject:contextString
|
|
121
|
+
requiringSecureCoding:YES
|
|
122
|
+
error:&archiveError];
|
|
123
|
+
if (archiveError != nil) {
|
|
124
|
+
reject(@"createPack", @"Failed to archive context data", archiveError);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
[[MLNOfflineStorage sharedOfflineStorage]
|
|
129
|
+
addPackForRegion:offlineRegion
|
|
130
|
+
withContext:contextData
|
|
131
|
+
completionHandler:^(MLNOfflinePack *pack, NSError *error) {
|
|
132
|
+
if (error != nil) {
|
|
133
|
+
reject(@"createPack", error.description, error);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
resolve([self _convertPackToDict:pack]);
|
|
137
|
+
[pack resume];
|
|
138
|
+
}];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
- (void)mergeOfflineRegions:(NSString *)path
|
|
142
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
143
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
144
|
+
NSString *absolutePath;
|
|
145
|
+
if ([path isAbsolutePath]) {
|
|
146
|
+
absolutePath = path;
|
|
147
|
+
} else {
|
|
148
|
+
NSBundle *mainBundle = [NSBundle mainBundle];
|
|
149
|
+
NSString *fileName = [path stringByDeletingPathExtension];
|
|
150
|
+
NSString *extension = [path pathExtension];
|
|
151
|
+
absolutePath = [mainBundle pathForResource:fileName ofType:extension];
|
|
152
|
+
if (!absolutePath) {
|
|
153
|
+
return reject(
|
|
154
|
+
@"asset_does_not_exist",
|
|
155
|
+
[NSString
|
|
156
|
+
stringWithFormat:@"The given assetName, %@, can't be found in the app's bundle.",
|
|
157
|
+
path],
|
|
158
|
+
nil);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
[[MLNOfflineStorage sharedOfflineStorage]
|
|
163
|
+
addContentsOfFile:absolutePath
|
|
164
|
+
withCompletionHandler:^(NSURL *fileURL, NSArray<MLNOfflinePack *> *packs, NSError *error) {
|
|
165
|
+
if (error != nil) {
|
|
166
|
+
reject(@"mergeOfflineRegions", error.description, error);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
resolve(nil);
|
|
170
|
+
}];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
- (void)getPacks:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
|
|
174
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
175
|
+
NSArray<MLNOfflinePack *> *packs = [[MLNOfflineStorage sharedOfflineStorage] packs];
|
|
176
|
+
|
|
177
|
+
if (packs == nil) {
|
|
178
|
+
// Packs have not loaded yet
|
|
179
|
+
[self->packRequestQueue addObject:resolve];
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
resolve([self _convertPacksToJson:packs]);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
- (void)invalidateAmbientCache:(RCTPromiseResolveBlock)resolve
|
|
188
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
189
|
+
[[MLNOfflineStorage sharedOfflineStorage]
|
|
190
|
+
invalidateAmbientCacheWithCompletionHandler:^(NSError *error) {
|
|
191
|
+
if (error != nil) {
|
|
192
|
+
reject(@"invalidateAmbientCache", error.description, error);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
resolve(nil);
|
|
196
|
+
}];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
- (void)clearAmbientCache:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
|
|
200
|
+
[[MLNOfflineStorage sharedOfflineStorage]
|
|
201
|
+
clearAmbientCacheWithCompletionHandler:^(NSError *error) {
|
|
202
|
+
if (error != nil) {
|
|
203
|
+
reject(@"clearAmbientCache", error.description, error);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
resolve(nil);
|
|
207
|
+
}];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
- (void)setMaximumAmbientCacheSize:(double)size
|
|
211
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
212
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
213
|
+
[[MLNOfflineStorage sharedOfflineStorage]
|
|
214
|
+
setMaximumAmbientCacheSize:(NSUInteger)size
|
|
215
|
+
withCompletionHandler:^(NSError *error) {
|
|
216
|
+
if (error != nil) {
|
|
217
|
+
reject(@"setMaximumAmbientCacheSize", error.description, error);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
resolve(nil);
|
|
221
|
+
}];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
- (void)resetDatabase:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
|
|
225
|
+
[[MLNOfflineStorage sharedOfflineStorage] resetDatabaseWithCompletionHandler:^(NSError *error) {
|
|
226
|
+
if (error != nil) {
|
|
227
|
+
reject(@"resetDatabase", error.description, error);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
resolve(nil);
|
|
231
|
+
}];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
- (void)getPackStatus:(NSString *)packId
|
|
235
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
236
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
237
|
+
MLNOfflinePack *pack = [self _getPackById:packId];
|
|
238
|
+
|
|
239
|
+
if (pack == nil) {
|
|
240
|
+
resolve(nil);
|
|
241
|
+
NSLog(@"[MLRNOfflineModule] Pack not found");
|
|
242
|
+
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (pack.state == MLNOfflinePackStateUnknown) {
|
|
247
|
+
[pack addObserver:self
|
|
248
|
+
forKeyPath:@"state"
|
|
249
|
+
options:NSKeyValueObservingOptionNew
|
|
250
|
+
context:(__bridge_retained void *)resolve];
|
|
251
|
+
[pack requestProgress];
|
|
252
|
+
} else {
|
|
253
|
+
resolve([self _makeRegionStatusPayload:packId pack:pack]);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
- (void)observerStateForPack:(MLNOfflinePack *)pack context:(nullable void *)context {
|
|
258
|
+
RCTPromiseResolveBlock resolve = (__bridge_transfer RCTPromiseResolveBlock)context;
|
|
259
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
260
|
+
NSDictionary *metadata = [self _unarchiveContext:pack];
|
|
261
|
+
NSString *packId = metadata[@"id"];
|
|
262
|
+
resolve([self _makeRegionStatusPayload:packId pack:pack]);
|
|
263
|
+
});
|
|
264
|
+
[pack removeObserver:self forKeyPath:@"state" context:context];
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
- (void)setPackObserver:(NSString *)packId
|
|
268
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
269
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
270
|
+
MLNOfflinePack *pack = [self _getPackById:packId];
|
|
271
|
+
|
|
272
|
+
if (pack == nil) {
|
|
273
|
+
resolve(@NO);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// On iOS, observers are set up automatically via NSNotificationCenter
|
|
278
|
+
resolve(@YES);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
- (void)invalidatePack:(NSString *)packId
|
|
282
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
283
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
284
|
+
MLNOfflinePack *pack = [self _getPackById:packId];
|
|
285
|
+
|
|
286
|
+
if (pack == nil) {
|
|
287
|
+
resolve(nil);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
[[MLNOfflineStorage sharedOfflineStorage] invalidatePack:pack
|
|
291
|
+
withCompletionHandler:^(NSError *error) {
|
|
292
|
+
if (error != nil) {
|
|
293
|
+
reject(@"invalidatePack", error.description, error);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
resolve(nil);
|
|
297
|
+
}];
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
- (void)deletePack:(NSString *)packId
|
|
301
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
302
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
303
|
+
MLNOfflinePack *pack = [self _getPackById:packId];
|
|
304
|
+
|
|
305
|
+
if (pack == nil) {
|
|
306
|
+
resolve(nil);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (pack.state == MLNOfflinePackStateInvalid) {
|
|
310
|
+
NSError *error = [NSError errorWithDomain:MLNErrorDomain
|
|
311
|
+
code:1
|
|
312
|
+
userInfo:@{
|
|
313
|
+
NSLocalizedDescriptionKey :
|
|
314
|
+
NSLocalizedString(@"Pack has already been deleted", nil)
|
|
315
|
+
}];
|
|
316
|
+
reject(@"deletePack", error.description, error);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
[[MLNOfflineStorage sharedOfflineStorage] removePack:pack
|
|
320
|
+
withCompletionHandler:^(NSError *error) {
|
|
321
|
+
if (error != nil) {
|
|
322
|
+
reject(@"deletePack", error.description, error);
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
resolve(nil);
|
|
326
|
+
}];
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
- (void)pausePackDownload:(NSString *)packId
|
|
330
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
331
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
332
|
+
MLNOfflinePack *pack = [self _getPackById:packId];
|
|
333
|
+
|
|
334
|
+
if (pack == nil) {
|
|
335
|
+
reject(@"pausePackDownload", @"Unknown offline region", nil);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (pack.state == MLNOfflinePackStateInactive || pack.state == MLNOfflinePackStateComplete) {
|
|
340
|
+
resolve(nil);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
[pack suspend];
|
|
345
|
+
resolve(nil);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
- (void)resumePackDownload:(NSString *)packId
|
|
349
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
350
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
351
|
+
MLNOfflinePack *pack = [self _getPackById:packId];
|
|
352
|
+
|
|
353
|
+
if (pack == nil) {
|
|
354
|
+
reject(@"resumePack", @"Unknown offline region", nil);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (pack.state == MLNOfflinePackStateActive || pack.state == MLNOfflinePackStateComplete) {
|
|
359
|
+
resolve(nil);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
[pack resume];
|
|
364
|
+
resolve(nil);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
- (void)setTileCountLimit:(double)limit {
|
|
368
|
+
[[MLNOfflineStorage sharedOfflineStorage] setMaximumAllowedMapboxTiles:(uint64_t)limit];
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
- (void)setProgressEventThrottle:(double)throttleValue {
|
|
372
|
+
eventThrottle = throttleValue;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
- (void)offlinePackProgressDidChange:(NSNotification *)notification {
|
|
376
|
+
MLNOfflinePack *pack = notification.object;
|
|
377
|
+
|
|
378
|
+
if (pack.state == MLNOfflinePackStateInvalid) {
|
|
379
|
+
return; // Avoid invalid offline pack exception
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if ([self _shouldSendProgressEvent:[self _getCurrentTimestamp] pack:pack]) {
|
|
383
|
+
NSDictionary *metadata = [self _unarchiveContext:pack];
|
|
384
|
+
NSString *packId = metadata[@"id"];
|
|
385
|
+
NSDictionary *payload = [self _makeRegionStatusPayload:packId pack:pack];
|
|
386
|
+
if (_eventEmitterCallback) {
|
|
387
|
+
[self emitOnProgress:payload];
|
|
388
|
+
}
|
|
389
|
+
lastPackTimestamp = [self _getCurrentTimestamp];
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
lastPackState = pack.state;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
- (void)offlinePackDidReceiveError:(NSNotification *)notification {
|
|
396
|
+
MLNOfflinePack *pack = notification.object;
|
|
397
|
+
if (pack.state == MLNOfflinePackStateInvalid) {
|
|
398
|
+
return; // Avoid invalid offline pack exception
|
|
399
|
+
}
|
|
400
|
+
NSDictionary *metadata = [self _unarchiveContext:pack];
|
|
401
|
+
|
|
402
|
+
NSString *packId = metadata[@"id"];
|
|
403
|
+
if (packId != nil && _eventEmitterCallback) {
|
|
404
|
+
NSError *error = notification.userInfo[MLNOfflinePackUserInfoKeyError];
|
|
405
|
+
NSDictionary *payload = @{@"id" : packId, @"message" : error.description ?: @"Unknown error"};
|
|
406
|
+
[self emitOnError:payload];
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
- (void)offlinePackDidReceiveMaxAllowedMapboxTiles:(NSNotification *)notification {
|
|
411
|
+
MLNOfflinePack *pack = notification.object;
|
|
412
|
+
NSDictionary *metadata = [self _unarchiveContext:pack];
|
|
413
|
+
|
|
414
|
+
NSString *packId = metadata[@"id"];
|
|
415
|
+
if (packId != nil && _eventEmitterCallback) {
|
|
416
|
+
NSDictionary *payload = @{@"id" : packId, @"message" : @"Tile limit exceeded"};
|
|
417
|
+
|
|
418
|
+
[self emitOnError:payload];
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
- (double)_getCurrentTimestamp {
|
|
423
|
+
return CACurrentMediaTime() * 1000;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
- (NSString *)_serializeDictionaryToJSON:(NSDictionary *)dictionary {
|
|
427
|
+
if (dictionary == nil) {
|
|
428
|
+
return @"{}";
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
NSError *serializeError;
|
|
432
|
+
NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary
|
|
433
|
+
options:0
|
|
434
|
+
error:&serializeError];
|
|
435
|
+
|
|
436
|
+
if (serializeError || data == nil) {
|
|
437
|
+
return @"{}";
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
|
441
|
+
return string ?: @"{}";
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
- (NSDictionary *)_unarchiveContext:(MLNOfflinePack *)pack {
|
|
445
|
+
NSError *unarchiveError = nil;
|
|
446
|
+
id contextUnknown = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSString class]
|
|
447
|
+
fromData:pack.context
|
|
448
|
+
error:&unarchiveError];
|
|
449
|
+
|
|
450
|
+
if (unarchiveError != nil) {
|
|
451
|
+
NSLog(@"[MLRNOfflineModule] Failed to unarchive context: %@",
|
|
452
|
+
unarchiveError.localizedDescription);
|
|
453
|
+
return @{};
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// After migration, all packs should be in JSON string format
|
|
457
|
+
if (contextUnknown == nil) {
|
|
458
|
+
return @{};
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Parse JSON string to dictionary
|
|
462
|
+
if ([contextUnknown isKindOfClass:[NSString class]]) {
|
|
463
|
+
NSDictionary *contextDictionary = [NSJSONSerialization
|
|
464
|
+
JSONObjectWithData:[contextUnknown dataUsingEncoding:NSUTF8StringEncoding]
|
|
465
|
+
options:NSJSONReadingMutableContainers
|
|
466
|
+
error:nil];
|
|
467
|
+
return contextDictionary ?: @{};
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// This should not happen after migration, but handle gracefully
|
|
471
|
+
return @{};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Migrate offline packs to the latest context format.
|
|
476
|
+
*
|
|
477
|
+
* - Until v5 context uses NSDictionary
|
|
478
|
+
* - From v6 context uses JSON string
|
|
479
|
+
* - From v11 context uses JSON string with with `id` (UUID) and `metadata` (JSON string)
|
|
480
|
+
*/
|
|
481
|
+
- (void)runMigrations {
|
|
482
|
+
NSArray<MLNOfflinePack *> *packs = [[MLNOfflineStorage sharedOfflineStorage] packs];
|
|
483
|
+
|
|
484
|
+
if (packs == nil) {
|
|
485
|
+
NSLog(@"[MLRNOfflineModule] No packs found for migration");
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
NSMutableArray<MLNOfflinePack *> *packsToMigrate = [NSMutableArray new];
|
|
490
|
+
|
|
491
|
+
for (MLNOfflinePack *pack in packs) {
|
|
492
|
+
BOOL needsMigration = NO;
|
|
493
|
+
|
|
494
|
+
NSError *unarchiveError = nil;
|
|
495
|
+
NSSet *allowedClasses = [NSSet setWithArray:@[ [NSDictionary class], [NSString class] ]];
|
|
496
|
+
id contextUnknown = [NSKeyedUnarchiver unarchivedObjectOfClasses:allowedClasses
|
|
497
|
+
fromData:pack.context
|
|
498
|
+
error:&unarchiveError];
|
|
499
|
+
|
|
500
|
+
if (unarchiveError != nil) {
|
|
501
|
+
NSLog(@"[MLRNOfflineModule] Failed to unarchive context during migration check: %@",
|
|
502
|
+
unarchiveError.localizedDescription);
|
|
503
|
+
needsMigration = YES;
|
|
504
|
+
}
|
|
505
|
+
// <= v5 format (NSDictionary)
|
|
506
|
+
else if ([contextUnknown isKindOfClass:[NSDictionary class]]) {
|
|
507
|
+
needsMigration = YES;
|
|
508
|
+
}
|
|
509
|
+
// Check >= v6+ format (JSON string)
|
|
510
|
+
else {
|
|
511
|
+
NSDictionary *contextDictionary = [self _unarchiveContext:pack];
|
|
512
|
+
if (contextDictionary == nil || contextDictionary[MLRN_MIGRATION_KEY] == nil ||
|
|
513
|
+
[contextDictionary[MLRN_MIGRATION_KEY] integerValue] != MLRN_MIGRATION_VERSION) {
|
|
514
|
+
needsMigration = YES;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
if (needsMigration) {
|
|
519
|
+
[packsToMigrate addObject:pack];
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
if (packsToMigrate.count == 0) {
|
|
524
|
+
NSLog(@"[MLRNOfflineModule] No packs need migration");
|
|
525
|
+
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
NSLog(@"[MLRNOfflineModule] Migrating %lu offline pack(s)", (unsigned long)packsToMigrate.count);
|
|
530
|
+
|
|
531
|
+
for (MLNOfflinePack *pack in packsToMigrate) {
|
|
532
|
+
[self migratePack:pack];
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
- (void)migratePack:(MLNOfflinePack *)pack {
|
|
537
|
+
NSDictionary *oldContextDictionary = nil;
|
|
538
|
+
|
|
539
|
+
NSError *unarchiveError = nil;
|
|
540
|
+
NSSet *allowedClasses = [NSSet setWithArray:@[ [NSDictionary class], [NSString class] ]];
|
|
541
|
+
id oldContextUnknown = [NSKeyedUnarchiver unarchivedObjectOfClasses:allowedClasses
|
|
542
|
+
fromData:pack.context
|
|
543
|
+
error:&unarchiveError];
|
|
544
|
+
|
|
545
|
+
if (unarchiveError != nil) {
|
|
546
|
+
NSLog(@"[MLRNOfflineModule] Failed to unarchive context during migration: %@",
|
|
547
|
+
unarchiveError.localizedDescription);
|
|
548
|
+
oldContextDictionary = @{};
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// Handle <= v5 NSDictionary
|
|
552
|
+
else if ([oldContextUnknown isKindOfClass:[NSDictionary class]]) {
|
|
553
|
+
oldContextDictionary = oldContextUnknown;
|
|
554
|
+
}
|
|
555
|
+
// Handle >= v6+ JSON string
|
|
556
|
+
else {
|
|
557
|
+
oldContextDictionary = [self _unarchiveContext:pack];
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (oldContextDictionary == nil) {
|
|
561
|
+
oldContextDictionary = @{};
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
NSString *packId = [[[NSUUID UUID] UUIDString] lowercaseString];
|
|
565
|
+
NSMutableDictionary *newContextDictionary = [NSMutableDictionary new];
|
|
566
|
+
|
|
567
|
+
newContextDictionary[MLRN_MIGRATION_KEY] = @(MLRN_MIGRATION_VERSION);
|
|
568
|
+
newContextDictionary[@"id"] = packId;
|
|
569
|
+
newContextDictionary[@"metadata"] = [self _serializeDictionaryToJSON:oldContextDictionary];
|
|
570
|
+
|
|
571
|
+
NSError *archiveError = nil;
|
|
572
|
+
NSData *newContextData = [NSKeyedArchiver
|
|
573
|
+
archivedDataWithRootObject:[self _serializeDictionaryToJSON:newContextDictionary]
|
|
574
|
+
requiringSecureCoding:YES
|
|
575
|
+
error:&archiveError];
|
|
576
|
+
|
|
577
|
+
if (archiveError != nil) {
|
|
578
|
+
NSLog(@"[MLRNOfflineModule] Failed to archive context for pack %@: %@", packId,
|
|
579
|
+
archiveError.localizedDescription);
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
[pack setContext:newContextData
|
|
584
|
+
completionHandler:^(NSError *error) {
|
|
585
|
+
if (error != nil) {
|
|
586
|
+
NSLog(@"[MLRNOfflineModule] Failed to migrate pack %@: %@", packId,
|
|
587
|
+
error.localizedDescription);
|
|
588
|
+
} else {
|
|
589
|
+
NSLog(@"[MLRNOfflineModule] Successfully migrated pack %@", packId);
|
|
590
|
+
}
|
|
591
|
+
}];
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
- (NSString *)_stateToString:(MLNOfflinePackState)state {
|
|
595
|
+
switch (state) {
|
|
596
|
+
case MLNOfflinePackStateActive:
|
|
597
|
+
return @"active";
|
|
598
|
+
case MLNOfflinePackStateComplete:
|
|
599
|
+
return @"complete";
|
|
600
|
+
case MLNOfflinePackStateInactive:
|
|
601
|
+
default:
|
|
602
|
+
return @"inactive";
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
- (NSDictionary *)_makeRegionStatusPayload:(NSString *)packId pack:(MLNOfflinePack *)pack {
|
|
607
|
+
uint64_t completedResources = pack.progress.countOfResourcesCompleted;
|
|
608
|
+
uint64_t expectedResources = pack.progress.countOfResourcesExpected;
|
|
609
|
+
|
|
610
|
+
double percentage = 0.0;
|
|
611
|
+
if (expectedResources > 0) {
|
|
612
|
+
percentage = 100.0 * (double)completedResources / (double)expectedResources;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
return @{
|
|
616
|
+
@"id" : packId,
|
|
617
|
+
@"state" : [self _stateToString:pack.state],
|
|
618
|
+
@"percentage" : @(percentage),
|
|
619
|
+
@"completedResourceCount" : @(pack.progress.countOfResourcesCompleted),
|
|
620
|
+
@"completedResourceSize" : @(pack.progress.countOfBytesCompleted),
|
|
621
|
+
@"completedTileSize" : @(pack.progress.countOfTileBytesCompleted),
|
|
622
|
+
@"completedTileCount" : @(pack.progress.countOfTilesCompleted),
|
|
623
|
+
@"requiredResourceCount" : @(pack.progress.maximumResourcesExpected)
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
- (NSArray<NSDictionary *> *)_convertPacksToJson:(NSArray<MLNOfflinePack *> *)packs {
|
|
628
|
+
NSMutableArray<NSDictionary *> *jsonPacks = [NSMutableArray new];
|
|
629
|
+
|
|
630
|
+
if (packs == nil) {
|
|
631
|
+
return jsonPacks;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
for (MLNOfflinePack *pack in packs) {
|
|
635
|
+
NSDictionary *packDict = [self _convertPackToDict:pack];
|
|
636
|
+
if (packDict != nil) {
|
|
637
|
+
[jsonPacks addObject:packDict];
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
return jsonPacks;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
- (NSDictionary *)_convertPackToDict:(MLNOfflinePack *)pack {
|
|
645
|
+
MLNTilePyramidOfflineRegion *region = (MLNTilePyramidOfflineRegion *)pack.region;
|
|
646
|
+
if (region == nil) {
|
|
647
|
+
return nil;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
NSArray *bounds = [MLRNUtils fromCoordinateBounds:region.bounds];
|
|
651
|
+
NSDictionary *contextDictionary = [self _unarchiveContext:pack];
|
|
652
|
+
|
|
653
|
+
return @{
|
|
654
|
+
@"id" : contextDictionary[@"id"] ?: @"",
|
|
655
|
+
@"bounds" : bounds,
|
|
656
|
+
@"metadata" : contextDictionary[@"metadata"]
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
- (MLNOfflinePack *)_getPackById:(NSString *)packId {
|
|
661
|
+
NSArray<MLNOfflinePack *> *packs = [[MLNOfflineStorage sharedOfflineStorage] packs];
|
|
662
|
+
|
|
663
|
+
if (packs == nil || packId == nil) {
|
|
664
|
+
return nil;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
for (MLNOfflinePack *pack in packs) {
|
|
668
|
+
NSDictionary *metadata = [self _unarchiveContext:pack];
|
|
669
|
+
if ([packId isEqualToString:metadata[@"id"]]) {
|
|
670
|
+
return pack;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
return nil;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
- (BOOL)_shouldSendProgressEvent:(double)currentTimestamp pack:(MLNOfflinePack *)currentPack {
|
|
678
|
+
if (lastPackState == -1) {
|
|
679
|
+
return YES;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
if (lastPackState != currentPack.state) {
|
|
683
|
+
return YES;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
if (currentTimestamp - lastPackTimestamp > eventThrottle) {
|
|
687
|
+
return YES;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
return NO;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
@end
|
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.setConnected = exports.removeCustomHeader = exports.addCustomHeader = exports.StyleURL = exports.StyleSource =
|
|
6
|
+
exports.setConnected = exports.removeCustomHeader = exports.addCustomHeader = exports.StyleURL = exports.StyleSource = void 0;
|
|
7
7
|
var _reactNative = require("react-native");
|
|
8
8
|
const MLRNModule = Object.create(_reactNative.NativeModules.MLRNModule);
|
|
9
9
|
const {
|
|
10
|
-
OfflinePackDownloadState,
|
|
11
10
|
StyleSource,
|
|
12
11
|
StyleURL,
|
|
13
12
|
addCustomHeader,
|
|
@@ -19,5 +18,4 @@ exports.removeCustomHeader = removeCustomHeader;
|
|
|
19
18
|
exports.addCustomHeader = addCustomHeader;
|
|
20
19
|
exports.StyleURL = StyleURL;
|
|
21
20
|
exports.StyleSource = StyleSource;
|
|
22
|
-
exports.OfflinePackDownloadState = OfflinePackDownloadState;
|
|
23
21
|
//# sourceMappingURL=MLRNModule.js.map
|