Search code examples
iosswiftflutterreferrerinstall-referrer

How to access NSUserActivity in FlutterAppDelegate interface and Access referrerUrl for AppStore install


This is the current implementation of AppDelegate

import UIKit
import Flutter
import flutter_downloader
import moengage_flutter
import MoEngage
import GoogleCast
import UserNotifications


@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate, GCKLoggerDelegate {
  let kReceiverAppID = kGCKDefaultMediaReceiverApplicationID
  let kDebugLoggingEnabled = true
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
  ) -> Bool {
      if #available(iOS 10.0, *) {
        UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
      }

    GeneratedPluginRegistrant.register(with: self)
    FlutterDownloaderPlugin.setPluginRegistrantCallback(registerPlugins)
      
      //print(application.NSUserActivity.referrerURL)
      //print(self.NSUserActivity)

      
      print("refer");
    var sdkConfig : MOSDKConfig
    let yourAppID = "" //App ID: You can be obtain it from App Settings in MoEngage Dashboard.
    if let config = MoEngage.sharedInstance().getDefaultSDKConfiguration() {
        sdkConfig = config
        sdkConfig.moeAppID = yourAppID
    }
    else{
        sdkConfig = MOSDKConfig.init(appID: yourAppID)
    }
      sdkConfig.appGroupID = ""
        sdkConfig.moeDataCenter = DATA_CENTER_01
        sdkConfig.optOutIDFATracking = true
        sdkConfig.optOutIDFVTracking = false
        sdkConfig.optOutDataTracking = false
        sdkConfig.optOutPushNotification = false
        sdkConfig.optOutInAppCampaign = false
        // use MODataCenter enum to set the datacenter for your account

    MOFlutterInitializer.sharedInstance.initializeWithSDKConfig(sdkConfig, andLaunchOptions: launchOptions)
      //
      if #available(iOS 10.0, *) {
        // For iOS 10 display notification (sent via APNS)
        UNUserNotificationCenter.current().delegate = self

        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
        UNUserNotificationCenter.current().requestAuthorization(
          options: authOptions,
          completionHandler: { _, _ in }
        )
      } else {
        let settings: UIUserNotificationSettings =
          UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
        application.registerUserNotificationSettings(settings)
      }

      application.registerForRemoteNotifications()

      
    let criteria = GCKDiscoveryCriteria(applicationID: kReceiverAppID)
        let options = GCKCastOptions(discoveryCriteria: criteria)
        GCKCastContext.setSharedInstanceWith(options)
        GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true
        GCKLogger.sharedInstance().delegate = self
    
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
    override func applicationWillResignActive(
      _ application: UIApplication
    ) {
      self.window.isHidden = true;
    }
    override func applicationDidBecomeActive(
      _ application: UIApplication
    ) {
      self.window.isHidden = false;
    }
}
private func registerPlugins(registry: FlutterPluginRegistry) { 
    if (!registry.hasPlugin("FlutterDownloaderPlugin")) {
        FlutterDownloaderPlugin.register(with: registry.registrar(forPlugin: "FlutterDownloaderPlugin")!)
    }
}

    

Tried like this but throws compilation error as method does not override super class

override func application(
        _ application: UIApplication,continue userActivity: NSUserActivity,

        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
      ) 

I want to access NSUserActivity for userActivity.referrerURL

If you have any other ideas to access this referrerURL in flutter plugin for ios that would be awesome as well. Any help will be appreciated.I really need help here


Solution

  • You can use referrer package that will give you exactly userActivity.referrerURL?.absoluteString from ios native code layer. All you need to do is in flutter layer call:

    import 'package:referrer/referrer.dart';
    final referrerInfo = await Referrer().getReferrer();
    return referrerInfo?.referrer.toString()
    

    If you for some other reason want to call it yourself from the native code (as for example you want to perform additional operations/modifications in native layer), all you need to do is:

    //ReferrerPlugin.swift file
    public class ReferrerPlugin: NSObject, FlutterPlugin {
      static let instance = ReferrerPlugin()
    
      public static func register(with registrar: FlutterPluginRegistrar) {
        let channel = FlutterMethodChannel(name: "channel", binaryMessenger: registrar.messenger())
        registrar.addMethodCallDelegate(instance, channel: channel)
        registrar.addApplicationDelegate(instance)
      }
    
      private var latestReferrer: String?
    
      //handling executing method channel calls
      public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        switch call.method {
        case "getReferrer":
          result(latestReferrer)
        default:
          result(FlutterMethodNotImplemented)
        }
      }
      
    //https://developer.apple.com/documentation/uikit/uiapplicationdelegate/application(_:continue:restorationhandler:)  
      public func application(
        _ application: UIApplication,
        continue userActivity: NSUserActivity,
        restorationHandler: @escaping ([Any]) -> Void
      ) -> Bool {
        latestReferrer = userActivity.referrerURL?.absoluteString
        return false
      }
    }
    
    //AppDelegate.swift file
    @main
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)
        //it is important to register plugin, to listen for method channel calls
        ReferrerPlugin.register(with: self.registrar(forPlugin: "my_plugin")!)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    }
    

    Part for Android if anyone else reading this stumble on this subject

    //MainActivity.kt file
    class MainActivity : FlutterFragmentActivity() {
        override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
            super.configureFlutterEngine(flutterEngine)
            MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "channel").setMethodCallHandler {
                    call, result ->
                if (call.method == "getReferrer") {
                    result.success(this.referrer.toString())
                } else {
                    result.notImplemented()
                }
            }
        }
    }
    

    And in Flutter layer:

    //ReferrerPlugin.dart file
    class ReferrerPlugin {
      final _platform = const MethodChannel('channel');
    
      Future<String?> getReferrer() async {
        try {
          final result = await _platform.invokeMethod<String>('getReferrer');
          return result;
        } on PlatformException catch (e) {
          return null;
        }
      }
    }
    
    //Execution:
    final plugin = ReferrerPlugin();
    final result = await plugin.getReferrer();
    

    The benefit of such approach is that, you can create this way multiple plugins, and you don't introduce additional dependency to code.