diff --git a/Classes/BITAuthenticator.h b/Classes/BITAuthenticator.h index 9c677f6378..721e1c5560 100644 --- a/Classes/BITAuthenticator.h +++ b/Classes/BITAuthenticator.h @@ -111,6 +111,13 @@ typedef NS_ENUM(NSUInteger, BITAuthenticatorAppRestrictionEnforcementFrequency) * sure only users who are testers of your app are allowed to run it. * * This module automatically disables itself when running in an App Store build by default! + * + * @warning It is mandatory to call `authenticateInstallation` somewhen after calling + * `[[BITHockeyManager sharedHockeyManager] startManager]` or fully customize the identification + * and validation workflow yourself. + * If your app shows a modal view on startup, make sure to call `authenticateInstallation` + * either once your modal view is fully presented (e.g. its `viewDidLoad:` method is processed) + * or once your modal view is dismissed. */ @interface BITAuthenticator : BITHockeyBaseManager @@ -131,23 +138,6 @@ typedef NS_ENUM(NSUInteger, BITAuthenticatorAppRestrictionEnforcementFrequency) */ @property (nonatomic, assign) BITAuthenticatorIdentificationType identificationType; -/** - Defines if the BITAuthenticator automatically identifies the user and also - checks if he's still allowed to use the app (depending on `restrictApplicationUsage`) - - If this is set to NO, it's your responsiblity to call - - - (void) identifyWithCompletion:(void(^)(BOOL identified, NSError *error)) completion; - - and - - - (void) validateWithCompletion:(void(^)(BOOL identified, NSError *error)) completion; - - at approciate times and also block the application or re-identify the user if validation failed. - - _Default_: `YES` - */ -@property (nonatomic, assign) BOOL automaticMode; /** * Enables or disables checking if the user is allowed to run this app @@ -285,6 +275,26 @@ typedef NS_ENUM(NSUInteger, BITAuthenticatorAppRestrictionEnforcementFrequency) /// @name Authentication ///----------------------------------------------------------------------------- +/** + * Invoked automatic identification and validation + * + * If the `BITAuthenticator` is in automatic mode this will initiate identifying + * the current user according to the type specified in `identificationType` and + * validate if the identified user is allowed to run this application. + * + * If the user is not yet identified it will present a modal view asking the user to + * provide the required information. + * + * If your app provides it's own startup modal screen, e.g. a guide or a login, then + * you might either call this method once that UI is fully presented or once + * the user e.g. did actually login already. + * + * @warning You need to call this method in your code even if automatic mode is enabled! + * + * @see identificationType + */ +- (void) authenticateInstallation; + /** * Identifies the user according to the type specified in `identificationType`. * @@ -296,7 +306,8 @@ typedef NS_ENUM(NSUInteger, BITAuthenticatorAppRestrictionEnforcementFrequency) * once needed. * * @see identificationType - * @see automaticMode + * @see authenticateInstallation + * @see validateWithCompletion: * * @param completion Block being executed once identification completed */ @@ -321,7 +332,8 @@ typedef NS_ENUM(NSUInteger, BITAuthenticatorAppRestrictionEnforcementFrequency) * once needed. * * @see identificationType - * @see automaticMode + * @see authenticateInstallation + * @see identifyWithCompletion: * * @param completion Block being executed once validation completed */ diff --git a/Classes/BITAuthenticator.m b/Classes/BITAuthenticator.m index fffebf9eda..c70b01238b 100644 --- a/Classes/BITAuthenticator.m +++ b/Classes/BITAuthenticator.m @@ -50,6 +50,8 @@ static NSString* const kBITAuthenticatorAuthTokenTypeKey = @"BITAuthenticatorAut id _appDidBecomeActiveObserver; id _appWillResignActiveObserver; UIViewController *_authenticationController; + + BOOL _isSetup; } - (void)dealloc { @@ -62,7 +64,7 @@ static NSString* const kBITAuthenticatorAuthTokenTypeKey = @"BITAuthenticatorAut _webpageURL = [NSURL URLWithString:@"https://rink.hockeyapp.net/"]; _identificationType = BITAuthenticatorIdentificationTypeAnonymous; - _automaticMode = YES; + _isSetup = NO; _restrictApplicationUsage = NO; _restrictionEnforcementFrequency = BITAuthenticatorAppRestrictionEnforcementOnFirstLaunch; } @@ -74,24 +76,37 @@ static NSString* const kBITAuthenticatorAuthTokenTypeKey = @"BITAuthenticatorAut //disabled in the appStore if([self isAppStoreEnvironment]) return; - switch ([[UIApplication sharedApplication] applicationState]) { - case UIApplicationStateActive: - [self authenticate]; - break; - case UIApplicationStateBackground: - case UIApplicationStateInactive: - // do nothing, wait for active state - break; - } - - [self registerObservers]; + _isSetup = YES; } #pragma mark - -- (void) authenticate { - //when running in manual mode, we don't actually do anything ourselves - if(!self.automaticMode) return; +- (void)authenticateInstallation { + //disabled in the appStore + if([self isAppStoreEnvironment]) return; + // make sure this is called after startManager so all modules are fully setup + if (!_isSetup) { + [self performSelector:@selector(authenticateInstallation) withObject:nil afterDelay:0.1]; + } + + static dispatch_once_t authenticatePredicate; + dispatch_once(&authenticatePredicate, ^{ + + switch ([[UIApplication sharedApplication] applicationState]) { + case UIApplicationStateActive: + [self authenticate]; + break; + case UIApplicationStateBackground: + case UIApplicationStateInactive: + // do nothing, wait for active state + break; + } + + [self registerObservers]; + }); +} + +- (void) authenticate { [self identifyWithCompletion:^(BOOL identified, NSError *error) { if(identified) { if([self needsValidation]) { diff --git a/docs/Guide-Installation-Setup-Advanced-template.md b/docs/Guide-Installation-Setup-Advanced-template.md index 1084eb0afa..cfa1ed35de 100644 --- a/docs/Guide-Installation-Setup-Advanced-template.md +++ b/docs/Guide-Installation-Setup-Advanced-template.md @@ -129,6 +129,8 @@ The SDK runs on devices with iOS 5.0 or higher. 7. Replace `LIVE_IDENTIFIER` with the app identifier of your release app. We suggest to setup different apps on HockeyApp for your test and production builds. You usually will have way more test versions, but your production version usually has way more crash reports. This helps to keep data separated, getting a better overview and less trouble setting the right app versions downloadable for your beta users. +8. If you want to use the beta distribution feature on iOS 7 or later with In-App Updates, restrict versions to specific users or want to know who is actually testing your app, you need to follow the instructions on our guide [Identify and authenticate users of Ad-Hoc or Enterprise builds](HowTo-Authenticating-Users-on-iOS) + *Note:* The SDK is optimized to defer everything possible to a later time while making sure e.g. crashes on startup can also be caught and each module executes other code with a delay some seconds. This ensures that applicationDidFinishLaunching will process as fast as possible and the SDK will not block the startup sequence resulting in a possible kill by the watchdog process. diff --git a/docs/Guide-Installation-Setup-template.md b/docs/Guide-Installation-Setup-template.md index a5f2ca9b91..6b2a773b2c 100644 --- a/docs/Guide-Installation-Setup-template.md +++ b/docs/Guide-Installation-Setup-template.md @@ -99,6 +99,8 @@ The SDK runs on devices with iOS 5.0 or higher. 7. Replace `LIVE_IDENTIFIER` with the app identifier of your release app. We suggest to setup different apps on HockeyApp for your test and production builds. You usually will have way more test versions, but your production version usually has way more crash reports. This helps to keep data separated, getting a better overview and less trouble setting the right app versions downloadable for your beta users. +8. If you want to use the beta distribution feature on iOS 7 or later with In-App Updates, restrict versions to specific users or want to know who is actually testing your app, you need to follow the instructions on our guide [Identify and authenticate users of Ad-Hoc or Enterprise builds](HowTo-Authenticating-Users-on-iOS) + *Note:* The SDK is optimized to defer everything possible to a later time while making sure e.g. crashes on startup can also be caught and each module executes other code with a delay some seconds. This ensures that applicationDidFinishLaunching will process as fast as possible and the SDK will not block the startup sequence resulting in a possible kill by the watchdog process. diff --git a/docs/HowTo-Authenticating-Users-on-iOS-template.md b/docs/HowTo-Authenticating-Users-on-iOS-template.md index 5dad53f08b..0aa79c7b7f 100644 --- a/docs/HowTo-Authenticating-Users-on-iOS-template.md +++ b/docs/HowTo-Authenticating-Users-on-iOS-template.md @@ -26,6 +26,22 @@ Previous versions of HockeySDK for iOS used the response of the method `UIDevice The user needs to enter the email address and password of his HockeyApp account. +The `BITAuthenticator` class doesn't do anything on its own. In addition to setting up the behavior, you also need to trigger the process yourself. + +The most simple option is to place a call to `[[BITHockeyManager sharedHockeyManager] authenticateInstallation]` in your code. This will show a UI asking for identification details according to the chosen strategy. + +**IMPORTANT**: If your app shows a modal view on startup, make sure to call `authenticateInstallation` either once your modal view is fully presented (e.g. its `viewDidLoad:` method is processed) or once your modal view is dismissed. + +The second option is to implement your own workflow by using + + - (void) identifyWithCompletion:(void(^)(BOOL identified, NSError *error)) completion; + +to identify the current user depending on your strategy and + + - (void) validateWithCompletion:(void(^)(BOOL validated, NSError *error)) completion; + +to validate the user may still use the app if required. + The following sections explain the different strategies and their advantages / disadvantages. @@ -35,6 +51,7 @@ Initialize HockeySDK with the following code: [[BITHockeyManager sharedHockeyManager] configureWithIdentifier:@"<#APP_ID#>" delegate:self]; [[BITHockeyManager sharedHockeyManager] startManager]; + [[BITHockeyManager sharedHockeyManager] authenticateInstallation]; Replace APP_ID with the your App ID (can be found on the app page). @@ -57,6 +74,7 @@ Initialize HockeySDK with the following code: [[BITHockeyManager sharedHockeyManager] configureWithIdentifier:@"<#APP_ID#>" delegate:self]; [[BITHockeyManager sharedHockeyManager].authenticator setIdentificationType:BITAuthenticatorIdentificationTypeDevice]; [[BITHockeyManager sharedHockeyManager] startManager]; + [[BITHockeyManager sharedHockeyManager] authenticateInstallation]; Replace APP_ID with the your App ID (can be found on the app page). @@ -104,6 +122,7 @@ Initialize HockeySDK with the following code: [[BITHockeyManager sharedHockeyManager].authenticator setAuthenticationSecret:@"<#SECRET#>"]; [[BITHockeyManager sharedHockeyManager].authenticator setIdentificationType:BITAuthenticatorIdentificationTypeHockeyAppEmail]; [[BITHockeyManager sharedHockeyManager] startManager]; + [[BITHockeyManager sharedHockeyManager] authenticateInstallation]; Replace APP_ID with the your App ID and SECRET with the Secret (both values can be found on the app page). @@ -127,6 +146,7 @@ Initialize HockeySDK with the following code: [[BITHockeyManager sharedHockeyManager] configureWithIdentifier:@"APP_ID" delegate:self]; [[BITHockeyManager sharedHockeyManager].authenticator setIdentificationType:BITAuthenticatorIdentificationTypeHockeyAppUser]; [[BITHockeyManager sharedHockeyManager] startManager]; + [[BITHockeyManager sharedHockeyManager] authenticateInstallation]; Replace APP_ID with the your App ID (can be found on the app page).