Skip to content
This repository has been archived by the owner on Jun 21, 2023. It is now read-only.

Adds NSURLSession delegate to MGLNetworkConfiguration #228

Merged
merged 16 commits into from
Mar 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions platform/darwin/src/MGLNetworkConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,42 @@

NS_ASSUME_NONNULL_BEGIN

@class MGLNetworkConfiguration;

@protocol MGLNetworkConfigurationDelegate <NSObject>
@optional

/**
:nodoc:
Provides an `NSURLSession` object for the specified `MGLNetworkConfiguration`.
This API should be considered experimental, likely to be removed or changed in
future releases.

This method is called from background threads, i.e. it is not called on the main
thread.

@note Background sessions (i.e. created with
`-[NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:]`)
and sessions created with a delegate that conforms to `NSURLSessionDataDelegate`
are not supported at this time.
*/
- (NSURLSession *)sessionForNetworkConfiguration:(MGLNetworkConfiguration *)configuration;
@end


/**
The `MGLNetworkConfiguration` object provides a global way to set a base
`NSURLSessionConfiguration`, and other resources.
*/
MGL_EXPORT
@interface MGLNetworkConfiguration : NSObject

/**
:nodoc:
Delegate for the `MGLNetworkConfiguration` class.
*/
@property (nonatomic, weak) id<MGLNetworkConfigurationDelegate> delegate;

/**
Returns the shared instance of the `MGLNetworkConfiguration` class.
*/
Expand All @@ -23,12 +52,14 @@ MGL_EXPORT
If this property is set to nil or if no session configuration is provided this property
is set to the default session configuration.

Assign this object before instantiating any `MGLMapView` object.
Assign this object before instantiating any `MGLMapView` object, or using
`MGLOfflineStorage`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What’s an example of a place where this object can be assigned safely? Consider that fixing #227 may require us to invoke +[MGLOfflineStorage sharedStorage] in an +initialize method.

Copy link
Contributor Author

@julianrex julianrex Mar 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh. Let's address that when we fix #227. Hopefully we can find a way around without having to use an +initialize.


@note: `NSURLSession` objects store a copy of this configuration. Any further changes
@note `NSURLSession` objects store a copy of this configuration. Any further changes
to mutable properties on this configuration object passed to a session’s initializer
will not affect the behavior of that session.


@note Background sessions are not currently supported.
*/
@property (atomic, strong, null_resettable) NSURLSessionConfiguration *sessionConfiguration;

Expand Down
98 changes: 72 additions & 26 deletions platform/darwin/src/MGLNetworkConfiguration.m
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
#import "MGLNetworkConfiguration_Private.h"
#import "MGLNetworkIntegrationManager.h"
#import "MGLLoggingConfiguration_Private.h"
#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
#import "MGLAccountManager_Private.h"
#endif

#import "MGLReachability.h"

static NSString * const MGLStartTime = @"start_time";
static NSString * const MGLResourceType = @"resource_type";
NSString * const kMGLDownloadPerformanceEvent = @"mobile.performance_trace";

@interface MGLNetworkConfiguration ()
@interface MGLNetworkConfiguration () <MGLNativeNetworkDelegate>

@property (strong) NSURLSessionConfiguration *sessionConfig;
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSDictionary*> *events;
@property (nonatomic, weak) id<MGLNetworkConfigurationMetricsDelegate> metricsDelegate;
@property (nonatomic) dispatch_queue_t eventsQueue;

@end

@implementation MGLNetworkConfiguration
{
NSURLSessionConfiguration *_sessionConfig;
}

- (instancetype)init {
if (self = [super init]) {
Expand All @@ -34,26 +40,51 @@ + (instancetype)sharedManager {
_sharedManager = [[self alloc] init];
});

[self setNativeNetworkManagerDelegateToDefault];
// Notice, this is reset for each call. This is primarily for testing purposes.
// TODO: Consider only calling this for testing?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this to-do still relevant? (×2)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll create a new ticket to track this.

[_sharedManager resetNativeNetworkManagerDelegate];

return _sharedManager;
}

+ (void)setNativeNetworkManagerDelegateToDefault {
- (void)resetNativeNetworkManagerDelegate {
// Tell core about our network integration. `delegate` here is not (yet)
// intended to be set to nil, except for testing.
[MGLNativeNetworkManager sharedManager].delegate =
MGLNetworkIntegrationManager.sharedManager;
[MGLNativeNetworkManager sharedManager].delegate = self;
}

- (void)setSessionConfiguration:(NSURLSessionConfiguration *)sessionConfiguration {
@synchronized (self) {
if (sessionConfiguration == nil) {
_sessionConfig = [self defaultSessionConfiguration];
} else {
_sessionConfig = sessionConfiguration;
}
+ (NSURLSessionConfiguration *)defaultSessionConfiguration {
NSURLSessionConfiguration* sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];

sessionConfiguration.timeoutIntervalForResource = 30;
sessionConfiguration.HTTPMaximumConnectionsPerHost = 8;
sessionConfiguration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
sessionConfiguration.URLCache = nil;

return sessionConfiguration;
}

#pragma mark - MGLNativeNetworkDelegate

- (NSURLSession *)sessionForNetworkManager:(MGLNativeNetworkManager *)networkManager {
// Note: this method is NOT called on the main thread.
NSURLSession *session;
if ([self.delegate respondsToSelector:@selector(sessionForNetworkConfiguration:)]) {
session = [self.delegate sessionForNetworkConfiguration:self];
}

// Check for a background session; string checking is fragile, but this is not
// a deal breaker as we're only doing this to provide more clarity to the
// developer
NSAssert(![session isKindOfClass:NSClassFromString(@"__NSURLBackgroundSession")],
@"Background NSURLSessions are not yet supported");

if (session.delegate) {
NSAssert(![session.delegate conformsToProtocol:@protocol(NSURLSessionDataDelegate)],
@"Session delegates conforming to NSURLSessionDataDelegate are not yet supported");
}

return session;
}

- (NSURLSessionConfiguration *)sessionConfiguration {
Expand All @@ -64,21 +95,27 @@ - (NSURLSessionConfiguration *)sessionConfiguration {
return sessionConfig;
}

- (NSURLSessionConfiguration *)defaultSessionConfiguration {
NSURLSessionConfiguration* sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];

sessionConfiguration.timeoutIntervalForResource = 30;
sessionConfiguration.HTTPMaximumConnectionsPerHost = 8;
sessionConfiguration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
sessionConfiguration.URLCache = nil;

return sessionConfiguration;
- (void)setSessionConfiguration:(NSURLSessionConfiguration *)sessionConfiguration {
@synchronized (self) {
if (sessionConfiguration == nil) {
_sessionConfig = [MGLNetworkConfiguration defaultSessionConfiguration];
} else {
_sessionConfig = sessionConfiguration;
}
}
}

#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
- (NSString *)skuToken {
return MGLAccountManager.skuToken;
}
#endif

- (void)startDownloadEvent:(NSString *)urlString type:(NSString *)resourceType {
if (urlString && ![self eventDictionaryForKey:urlString]) {
if (urlString && resourceType && ![self eventDictionaryForKey:urlString]) {
NSDate *startDate = [NSDate date];
[self setEventDictionary:@{ MGLStartTime: startDate, MGLResourceType: resourceType } forKey:urlString];
[self setEventDictionary:@{ MGLStartTime: startDate, MGLResourceType: resourceType }
forKey:urlString];
}
}

Expand All @@ -90,6 +127,16 @@ - (void)cancelDownloadEventForResponse:(NSURLResponse *)response {
[self sendEventForURLResponse:response withAction:@"cancel"];
}

- (void)debugLog:(NSString *)format, ... {
MGLLogDebug(format);
}

- (void)errorLog:(NSString *)format, ... {
MGLLogError(format);
}

#pragma mark - Event management

- (void)sendEventForURLResponse:(NSURLResponse *)response withAction:(NSString *)action
{
if ([response isKindOfClass:[NSURLResponse class]]) {
Expand All @@ -103,7 +150,6 @@ - (void)sendEventForURLResponse:(NSURLResponse *)response withAction:(NSString *
});
}
}

}

- (NSDictionary *)eventAttributesForURL:(NSURLResponse *)response withAction:(NSString *)action
Expand Down
3 changes: 2 additions & 1 deletion platform/darwin/src/MGLNetworkConfiguration_Private.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#import "MGLNetworkConfiguration.h"
#include <mbgl/interface/native_apple_interface.h>

NS_ASSUME_NONNULL_BEGIN

Expand All @@ -16,7 +17,7 @@ extern NSString * const kMGLDownloadPerformanceEvent;
@property (nonatomic, strong) NSMutableDictionary<NSString*, NSDictionary*> *events;
@property (nonatomic, weak) id<MGLNetworkConfigurationMetricsDelegate> metricsDelegate;

+ (void)setNativeNetworkManagerDelegateToDefault;
- (void)resetNativeNetworkManagerDelegate;
- (void)startDownloadEvent:(NSString *)urlString type:(NSString *)resourceType;
- (void)stopDownloadEventForResponse:(NSURLResponse *)response;
- (void)cancelDownloadEventForResponse:(NSURLResponse *)response;
Expand Down
8 changes: 0 additions & 8 deletions platform/darwin/src/MGLNetworkIntegrationManager.h

This file was deleted.

54 changes: 0 additions & 54 deletions platform/darwin/src/MGLNetworkIntegrationManager.m

This file was deleted.

13 changes: 9 additions & 4 deletions platform/darwin/src/MGLOfflineStorage.mm
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,12 @@ + (instancetype)sharedOfflineStorage {
[sharedOfflineStorage reloadPacks];
});

// Always ensure the network delegate is setup
[MGLNetworkConfiguration setNativeNetworkManagerDelegateToDefault];
// Always ensure the MGLNativeNetworkManager delegate is setup. Calling
// `resetNativeNetworkManagerDelegate` is not necessary here, since the shared
// manager already calls it.
//
// TODO: Consider only calling this for testing?
[MGLNetworkConfiguration sharedManager];

return sharedOfflineStorage;
}
Expand Down Expand Up @@ -217,8 +221,9 @@ + (NSString *)legacyCachePath {

- (instancetype)init {
// Ensure network configuration & appropriate delegate prior to starting the
// run loop
[MGLNetworkConfiguration setNativeNetworkManagerDelegateToDefault];
// run loop. Calling `resetNativeNetworkManagerDelegate` is not necessary here,
// since the shared manager already calls it.
[MGLNetworkConfiguration sharedManager];

MGLInitializeRunLoop();

Expand Down
28 changes: 28 additions & 0 deletions platform/ios/Integration Tests/MGLIntegrationTestCase.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#import <XCTest/XCTest.h>
#import <Mapbox/Mapbox.h>
#import "MGLTestUtility.h"

#define MGLTestFail(myself, ...) \
_XCTPrimitiveFail(myself, __VA_ARGS__)

#define MGLTestAssert(myself, expression, ...) \
_XCTPrimitiveAssertTrue(myself, expression, @#expression, __VA_ARGS__)

#define MGLTestAssertEqualWithAccuracy(myself, expression1, expression2, accuracy, ...) \
_XCTPrimitiveAssertEqualWithAccuracy(myself, expression1, @#expression1, expression2, @#expression2, accuracy, @#accuracy, __VA_ARGS__)
#define MGLTestAssertNil(myself, expression, ...) \
_XCTPrimitiveAssertNil(myself, expression, @#expression, __VA_ARGS__)

#define MGLTestAssertNotNil(myself, expression, ...) \
_XCTPrimitiveAssertNotNil(myself, expression, @#expression, __VA_ARGS__)

#define MGLTestWarning(expression, format, ...) \
({ \
if (!(expression)) { \
NSString *message = [NSString stringWithFormat:format, ##__VA_ARGS__]; \
printf("warning: Test Case '%s' at line %d: '%s' %s\n", __PRETTY_FUNCTION__, __LINE__, #expression, message.UTF8String); \
} \
})

@interface MGLIntegrationTestCase: XCTestCase
@end
Loading