diff --git a/CHANGELOG.md b/CHANGELOG.md index 5674d0af..ce0128cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- Migrated the iOS example app to the UIScene lifecycle (adds SceneDelegate, UIApplicationSceneManifest); the iOS example now requires iOS 15+ + # 5.0.0 - Update keychain default on Mac to be data protected ([#259](https://github.com/google/GTMAppAuth/pull/259)) - Update AppAuth dependency to 2.0.0 ([#262](https://github.com/google/GTMAppAuth/pull/262)) diff --git a/Examples/Example-iOS/Example-iOS.xcodeproj/project.pbxproj b/Examples/Example-iOS/Example-iOS.xcodeproj/project.pbxproj index e6400b1d..7cecab0b 100644 --- a/Examples/Example-iOS/Example-iOS.xcodeproj/project.pbxproj +++ b/Examples/Example-iOS/Example-iOS.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 346E916E1C29D42800D3620B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 346E916D1C29D42800D3620B /* main.m */; }; 346E91711C29D42800D3620B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 346E91701C29D42800D3620B /* AppDelegate.m */; }; + 346E91B11C29D42800D3620B /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 346E91B01C29D42800D3620B /* SceneDelegate.m */; }; 346E91791C29D42800D3620B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 346E91781C29D42800D3620B /* Assets.xcassets */; }; 346E917C1C29D42800D3620B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 346E917A1C29D42800D3620B /* LaunchScreen.storyboard */; }; 346E91991C2A245000D3620B /* SafariServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 346E91981C2A245000D3620B /* SafariServices.framework */; }; @@ -25,6 +26,8 @@ 346E916D1C29D42800D3620B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 346E916F1C29D42800D3620B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 346E91701C29D42800D3620B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 346E91AF1C29D42800D3620B /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = ""; }; + 346E91B01C29D42800D3620B /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = ""; }; 346E91781C29D42800D3620B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 346E917B1C29D42800D3620B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 346E917D1C29D42800D3620B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -84,6 +87,8 @@ 346E916D1C29D42800D3620B /* main.m */, 346E916F1C29D42800D3620B /* AppDelegate.h */, 346E91701C29D42800D3620B /* AppDelegate.m */, + 346E91AF1C29D42800D3620B /* SceneDelegate.h */, + 346E91B01C29D42800D3620B /* SceneDelegate.m */, 34CB09BA1C42007600A54261 /* GTMAppAuthExampleViewController.h */, 34CB09BB1C42007600A54261 /* GTMAppAuthExampleViewController.m */, 34CB09BC1C42007600A54261 /* GTMAppAuthExampleViewController.xib */, @@ -184,6 +189,7 @@ buildActionMask = 2147483647; files = ( 346E91711C29D42800D3620B /* AppDelegate.m in Sources */, + 346E91B11C29D42800D3620B /* SceneDelegate.m in Sources */, 346E916E1C29D42800D3620B /* main.m in Sources */, 34CB09BD1C42007600A54261 /* GTMAppAuthExampleViewController.m in Sources */, ); @@ -300,7 +306,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = Source/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -319,7 +325,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = Source/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/Examples/Example-iOS/Example-iOSForPod.xcodeproj/project.pbxproj b/Examples/Example-iOS/Example-iOSForPod.xcodeproj/project.pbxproj index 8e207966..b0adb18c 100644 --- a/Examples/Example-iOS/Example-iOSForPod.xcodeproj/project.pbxproj +++ b/Examples/Example-iOS/Example-iOSForPod.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 73361D7E28BED1170061AC82 /* Pods_Example_iOSForPod.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73361D7D28BED1170061AC82 /* Pods_Example_iOSForPod.framework */; }; 73361D7F28BED1170061AC82 /* Pods_Example_iOSForPod.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 73361D7D28BED1170061AC82 /* Pods_Example_iOSForPod.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; C1AF3AEB28187F71003BAEFF /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = C1AF3AE928187F71003BAEFF /* README.md */; }; + D863799828187F71003BAEFF /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D863799728187F71003BAEFF /* SceneDelegate.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -56,6 +57,8 @@ 73E4FD2928B056AF003D602E /* AppAuth.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AppAuth.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8536F19A676D520C21C03D35 /* Pods-Example-iOSForPod.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example-iOSForPod.debug.xcconfig"; path = "Target Support Files/Pods-Example-iOSForPod/Pods-Example-iOSForPod.debug.xcconfig"; sourceTree = ""; }; C1AF3AE928187F71003BAEFF /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + D863799628187F71003BAEFF /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = ""; }; + D863799728187F71003BAEFF /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -112,6 +115,8 @@ 346E916D1C29D42800D3620B /* main.m */, 346E916F1C29D42800D3620B /* AppDelegate.h */, 346E91701C29D42800D3620B /* AppDelegate.m */, + D863799628187F71003BAEFF /* SceneDelegate.h */, + D863799728187F71003BAEFF /* SceneDelegate.m */, 34CB09BA1C42007600A54261 /* GTMAppAuthExampleViewController.h */, 34CB09BB1C42007600A54261 /* GTMAppAuthExampleViewController.m */, 34CB09BC1C42007600A54261 /* GTMAppAuthExampleViewController.xib */, @@ -254,6 +259,7 @@ buildActionMask = 2147483647; files = ( 346E91711C29D42800D3620B /* AppDelegate.m in Sources */, + D863799828187F71003BAEFF /* SceneDelegate.m in Sources */, 346E916E1C29D42800D3620B /* main.m in Sources */, 34CB09BD1C42007600A54261 /* GTMAppAuthExampleViewController.m in Sources */, ); @@ -314,7 +320,7 @@ "../Source/**", ../../../../../, ); - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -357,7 +363,7 @@ "../Source/**", ../../../../../, ); - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -372,7 +378,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = Source/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = ( "-ObjC", @@ -390,7 +396,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = Source/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = ( "-ObjC", diff --git a/Examples/Example-iOS/Source/AppDelegate.h b/Examples/Example-iOS/Source/AppDelegate.h index e0d40fb7..f235ac36 100644 --- a/Examples/Example-iOS/Source/AppDelegate.h +++ b/Examples/Example-iOS/Source/AppDelegate.h @@ -17,19 +17,9 @@ */ #import -@protocol OIDExternalUserAgentSession; - /*! @brief The example application's delegate. */ @interface AppDelegate : UIResponder -/*! @brief The authorization flow session which receives the return URL from - \SFSafariViewController. - @discussion We need to store this in the app delegate as it's that delegate which receives the - incoming URL on UIApplicationDelegate.application:openURL:options:. This property will be - nil, except when an authorization flow is in progress. - */ -@property(nonatomic, strong, nullable) id currentAuthorizationFlow; - @end diff --git a/Examples/Example-iOS/Source/AppDelegate.m b/Examples/Example-iOS/Source/AppDelegate.m index 56b27753..971a27dd 100644 --- a/Examples/Example-iOS/Source/AppDelegate.m +++ b/Examples/Example-iOS/Source/AppDelegate.m @@ -23,51 +23,18 @@ @implementation AppDelegate -@synthesize window = _window; - - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - UIViewController *mainViewController = - [[GTMAppAuthExampleViewController alloc] init]; - window.rootViewController = mainViewController; - - _window = window; - [_window makeKeyAndVisible]; - return YES; } -/*! @brief Handles inbound URLs. Checks if the URL matches the redirect URI for a pending - AppAuth authorization request. - */ -- (BOOL)application:(UIApplication *)app - openURL:(NSURL *)url - options:(NSDictionary *)options { - // Sends the URL to the current authorization flow (if any) which will process it if it relates to - // an authorization response. - if ([_currentAuthorizationFlow resumeExternalUserAgentFlowWithURL:url]) { - _currentAuthorizationFlow = nil; - return YES; - } - - // Your additional URL handling (if any) goes here. +#pragma mark - UISceneSession lifecycle - return NO; -} - -/*! @brief Forwards inbound URLs for iOS 8.x and below to @c application:openURL:options:. - @discussion When you drop support for versions of iOS earlier than 9.0, you can delete this - method. NB. this implementation doesn't forward the sourceApplication or annotations. If you - need these, then you may want @c application:openURL:options to call this method instead. - */ -- (BOOL)application:(UIApplication *)application - openURL:(NSURL *)url - sourceApplication:(NSString *)sourceApplication - annotation:(id)annotation { - return [self application:application - openURL:url - options:@{}]; +- (UISceneConfiguration *)application:(UIApplication *)application + configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession + options:(UISceneConnectionOptions *)options { + return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" + sessionRole:connectingSceneSession.role]; } @end diff --git a/Examples/Example-iOS/Source/GTMAppAuthExampleViewController.m b/Examples/Example-iOS/Source/GTMAppAuthExampleViewController.m index 8d13c588..d9edbd78 100644 --- a/Examples/Example-iOS/Source/GTMAppAuthExampleViewController.m +++ b/Examples/Example-iOS/Source/GTMAppAuthExampleViewController.m @@ -28,7 +28,7 @@ @import GTMSessionFetcherCore; #endif -#import "AppDelegate.h" +#import "SceneDelegate.h" /*! @brief The OIDC issuer from which the configuration will be discovered. */ @@ -197,10 +197,10 @@ - (IBAction)authWithAutoCodeExchange:(nullable id)sender { responseType:OIDResponseTypeCode additionalParameters:nil]; // performs authentication request - AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate; + SceneDelegate *sceneDelegate = (SceneDelegate *)self.view.window.windowScene.delegate; [self logMessage:@"Initiating authorization request with scope: %@", request.scope]; - appDelegate.currentAuthorizationFlow = + sceneDelegate.currentAuthorizationFlow = [OIDAuthState authStateByPresentingAuthorizationRequest:request presentingViewController:self callback:^(OIDAuthState *_Nullable authState, diff --git a/Examples/Example-iOS/Source/Info.plist b/Examples/Example-iOS/Source/Info.plist index 308626ab..482e88cb 100644 --- a/Examples/Example-iOS/Source/Info.plist +++ b/Examples/Example-iOS/Source/Info.plist @@ -35,6 +35,23 @@ UILaunchStoryboardName LaunchScreen + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + SceneDelegate + + + + UIRequiredDeviceCapabilities armv7 diff --git a/Examples/Example-iOS/Source/SceneDelegate.h b/Examples/Example-iOS/Source/SceneDelegate.h new file mode 100644 index 00000000..3dd615a3 --- /dev/null +++ b/Examples/Example-iOS/Source/SceneDelegate.h @@ -0,0 +1,32 @@ +/*! @file SceneDelegate.h + @brief GTMAppAuth SDK iOS Example + @copyright + Copyright 2016 Google Inc. + @copydetails + 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 + +@protocol OIDExternalUserAgentSession; + +/*! @brief The example application's scene delegate. +*/ +@interface SceneDelegate : UIResponder + +@property(strong, nonatomic) UIWindow *window; + +/*! @brief The authorization flow session which receives the return URL from \SFSafariViewController. + */ +@property(nonatomic, strong, nullable) id currentAuthorizationFlow; + +@end diff --git a/Examples/Example-iOS/Source/SceneDelegate.m b/Examples/Example-iOS/Source/SceneDelegate.m new file mode 100644 index 00000000..1c00911e --- /dev/null +++ b/Examples/Example-iOS/Source/SceneDelegate.m @@ -0,0 +1,48 @@ +/*! @file SceneDelegate.m + @brief GTMAppAuth SDK iOS Example + @copyright + Copyright 2016 Google Inc. + @copydetails + 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 "SceneDelegate.h" + +@import AppAuth; + +#import "GTMAppAuthExampleViewController.h" + +@implementation SceneDelegate + +- (void)scene:(UIScene *)scene + willConnectToSession:(UISceneSession *)session + options:(UISceneConnectionOptions *)connectionOptions { + if (![scene isKindOfClass:[UIWindowScene class]]) { + return; + } + UIWindowScene *windowScene = (UIWindowScene *)scene; + self.window = [[UIWindow alloc] initWithWindowScene:windowScene]; + self.window.rootViewController = [[GTMAppAuthExampleViewController alloc] init]; + [self.window makeKeyAndVisible]; +} + +- (void)scene:(UIScene *)scene openURLContexts:(NSSet *)URLContexts { + UIOpenURLContext *context = URLContexts.anyObject; + if (!context) { + return; + } + if ([self.currentAuthorizationFlow resumeExternalUserAgentFlowWithURL:context.URL]) { + self.currentAuthorizationFlow = nil; + } +} + +@end