diff --git a/doc/CustomCodeTemplates.md b/doc/CustomCodeTemplates.md index 2183ee50..704e1875 100644 --- a/doc/CustomCodeTemplates.md +++ b/doc/CustomCodeTemplates.md @@ -159,6 +159,13 @@ Call `[CleverTapPluginCustomTemplates registerCustomTemplates]` in your `AppDele } ``` +If your app uses the `UIScene` lifecycle, also notify the plugin of the cold-launch push payload from your SceneDelegate so `getInitialUrl` keeps working (see [Integrate-iOS.md](Integrate-iOS.md#handling-deep-links-under-the-uiscene-lifecycle)): +```objc +- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { + [[CleverTapPlugin sharedInstance] sceneWillConnectWithOptions:connectionOptions]; +} +``` + ## Syncing in-app templates to the dashboard For the templates to be usable in campaigns they must be synced with the dashboard. When all templates and functions are defined and registered in the SDK, they can be synced by calling `CleverTap.syncCustomTemplates()` or `CleverTap.syncCustomTemplatesInProd()` in your Flutter application. The syncing can only be done in debug builds and with an SDK user marked as a "test user". We recommend only calling this function while developing the templates and deleting the invocation in release builds. diff --git a/doc/Integrate-iOS.md b/doc/Integrate-iOS.md index 02e8a078..4e2f5078 100644 --- a/doc/Integrate-iOS.md +++ b/doc/Integrate-iOS.md @@ -31,7 +31,27 @@ After installation, you will need to integrate CleverTap SDK into your app. CleverTap.autoIntegrate() // integrate CleverTap SDK using the autoIntegrate option CleverTapPlugin.sharedInstance()?.applicationDidLaunch(options: launchOptions) ``` - + +### Handling deep links under the UIScene lifecycle + +If your app uses the `UIScene` lifecycle (a `SceneDelegate` with a `UIApplicationSceneManifest` in `Info.plist`), the cold-launch push payload is delivered to `scene(_:willConnectTo:options:)` rather than `didFinishLaunchingWithOptions:`. In that case `launchOptions` is `nil`, so you must ALSO notify the plugin from your SceneDelegate for `getInitialUrl` to return the deep link on a cold launch. + + ###### Objective-C + ```objc + - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { + [[CleverTapPlugin sharedInstance] sceneWillConnectWithOptions:connectionOptions]; + } + ``` + + ###### Swift + ```swift + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + CleverTapPlugin.sharedInstance()?.sceneWillConnect(withOptions: connectionOptions) + } + ``` + +> Apps that do NOT use the `UIScene` lifecycle need no changes - keep calling `applicationDidLaunchWithOptions:` from `didFinishLaunchingWithOptions:` as shown above. + ### Set up and register for push notifications 1. [Set up push notifications for your app](https://developer.apple.com/documentation/usernotifications/registering_your_app_with_apns). diff --git a/ios/Classes/CleverTapPlugin.h b/ios/Classes/CleverTapPlugin.h index 404c84f3..3997b1b5 100644 --- a/ios/Classes/CleverTapPlugin.h +++ b/ios/Classes/CleverTapPlugin.h @@ -32,6 +32,7 @@ static NSString *const kCleverTapCustomTemplateClose = @"c + (instancetype)sharedInstance; - (void)applicationDidLaunchWithOptions:(NSDictionary *)options; +- (void)sceneWillConnectWithOptions:(UISceneConnectionOptions *)connectionOptions API_AVAILABLE(ios(13.0)); - (void)postNotificationWithName:(NSString *)name andBody:(NSDictionary *)body; @property NSString *launchDeepLink; diff --git a/ios/Classes/CleverTapPlugin.m b/ios/Classes/CleverTapPlugin.m index 5daa8513..4a7549d2 100644 --- a/ios/Classes/CleverTapPlugin.m +++ b/ios/Classes/CleverTapPlugin.m @@ -1,4 +1,5 @@ +#import #import "CleverTap.h" #import "CleverTapPlugin.h" #import "CleverTap+Inbox.h" @@ -79,6 +80,20 @@ - (void)applicationDidLaunchWithOptions:(NSDictionary *)options { } } +- (void)sceneWillConnectWithOptions:(UISceneConnectionOptions *)connectionOptions API_AVAILABLE(ios(13.0)) { + + if (@available(iOS 13.0, *)) { + UNNotificationResponse *response = connectionOptions.notificationResponse; + if (response) { + NSDictionary *userInfo = response.notification.request.content.userInfo; + if (userInfo && userInfo[@"wzrk_dl"]) { + self.launchDeepLink = userInfo[@"wzrk_dl"]; + NSLog(@"CleverTapFlutter: setting launch deeplink (scene): %@", self.launchDeepLink); + } + } + } +} + - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { if ([@"getPlatformVersion" isEqualToString:call.method]) @@ -780,8 +795,20 @@ - (void)fetchInboxWithCallback:(FlutterMethodCall *)call withResult:(FlutterResu }]; } +- (UIWindow *)ct_keyWindow { + + if (@available(iOS 11.0, *)) { + for (UIWindow *window in [UIApplication sharedApplication].windows) { + if (window.isKeyWindow) { + return window; + } + } + } + return [[UIApplication sharedApplication] keyWindow]; +} + - (void)showInbox:(FlutterMethodCall *)call withResult:(FlutterResult)result { - + NSDictionary *styleConfig = call.arguments[@"styleConfig"]; if ([styleConfig isKindOfClass:[NSNull class]]) { styleConfig = nil; @@ -789,7 +816,7 @@ - (void)showInbox:(FlutterMethodCall *)call withResult:(FlutterResult)result { CleverTapInboxViewController *inboxController = [[CleverTap sharedInstance] newInboxViewControllerWithConfig:[self _dictToInboxStyleConfig:styleConfig ? styleConfig : nil] andDelegate:(id )self]; if (inboxController) { UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:inboxController]; - UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow]; + UIWindow *keyWindow = [self ct_keyWindow]; UIViewController *mainViewController = keyWindow.rootViewController; [mainViewController presentViewController:navigationController animated:YES completion:nil]; }