[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.
This commit is contained in:
committed by
Minh Nguyễn
parent
fff13d0976
commit
b493bdc649
@@ -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))
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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]);
|
||||
// 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];
|
||||
|
||||
_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);
|
||||
|
||||
// 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];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user