Skip to content

Commit

Permalink
Merge pull request #898 from Microsoft/develop
Browse files Browse the repository at this point in the history
Release 1.2.0
  • Loading branch information
jaeklim authored Jan 10, 2018
2 parents 0eaa394 + 543b8f9 commit dd37806
Show file tree
Hide file tree
Showing 131 changed files with 4,709 additions and 2,632 deletions.
3 changes: 2 additions & 1 deletion AppCenter.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'AppCenter'
s.version = '1.1.0'
s.version = '1.2.0'

s.summary = 'Visual Studio App Center is your continuous integration, delivery and learning solution for iOS and macOS apps.'
s.description = <<-DESC
Expand All @@ -25,6 +25,7 @@ Pod::Spec.new do |s|

s.homepage = 'https://appcenter.ms'
s.documentation_url = "https://docs.microsoft.com/en-us/appcenter/sdk"
s.social_media_url = 'https://twitter.com/vsappcenter'

s.license = { :type => 'MIT', :file => 'AppCenter-SDK-Apple/iOS/LICENSE' }
s.author = { 'Microsoft' => '[email protected]' }
Expand Down
78 changes: 68 additions & 10 deletions AppCenter/AppCenter.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

23 changes: 14 additions & 9 deletions AppCenter/AppCenter/Internals/AppDelegate/MSAppDelegateForwarder.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
#import <Foundation/Foundation.h>
#if TARGET_OS_OSX
#import "MSNSAppDelegate.h"
#else
#import "MSUIAppDelegate.h"
#endif
#import "MSCustomApplicationDelegate.h"

NS_ASSUME_NONNULL_BEGIN

@interface MSAppDelegateForwarder : NSObject <MSAppDelegate>
/**
* Enum used to represent all kind of executors running the completion handler.
*/
typedef NS_OPTIONS(NSUInteger, MSCompletionExecutor) {
MSCompletionExecutorNone = (1 << 0),
MSCompletionExecutorOriginal = (1 << 1),
MSCompletionExecutorCustom = (1 << 2),
MSCompletionExecutorForwarder = (1 << 3)
};

@interface MSAppDelegateForwarder : NSObject <MSCustomApplicationDelegate>

/**
* Enable/Disable Application forwarding.
Expand All @@ -19,14 +24,14 @@ NS_ASSUME_NONNULL_BEGIN
*
* @param delegate A delegate.
*/
+ (void)addDelegate:(id<MSAppDelegate>)delegate;
+ (void)addDelegate:(id<MSCustomApplicationDelegate>)delegate;

/**
* Remove a delegate. This method is thread safe.
*
* @param delegate A delegate.
*/
+ (void)removeDelegate:(id<MSAppDelegate>)delegate;
+ (void)removeDelegate:(id<MSCustomApplicationDelegate>)delegate;

/**
* Add an app delegate selector to swizzle.
Expand Down
147 changes: 10 additions & 137 deletions AppCenter/AppCenter/Internals/AppDelegate/MSAppDelegateForwarder.m
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#if TARGET_OS_OSX
#import <AppKit/AppKit.h>
#import "MSNSAppDelegate.h"
#else
#import <UIKit/UIKit.h>
#import "MSUIAppDelegate.h"
#endif

#import "MSCustomApplicationDelegate.h"
#import "MSAppDelegateForwarderPrivate.h"
#import "MSAppCenterInternal.h"
#import "MSLogger.h"
Expand All @@ -18,14 +11,11 @@
static NSString *const kMSIsAppDelegateForwarderEnabledKey = @"AppCenterAppDelegateForwarderEnabled";

// Original selectors with special handling.
static NSString *const kMSDidReceiveRemoteNotificationFetchHandler =
@"application:didReceiveRemoteNotification:fetchCompletionHandler:";
static NSString *const kMSOpenURLSourceApplicationAnnotation = @"application:openURL:sourceApplication:annotation:";
static NSString *const kMSOpenURLOptions = @"application:openURL:options:";

static NSHashTable<id<MSAppDelegate>> *_delegates = nil;
static NSHashTable<id<MSCustomApplicationDelegate>> *_delegates = nil;
static NSMutableSet<NSString *> *_selectorsToSwizzle = nil;
static NSArray<NSString *> *_selectorsNotToOverride = nil;
static NSDictionary<NSString *, NSString *> *_deprecatedSelectors = nil;
static NSMutableDictionary<NSString *, NSValue *> *_originalImplementations = nil;
static NSMutableArray<dispatch_block_t> *traceBuffer = nil;
Expand Down Expand Up @@ -75,27 +65,18 @@ + (instancetype)sharedInstance {

#pragma mark - Accessors

+ (NSHashTable<id<MSAppDelegate>> *)delegates {
+ (NSHashTable<id<MSCustomApplicationDelegate>> *)delegates {
return _delegates ?: (_delegates = [NSHashTable weakObjectsHashTable]);
}

+ (void)setDelegates:(NSHashTable<id<MSAppDelegate>> *)delegates {
+ (void)setDelegates:(NSHashTable<id<MSCustomApplicationDelegate>> *)delegates {
_delegates = delegates;
}

+ (NSMutableSet<NSString *> *)selectorsToSwizzle {
return _selectorsToSwizzle ?: (_selectorsToSwizzle = [NSMutableSet new]);
}

+ (NSArray<NSString *> *)selectorsNotToOverride {
if (!_selectorsNotToOverride) {
#if !TARGET_OS_OSX
_selectorsNotToOverride = @[ kMSDidReceiveRemoteNotificationFetchHandler ];
#endif
}
return _selectorsNotToOverride;
}

+ (NSDictionary<NSString *, NSString *> *)deprecatedSelectors {
if (!_deprecatedSelectors) {
#if TARGET_OS_OSX
Expand Down Expand Up @@ -152,15 +133,15 @@ + (void)setEnabled:(BOOL)enabled {

#pragma mark - Delegates

+ (void)addDelegate:(id<MSAppDelegate>)delegate {
+ (void)addDelegate:(id<MSCustomApplicationDelegate>)delegate {
@synchronized(self) {
if (self.enabled) {
[self.delegates addObject:delegate];
}
}
}

+ (void)removeDelegate:(id<MSAppDelegate>)delegate {
+ (void)removeDelegate:(id<MSCustomApplicationDelegate>)delegate {
@synchronized(self) {
if (self.enabled) {
[self.delegates removeObject:delegate];
Expand All @@ -184,8 +165,7 @@ + (void)swizzleOriginalDelegate:(id<MSApplicationDelegate>)originalDelegate {
if (originalImp) {

// Save the original implementation for later use.
MSAppDelegateForwarder.originalImplementations[selectorString] =
[NSValue valueWithBytes:&originalImp objCType:@encode(IMP)];
self.originalImplementations[selectorString] = [NSValue valueWithBytes:&originalImp objCType:@encode(IMP)];
}
}
[self.selectorsToSwizzle removeAllObjects];
Expand All @@ -208,18 +188,7 @@ + (IMP)swizzleOriginalSelector:(SEL)originalSelector

// Replace original implementation by the custom one.
if (originalMethod) {

/*
* Also, some selectors should not be overridden mostly because the original implementation highly
* depend on the SDK return value for its own logic so customers already have to call the SDK API
* in their implementation which makes swizzling useless.
*/
if (![self.selectorsNotToOverride containsObject:originalSelectorStr]) {
originalImp = method_setImplementation(originalMethod, customImp);
} else {
warningMsg =
[NSString stringWithFormat:@"This selector is not supported when already implemented. %@", remediationMsg];
}
originalImp = method_setImplementation(originalMethod, customImp);
} else if (![originalClass instancesRespondToSelector:originalSelector]) {

// Check for deprecation.
Expand Down Expand Up @@ -326,6 +295,7 @@ - (void)custom_setDelegate:(id<MSApplicationDelegate>)delegate {
#pragma mark - Custom UIApplicationDelegate

#if !TARGET_OS_OSX

/*
* Those methods will never get called but their implementation will be used by swizzling.
* Those implementations will run within the delegate context. Meaning that `self` will point
Expand Down Expand Up @@ -375,103 +345,6 @@ - (BOOL)custom_application:(UIApplication *)application
}
#endif

#if TARGET_OS_OSX
- (void)custom_application:(NSApplication *)application
#else
- (void)custom_application:(UIApplication *)application
#endif
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
IMP originalImp = NULL;

// Forward to the original delegate.
[MSAppDelegateForwarder.originalImplementations[NSStringFromSelector(_cmd)] getValue:&originalImp];
if (originalImp) {
#if TARGET_OS_OSX
((void (*)(id, SEL, NSApplication *, NSData *))originalImp)(self, _cmd, application, deviceToken);
#else
((void (*)(id, SEL, UIApplication *, NSData *))originalImp)(self, _cmd, application, deviceToken);
#endif
}

// Forward to custom delegates.
[[MSAppDelegateForwarder sharedInstance] application:application
didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

#if TARGET_OS_OSX
- (void)custom_application:(NSApplication *)application
#else
- (void)custom_application:(UIApplication *)application
#endif
didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
IMP originalImp = NULL;

// Forward to the original delegate.
[MSAppDelegateForwarder.originalImplementations[NSStringFromSelector(_cmd)] getValue:&originalImp];
if (originalImp) {
#if TARGET_OS_OSX
((void (*)(id, SEL, NSApplication *, NSError *))originalImp)(self, _cmd, application, error);
#else
((void (*)(id, SEL, UIApplication *, NSError *))originalImp)(self, _cmd, application, error);
#endif
}

// Forward to custom delegates.
[[MSAppDelegateForwarder sharedInstance] application:application
didFailToRegisterForRemoteNotificationsWithError:error];
}

#if TARGET_OS_OSX
- (void)custom_application:(NSApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
#else
- (void)custom_application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
#endif
IMP originalImp = NULL;

// Forward to the original delegate.
[MSAppDelegateForwarder.originalImplementations[NSStringFromSelector(_cmd)] getValue:&originalImp];
if (originalImp) {
#if TARGET_OS_OSX
((void (*)(id, SEL, NSApplication *, NSDictionary *))originalImp)(self, _cmd, application, userInfo);
#else
((void (*)(id, SEL, UIApplication *, NSDictionary *))originalImp)(self, _cmd, application, userInfo);
#endif
}

// Forward to custom delegates.
[[MSAppDelegateForwarder sharedInstance] application:application didReceiveRemoteNotification:userInfo];
}

#if !TARGET_OS_OSX
- (void)custom_application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

// Collect `UIBackgroundFetchResult` from delegates in order to call the original completion handler later.
__block UIBackgroundFetchResult forwardedFetchResult = UIBackgroundFetchResultNoData;
void (^forwardedCompletionHandler)(UIBackgroundFetchResult) = ^(UIBackgroundFetchResult fetchResult) {
forwardedFetchResult = fetchResult;
};

/*
* FIXME: We still need to chain the forwardedFetchResult somehow in case of multiple custom delegate implementing
* this selector.
*/

/*
* Forward to custom delegates. This method doesn't override original the delegate implementation so there is no need
* to forward to the original implementation. As a consequence customers must call the corresponding APIs in the SDK
* if they implement this selector in their delegate.
*/
[[MSAppDelegateForwarder sharedInstance] application:application
didReceiveRemoteNotification:userInfo
fetchCompletionHandler:forwardedCompletionHandler];

// Must call the original completion handler.
completionHandler(forwardedFetchResult);
}
#endif

#pragma mark - Forwarding

- (void)forwardInvocation:(NSInvocation *)invocation {
Expand All @@ -490,7 +363,7 @@ - (void)forwardInvocation:(NSInvocation *)invocation {
}

// Forward to delegates executing a custom method.
for (id<MSAppDelegate> delegate in [self class].delegates) {
for (id<MSCustomApplicationDelegate> delegate in [self class].delegates) {
if ([delegate respondsToSelector:invocation.selector]) {
[invocation invokeWithTarget:delegate];

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#import <Foundation/Foundation.h>

#import "MSAppDelegateForwarder.h"

NS_ASSUME_NONNULL_BEGIN
Expand All @@ -9,18 +7,13 @@ NS_ASSUME_NONNULL_BEGIN
/**
* Hash table containing all the delegates as weak references.
*/
@property(nonatomic, class) NSHashTable<id<MSAppDelegate>> *delegates;
@property(nonatomic, class) NSHashTable<id<MSCustomApplicationDelegate>> *delegates;

/**
* Keep track of original selectors to swizzle.
*/
@property(nonatomic, class, readonly) NSMutableSet<NSString *> *selectorsToSwizzle;

/**
* List of original selectors not to override if already implemented in the original application delegate.
*/
@property(nonatomic, class, readonly) NSArray<NSString *> *selectorsNotToOverride;

/**
* Dictionary of deprecated original selectors indexed by their new equivalent.
*/
Expand All @@ -42,6 +35,11 @@ NS_ASSUME_NONNULL_BEGIN
#endif
@property(nonatomic, class) IMP originalSetDelegateImp;

/**
* Returns the singleton instance of MSAppDelegateForwarder.
*/
+ (instancetype)sharedInstance;

/**
* Register swizzling for the given original application delegate.
*
Expand Down
19 changes: 19 additions & 0 deletions AppCenter/AppCenter/Internals/AppDelegate/MSAppDelegateUtil.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#import <Foundation/Foundation.h>
#if TARGET_OS_OSX
#import <AppKit/AppKit.h>
#ifndef MSApplicationDelegate
#define MSApplicationDelegate NSApplicationDelegate
#endif
#ifndef MSApplication
#define MSApplication NSApplication
#endif
#else
#import <UIKit/UIKit.h>
#ifndef MSApplicationDelegate
#define MSApplicationDelegate UIApplicationDelegate
#endif
#ifndef MSApplication
#define MSApplication UIApplication
#endif
#endif

Loading

0 comments on commit dd37806

Please sign in to comment.