1// Copyright 2015-present 650 Industries. All rights reserved.
2
3#import "EXLinkingManager.h"
4#import "EXScopedModuleRegistry.h"
5
6#import <React/RCTBridge.h>
7#import <React/RCTEventDispatcher.h>
8#import <React/RCTUtils.h>
9
10NSString * const EXLinkingEventOpenUrl = @"url";
11
12@interface EXLinkingManager ()
13
14@property (nonatomic, weak) id <EXLinkingManagerScopedModuleDelegate> kernelLinkingDelegate;
15@property (nonatomic, strong) NSURL *initialUrl;
16@property (nonatomic) BOOL hasListeners;
17
18@end
19
20@implementation EXLinkingManager
21
22EX_EXPORT_SCOPED_MODULE(RCTLinkingManager, KernelLinkingManager);
23
24- (instancetype)initWithExperienceId:(NSString *)experienceId kernelServiceDelegate:(id)kernelServiceInstance params:(NSDictionary *)params
25{
26  if (self = [super initWithExperienceId:experienceId kernelServiceDelegate:kernelServiceInstance params:params]) {
27    _kernelLinkingDelegate = kernelServiceInstance;
28    _initialUrl = params[@"initialUri"];
29  }
30  return self;
31}
32
33#pragma mark - RCTEventEmitter methods
34
35- (NSArray<NSString *> *)supportedEvents
36{
37  return @[EXLinkingEventOpenUrl];
38}
39
40- (void)startObserving
41{
42  _hasListeners = YES;
43}
44
45- (void)stopObserving
46{
47  _hasListeners = NO;
48}
49
50#pragma mark - Linking methods
51
52- (void)dispatchOpenUrlEvent:(NSURL *)url
53{
54  if (!url || !url.absoluteString) {
55    RCTFatal(RCTErrorWithMessage([NSString stringWithFormat:@"Tried to open a deep link to an invalid url: %@", url]));
56    return;
57  }
58  if (_hasListeners) {
59    [self sendEventWithName:EXLinkingEventOpenUrl body:@{@"url": url.absoluteString}];
60  }
61}
62
63RCT_EXPORT_METHOD(openURL:(NSURL *)URL
64                  resolve:(RCTPromiseResolveBlock)resolve
65                  reject:(RCTPromiseRejectBlock)reject)
66{
67  if ([_kernelLinkingDelegate linkingModule:self shouldOpenExpoUrl:URL]) {
68    [_kernelLinkingDelegate linkingModule:self didOpenUrl:URL.absoluteString];
69    resolve(@YES);
70  } else {
71    BOOL opened = [RCTSharedApplication() openURL:URL];
72    if (opened) {
73      resolve(nil);
74    } else {
75      reject(RCTErrorUnspecified, [NSString stringWithFormat:@"Unable to open URL: %@", URL], nil);
76    }
77  }
78}
79
80RCT_EXPORT_METHOD(canOpenURL:(NSURL *)URL
81                  resolve:(RCTPromiseResolveBlock)resolve
82                  reject:(__unused RCTPromiseRejectBlock)reject)
83{
84  BOOL canOpen = [_kernelLinkingDelegate linkingModule:self shouldOpenExpoUrl:URL];
85  if (!canOpen) {
86    canOpen = [RCTSharedApplication() canOpenURL:URL];
87  }
88  resolve(@(canOpen));
89}
90
91RCT_EXPORT_METHOD(getInitialURL:(RCTPromiseResolveBlock)resolve
92                  reject:(__unused RCTPromiseRejectBlock)reject)
93{
94  resolve(RCTNullIfNil(_initialUrl.absoluteString));
95}
96
97@end
98