FIRAppDistributionAppDelegateInterceptor.m 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Copyright 2019 Google
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
  15. #import "FIRAppDistributionAppDelegateInterceptor.h"
  16. #import "FIRFADLogger+Private.h"
  17. #import <AuthenticationServices/AuthenticationServices.h>
  18. #import <SafariServices/SafariServices.h>
  19. #import <UIKit/UIKit.h>
  20. @implementation FIRAppDistributionAppDelegateInterceptor
  21. API_AVAILABLE(ios(9.0))
  22. SFSafariViewController *_safariVC;
  23. API_AVAILABLE(ios(12.0))
  24. ASWebAuthenticationSession *_webAuthenticationVC;
  25. API_AVAILABLE(ios(11.0))
  26. SFAuthenticationSession *_safariAuthenticationVC;
  27. - (instancetype)init {
  28. self = [super init];
  29. self.safariHostingViewController = [[UIViewController alloc] init];
  30. return self;
  31. }
  32. + (instancetype)sharedInstance {
  33. static dispatch_once_t once;
  34. static FIRAppDistributionAppDelegateInterceptor *sharedInstance;
  35. dispatch_once(&once, ^{
  36. sharedInstance = [[FIRAppDistributionAppDelegateInterceptor alloc] init];
  37. });
  38. return sharedInstance;
  39. }
  40. - (void)appDistributionRegistrationFlow:(NSURL *)URL
  41. withCompletion:(void (^)(NSError *_Nullable error))completion {
  42. NSString *callbackURL = [NSString stringWithFormat:@"com.firebase.appdistribution.%@", [[FIRApp defaultApp] options].googleAppID];
  43. FIRFADInfoLog(@"Registration URL: %@", URL);
  44. FIRFADInfoLog(@"Callback URL: %@", callbackURL);
  45. if (@available(iOS 12.0, *)) {
  46. ASWebAuthenticationSession *authenticationVC = [[ASWebAuthenticationSession alloc]
  47. initWithURL:URL
  48. callbackURLScheme:callbackURL
  49. completionHandler:^(NSURL *_Nullable callbackURL, NSError *_Nullable error) {
  50. [self resetUIState];
  51. FIRFADInfoLog(@"Sign in complete using ASWebAuthenticationSession");
  52. // TODO (b/161538029): Map these errors to AppDistribution error codes
  53. completion(error);
  54. }];
  55. if (@available(iOS 13.0, *)) {
  56. authenticationVC.presentationContextProvider = self;
  57. }
  58. _webAuthenticationVC = authenticationVC;
  59. [authenticationVC start];
  60. } else if (@available(iOS 11.0, *)) {
  61. _safariAuthenticationVC = [[SFAuthenticationSession alloc]
  62. initWithURL:URL
  63. callbackURLScheme:callbackURL
  64. completionHandler:^(NSURL *_Nullable callbackURL, NSError *_Nullable error) {
  65. [self resetUIState];
  66. FIRFADInfoLog(@"Sign in complete using SFAuthenticationSession");
  67. // TODO (b/161538029): Map these errors to AppDistribution error codes
  68. completion(error);
  69. }];
  70. [_safariAuthenticationVC start];
  71. } else if (@available(iOS 9.0, *)){
  72. SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:URL];
  73. safariVC.delegate = self;
  74. _safariVC = safariVC;
  75. [self->_safariHostingViewController presentViewController:safariVC animated:YES completion:nil];
  76. self.registrationFlowCompletion = completion;
  77. }
  78. }
  79. - (void)showUIAlert:(UIAlertController *)alertController {
  80. [self initializeUIState];
  81. [self.window.rootViewController presentViewController:alertController
  82. animated:YES
  83. completion:nil];
  84. }
  85. - (BOOL)application:(UIApplication *)application
  86. openURL:(NSURL *)URL
  87. options:(NSDictionary<NSString *, id> *)options {
  88. [self registrationFlowCompletion];
  89. [self resetUIState];
  90. return NO;
  91. }
  92. - (void)initializeUIState {
  93. if (self.window) {
  94. return;
  95. }
  96. // Create an empty window + viewController to host the Safari UI.
  97. self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  98. self.window.rootViewController = self.safariHostingViewController;
  99. // Place it at the highest level within the stack.
  100. self.window.windowLevel = +CGFLOAT_MAX;
  101. // Run it.
  102. [self.window makeKeyAndVisible];
  103. }
  104. - (void)resetUIState {
  105. if (self.window) {
  106. self.window.hidden = YES;
  107. self.window = nil;
  108. }
  109. self.registrationFlowCompletion = nil;
  110. if (@available(iOS 11.0, *)) {
  111. _safariAuthenticationVC = nil;
  112. } else if (@available(iOS 12.0, *)) {
  113. _webAuthenticationVC = nil;
  114. } else if (@available(iOS 9.0, *)) {
  115. _safariVC = nil;
  116. }
  117. }
  118. - (void)safariViewControllerDidFinish:(SFSafariViewController *)controller NS_AVAILABLE_IOS(9.0) {
  119. [self resetUIState];
  120. }
  121. - (ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:
  122. (ASWebAuthenticationSession *)session API_AVAILABLE(ios(13.0)) {
  123. return self.safariHostingViewController.view.window;
  124. }
  125. @end