我是 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 应用程序不会启动。
任何帮助将不胜感激。
谢谢。
我在@sonle的帮助下解决了问题
通过增加执行深层链接的时间,解决了问题。
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
handleDeepLink(deeplink)
}
感谢Sonle的指导。