Skip to content

Commit 9d3fb8c

Browse files
committed
fix(dynamiclinks): improve onLink handling
1 parent 86e728e commit 9d3fb8c

File tree

6 files changed

+214
-84
lines changed

6 files changed

+214
-84
lines changed

packages/firebase-dynamic-links/index.android.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export class DynamicLinkAndroidParameters implements IDynamicLinkAndroidParamete
108108
set fallbackUrl(value) {
109109
try {
110110
this.#builder.setFallbackUrl(android.net.Uri.parse(value));
111-
} catch (error) { }
111+
} catch (error) {}
112112
}
113113

114114
get minimumVersion() {
@@ -181,7 +181,7 @@ export class DynamicLinkIOSParameters implements IDynamicLinkIOSParameters {
181181
try {
182182
this.#builder?.setFallbackUrl?.(android.net.Uri.parse(value));
183183
this.#fallbackUrl = value;
184-
} catch (error) { }
184+
} catch (error) {}
185185
}
186186

187187
get iPadBundleId(): string {
@@ -199,7 +199,7 @@ export class DynamicLinkIOSParameters implements IDynamicLinkIOSParameters {
199199
set iPadFallbackUrl(value) {
200200
try {
201201
this.#builder?.setIpadFallbackUrl?.(android.net.Uri.parse(value));
202-
} catch (error) { }
202+
} catch (error) {}
203203
}
204204

205205
get minimumVersion(): string {
@@ -331,7 +331,7 @@ export class DynamicLinkSocialParameters implements IDynamicLinkSocialParameters
331331
set imageUrl(value) {
332332
try {
333333
this.#builder?.setImageUrl?.(android.net.Uri.parse(value));
334-
} catch (error) { }
334+
} catch (error) {}
335335
}
336336

337337
get title(): string {
@@ -437,6 +437,14 @@ export class DynamicLink implements IDynamicLink {
437437
get android() {
438438
return this.native;
439439
}
440+
441+
toJSON() {
442+
return {
443+
minimumAppVersion: this.minimumAppVersion,
444+
url: this.url,
445+
utmParameters: this.utmParameters,
446+
};
447+
}
440448
}
441449

442450
export class DynamicLinks implements IDynamicLinks {
@@ -450,6 +458,7 @@ export class DynamicLinks implements IDynamicLinks {
450458
return defaultDynamicLinks;
451459
}
452460
defaultDynamicLinks = this;
461+
453462
if (!DynamicLinks.#didInit) {
454463
DynamicLinks.#callback = new org.nativescript.firebase.dynamic_links.FirebaseDynamicLinks.Callback<com.google.firebase.dynamiclinks.PendingDynamicLinkData>({
455464
onSuccess(param0) {
@@ -461,7 +470,8 @@ export class DynamicLinks implements IDynamicLinks {
461470
console.error('Unknown error occurred when attempting to handle a universal link', param0);
462471
},
463472
});
464-
Application.on(AndroidApplication.activityNewIntentEvent, (data: AndroidActivityNewIntentEventData) => {
473+
474+
Application.android.on(AndroidApplication.activityNewIntentEvent, (data: AndroidActivityNewIntentEventData) => {
465475
org.nativescript.firebase.dynamic_links.FirebaseDynamicLinks.onNewIntent(com.google.firebase.dynamiclinks.FirebaseDynamicLinks.getInstance(), data.intent, DynamicLinks.#callback);
466476
});
467477
DynamicLinks.#didInit = true;
@@ -492,15 +502,15 @@ export class DynamicLinks implements IDynamicLinks {
492502
const dl = this.native.createDynamicLink();
493503
try {
494504
dl.setLink(android.net.Uri.parse(link));
495-
} catch (error) { }
505+
} catch (error) {}
496506
dl.setDomainUriPrefix(domainUriPrefix);
497507
return DynamicLinkParameters.fromNative(dl);
498508
}
499509
createShortLink(link: string, domainUriPrefix: string, shortLinkType: ShortLinkType = ShortLinkType.DEFAULT): DynamicLinkParameters {
500510
const dl = this.native.createDynamicLink();
501511
try {
502512
dl.setLink(android.net.Uri.parse(link));
503-
} catch (error) { }
513+
} catch (error) {}
504514
dl.setDomainUriPrefix(domainUriPrefix);
505515
return DynamicLinkParameters.fromNative(dl, shortLinkType);
506516
}

packages/firebase-dynamic-links/index.ios.ts

Lines changed: 20 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Application } from '@nativescript/core';
12
import { deserialize, firebase, FirebaseApp, FirebaseError } from '@nativescript/firebase-core';
23
import { IDynamicLink, IDynamicLinkAnalyticsParameters, IDynamicLinkAndroidParameters, IDynamicLinkIOSParameters, IDynamicLinkITunesParameters, IDynamicLinkNavigationParameters, IDynamicLinkParameters, IDynamicLinks, IDynamicLinkSocialParameters, ShortLinkType } from './common';
34

@@ -13,73 +14,7 @@ Object.defineProperty(fb, 'dynamicLinks', {
1314
writable: false,
1415
});
1516

16-
declare const FIRApp;
17-
let appDelegate: AppDelegateImpl;
18-
let _launchOptions: NSDictionary<string, any>;
19-
@NativeClass
20-
@ObjCClass(UIApplicationDelegate)
21-
class AppDelegateImpl extends UIResponder implements UIApplicationDelegate {
22-
static get sharedInstance() {
23-
if (!appDelegate) {
24-
appDelegate = AppDelegateImpl.alloc().init() as AppDelegateImpl;
25-
}
26-
return appDelegate;
27-
}
28-
29-
static get launchOptions() {
30-
return _launchOptions;
31-
}
32-
applicationOpenURLOptions(app: UIApplication, url: NSURL, options: NSDictionary<string, any>): boolean {
33-
return this.applicationOpenURLSourceApplicationAnnotation(app, url, options.objectForKey(UIApplicationOpenURLOptionsSourceApplicationKey), options.objectForKey(UIApplicationOpenURLOptionsAnnotationKey));
34-
}
35-
36-
applicationOpenURLSourceApplicationAnnotation(application: UIApplication, url: NSURL, sourceApplication: string, annotation: any): boolean {
37-
let dynamicLink = FIRDynamicLinks.dynamicLinks().dynamicLinkFromCustomSchemeURL(url);
38-
39-
if (!dynamicLink) {
40-
dynamicLink = FIRDynamicLinks.dynamicLinks().dynamicLinkFromUniversalLinkURL(url);
41-
}
42-
43-
if (!dynamicLink) {
44-
return false;
45-
}
46-
47-
if (dynamicLink.url) {
48-
if (typeof DynamicLinks._onLink === 'function') {
49-
DynamicLinks._onLink(DynamicLink.fromNative(dynamicLink));
50-
}
51-
}
52-
53-
return false;
54-
}
55-
56-
applicationContinueUserActivityRestorationHandler(application: UIApplication, userActivity: NSUserActivity, restorationHandler: (p1: NSArray<UIUserActivityRestoring>) => void): boolean {
57-
let retried = false;
58-
let callback = (dynamicLink, error) => {
59-
if (!error && dynamicLink?.url) {
60-
if (typeof DynamicLinks._onLink === 'function') {
61-
DynamicLinks._onLink(DynamicLink.fromNative(dynamicLink));
62-
}
63-
}
64-
65-
if (error && !retried && NSPOSIXErrorDomain === error.domain && error.code === 53) {
66-
retried = true;
67-
FIRDynamicLinks.dynamicLinks().handleUniversalLinkCompletion(userActivity.webpageURL, callback);
68-
}
69-
70-
if (error) {
71-
console.error('Unknown error occurred when attempting to handle a universal link', error);
72-
}
73-
};
74-
FIRDynamicLinks.dynamicLinks().handleUniversalLinkCompletion(userActivity.webpageURL, callback);
75-
return false;
76-
}
77-
78-
applicationDidFinishLaunchingWithOptions?(application: UIApplication, launchOptions: NSDictionary<string, any>): boolean {
79-
_launchOptions = launchOptions;
80-
return false;
81-
}
82-
}
17+
declare const FIRApp, TNSFirebaseDynamicLinksAppDelegate;
8318

8419
export class DynamicLinkAnalyticsParameters implements IDynamicLinkAnalyticsParameters {
8520
#native: FIRDynamicLinkGoogleAnalyticsParameters;
@@ -494,24 +429,25 @@ export class DynamicLink implements IDynamicLink {
494429
get ios() {
495430
return this.native;
496431
}
432+
433+
toJSON() {
434+
return {
435+
minimumAppVersion: this.minimumAppVersion,
436+
url: this.url,
437+
utmParameters: this.utmParameters,
438+
};
439+
}
497440
}
498441

499442
export class DynamicLinks implements IDynamicLinks {
500443
#native: FIRDynamicLinks;
501444
#app: FirebaseApp;
502-
static _onLink: (link: DynamicLink) => void;
503-
static #appDelegateInitialized = false;
445+
static #onLink: (link: DynamicLink) => void;
504446
constructor() {
505-
if(defaultDynamicLinks){
447+
if (defaultDynamicLinks) {
506448
return defaultDynamicLinks;
507449
}
508450
defaultDynamicLinks = this;
509-
510-
if (!DynamicLinks.#appDelegateInitialized) {
511-
GULAppDelegateSwizzler.proxyOriginalDelegate();
512-
GULAppDelegateSwizzler.registerAppDelegateInterceptor(AppDelegateImpl.sharedInstance);
513-
DynamicLinks.#appDelegateInitialized = true;
514-
}
515451
}
516452

517453
createLink(link: string, domainUriPrefix: string): DynamicLinkParameters {
@@ -542,7 +478,14 @@ export class DynamicLinks implements IDynamicLinks {
542478
}
543479

544480
onLink(listener: (link: DynamicLink) => void) {
545-
DynamicLinks._onLink = listener;
481+
DynamicLinks.#onLink = listener;
482+
if (listener) {
483+
TNSFirebaseDynamicLinksAppDelegate.onLinkCallback = (link) => {
484+
listener(DynamicLink.fromNative(link));
485+
};
486+
} else {
487+
TNSFirebaseDynamicLinksAppDelegate.onLinkCallback = null;
488+
}
546489
}
547490
resolveLink(link: string): Promise<DynamicLink> {
548491
return new Promise((resolve, reject) => {
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import Foundation
2+
import UIKit
3+
import GoogleUtilities
4+
import FirebaseDynamicLinks
5+
6+
@objc(TNSFirebaseDynamicLinksAppDelegate)
7+
public class TNSFirebaseDynamicLinksAppDelegate: UIResponder , UIApplicationDelegate {
8+
9+
private static var _launchOptions: [AnyHashable : Any]? = nil
10+
11+
private static var _sharedInstance: TNSFirebaseDynamicLinksAppDelegate? = nil
12+
13+
@objc public static var onLinkCallback: ((DynamicLink) -> Void)? = nil
14+
15+
@objc public static var sharedInstance: TNSFirebaseDynamicLinksAppDelegate {
16+
get {
17+
if(_sharedInstance == nil){
18+
_sharedInstance = TNSFirebaseDynamicLinksAppDelegate()
19+
20+
NotificationCenter.default.addObserver(TNSFirebaseDynamicLinksAppDelegate._sharedInstance!, selector: #selector(TNSFirebaseDynamicLinksAppDelegate.applicationDidFinishLaunchingNotification(_:)), name: UIApplication.didFinishLaunchingNotification, object: nil)
21+
}
22+
23+
return _sharedInstance!
24+
}
25+
}
26+
27+
28+
@objc public func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
29+
30+
return application(app, open: url, sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String, annotation: options[UIApplication.OpenURLOptionsKey.annotation]!)
31+
}
32+
33+
@objc public func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
34+
35+
var dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url);
36+
37+
if (dynamicLink == nil) {
38+
dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromUniversalLink: url);
39+
}
40+
41+
if (dynamicLink == nil) {
42+
return false
43+
}
44+
45+
if (dynamicLink?.url != nil) {
46+
TNSFirebaseDynamicLinksAppDelegate.onLinkCallback?(dynamicLink!)
47+
}
48+
49+
return false
50+
51+
}
52+
53+
@objc public func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
54+
var retried = false;
55+
56+
if(userActivity.webpageURL != nil){
57+
DynamicLinks.dynamicLinks().handleUniversalLink(userActivity.webpageURL!) { dynamicLink, error in
58+
if(error == nil && dynamicLink?.url != nil){
59+
TNSFirebaseDynamicLinksAppDelegate.onLinkCallback?(dynamicLink!)
60+
}
61+
62+
63+
if(error != nil && !retried && (error as? NSError)?.domain == NSPOSIXErrorDomain && (error as? NSError)?.code == 53){
64+
retried = true
65+
DynamicLinks.dynamicLinks().handleUniversalLink(userActivity.webpageURL!) { dynamicLink, error in
66+
67+
if(error == nil && dynamicLink?.url != nil){
68+
TNSFirebaseDynamicLinksAppDelegate.onLinkCallback?(dynamicLink!)
69+
}
70+
if(error != nil && error?.localizedDescription != nil){
71+
NSLog("%@", "CONSOLE LOG: ", error!.localizedDescription)
72+
}
73+
74+
}
75+
}
76+
}
77+
}
78+
79+
return false
80+
}
81+
82+
83+
@objc private func applicationDidFinishLaunchingNotification(_ notification: NSNotification) {
84+
TNSFirebaseDynamicLinksAppDelegate._launchOptions = notification.userInfo
85+
86+
GULAppDelegateSwizzler.registerAppDelegateInterceptor(TNSFirebaseDynamicLinksAppDelegate.sharedInstance)
87+
GULAppDelegateSwizzler.proxyOriginalDelegateIncludingAPNSMethods()
88+
89+
guard GULAppDelegateSwizzler.sharedApplication()?.delegate != nil else {
90+
return
91+
}
92+
93+
let selector = #selector((TNSFirebaseDynamicLinksAppDelegate).application(_:open:options:))
94+
if (!(GULAppDelegateSwizzler.sharedApplication()!.delegate!.responds(to: selector))) {
95+
96+
let method = class_getInstanceMethod(
97+
object_getClass(TNSFirebaseDynamicLinksAppDelegate.sharedInstance),
98+
selector
99+
)
100+
101+
if(method != nil){
102+
class_addMethod(
103+
object_getClass(
104+
GULAppDelegateSwizzler.sharedApplication()!.delegate
105+
), selector,
106+
method_getImplementation(method!),
107+
method_getTypeEncoding(method!)
108+
)
109+
}
110+
}
111+
112+
113+
114+
let sourceSelector = #selector(TNSFirebaseDynamicLinksAppDelegate.application(_:open:sourceApplication:annotation:))
115+
if (!(GULAppDelegateSwizzler.sharedApplication()!.delegate!.responds(to: sourceSelector))) {
116+
117+
118+
let method = class_getInstanceMethod(
119+
object_getClass(TNSFirebaseDynamicLinksAppDelegate.sharedInstance),
120+
sourceSelector
121+
)
122+
123+
124+
if(method != nil){
125+
class_addMethod(
126+
object_getClass(
127+
GULAppDelegateSwizzler.sharedApplication()!.delegate
128+
), sourceSelector,
129+
method_getImplementation(method!),
130+
method_getTypeEncoding(method!)
131+
)
132+
}
133+
}
134+
135+
136+
let restoreSelector = #selector(TNSFirebaseDynamicLinksAppDelegate.application(_:continue:restorationHandler:))
137+
if (!(GULAppDelegateSwizzler.sharedApplication()!.delegate!.responds(to: restoreSelector))) {
138+
139+
140+
let method = class_getInstanceMethod(
141+
object_getClass(TNSFirebaseDynamicLinksAppDelegate.sharedInstance),
142+
restoreSelector
143+
)
144+
145+
if(method != nil){
146+
class_addMethod(
147+
object_getClass(
148+
GULAppDelegateSwizzler.sharedApplication()!.delegate
149+
), restoreSelector,
150+
method_getImplementation(method!),
151+
method_getTypeEncoding(method!)
152+
)
153+
}
154+
}
155+
}
156+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#import <Foundation/Foundation.h>
2+
#import <UIKit/UIKit.h>
3+
4+
@interface TNSFirebaseDynamicLinksLoader: NSObject
5+
@end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#import "TNSFirebaseDynamicLinksLoader.h"
2+
#import <objc/runtime.h>
3+
@implementation TNSFirebaseDynamicLinksLoader : NSObject
4+
+ (void)load {
5+
Class clazz = NSClassFromString(@"TNSFirebaseDynamicLinksAppDelegate");
6+
#pragma clang diagnostic push
7+
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
8+
[clazz performSelector: NSSelectorFromString(@"sharedInstance")];
9+
#pragma clang diagnostic pop
10+
}
11+
@end

0 commit comments

Comments
 (0)