如果应用程序在 swift iOS 中从内存中删除,深度链接不会导航到预期位置

问题描述 投票:0回答:1

我是 ReactNative 的新手。 在我当前的应用程序中,深度链接是经过编码的,并且通过 appDelegate 完成时运行良好。 后来,应用程序也支持Carplay,因此引入了sceneDelegate来处理多个场景。

之后,每当调用深度链接时

  • 如果应用程序处于后台状态,则会在特定位置启动应用程序
  • 如果应用程序从内存中删除并单击深层链接,则它只会启动该应用程序,但不会导航到所需的屏幕。

这里有什么问题, 即使应用程序已从内存中删除,我需要更改/添加哪些内容才能使应用程序在所需位置启动。

这是我的应用程序委托。

func appDelegate() -> AppDelegate {
    return UIApplication.shared.delegate as! AppDelegate
}

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
  var window: UIWindow?
  var appCenter: AppCenterReactNative!
  var appCenterAnaltics: AppCenterReactNativeAnalytics!
  var appCenterCrashes: AppCenterReactNativeCrashes!
  let mParticleKey: String = ReactNativeConfig.env(for: "MPARTICLE_IOS_KEY");
  let mParticleSecret: String = ReactNativeConfig.env(for: "MPARTICLE_IOS_SECRET");
  // var mParticleEmail: String = ReactNativeConfig.env(for: "MPARTICLE_EMAIL");
  let mParticleEnv: String = ReactNativeConfig.env(for: "MPARTICLE_ENV");
  let mParticleDataPlanName: String = ReactNativeConfig.env(for: "MPARTICLE_DATAPLAN");
  let mParticleDataPlanVersion: String = ReactNativeConfig.env(for: "MPARTICLE_DATAPLAN_VERSION");
  let moEngageAppID: String = ReactNativeConfig.env(for: "MOENGAGE_APP_ID");
  
  /* CarPlay setup */
  var playableContentManager: MPPlayableContentManager?
  var remoteCommandCenter: MPRemoteCommandCenter?
  let carplayPlaylist = CarPlayPlaylist()
  let carplayArtworkCache = NSCache<AnyObject, UIImage>()
  
  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
    initializeFlipper(with: application)

    /* Moengage */
    let sdkConfig = MoEngageSDKConfig(appId: moEngageAppID, dataCenter: .data_center_01);
    MoEngageInitializer.sharedInstance().initializeDefaultSDKConfig(sdkConfig, andLaunchOptions: launchOptions ?? [:])
    
    AppCenterReactNative.register()
    AppCenterReactNativeAnalytics.register(withInitiallyEnabled: true);
    AppCenterReactNativeCrashes.registerWithAutomaticProcessing();

    FirebaseApp.configure()
        
    /* ChromeCast activate */
    let receiverAppID:String = "CC1AD845"; // or @"ABCD1234"
    let criteria = GCKDiscoveryCriteria(applicationID: receiverAppID)
    let options = GCKCastOptions(discoveryCriteria: criteria)
    GCKCastContext.setSharedInstanceWith(options)
    
    let bridge = RCTBridge(delegate: self, launchOptions: launchOptions)!
    let rootView = RCTRootView(bridge: bridge, moduleName: "nova", initialProperties: nil)
    
    let rootViewController = UIViewController()
    rootViewController.view = rootView

    self.window = UIWindow(frame: UIScreen.main.bounds)
    self.window?.rootViewController = rootViewController
    self.window?.makeKeyAndVisible()

    /* MPNowPlayingInfoCenter */
    UIApplication.shared.beginReceivingRemoteControlEvents()

    setupCarPlay();

    RNSplashScreen.show()

    /* Setup MParticle */
    var dPlanVersion:NSNumber = 0
    if let versionInt = Int(mParticleDataPlanVersion) {
     dPlanVersion = NSNumber(value:versionInt)
    }

    var mParticleEnvMode: MPEnvironment = MPEnvironment.development
    if(mParticleEnv == "PROD") {
      mParticleEnvMode =  MPEnvironment.production
    }
    let mParticleOptions = MParticleOptions(key: mParticleKey, secret: mParticleSecret)
    mParticleOptions.environment = mParticleEnvMode
    mParticleOptions.dataPlanId = mParticleDataPlanName
    mParticleOptions.dataPlanVersion = dPlanVersion
    mParticleOptions.proxyAppDelegate = false
    if #available(iOS 14, *) {
       mParticleOptions.attStatus = NSNumber.init(value: ATTrackingManager.trackingAuthorizationStatus.rawValue)
    }
    
    // Remove AST Events
    mParticleOptions.onCreateBatch = { (batch: [AnyHashable: Any]) -> [AnyHashable: Any]? in
        var modifiedBatch = batch
        guard var modifiedMessages = batch["msgs"] as? [AnyHashable] else { return batch }
        var index = 0
        for message in modifiedMessages {
            // the following removes Application State Transition (AST) events, except for those uploaded on installs and upgrades
            // Install AST events are used by many server-side integrations and are used by
            // mParticle to ensure there is a user profile created
            guard let messageAsDictionary = message as? [AnyHashable: Any] else { continue }
            guard let type = messageAsDictionary["dt"] as? String else { continue }
            let isFirstRun = messageAsDictionary["ifr"] as? Bool ?? false
            let isUpgrade = messageAsDictionary["iu"] as? Bool ?? false
            if type == "ast" && !isFirstRun && !isUpgrade {
                modifiedMessages.remove(at: index)
                index -= 1
            }
            index += 1
        }
        modifiedBatch["msgs"] = modifiedMessages
        return modifiedBatch
    }
    // Start the SDK
    MParticle.sharedInstance().start(with: mParticleOptions)
    
    return true
  } 

  private func initializeFlipper(with application: UIApplication) {
    #if DEBUG
      let client = FlipperClient.shared()
        
      let layoutDescriptorMapper = SKDescriptorMapper(defaults: ())
      client?.add(FlipperKitLayoutPlugin(rootNode: application, with: layoutDescriptorMapper!))
      client?.add(FKUserDefaultsPlugin(suiteName: "nova"))
      client?.add(FlipperKitReactPlugin())
      client?.add(FlipperKitNetworkPlugin(networkAdapter: SKIOSNetworkAdapter()))
      client?.start()
    #endif
  }

  /* Allow for orientation change */
  func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return Orientation.getOrientation()
  }

  /* Allow Link back URLs ('nova://') */
  public func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    return RCTLinkingManager.application(app, open: url, options: options)
  }
  
  public func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    return RCTLinkingManager.application(application, continue: userActivity, restorationHandler: restorationHandler)
  }
}

extension AppDelegate: RCTBridgeDelegate {
    func sourceURL(for bridge: RCTBridge!) -> URL! {
        #if DEBUG
        return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
        #else
        return CodePush.bundleURL()
        #endif
    }
}

这是我的场景Delegate

@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate, RCTBridgeDelegate {

  let mParticleKey: String = ReactNativeConfig.env(for: "MPARTICLE_IOS_KEY");
  let mParticleSecret: String = ReactNativeConfig.env(for: "MPARTICLE_IOS_SECRET");
  // var mParticleEmail: String = ReactNativeConfig.env(for: "MPARTICLE_EMAIL");
  let mParticleEnv: String = ReactNativeConfig.env(for: "MPARTICLE_ENV");
  let mParticleDataPlanName: String = ReactNativeConfig.env(for: "MPARTICLE_DATAPLAN");
  let mParticleDataPlanVersion: String = ReactNativeConfig.env(for: "MPARTICLE_DATAPLAN_VERSION");


  func sourceURL(for bridge: RCTBridge!) -> URL! {
    let jsCodeLocation: URL
    jsCodeLocation = RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
    return jsCodeLocation
  }
  
  var window: UIWindow?
  
  func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    var deeplink: URL?
    if let userActivity = connectionOptions.userActivities.first(where: { $0.activityType == NSUserActivityTypeBrowsingWeb }),
        let webpageURL = userActivity.webpageURL {
        // get universal link
        deeplink = webpageURL
    } else if let urlContext = connectionOptions.urlContexts.first {
        // get app scheme deep link
        deeplink = urlContext.url
    }
    handleDeepLink(deeplink)
    
    let bridge = RCTBridge.init(delegate: self, launchOptions: nil)
    let rootView = RCTRootView.init(bridge: bridge!, moduleName: "nova", initialProperties: nil)
      
    let rootViewController = UIViewController()
    rootViewController.view = rootView

    

    AppCenterReactNative.register()
    AppCenterReactNativeAnalytics.register(withInitiallyEnabled: true);
    AppCenterReactNativeCrashes.registerWithAutomaticProcessing();

    FirebaseApp.configure()

    /* ChromeCast activate */
    let receiverAppID:String = "CC1AD845"; // or @"ABCD1234"
    let criteria = GCKDiscoveryCriteria(applicationID: receiverAppID)
    let options = GCKCastOptions(discoveryCriteria: criteria)
    GCKCastContext.setSharedInstanceWith(options)
    
    /* MPNowPlayingInfoCenter */
    UIApplication.shared.beginReceivingRemoteControlEvents()

    RNSplashScreen.show()

    // Instantiate root view here instead of scene to start the bundler on app launch
    RNBridgeInstanceHolder.sharedInstance.bridge = bridge
    RNBridgeInstanceHolder.sharedInstance.rctRootView = rootView
    
    if let windowScene = scene as? UIWindowScene {
       let window = UIWindow(windowScene: windowScene)
      window.rootViewController = rootViewController
       self.window = window
       window.makeKeyAndVisible()
    }

    if #unavailable(iOS 14.0) {
      appDelegate().setupCarPlay()
    }

    /* Setup MParticle */
    var dPlanVersion:NSNumber = 0
    if let versionInt = Int(mParticleDataPlanVersion) {
     dPlanVersion = NSNumber(value:versionInt)
    }

    var mParticleEnvMode: MPEnvironment = MPEnvironment.development
    if(mParticleEnv == "PROD") {
      mParticleEnvMode =  MPEnvironment.production
    }
    let mParticleOptions = MParticleOptions(key: mParticleKey, secret: mParticleSecret)
    mParticleOptions.environment = mParticleEnvMode
    mParticleOptions.dataPlanId = mParticleDataPlanName
    mParticleOptions.dataPlanVersion = dPlanVersion
    mParticleOptions.proxyAppDelegate = false
    if #available(iOS 14, *) {
       mParticleOptions.attStatus = NSNumber.init(value: ATTrackingManager.trackingAuthorizationStatus.rawValue)
    }
    
    // Remove AST Events
    mParticleOptions.onCreateBatch = { (batch: [AnyHashable: Any]) -> [AnyHashable: Any]? in
        var modifiedBatch = batch
        guard var modifiedMessages = batch["msgs"] as? [AnyHashable] else { return batch }
        var index = 0
        for message in modifiedMessages {
            // the following removes Application State Transition (AST) events, except for those uploaded on installs and upgrades
            // Install AST events are used by many server-side integrations and are used by
            // mParticle to ensure there is a user profile created
            guard let messageAsDictionary = message as? [AnyHashable: Any] else { continue }
            guard let type = messageAsDictionary["dt"] as? String else { continue }
            let isFirstRun = messageAsDictionary["ifr"] as? Bool ?? false
            let isUpgrade = messageAsDictionary["iu"] as? Bool ?? false
            if type == "ast" && !isFirstRun && !isUpgrade {
                modifiedMessages.remove(at: index)
                index -= 1
            }
            index += 1
        }
        modifiedBatch["msgs"] = modifiedMessages
        return modifiedBatch
    }
    // Start the SDK
    MParticle.sharedInstance().start(with: mParticleOptions)
      
  }

  //handels app scheme novaplayer:// in active and inactive foreground mode
  func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
      if let url = URLContexts.first?.url {
        handleDeepLink(url)
      }
  }

  //handels universal links https://novaplayer in active and inactive foreground mode
  func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    if userActivity.activityType == NSUserActivityTypeBrowsingWeb {
    if let url = userActivity.webpageURL {               
        handleDeepLink(url)
      }
    }
  }
    
  //function to pass deelink value to react native
  func handleDeepLink(_ deeplink: URL?) {
      guard let deeplink = deeplink else {
          os_log("No deeplink found", log: OSLog.default, type: .debug)
          return
      }
      os_log("Deeplink URL FOUND: %@", log: OSLog.default, type: .debug, deeplink.absoluteString)
      RCTLinkingManager.application(UIApplication.shared, open: deeplink, options: [:])
  }

}

这是我的 info.plist 代码。

<key>UIApplicationSceneManifest</key>
    <dict>
        <key>UISceneConfigurations</key>
        <dict>
            <key>CPTemplateApplicationSceneSessionRoleApplication</key>
            <array>
                <dict>
                    <key>UISceneClassName</key>
                    <string>CPTemplateApplicationScene</string>
                    <key>UISceneConfigurationName</key>
                    <string>CarPlay Configuration</string>
                    <key>UISceneDelegateClassName</key>
                    <string>$(PRODUCT_MODULE_NAME).CarPlaySceneDelegate</string>
                </dict>
            </array>
            <key>UIWindowSceneSessionRoleApplication</key>
            <array>
                <dict>
                    <key>UISceneConfigurationName</key>
                    <string>Default Configuration</string>
                    <key>UISceneDelegateClassName</key>
                    <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
                </dict>
            </array>
        </dict>
    </dict>

它在 Android 构建中按预期工作,但仅在 iOS 构建中存在问题。 如果我切换回没有 scenedelegate 的 appDelegate,那么我的 Carplay 应用程序不会启动。

任何帮助将不胜感激。

谢谢。

ios swift react-native deep-linking
1个回答
0
投票

我在@sonle的帮助下解决了问题

通过增加执行深层链接的时间,解决了问题。

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            handleDeepLink(deeplink)
        }

感谢Sonle的指导。

© www.soinside.com 2019 - 2024. All rights reserved.