summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinh Nguyễn <mxn@1ec5.org>2016-03-17 16:37:37 -0700
committerMinh Nguyễn <mxn@1ec5.org>2016-03-18 14:02:32 -0700
commitb493bdc649b4e32cbedb3fd5cb9e3e4157dfdb34 (patch)
treeb46f2d6f5e2781e4ee8e5a38747039ff8ce9a5d5
parentfff13d0976015650c2c79348dd8d51d25ce0b2d1 (diff)
downloadqtlocation-mapboxgl-b493bdc649b4e32cbedb3fd5cb9e3e4157dfdb34.tar.gz
[ios, osx] Unified offline and ambient caches
There is now only one instance of mbgl::OfflineFileSource, created when the shared MGLOfflineStorage object is initialized. Also create and use the shared MGLOfflineStorage object when initializing an MGLMapView object. The unified cache file is located in a subdirectory of Application Support, where the SDK has control over the file’s lifetime. The subdirectory is already named after the host application’s bundle identifier, ensuring that each Mapbox-powered application has an independent tile limit. If there’s an ambient cache in a subdirectory of Caches, delete it. If there’s an offline cache in a subdirectory of Documents on iOS or Caches on OS X, move it to the unified cache location in a subdirectory of Application Support. Fixes the iOS/OS X side of #4338.
-rw-r--r--CHANGELOG.md3
-rw-r--r--platform/darwin/src/MGLOfflineStorage.mm41
-rw-r--r--platform/ios/src/MGLMapView.mm42
-rw-r--r--platform/osx/src/MGLMapView.mm60
4 files changed, 64 insertions, 82 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 618f4d2615..9cd8ae1e20 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -57,9 +57,10 @@ Known issues:
- Black Screen On Ice Cream Sandwich and Jelly Bean devices ([#2802](https://github.com/mapbox/mapbox-gl-native/issues/2802))
- Resolved in 2.2.0
-## iOS master
+## iOS 3.2.0
- Offline packs can now be downloaded to allow users to view specific regions of the map offline. A new MGLOfflineStorage class provides APIs for managing MGLOfflinePacks. ([#4221](https://github.com/mapbox/mapbox-gl-native/pull/4221))
+- Tiles and other resources are cached in the same file that holds offline resources. The combined cache file is located in a subdirectory of the user’s Application Support directory, which means iOS will not delete the file when disk space runs low. ([#4377](https://github.com/mapbox/mapbox-gl-native/pull/4377))
- The user dot no longer disappears after panning the map across the antimeridian at low zoom levels. ([#4275](https://github.com/mapbox/mapbox-gl-native/pull/4275))
- The map no longer recoils when panning quickly at low zoom levels. ([#4214](https://github.com/mapbox/mapbox-gl-native/pull/4214))
- An icon laid out along a line no longer appears if it would extend past the end of the line. Some one-way arrows no longer point the wrong way. ([#3839](https://github.com/mapbox/mapbox-gl-native/pull/3839))
diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm
index 3eac28ca78..1f925b3ee2 100644
--- a/platform/darwin/src/MGLOfflineStorage.mm
+++ b/platform/darwin/src/MGLOfflineStorage.mm
@@ -22,18 +22,20 @@
static dispatch_once_t onceToken;
static MGLOfflineStorage *sharedOfflineStorage;
dispatch_once(&onceToken, ^{
- sharedOfflineStorage = [[self alloc] initWithFileName:@"offline.db"];
+ sharedOfflineStorage = [[self alloc] initWithFileName:@"cache.db"];
});
return sharedOfflineStorage;
}
+// This method can’t be called -init, because that selector has been marked
+// unavailable in MGLOfflineStorage.h.
- (instancetype)initWithFileName:(NSString *)fileName {
if (self = [super init]) {
-#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- NSString *cachePath = [paths.firstObject stringByAppendingPathComponent:fileName];
-#elif TARGET_OS_MAC
- NSURL *cacheDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory
+ // Place the cache in a location specific to the application, so that
+ // packs downloaded by other applications don’t count toward this
+ // application’s limits.
+ // ~/Library/Application Support/tld.app.bundle.id/cache.db
+ NSURL *cacheDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create:YES
@@ -46,7 +48,34 @@
error:nil];
NSURL *cacheURL = [cacheDirectoryURL URLByAppendingPathComponent:fileName];
NSString *cachePath = cacheURL ? cacheURL.path : @"";
+
+ // Move the offline cache from v3.2.0-beta.1 to a location that can also
+ // be used for ambient caching.
+ NSString *legacyCacheFileName = @"offline.db";
+#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
+ // ~/Documents/offline.db
+ NSArray *legacyPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+ NSString *legacyCachePath = [legacyPaths.firstObject stringByAppendingPathComponent:legacyCacheFileName];
+#elif TARGET_OS_MAC
+ // ~/Library/Caches/tld.app.bundle.id/offline.db
+ NSURL *legacyCacheDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory
+ inDomain:NSUserDomainMask
+ appropriateForURL:nil
+ create:YES
+ error:nil];
+ legacyCacheDirectoryURL = [legacyCacheDirectoryURL URLByAppendingPathComponent:
+ [NSBundle mainBundle].bundleIdentifier];
+ [[NSFileManager defaultManager] createDirectoryAtURL:legacyCacheDirectoryURL
+ withIntermediateDirectories:YES
+ attributes:nil
+ error:nil];
+ NSURL *legacyCacheURL = [legacyCacheDirectoryURL URLByAppendingPathComponent:legacyCacheFileName];
+ NSString *legacyCachePath = legacyCacheURL ? legacyCacheURL.path : @"";
#endif
+ if (![[NSFileManager defaultManager] fileExistsAtPath:cachePath]) {
+ [[NSFileManager defaultManager] moveItemAtPath:legacyCachePath toPath:cachePath error:NULL];
+ }
+
_mbglFileSource = new mbgl::DefaultFileSource(cachePath.UTF8String, [NSBundle mainBundle].resourceURL.path.UTF8String);
// Observe for changes to the global access token (and find out the current one).
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index 21d15ed1dd..2def0c54f0 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -30,6 +30,7 @@
#import "Mapbox.h"
#import "../../darwin/src/MGLGeometry_Private.h"
#import "../../darwin/src/MGLMultiPoint_Private.h"
+#import "../../darwin/src/MGLOfflineStorage_Private.h"
#import "NSBundle+MGLAdditions.h"
#import "NSString+MGLAdditions.h"
@@ -37,7 +38,6 @@
#import "NSException+MGLAdditions.h"
#import "MGLUserLocationAnnotationView.h"
#import "MGLUserLocation_Private.h"
-#import "MGLAccountManager_Private.h"
#import "MGLAnnotationImage_Private.h"
#import "MGLMapboxEvents.h"
#import "MGLCompactCalloutView.h"
@@ -187,7 +187,6 @@ public:
{
mbgl::Map *_mbglMap;
MBGLView *_mbglView;
- mbgl::DefaultFileSource *_mbglFileSource;
BOOL _opaque;
@@ -303,18 +302,15 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
// setup mbgl view
const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale];
_mbglView = new MBGLView(self, scaleFactor);
-
- // setup mbgl cache & file source
- NSString *fileCachePath = @"";
+
+ // Delete the pre-offline ambient cache at ~/Library/Caches/cache.db.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
- if ([paths count] != 0) {
- NSString *libraryDirectory = [paths objectAtIndex:0];
- fileCachePath = [libraryDirectory stringByAppendingPathComponent:@"cache.db"];
- }
- _mbglFileSource = new mbgl::DefaultFileSource([fileCachePath UTF8String], [[[[NSBundle mainBundle] resourceURL] path] UTF8String]);
+ NSString *fileCachePath = [paths.firstObject stringByAppendingPathComponent:@"cache.db"];
+ [[NSFileManager defaultManager] removeItemAtPath:fileCachePath error:NULL];
// setup mbgl map
- _mbglMap = new mbgl::Map(*_mbglView, *_mbglFileSource, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None);
+ mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource;
+ _mbglMap = new mbgl::Map(*_mbglView, *mbglFileSource, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None);
// start paused if in IB
if (_isTargetingInterfaceBuilder || background) {
@@ -322,13 +318,6 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
_mbglMap->pause();
}
- // Observe for changes to the global access token (and find out the current one).
- [[MGLAccountManager sharedManager] addObserver:self
- forKeyPath:@"accessToken"
- options:(NSKeyValueObservingOptionInitial |
- NSKeyValueObservingOptionNew)
- context:NULL];
-
// Notify map object when network reachability status changes.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(reachabilityChanged:)
@@ -506,7 +495,6 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
- [[MGLAccountManager sharedManager] removeObserver:self forKeyPath:@"accessToken"];
[_attributionButton removeObserver:self forKeyPath:@"hidden"];
[self validateDisplayLink];
@@ -517,12 +505,6 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
_mbglMap = nullptr;
}
- if (_mbglFileSource)
- {
- delete _mbglFileSource;
- _mbglFileSource = nullptr;
- }
-
if (_mbglView)
{
delete _mbglView;
@@ -1606,15 +1588,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(__unused void *)context
{
- // Synchronize mbgl::Map’s access token with the global one in MGLAccountManager.
- if ([keyPath isEqualToString:@"accessToken"] && object == [MGLAccountManager sharedManager])
- {
- NSString *accessToken = change[NSKeyValueChangeNewKey];
- if (![accessToken isKindOfClass:[NSNull class]]) {
- _mbglFileSource->setAccessToken((std::string)[accessToken UTF8String]);
- }
- }
- else if ([keyPath isEqualToString:@"hidden"] && object == _attributionButton)
+ if ([keyPath isEqualToString:@"hidden"] && object == _attributionButton)
{
NSNumber *hiddenNumber = change[NSKeyValueChangeNewKey];
BOOL attributionButtonWasHidden = [hiddenNumber boolValue];
diff --git a/platform/osx/src/MGLMapView.mm b/platform/osx/src/MGLMapView.mm
index 07c080663f..e09a6c2672 100644
--- a/platform/osx/src/MGLMapView.mm
+++ b/platform/osx/src/MGLMapView.mm
@@ -4,10 +4,11 @@
#import "MGLOpenGLLayer.h"
#import "MGLStyle.h"
-#import "../../darwin/src/MGLAccountManager_Private.h"
#import "../../darwin/src/MGLGeometry_Private.h"
#import "../../darwin/src/MGLMultiPoint_Private.h"
+#import "../../darwin/src/MGLOfflineStorage_Private.h"
+#import "MGLAccountManager.h"
#import "MGLMapCamera.h"
#import "MGLPolygon.h"
#import "MGLPolyline.h"
@@ -151,7 +152,6 @@ public:
/// Cross-platform map view controller.
mbgl::Map *_mbglMap;
MGLMapViewImpl *_mbglView;
- mbgl::DefaultFileSource *_mbglFileSource;
NSPanGestureRecognizer *_panGestureRecognizer;
NSMagnificationGestureRecognizer *_magnificationGestureRecognizer;
@@ -232,36 +232,25 @@ public:
// Set up cross-platform controllers and resources.
_mbglView = new MGLMapViewImpl(self, [NSScreen mainScreen].backingScaleFactor);
- // Place the cache in a location that can be shared among all the
- // applications that embed the Mapbox OS X SDK.
- NSURL *cacheDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory
- inDomain:NSUserDomainMask
- appropriateForURL:nil
- create:YES
- error:nil];
- cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent:
- [[NSBundle mgl_frameworkBundle] bundleIdentifier]];
- [[NSFileManager defaultManager] createDirectoryAtURL:cacheDirectoryURL
- withIntermediateDirectories:YES
- attributes:nil
- error:nil];
- NSURL *cacheURL = [cacheDirectoryURL URLByAppendingPathComponent:@"cache.db"];
- NSString *cachePath = cacheURL ? cacheURL.path : @"";
- _mbglFileSource = new mbgl::DefaultFileSource(cachePath.UTF8String, [[[[NSBundle mainBundle] resourceURL] path] UTF8String]);
-
- _mbglMap = new mbgl::Map(*_mbglView, *_mbglFileSource, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None);
+ // Delete the pre-offline ambient cache at
+ // ~/Library/Caches/com.mapbox.sdk.ios/cache.db.
+ NSURL *cachesDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory
+ inDomain:NSUserDomainMask
+ appropriateForURL:nil
+ create:NO
+ error:nil];
+ cachesDirectoryURL = [cachesDirectoryURL URLByAppendingPathComponent:
+ [NSBundle mgl_frameworkBundle].bundleIdentifier];
+ NSURL *legacyCacheURL = [cachesDirectoryURL URLByAppendingPathComponent:@"cache.db"];
+ [[NSFileManager defaultManager] removeItemAtURL:legacyCacheURL error:NULL];
+
+ mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource;
+ _mbglMap = new mbgl::Map(*_mbglView, *mbglFileSource, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None);
// Install the OpenGL layer. Interface Builder’s synchronous drawing means
// we can’t display a map, so don’t even bother to have a map layer.
self.layer = _isTargetingInterfaceBuilder ? [CALayer layer] : [MGLOpenGLLayer layer];
- // Observe for changes to the global access token (and find out the current one).
- [[MGLAccountManager sharedManager] addObserver:self
- forKeyPath:@"accessToken"
- options:(NSKeyValueObservingOptionInitial |
- NSKeyValueObservingOptionNew)
- context:NULL];
-
// Notify map object when network reachability status changes.
MGLReachability *reachability = [MGLReachability reachabilityForInternetConnection];
reachability.reachableBlock = ^(MGLReachability *) {
@@ -443,7 +432,6 @@ public:
}
- (void)dealloc {
- [[MGLAccountManager sharedManager] removeObserver:self forKeyPath:@"accessToken"];
[self.window removeObserver:self forKeyPath:@"contentLayoutRect"];
[self.window removeObserver:self forKeyPath:@"titlebarAppearsTransparent"];
@@ -455,25 +443,15 @@ public:
delete _mbglMap;
_mbglMap = nullptr;
}
- if (_mbglFileSource) {
- delete _mbglFileSource;
- _mbglFileSource = nullptr;
- }
if (_mbglView) {
delete _mbglView;
_mbglView = nullptr;
}
}
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(__unused void *)context {
- // Synchronize mbgl::Map’s access token with the global one in MGLAccountManager.
- if ([keyPath isEqualToString:@"accessToken"] && object == [MGLAccountManager sharedManager]) {
- NSString *accessToken = change[NSKeyValueChangeNewKey];
- if (![accessToken isKindOfClass:[NSNull class]]) {
- _mbglFileSource->setAccessToken((std::string)accessToken.UTF8String);
- }
- } else if ([keyPath isEqualToString:@"contentLayoutRect"] ||
- [keyPath isEqualToString:@"titlebarAppearsTransparent"]) {
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(__unused id)object change:(__unused NSDictionary *)change context:(__unused void *)context {
+ if ([keyPath isEqualToString:@"contentLayoutRect"] ||
+ [keyPath isEqualToString:@"titlebarAppearsTransparent"]) {
[self adjustContentInsets];
}
}