/* * Copyright 2017 Google * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import "FIRAuthURLPresenter.h" #import #import "FIRAuthErrorUtils.h" #import "FIRAuthUIDelegate.h" NS_ASSUME_NONNULL_BEGIN @interface FIRAuthDefaultUIDelegate : NSObject /** @fn defaultUIDelegate @brief Returns a default FIRAuthUIDelegate object. @return The default FIRAuthUIDelegate object. */ + (id)defaultUIDelegate; @end @interface FIRAuthURLPresenter () @end @implementation FIRAuthURLPresenter { /** @var _isPresenting @brief Whether or not some web-based content is being presented. */ BOOL _isPresenting; /** @var _callbackMatcher @brief The callback URL matcher for the current presentation, if one is active. */ FIRAuthURLCallbackMatcher _Nullable _callbackMatcher; /** @var _safariViewController @brief The SFSafariViewController used for the current presentation, if any. */ SFSafariViewController *_Nullable _safariViewController; /** @var _UIDelegate @brief The UIDelegate used to present the SFSafariViewController. */ id _UIDelegate; /** @var _completion @brief The completion handler for the current presentaion, if one is active. @remarks This variable is also used as a flag to indicate a presentation is active. */ FIRAuthURLPresentationCompletion _Nullable _completion; } - (void)presentURL:(NSURL *)URL UIDelegate:(nullable id)UIDelegate callbackMatcher:(FIRAuthURLCallbackMatcher)callbackMatcher completion:(FIRAuthURLPresentationCompletion)completion { if (_isPresenting) { // Unable to start a new presentation on top of another. _completion(nil, [FIRAuthErrorUtils webContextAlreadyPresentedErrorWithMessage:nil]); return; } _isPresenting = YES; _callbackMatcher = callbackMatcher; _completion = completion; _UIDelegate = UIDelegate ?: [FIRAuthDefaultUIDelegate defaultUIDelegate]; if ([SFSafariViewController class]) { SFSafariViewController *safariViewController = [[SFSafariViewController alloc] initWithURL:URL]; _safariViewController = safariViewController; _safariViewController.delegate = self; [_UIDelegate presentViewController:safariViewController animated:YES completion:nil]; return; } else { // TODO: Use web view instead. [[UIApplication sharedApplication] openURL:URL]; } } - (BOOL)canHandleURL:(NSURL *)URL { if (_isPresenting && _callbackMatcher && _callbackMatcher(URL)) { [self finishPresentationWithURL:URL error:nil]; return YES; } return NO; } #pragma mark - SFSafariViewControllerDelegate - (void)safariViewControllerDidFinish:(SFSafariViewController *)controller { if (controller == _safariViewController) { _safariViewController = nil; //TODO:Ensure that the SFSafariViewController is actually removed from the screen before //invoking finishPresentationWithURL:error: [self finishPresentationWithURL:nil error:[FIRAuthErrorUtils webContextCancelledErrorWithMessage:nil]]; } } #pragma mark - Private methods /** @fn finishPresentationWithURL:error: @brief Finishes the presentation for a given URL, if any. @param URL The URL to finish presenting. @param error The error with which to finish presenting, if any. */ - (void)finishPresentationWithURL:(nullable NSURL *)URL error:(nullable NSError *)error { _callbackMatcher = nil; id UIDelegate = _UIDelegate; _UIDelegate = nil; FIRAuthURLPresentationCompletion completion = _completion; _completion = nil; void (^finishBlock)() = ^() { _isPresenting = NO; completion(URL, error); }; SFSafariViewController *safariViewController = _safariViewController; _safariViewController = nil; if (safariViewController) { [UIDelegate dismissViewControllerAnimated:YES completion:finishBlock]; } else { finishBlock(); } } @end NS_ASSUME_NONNULL_END