Skip to content

Commit 3643707

Browse files
thiagobrezokwasniewski
authored andcommitted
fix: deep and universal links when app is running
1 parent fef6d8e commit 3643707

File tree

6 files changed

+96
-0
lines changed

6 files changed

+96
-0
lines changed

packages/react-native/Libraries/LinkingIOS/RCTLinkingManager.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,13 @@
2424
continueUserActivity:(nonnull NSUserActivity *)userActivity
2525
restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> *_Nullable))restorationHandler;
2626

27+
+ (BOOL)scene:(nonnull UIScene *)scene
28+
willConnectTo:(nonnull UISceneSession *)session
29+
options:(nonnull UISceneConnectionOptions *)connectionOptions;
30+
31+
+ (BOOL)scene:(nonnull UIScene *)scene
32+
openURLContexts:(nonnull NSSet<UIOpenURLContext *> *)URLContexts;
33+
34+
+ (BOOL)onOpenURL:(nonnull NSURL *)url;
35+
2736
@end

packages/react-native/Libraries/LinkingIOS/RCTLinkingManager.mm

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#import "RCTLinkingPlugins.h"
1616

1717
static NSString *const kOpenURLNotification = @"RCTOpenURLNotification";
18+
static NSURL *initialURL = nil;
1819

1920
static void postNotificationWithURL(NSURL *URL, id sender)
2021
{
@@ -81,6 +82,54 @@ + (BOOL)application:(UIApplication *)application
8182
return YES;
8283
}
8384

85+
// iOS 13+ - Corresponding apis for SceneDelegate
86+
87+
// Both Deep Links and Universal Links - called when the app was previously NOT running
88+
+ (BOOL)scene:(UIScene *)scene
89+
willConnectTo:(UISceneSession *)session
90+
options:(UISceneConnectionOptions *) connectionOptions
91+
{
92+
93+
// Deep Links
94+
for (UIOpenURLContext *urlContext in connectionOptions.URLContexts) {
95+
if (urlContext) {
96+
initialURL = urlContext.URL;
97+
postNotificationWithURL(urlContext.URL, self);
98+
}
99+
}
100+
101+
// Universal Links
102+
for (NSUserActivity *userActivity in connectionOptions.userActivities) {
103+
if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
104+
initialURL = userActivity.webpageURL;
105+
postNotificationWithURL(userActivity.webpageURL, self);
106+
}
107+
}
108+
109+
return YES;
110+
}
111+
112+
// Deep Links - called when the app was previously running or suspended
113+
+ (BOOL)scene:(UIScene *)scene
114+
openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts
115+
{
116+
for (UIOpenURLContext *urlContext in URLContexts) {
117+
if (urlContext) {
118+
postNotificationWithURL(urlContext.URL, self);
119+
}
120+
}
121+
122+
return YES;
123+
}
124+
125+
// Universal Links - called when the app was previously running or suspended
126+
// Called from SwiftUI's onOpenURL(perform:)
127+
+ (BOOL)onOpenURL:(NSURL *)url
128+
{
129+
postNotificationWithURL(url, self);
130+
return YES;
131+
}
132+
84133
- (void)handleOpenURLNotification:(NSNotification *)notification
85134
{
86135
[self sendEventWithName:@"url" body:notification.userInfo];
@@ -153,6 +202,7 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
153202

154203
RCT_EXPORT_METHOD(getInitialURL : (RCTPromiseResolveBlock)resolve reject : (__unused RCTPromiseRejectBlock)reject)
155204
{
205+
#if !TARGET_OS_VISION
156206
NSURL *initialURL = nil;
157207
if (self.bridge.launchOptions[UIApplicationLaunchOptionsURLKey]) {
158208
initialURL = self.bridge.launchOptions[UIApplicationLaunchOptionsURLKey];
@@ -163,6 +213,8 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
163213
initialURL = ((NSUserActivity *)userActivityDictionary[@"UIApplicationLaunchOptionsUserActivityKey"]).webpageURL;
164214
}
165215
}
216+
#endif
217+
// React Native visionOS uses static property to retrieve initialURL.
166218
resolve(RCTNullIfNil(initialURL.absoluteString));
167219
}
168220

packages/rn-tester/RNTester-visionOS/AppDelegate.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,10 @@ class AppDelegate: RCTAppDelegate {
1010
override func bundleURL() -> URL? {
1111
RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "js/RNTesterApp.ios")
1212
}
13+
14+
override func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
15+
let configuration = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role)
16+
configuration.delegateClass = SceneDelegate.self
17+
return configuration
18+
}
1319
}

packages/rn-tester/RNTester-visionOS/Info.plist

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33
<plist version="1.0">
44
<dict>
5+
<key>CFBundleURLTypes</key>
6+
<array>
7+
<dict>
8+
<key>CFBundleTypeRole</key>
9+
<string>Editor</string>
10+
<key>CFBundleURLName</key>
11+
<string>com.reactjs.ios</string>
12+
<key>CFBundleURLSchemes</key>
13+
<array>
14+
<string>rntester</string>
15+
</array>
16+
</dict>
17+
</array>
518
<key>UIApplicationSceneManifest</key>
619
<dict>
720
<key>UIApplicationPreferredDefaultSceneSessionRole</key>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import UIKit
2+
import React
3+
4+
class SceneDelegate: NSObject, UIWindowSceneDelegate {
5+
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
6+
RCTLinkingManager.scene(scene, willConnectTo: session, options: connectionOptions)
7+
}
8+
9+
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
10+
RCTLinkingManager.scene(scene, openURLContexts: URLContexts)
11+
}
12+
}

packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
5C60EB1C226440DB0018C04F /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C60EB1B226440DB0018C04F /* AppDelegate.mm */; };
1616
763DC37D2B0F824400D2C0C5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 763DC37C2B0F824400D2C0C5 /* Assets.xcassets */; };
1717
763DC3802B0F824400D2C0C5 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 763DC37F2B0F824400D2C0C5 /* Preview Assets.xcassets */; };
18+
76B3ACF22BC5485C00B2E379 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76B3ACF12BC5485C00B2E379 /* SceneDelegate.swift */; };
1819
76E4BB282B34909800B02A15 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76E4BB272B34909800B02A15 /* App.swift */; };
1920
76E4BB2C2B34932200B02A15 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76E4BB2B2B34932200B02A15 /* AppDelegate.swift */; };
2021
8145AE06241172D900A3F8DA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8145AE05241172D900A3F8DA /* LaunchScreen.storyboard */; };
@@ -105,6 +106,7 @@
105106
763DC37C2B0F824400D2C0C5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
106107
763DC37F2B0F824400D2C0C5 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
107108
763DC3812B0F824400D2C0C5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
109+
76B3ACF12BC5485C00B2E379 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
108110
76E4BB272B34909800B02A15 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
109111
76E4BB2B2B34932200B02A15 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
110112
7CDA7A212644C6BB8C0D00D8 /* Pods-RNTesterIntegrationTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNTesterIntegrationTests.release.xcconfig"; path = "Target Support Files/Pods-RNTesterIntegrationTests/Pods-RNTesterIntegrationTests.release.xcconfig"; sourceTree = "<group>"; };
@@ -300,6 +302,7 @@
300302
763DC3732B0F824200D2C0C5 /* RNTester-visionOS */ = {
301303
isa = PBXGroup;
302304
children = (
305+
76B3ACF12BC5485C00B2E379 /* SceneDelegate.swift */,
303306
76E4BB2B2B34932200B02A15 /* AppDelegate.swift */,
304307
76E4BB272B34909800B02A15 /* App.swift */,
305308
763DC37C2B0F824400D2C0C5 /* Assets.xcassets */,
@@ -890,6 +893,7 @@
890893
files = (
891894
76E4BB2C2B34932200B02A15 /* AppDelegate.swift in Sources */,
892895
76E4BB282B34909800B02A15 /* App.swift in Sources */,
896+
76B3ACF22BC5485C00B2E379 /* SceneDelegate.swift in Sources */,
893897
);
894898
runOnlyForDeploymentPostprocessing = 0;
895899
};

0 commit comments

Comments
 (0)