1

When I click notification which having OpenDirect URL, it's not triggering sfmc_handleURL method in AppDelegate.m. Kindly find out below code for the implementation.

AppDelegate.h

#import <React/RCTBridgeDelegate.h>
#import <UIKit/UIKit.h>
#import <UserNotifications/UNUserNotificationCenter.h>
#import <MarketingCloudSDK/MarketingCloudSDK.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate, UNUserNotificationCenterDelegate, MarketingCloudSDKURLHandlingDelegate>

@property (nonatomic, strong) UIWindow *window;

@end

AppDelegate.m

#import "AppDelegate.h"

#import <AppCenterReactNative.h>
#import <AppCenterReactNativeAnalytics.h>
#import <AppCenterReactNativeCrashes.h>

#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>

#import <React/RCTAppSetupUtils.h>
#import <React/RCTLinkingManager.h>

#import <Firebase.h>

#import <CodePush/CodePush.h>

#import <MarketingCloudSDK/MarketingCloudSDK.h>

#import <UserNotifications/UserNotifications.h>

#if RCT_NEW_ARCH_ENABLED
#import <React/CoreModulesPlugins.h>
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#import <React/RCTSurfacePresenter.h>
#import <React/RCTSurfacePresenterBridgeAdapter.h>
#import <ReactCommon/RCTTurboModuleManager.h>

#import <react/config/ReactNativeConfig.h>

@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
    RCTTurboModuleManager *_turboModuleManager;
    RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
    std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
    facebook::react::ContextContainer::Shared _contextContainer;
}
@end
#endif

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // configure the Marketing Cloud SDK
    MarketingCloudSDKConfigBuilder *mcsdkBuilder = [MarketingCloudSDKConfigBuilder new];
    [mcsdkBuilder sfmc_setApplicationId:@"<ApplicationId>"];
    [mcsdkBuilder sfmc_setAccessToken:@"<AccessToken>"];
    [mcsdkBuilder sfmc_setAnalyticsEnabled:@(YES)];
    [mcsdkBuilder sfmc_setMarketingCloudServerUrl:@"<MarketingCloudServerUrl>"];

    NSError *error = nil;
    BOOL success = [[MarketingCloudSDK sharedInstance] sfmc_configureWithDictionary:[mcsdkBuilder sfmc_build] error:&error];
    
    if (success == YES) {
        //  MarketingCloudSDK sfmc_setURLHandlingDelegate
        [[MarketingCloudSDK sharedInstance] sfmc_setURLHandlingDelegate:self];
        dispatch_async(dispatch_get_main_queue(), ^{});
    } else {
        //  MarketingCloudSDK sfmc_configure failed
        os_log_debug(OS_LOG_DEFAULT, "MarketingCloudSDK sfmc_configure failed with error = %@", error);
    }
    
    [UNUserNotificationCenter currentNotificationCenter].delegate = self;
    [[UIApplication sharedApplication] registerForRemoteNotifications];

    [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions: UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge completionHandler:^(BOOL granted, NSError *_Nullable error) {
        if (error == nil) {
            if (granted == YES) {
                dispatch_async(dispatch_get_main_queue(), ^{});
            }
        }
    }];
    
    // RN setup
    [AppCenterReactNative register];
    [AppCenterReactNativeAnalytics registerWithInitiallyEnabled:true];
    [AppCenterReactNativeCrashes registerWithAutomaticProcessing];

    [FIRApp configure];

    RCTAppSetupPrepareApp(application);

    RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];

    #if RCT_NEW_ARCH_ENABLED
        _contextContainer = std::make_shared<facebook::react::ContextContainer const>();
        _reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
        _contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
        _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
        bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
    #endif

    UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"MyApp", nil);

    if (@available(iOS 13.0, *)) {
        rootView.backgroundColor = [UIColor systemBackgroundColor];
    } else {
        rootView.backgroundColor = [UIColor whiteColor];
    }

    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    UIViewController *rootViewController = [UIViewController new];
    rootViewController.view = rootView;
    self.window.rootViewController = rootViewController;
    [self.window makeKeyAndVisible];

    return YES;
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
    #if DEBUG
        return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
    #else
        return [CodePush bundleURL];
    #endif
}

- (void)application:(UIApplication *)application
    didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    [[MarketingCloudSDK sharedInstance] sfmc_setDeviceToken:deviceToken];
}

- (void)application:(UIApplication *)application
    didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
    didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {

    [[MarketingCloudSDK sharedInstance] sfmc_setNotificationRequest:response.notification.request];

    if (completionHandler != nil) {
        completionHandler();
    }
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
    completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    [[MarketingCloudSDK sharedInstance] sfmc_setNotificationUserInfo:userInfo];
    completionHandler(UIBackgroundFetchResultNewData);
}

// Implement the protocol method and have iOS handle the URL itself
- (void)sfmc_handleURL:(NSURL *)url type:(NSString *)type
{
    // THIS METHOD IS NOT GETTING CALLED when I click the notification with OpenDirect URL
    if ([[UIApplication sharedApplication] canOpenURL:url] == YES) {
      [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {
          if (success) {
              NSLog(@"url %@ opened successfully", url);
          }
          else {
              NSLog(@"url %@ could not be opened", url);
          }
      }];
    }
}

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
    return [RCTLinkingManager application:application openURL:url options:options];
}

#if RCT_NEW_ARCH_ENABLED

#pragma mark - RCTCxxBridgeDelegate

- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
{
    _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge delegate:self jsInvoker:bridge.jsCallInvoker];
    return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
}

#pragma mark RCTTurboModuleManagerDelegate

- (Class)getModuleClassFromName:(const char *)name
{
    return RCTCoreModulesClassProvider(name);
}

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
    return nullptr;
}

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name initParams: (const facebook::react::ObjCTurboModule::InitParams &)params
{
    return nullptr;
}

- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
    return RCTAppSetupDefaultModuleFromClass(moduleClass);
}

#endif

@end

1 Answer 1

1

With the same exact code above, I'm able to open the notification with open direct and it takes me to the open direct URL (ie) sfmc_handleURL triggers perfectly. I don't see any issue here.

Thanks, Prakashini

2
  • Thanks for the reply. Actually I am using github.com/invertase/notifee library to receive the push notification in App.jsx so with this Library it's not working as expected. Nov 30, 2022 at 5:41
  • 1
    Hi, If you have multiple push provider you may have to have the "swizzling" disabled, otherwise, the delegate methods of the other providers are intercepted and the notification payload may also be tweaked. Dec 1, 2022 at 6:55

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .