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.
This commit is contained in:
gcole
2017-08-08 10:20:56 -07:00
parent 64a51561d2
commit 3a12bb4fb8
5 changed files with 72 additions and 27 deletions
+3 -2
View File
@@ -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) => {}`.
@@ -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() {
+22 -2
View File
@@ -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,
+1 -1
View File
@@ -17,4 +17,4 @@
BOOL _loadedPacks;
NSMutableSet * _loadingPacks;
}
@end
@end
+26 -18
View File
@@ -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