From 3a12bb4fb83ecca8b75a59d56cc70dec9cb46bfa Mon Sep 17 00:00:00 2001 From: gcole Date: Mon, 7 Aug 2017 10:58:46 -0700 Subject: [PATCH] Make offline packs more robust. - Separate the access token initialization and offline maps initialization. - Make the initialization functions return promise so that the consumer code can know when mapbox and the offline packs are ready to be used. - Expose setConnected method. - Update docs. --- API.md | 5 ++- .../ReactNativeMapboxGLModule.java | 24 ++++++++-- index.js | 24 +++++++++- ios/RCTMapboxGL/RCTMapboxGLManager.h | 2 +- ios/RCTMapboxGL/RCTMapboxGLManager.m | 44 +++++++++++-------- 5 files changed, 72 insertions(+), 27 deletions(-) diff --git a/API.md b/API.md index 8c014a6..5a769f9 100644 --- a/API.md +++ b/API.md @@ -404,12 +404,13 @@ To enable or disable metrics, use `Mapbox.setMetricsEnabled(enabled: boolean)`. ## Offline -There are 3 main methods for interacting with the offline API: +There are 4 main methods for interacting with the offline API: +* `Mapbox.initializeOfflinePacks()`: Initializes the offline packs handlers. * `Mapbox.addOfflinePack`: Creates an offline pack * `Mapbox.getOfflinePacks`: Returns an array of all offline packs on the device * `Mapbox.removeOfflinePack`: Removes a single pack -Before using them, don't forget to set an access token with `Mapbox.setAccessToken(accessToken)` +Before using offline packs, you must call `Mapbox.initializeOfflinePacks()`. These methods return a promise, but they also accept a callback as the last argument with the signature `(err, value) => {}`. diff --git a/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLModule.java b/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLModule.java index 5e2c511..13f406c 100644 --- a/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLModule.java +++ b/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLModule.java @@ -33,6 +33,7 @@ import com.facebook.react.bridge.ReadableNativeMap; import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableNativeArray; +import com.facebook.react.modules.core.DeviceEventManagerModule; import com.facebook.react.modules.core.RCTNativeAppEventEmitter; import com.facebook.react.uimanager.annotations.ReactProp; import com.mapbox.mapboxsdk.MapboxAccountManager; @@ -138,15 +139,19 @@ public class ReactNativeMapboxGLModule extends ReactContextBaseJavaModule { // Access Token @ReactMethod - public void setAccessToken(final String accessToken) { + public void setAccessToken(final String accessToken, final Promise promise) { if (accessToken == null || accessToken.length() == 0 || accessToken.equals("your-mapbox.com-access-token")) { throw new JSApplicationIllegalArgumentException("Invalid access token. Register to mapbox.com and request an access token, then pass it to setAccessToken()"); } if (initialized) { String oldToken = MapboxAccountManager.getInstance().getAccessToken(); if (!oldToken.equals(accessToken)) { - throw new JSApplicationIllegalArgumentException("Mapbox access token cannot be initialized twice with different values"); + JSApplicationIllegalArgumentException error = + new JSApplicationIllegalArgumentException("Mapbox access token cannot be initialized twice with different values"); + promise.reject(error); + throw error; } + promise.resolve(null); return; } initialized = true; @@ -154,9 +159,15 @@ public class ReactNativeMapboxGLModule extends ReactContextBaseJavaModule { @Override public void run() { MapboxAccountManager.start(context.getApplicationContext(), accessToken); + promise.resolve(null); } }); - initializeOfflinePacks(); + } + + // Connected + @ReactMethod + public void setConnected(boolean connected) { + MapboxAccountManager.getInstance().setConnected(connected); } // Metrics @@ -264,7 +275,7 @@ public class ReactNativeMapboxGLModule extends ReactContextBaseJavaModule { } class OfflineRegionsInitialRequest implements OfflineManager.ListOfflineRegionsCallback { - ReactNativeMapboxGLModule module; + private final ReactNativeMapboxGLModule module; OfflineRegionsInitialRequest(ReactNativeMapboxGLModule module) { this.module = module; @@ -293,6 +304,10 @@ public class ReactNativeMapboxGLModule extends ReactContextBaseJavaModule { } }); } + + module.context + .getJSModule(RCTNativeAppEventEmitter.class) + .emit("MapboxOfflinePacksLoaded", null); } @Override @@ -301,6 +316,7 @@ public class ReactNativeMapboxGLModule extends ReactContextBaseJavaModule { } } + @ReactMethod void initializeOfflinePacks() { final ReactNativeMapboxGLModule _this = this; mainHandler.post(new Runnable() { diff --git a/index.js b/index.js index e899ddd..65aac03 100644 --- a/index.js +++ b/index.js @@ -85,9 +85,16 @@ function getMetricsEnabled() { // Access token function setAccessToken(token: string) { - MapboxGLManager.setAccessToken(token); + const promise = MapboxGLManager.setAccessToken(token); + return promise; } +// Connected +function setConnected(connected: boolean) { + MapboxGLManager.setConnected(connected); +} + + // Offline function bindCallbackToPromise(callback, promise) { if (callback) { @@ -99,6 +106,15 @@ function bindCallbackToPromise(callback, promise) { } } +function initializeOfflinePacks() { + return new Promise((resolve, reject) => { + NativeAppEventEmitter.addListener('MapboxOfflinePacksLoaded', () => { + resolve(); + }); + MapboxGLManager.initializeOfflinePacks(); + }); +} + function addOfflinePack(options, callback) { let _options = options; // Workaround the fact that RN Android can't serialize JSON correctly @@ -464,7 +480,11 @@ const Mapbox = { mapStyles, userTrackingMode, userLocationVerticalAlignment, unknownResourceCount, getMetricsEnabled, setMetricsEnabled, setAccessToken, - addOfflinePack, getOfflinePacks, removeOfflinePack, + setConnected, + initializeOfflinePacks, + addOfflinePack, + getOfflinePacks, + removeOfflinePack, addOfflinePackProgressListener, addOfflineMaxAllowedTilesListener, addOfflineErrorListener, diff --git a/ios/RCTMapboxGL/RCTMapboxGLManager.h b/ios/RCTMapboxGL/RCTMapboxGLManager.h index 7f5f7eb..ce3e15d 100644 --- a/ios/RCTMapboxGL/RCTMapboxGLManager.h +++ b/ios/RCTMapboxGL/RCTMapboxGLManager.h @@ -17,4 +17,4 @@ BOOL _loadedPacks; NSMutableSet * _loadingPacks; } -@end \ No newline at end of file +@end diff --git a/ios/RCTMapboxGL/RCTMapboxGLManager.m b/ios/RCTMapboxGL/RCTMapboxGLManager.m index 201eca1..6b77baf 100644 --- a/ios/RCTMapboxGL/RCTMapboxGLManager.m +++ b/ios/RCTMapboxGL/RCTMapboxGLManager.m @@ -128,13 +128,17 @@ RCT_EXPORT_METHOD(setMetricsEnabled:(BOOL)enabled) // Access token -RCT_EXPORT_METHOD(setAccessToken:(nonnull NSString *)accessToken) +RCT_EXPORT_METHOD(setAccessToken:(nonnull NSString *)accessToken + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { dispatch_async(dispatch_get_main_queue(), ^{ if (!accessToken || ![accessToken length] || [accessToken isEqual:@"your-mapbox.com-access-token"]) { + reject(nil, @"Mapbox api token is not valid.", nil); return; } [MGLAccountManager setAccessToken:accessToken]; + resolve(nil); }); } @@ -144,23 +148,6 @@ RCT_EXPORT_METHOD(setAccessToken:(nonnull NSString *)accessToken) { if (!(self = [super init])) { return nil; } - _recentPacks = [NSMutableSet new]; - _throttledPacks = [NSMutableSet new]; - _removedPacks = [NSMutableSet new]; - _throttleInterval = 300; - - _loadingPacks = [NSMutableSet new]; - _loadedPacks = NO; - - // Setup pack array loading notifications - [[MGLOfflineStorage sharedOfflineStorage] addObserver:self forKeyPath:@"packs" options:NSKeyValueObservingOptionInitial context:NULL]; - _packRequests = [NSMutableArray new]; - - // Setup offline pack notification handlers. - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(offlinePackProgressDidChange:) name:MGLOfflinePackProgressChangedNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(offlinePackDidReceiveError:) name:MGLOfflinePackErrorNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(offlinePackDidReceiveMaximumAllowedMapboxTiles:) name:MGLOfflinePackMaximumMapboxTilesReachedNotification object:nil]; - return self; } @@ -187,6 +174,7 @@ RCT_EXPORT_METHOD(setAccessToken:(nonnull NSString *)accessToken) for (MGLOfflinePack * pack in packs) { [pack resume]; } + [_bridge.eventDispatcher sendAppEventWithName:@"MapboxOfflinePacksLoaded" body:@{}]; } - (void)observeValueForKeyPath:(NSString *)keyPath @@ -297,6 +285,26 @@ RCT_EXPORT_METHOD(setAccessToken:(nonnull NSString *)accessToken) [_bridge.eventDispatcher sendAppEventWithName:@"MapboxOfflineError" body:event]; } +RCT_EXPORT_METHOD(initializeOfflinePacks) +{ + _recentPacks = [NSMutableSet new]; + _throttledPacks = [NSMutableSet new]; + _removedPacks = [NSMutableSet new]; + _throttleInterval = 300; + + _loadingPacks = [NSMutableSet new]; + _loadedPacks = NO; + + // Setup pack array loading notifications + [[MGLOfflineStorage sharedOfflineStorage] addObserver:self forKeyPath:@"packs" options:NSKeyValueObservingOptionInitial context:NULL]; + _packRequests = [NSMutableArray new]; + + // Setup offline pack notification handlers. + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(offlinePackProgressDidChange:) name:MGLOfflinePackProgressChangedNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(offlinePackDidReceiveError:) name:MGLOfflinePackErrorNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(offlinePackDidReceiveMaximumAllowedMapboxTiles:) name:MGLOfflinePackMaximumMapboxTilesReachedNotification object:nil]; +} + RCT_REMAP_METHOD(addOfflinePack, pack:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve