[ios, macos] Offline regions merge. (#12791)

* [ios, macos] Add offline regions merge.

* [ios, macos] Update changelogs.

* [ios, macos] Fix refreshing the offline packs after new content is added.

* [ios, macos] Update MGLOfflineStorage's add contents of file documentation.

* [ios, macos] Add MGLOfflineStorage test cases for adding file contents.

* [ios, macos] Add offline merge test database.

* [ios, macos] Add packs parameter to MGLBatchedOfflinePackAdditionCompletionHandler.

* [core] Fix a query mege duplication.

* [ios, macos] Remove unnecessary pack iteration.

* [ios, macos] Fix packs update KVO notifications.

* [ios, macos] Add localization strings.

* [core] Fix query readability.

* [ios, macos] Fix MGLOfflineStorageTest, cleanup the cache database after the test.

* [ios, macos] Fix offline packs, updating triggers a crash.
This commit is contained in:
Fabian Guerra Soto
2018-09-17 15:31:43 -07:00
committed by GitHub
parent 153e97c8e7
commit a938c3ef68
11 changed files with 272 additions and 8 deletions

View File

@@ -1,3 +1,6 @@
/* User-friendly error description */
"ADD_FILE_CONTENTS_FAILED_DESC" = "Unable to add offline packs from the file at %@.";
/* Clock position format, long: {hours} o’clock */
"CLOCK_FMT_LONG" = "%@ o’clock";

View File

@@ -134,6 +134,18 @@ typedef void (^MGLOfflinePackAdditionCompletionHandler)(MGLOfflinePack * _Nullab
*/
typedef void (^MGLOfflinePackRemovalCompletionHandler)(NSError * _Nullable error);
/**
A block to be called once the contents of a file are copied into the current packs.
@param fileURL The file URL of the offline database containing the offline packs
that were copied.
@param packs An array of all known offline packs, or `nil` if there was an error
creating or adding the pack.
@param error A pointer to an error object (if any) indicating why the pack could
not be created or added.
*/
typedef void (^MGLBatchedOfflinePackAdditionCompletionHandler)(NSURL *fileURL, NSArray<MGLOfflinePack *> * _Nullable packs, NSError * _Nullable error);
/**
The type of resource that is requested.
*/
@@ -174,6 +186,42 @@ MGL_EXPORT
*/
@property (class, nonatomic, readonly) MGLOfflineStorage *sharedOfflineStorage;
#pragma mark - Adding Contents of File
/**
Adds the offline packs located at the given file path to offline storage.
The file must be a valid offline region database bundled with the application
or downloaded separately.
The resulting packs are added or updated to the shared offline storage object’s `packs`
property, then the `completion` block is executed.
@param filePath A string representation of the file path. The file path must be
writable as schema updates may be perfomed.
@param completion The completion handler to call once the contents of the given
file has been added to offline storage. This handler is executed asynchronously
on the main queue.
*/
- (void)addContentsOfFile:(NSString *)filePath withCompletionHandler:(nullable MGLBatchedOfflinePackAdditionCompletionHandler)completion;
/**
Adds the offline packs located at the given URL to offline storage.
The file must be a valid offline region database bundled with the application
or downloaded separately.
The resulting packs are added or updated to the shared offline storage object’s `packs`
property, then the `completion` block is executed.
@param fileURL A file URL specifying the file to add. URL should be a valid system path.
The file URL must be writable as schema updates may be performed.
@param completion The completion handler to call once the contents of the given
file has been added to offline storage. This handler is executed asynchronously
on the main queue.
*/
- (void)addContentsOfURL:(NSURL *)fileURL withCompletionHandler:(nullable MGLBatchedOfflinePackAdditionCompletionHandler)completion;
#pragma mark - Accessing the Delegate
/**

View File

@@ -264,6 +264,89 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
}
}
#pragma mark Offline merge methods
- (void)addContentsOfFile:(NSString *)filePath withCompletionHandler:(MGLBatchedOfflinePackAdditionCompletionHandler)completion {
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
[self addContentsOfURL:fileURL withCompletionHandler:completion];
}
- (void)addContentsOfURL:(NSURL *)fileURL withCompletionHandler:(MGLBatchedOfflinePackAdditionCompletionHandler)completion {
NSFileManager *fileManager = [NSFileManager defaultManager];
if (!fileURL.isFileURL) {
[NSException raise:NSInvalidArgumentException format:@"%@ must be a valid file path", fileURL.absoluteString];
}
if (![fileManager isWritableFileAtPath:fileURL.path]) {
[NSException raise:NSInvalidArgumentException format:@"The file path: %@ must be writable", fileURL.absoluteString];
}
__weak MGLOfflineStorage *weakSelf = self;
[self _addContentsOfFile:fileURL.path withCompletionHandler:^(NSArray<MGLOfflinePack *> * _Nullable packs, NSError * _Nullable error) {
if (packs) {
NSMutableDictionary *packsByIdentifier = [NSMutableDictionary dictionary];
MGLOfflineStorage *strongSelf = weakSelf;
for (MGLOfflinePack *pack in packs) {
[packsByIdentifier setObject:pack forKey:@(pack.mbglOfflineRegion->getID())];
}
id mutablePacks = [strongSelf mutableArrayValueForKey:@"packs"];
NSMutableIndexSet *replaceIndexSet = [NSMutableIndexSet indexSet];
NSMutableArray *replacePacksArray = [NSMutableArray array];
[strongSelf.packs enumerateObjectsUsingBlock:^(MGLOfflinePack * _Nonnull pack, NSUInteger idx, BOOL * _Nonnull stop) {
MGLOfflinePack *newPack = packsByIdentifier[@(pack.mbglOfflineRegion->getID())];
if (newPack) {
MGLOfflinePack *previousPack = [mutablePacks objectAtIndex:idx];
[previousPack invalidate];
[replaceIndexSet addIndex:idx];
[replacePacksArray addObject:[packsByIdentifier objectForKey:@(newPack.mbglOfflineRegion->getID())]];
[packsByIdentifier removeObjectForKey:@(newPack.mbglOfflineRegion->getID())];
}
}];
if (replaceIndexSet.count > 0) {
[mutablePacks replaceObjectsAtIndexes:replaceIndexSet withObjects:replacePacksArray];
}
[mutablePacks addObjectsFromArray:packsByIdentifier.allValues];
}
if (completion) {
completion(fileURL, packs, error);
}
}];
}
- (void)_addContentsOfFile:(NSString *)filePath withCompletionHandler:(void (^)(NSArray<MGLOfflinePack *> * _Nullable packs, NSError * _Nullable error))completion {
self.mbglFileSource->mergeOfflineRegions(std::string(static_cast<const char *>([filePath UTF8String])), [&, completion, filePath](mbgl::expected<mbgl::OfflineRegions, std::exception_ptr> result) {
NSError *error;
NSMutableArray *packs;
if (!result) {
NSString *description = [NSString stringWithFormat:NSLocalizedStringWithDefaultValue(@"ADD_FILE_CONTENTS_FAILED_DESC", @"Foundation", nil, @"Unable to add offline packs from the file at %@.", @"User-friendly error description"), filePath];
error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:@{
NSLocalizedDescriptionKey: description,
NSLocalizedFailureReasonErrorKey: @(mbgl::util::toString(result.error()).c_str())
}];
} else {
auto& regions = result.value();
packs = [NSMutableArray arrayWithCapacity:regions.size()];
for (auto &region : regions) {
MGLOfflinePack *pack = [[MGLOfflinePack alloc] initWithMBGLRegion:new mbgl::OfflineRegion(std::move(region))];
[packs addObject:pack];
}
}
if (completion) {
dispatch_async(dispatch_get_main_queue(), [&, completion, error, packs](void) {
completion(packs, error);
});
}
});
}
#pragma mark Pack management methods
- (void)addPackForRegion:(id <MGLOfflineRegion>)region withContext:(NSData *)context completionHandler:(MGLOfflinePackAdditionCompletionHandler)completion {

View File

@@ -12,6 +12,24 @@
@implementation MGLOfflineStorageTests
+ (void)tearDown {
NSURL *cacheDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create:NO
error:nil];
// Unit tests don't use the main bundle; use com.mapbox.ios.sdk instead.
NSString *bundleIdentifier = [NSBundle bundleForClass:[MGLMapView class]].bundleIdentifier;
cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent:bundleIdentifier];
cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent:@".mapbox"];
XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:cacheDirectoryURL.path], @"Cache subdirectory should exist.");
NSURL *cacheURL = [cacheDirectoryURL URLByAppendingPathComponent:@"cache.db"];
[[NSFileManager defaultManager] removeItemAtURL:cacheURL error:nil];
XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:cacheURL.path], @"Cache subdirectory should not exist.");
}
- (void)setUp {
[super setUp];
@@ -264,4 +282,110 @@
[os setDelegate:nil];
}
- (void)testAddFileContent {
// Valid database
{
NSURL *resourceURL = [NSURL fileURLWithPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"barcelona" ofType:@"db"]];
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
NSString *filePath = [documentDir stringByAppendingPathComponent:@"barcelona.db"];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL exists = [fileManager fileExistsAtPath:filePath];
if (exists) {
[fileManager removeItemAtPath:filePath error:nil];
}
NSError *error;
[fileManager moveItemAtURL:resourceURL toURL:[NSURL fileURLWithPath:filePath] error:&error];
NSDictionary *atributes = @{ NSFilePosixPermissions: @0777 };
error = nil;
[fileManager setAttributes:atributes ofItemAtPath:filePath error:&error];
XCTAssertNil(error, @"Changing the file's permissions:%@ should not return an error.", filePath);
error = nil;
NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:filePath error:&error];
NSNumber *fileSizeNumber = [fileAttributes objectForKey:NSFileSize];
long long fileSize = [fileSizeNumber longLongValue];
long long dabaseFileSize = 32391168;
// Merging databases creates an empty file if the file does not exist at the given path.
XCTAssertEqual(fileSize, dabaseFileSize, @"The dabase file size must be:%l actual size:%l", dabaseFileSize, fileSize);
NSUInteger countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count;
[self keyValueObservingExpectationForObject:[MGLOfflineStorage sharedOfflineStorage] keyPath:@"packs" handler:^BOOL(id _Nonnull observedObject, NSDictionary * _Nonnull change) {
const auto changeKind = static_cast<NSKeyValueChange>([change[NSKeyValueChangeKindKey] unsignedLongValue]);
NSIndexSet *indices = change[NSKeyValueChangeIndexesKey];
return changeKind == NSKeyValueChangeInsertion && indices.count == 1;
}];
XCTestExpectation *fileAdditionCompletionHandlerExpectation = [self expectationWithDescription:@"add database content completion handler"];
MGLOfflineStorage *os = [MGLOfflineStorage sharedOfflineStorage];
[os addContentsOfFile:filePath withCompletionHandler:^(NSURL *fileURL, NSArray<MGLOfflinePack *> * _Nullable packs, NSError * _Nullable error) {
XCTAssertNotNil(fileURL, @"The fileURL should not be nil.");
XCTAssertNotNil(packs, @"Adding the contents of the barcelona.db should update one pack.");
XCTAssertNil(error, @"Adding contents to a file should not return an error.");
for (MGLOfflinePack *pack in [MGLOfflineStorage sharedOfflineStorage].packs) {
NSLog(@"PACK:%@", pack);
}
[fileAdditionCompletionHandlerExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:2 handler:nil];
// Depending on the database it may update or add a pack. For this case specifically the offline database adds one pack.
XCTAssertEqual([MGLOfflineStorage sharedOfflineStorage].packs.count, countOfPacks + 1, @"Adding contents of barcelona.db should add one pack.");
}
// Invalid database type
{
NSURL *resourceURL = [NSURL fileURLWithPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"one-liner" ofType:@"json"]];
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
NSString *filePath = [documentDir stringByAppendingPathComponent:@"on-liner-copy.json"];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL exists = [fileManager fileExistsAtPath:filePath];
if (exists) {
[fileManager removeItemAtPath:filePath error:nil];
}
NSError *error;
[fileManager copyItemAtURL:resourceURL toURL:[NSURL fileURLWithPath:filePath] error:&error];
XCTestExpectation *invalidFileCompletionHandlerExpectation = [self expectationWithDescription:@"invalid content database completion handler"];
MGLOfflineStorage *os = [MGLOfflineStorage sharedOfflineStorage];
[os addContentsOfFile:filePath withCompletionHandler:^(NSURL *fileURL, NSArray<MGLOfflinePack *> * _Nullable packs, NSError * _Nullable error) {
XCTAssertNotNil(error, @"Passing an invalid offline database file should return an error.");
XCTAssertNil(packs, @"Passing an invalid offline database file should not add packs to the offline database.");
[invalidFileCompletionHandlerExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:2 handler:nil];
}
// File non existent
{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
NSString *filePath = [documentDir stringByAppendingPathComponent:@"nonexistent.db"];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL exists = [fileManager fileExistsAtPath:filePath];
if (exists) {
[fileManager removeItemAtPath:filePath error:nil];
}
MGLOfflineStorage *os = [MGLOfflineStorage sharedOfflineStorage];
XCTAssertThrowsSpecificNamed([os addContentsOfFile:filePath withCompletionHandler:nil], NSException, NSInvalidArgumentException, "MGLOfflineStorage should rise an exception if an invalid database file is passed.");
}
// URL to a non-file
{
NSURL *resourceURL = [NSURL URLWithString:@"https://www.mapbox.com"];
MGLOfflineStorage *os = [MGLOfflineStorage sharedOfflineStorage];
XCTAssertThrowsSpecificNamed([os addContentsOfURL:resourceURL withCompletionHandler:nil], NSException, NSInvalidArgumentException, "MGLOfflineStorage should rise an exception if an invalid URL file is passed.");
}
}
@end

Binary file not shown.

View File

@@ -689,9 +689,9 @@ OfflineDatabase::mergeDatabase(const std::string& sideDatabasePath) {
// clang-format off
mapbox::sqlite::Query queryRegions{ getStatement(
"SELECT r.id, r.definition, r.description "
"SELECT DISTINCT r.id, r.definition, r.description "
"FROM side.regions sr "
"JOIN regions r ON sr.definition = r.definition") };
"JOIN regions r ON sr.definition = r.definition AND sr.description IS r.description") };
// clang-format on
OfflineRegions result;

View File

@@ -36,6 +36,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Added the `MGLShapeOfflineRegion` class for creating an offline pack that covers an arbitrary shape. ([#11447](https://github.com/mapbox/mapbox-gl-native/pull/11447))
* Fixed crashes when offline storage encountered certain SQLite errors. ([#12224](https://github.com/mapbox/mapbox-gl-native/pull/12224))
* Added `-[MGLOfflineStorage addContentsOfFile:withCompletionHandler:]` and `-[MGLOfflineStorage addContentsOfURL:withCompletionHandler:]` methods to add pregenerated offline packs to offline storage. ([#12791](https://github.com/mapbox/mapbox-gl-native/pull/12791))
### Other changes

View File

@@ -33,6 +33,8 @@
1F06668D1EC64F8E001C16D7 /* MGLLight.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F0666891EC64F8E001C16D7 /* MGLLight.mm */; };
1F26B6C120E189C9007BCC21 /* MBXCustomLocationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F26B6C020E189C9007BCC21 /* MBXCustomLocationViewController.m */; };
1F26B6C320E1A351007BCC21 /* simple_route.json in Resources */ = {isa = PBXBuildFile; fileRef = 1F26B6C220E1A351007BCC21 /* simple_route.json */; };
1F5627F62148387100038ED1 /* barcelona.db in Resources */ = {isa = PBXBuildFile; fileRef = 1F5627F52148387100038ED1 /* barcelona.db */; };
1F5627F72148387100038ED1 /* barcelona.db in Resources */ = {isa = PBXBuildFile; fileRef = 1F5627F52148387100038ED1 /* barcelona.db */; };
1F7454921ECBB42C00021D39 /* MGLLight.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F0666891EC64F8E001C16D7 /* MGLLight.mm */; };
1F7454931ECBB43F00021D39 /* MGLLight.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F0666881EC64F8E001C16D7 /* MGLLight.h */; settings = {ATTRIBUTES = (Public, ); }; };
1F7454961ECD450D00021D39 /* MGLLight_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F7454941ECD450D00021D39 /* MGLLight_Private.h */; };
@@ -782,6 +784,7 @@
1F26B6BF20E189C9007BCC21 /* MBXCustomLocationViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBXCustomLocationViewController.h; sourceTree = "<group>"; };
1F26B6C020E189C9007BCC21 /* MBXCustomLocationViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBXCustomLocationViewController.m; sourceTree = "<group>"; };
1F26B6C220E1A351007BCC21 /* simple_route.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = simple_route.json; sourceTree = "<group>"; };
1F5627F52148387100038ED1 /* barcelona.db */ = {isa = PBXFileReference; lastKnownFileType = file; name = barcelona.db; path = ../../darwin/test/barcelona.db; sourceTree = "<group>"; };
1F7454941ECD450D00021D39 /* MGLLight_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight_Private.h; sourceTree = "<group>"; };
1F7454A61ED08AB400021D39 /* MGLLightTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLLightTest.mm; path = ../../darwin/test/MGLLightTest.mm; sourceTree = "<group>"; };
1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLNSDateAdditionsTests.mm; path = ../../darwin/test/MGLNSDateAdditionsTests.mm; sourceTree = "<group>"; };
@@ -1922,6 +1925,7 @@
DA2E88551CC036F400F24E7B /* Info.plist */,
DA2784FB1DF02FF4001D5B8D /* Media.xcassets */,
DA35D0871E1A6309007DED41 /* one-liner.json */,
1F5627F52148387100038ED1 /* barcelona.db */,
);
name = "SDK Tests";
path = test;
@@ -2795,6 +2799,7 @@
buildActionMask = 2147483647;
files = (
16376B471FFDB92B0000563E /* one-liner.json in Resources */,
1F5627F72148387100038ED1 /* barcelona.db in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2843,6 +2848,7 @@
DA2784FC1DF02FF4001D5B8D /* Media.xcassets in Resources */,
353BAEF71D646370009A8DA9 /* amsterdam.geojson in Resources */,
DA35D0881E1A6309007DED41 /* one-liner.json in Resources */,
1F5627F62148387100038ED1 /* barcelona.db in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -1,12 +1,6 @@
/* Accessibility hint */
"ANNOTATION_A11Y_HINT" = "Shows more info";
/* No comment provided by engineer. */
"API_CLIENT_400_DESC" = "The session data task failed. Original request was: %@";
/* No comment provided by engineer. */
"API_CLIENT_400_REASON" = "The status code was %ld";
/* No comment provided by engineer. */
"CANCEL" = "Cancel";

View File

@@ -30,6 +30,7 @@
* Added the `MGLShapeOfflineRegion` class for creating an offline pack that covers an arbitrary shape. ([#11447](https://github.com/mapbox/mapbox-gl-native/pull/11447))
* Fixed crashes when offline storage encountered certain SQLite errors. ([#12224](https://github.com/mapbox/mapbox-gl-native/pull/12224))
* Added `-[MGLOfflineStorage addContentsOfFile:withCompletionHandler:]` and `-[MGLOfflineStorage addContentsOfURL:withCompletionHandler:]` methods to add pregenerated offline packs to offline storage. ([#12791](https://github.com/mapbox/mapbox-gl-native/pull/12791))
### Other changes

View File

@@ -18,6 +18,7 @@
170A82BF201BDD1B00943087 /* MGLHeatmapStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 170A82BE201BDD1B00943087 /* MGLHeatmapStyleLayerTests.mm */; };
170A82C4201FB6EC00943087 /* MGLHeatmapColorTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 170A82C2201FAFF800943087 /* MGLHeatmapColorTests.mm */; };
1753ED401E53CE6100A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */; };
1F5627F9214838A300038ED1 /* barcelona.db in Resources */ = {isa = PBXBuildFile; fileRef = 1F5627F8214838A200038ED1 /* barcelona.db */; };
1F7454A31ECFB00300021D39 /* MGLLight_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F7454A01ECFB00300021D39 /* MGLLight_Private.h */; };
1F7454A41ECFB00300021D39 /* MGLLight.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F7454A11ECFB00300021D39 /* MGLLight.h */; settings = {ATTRIBUTES = (Public, ); }; };
1F7454A51ECFB00300021D39 /* MGLLight.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F7454A21ECFB00300021D39 /* MGLLight.mm */; };
@@ -311,6 +312,7 @@
170A82BE201BDD1B00943087 /* MGLHeatmapStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLHeatmapStyleLayerTests.mm; sourceTree = "<group>"; };
170A82C2201FAFF800943087 /* MGLHeatmapColorTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLHeatmapColorTests.mm; sourceTree = "<group>"; };
1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLConversion.h; sourceTree = "<group>"; };
1F5627F8214838A200038ED1 /* barcelona.db */ = {isa = PBXFileReference; lastKnownFileType = file; name = barcelona.db; path = ../../darwin/test/barcelona.db; sourceTree = "<group>"; };
1F7454A01ECFB00300021D39 /* MGLLight_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight_Private.h; sourceTree = "<group>"; };
1F7454A11ECFB00300021D39 /* MGLLight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight.h; sourceTree = "<group>"; };
1F7454A21ECFB00300021D39 /* MGLLight.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLLight.mm; sourceTree = "<group>"; };
@@ -1125,6 +1127,7 @@
DAE6C33A1CC30DB200DB3429 /* Info.plist */,
DA2784FD1DF03060001D5B8D /* Media.xcassets */,
DA35D0891E1A631B007DED41 /* one-liner.json */,
1F5627F8214838A200038ED1 /* barcelona.db */,
);
name = "SDK Tests";
path = test;
@@ -1500,6 +1503,7 @@
35724FC41D630502002A4AB4 /* amsterdam.geojson in Resources */,
DA2784FE1DF03060001D5B8D /* Media.xcassets in Resources */,
DA35D08A1E1A631B007DED41 /* one-liner.json in Resources */,
1F5627F9214838A300038ED1 /* barcelona.db in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};