123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- /*
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
- #import <React/RCTLinkingManager.h>
- #import <FBReactNativeSpec/FBReactNativeSpec.h>
- #import <React/RCTBridge.h>
- #import <React/RCTEventDispatcher.h>
- #import <React/RCTUtils.h>
- #import <React/RCTLog.h>
- #import "RCTLinkingPlugins.h"
- static NSString *const kOpenURLNotification = @"RCTOpenURLNotification";
- static void postNotificationWithURL(NSURL *URL, id sender)
- {
- NSDictionary<NSString *, id> *payload = @{@"url": URL.absoluteString};
- [[NSNotificationCenter defaultCenter] postNotificationName:kOpenURLNotification
- object:sender
- userInfo:payload];
- }
- @interface RCTLinkingManager() <NativeLinkingSpec>
- @end
- @implementation RCTLinkingManager
- RCT_EXPORT_MODULE()
- - (dispatch_queue_t)methodQueue
- {
- return dispatch_get_main_queue();
- }
- - (void)startObserving
- {
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(handleOpenURLNotification:)
- name:kOpenURLNotification
- object:nil];
- }
- - (void)stopObserving
- {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- }
- - (NSArray<NSString *> *)supportedEvents
- {
- return @[@"url"];
- }
- + (BOOL)application:(UIApplication *)app
- openURL:(NSURL *)URL
- options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
- {
- postNotificationWithURL(URL, self);
- return YES;
- }
- // Corresponding api deprecated in iOS 9
- + (BOOL)application:(UIApplication *)application
- openURL:(NSURL *)URL
- sourceApplication:(NSString *)sourceApplication
- annotation:(id)annotation
- {
- postNotificationWithURL(URL, self);
- return YES;
- }
- + (BOOL)application:(UIApplication *)application
- continueUserActivity:(NSUserActivity *)userActivity
- restorationHandler:
- #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 12000) /* __IPHONE_12_0 */
- (nonnull void (^)(NSArray<id<UIUserActivityRestoring>> *_Nullable))restorationHandler {
- #else
- (nonnull void (^)(NSArray *_Nullable))restorationHandler {
- #endif
- if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
- NSDictionary *payload = @{@"url": userActivity.webpageURL.absoluteString};
- [[NSNotificationCenter defaultCenter] postNotificationName:kOpenURLNotification
- object:self
- userInfo:payload];
- }
- return YES;
- }
- - (void)handleOpenURLNotification:(NSNotification *)notification
- {
- [self sendEventWithName:@"url" body:notification.userInfo];
- }
- RCT_EXPORT_METHOD(openURL:(NSURL *)URL
- resolve:(RCTPromiseResolveBlock)resolve
- reject:(RCTPromiseRejectBlock)reject)
- {
- [RCTSharedApplication() openURL:URL options:@{} completionHandler:^(BOOL success) {
- if (success) {
- resolve(@YES);
- } else {
- #if TARGET_OS_SIMULATOR
- // Simulator-specific code
- if([URL.absoluteString hasPrefix:@"tel:"]){
- RCTLogWarn(@"Unable to open the Phone app in the simulator for telephone URLs. URL: %@", URL);
- resolve(@NO);
- } else {
- reject(RCTErrorUnspecified, [NSString stringWithFormat:@"Unable to open URL: %@", URL], nil);
- }
- #else
- // Device-specific code
- reject(RCTErrorUnspecified, [NSString stringWithFormat:@"Unable to open URL: %@", URL], nil);
- #endif
- }
- }];
- }
- RCT_EXPORT_METHOD(canOpenURL:(NSURL *)URL
- resolve:(RCTPromiseResolveBlock)resolve
- reject:(__unused RCTPromiseRejectBlock)reject)
- {
- if (RCTRunningInAppExtension()) {
- // Technically Today widgets can open urls, but supporting that would require
- // a reference to the NSExtensionContext
- resolve(@NO);
- return;
- }
- // This can be expensive, so we deliberately don't call on main thread
- BOOL canOpen = [RCTSharedApplication() canOpenURL:URL];
- NSString *scheme = [URL scheme];
- if (canOpen) {
- resolve(@YES);
- } else if (![[scheme lowercaseString] hasPrefix:@"http"] && ![[scheme lowercaseString] hasPrefix:@"https"]) {
- // On iOS 9 and above canOpenURL returns NO without a helpful error.
- // Check if a custom scheme is being used, and if it exists in LSApplicationQueriesSchemes
- NSArray *querySchemes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"LSApplicationQueriesSchemes"];
- if (querySchemes != nil && ([querySchemes containsObject:scheme] || [querySchemes containsObject:[scheme lowercaseString]])) {
- resolve(@NO);
- } else {
- reject(RCTErrorUnspecified, [NSString stringWithFormat:@"Unable to open URL: %@. Add %@ to LSApplicationQueriesSchemes in your Info.plist.", URL, scheme], nil);
- }
- } else {
- resolve(@NO);
- }
- }
- RCT_EXPORT_METHOD(getInitialURL:(RCTPromiseResolveBlock)resolve
- reject:(__unused RCTPromiseRejectBlock)reject)
- {
- NSURL *initialURL = nil;
- if (self.bridge.launchOptions[UIApplicationLaunchOptionsURLKey]) {
- initialURL = self.bridge.launchOptions[UIApplicationLaunchOptionsURLKey];
- } else {
- NSDictionary *userActivityDictionary =
- self.bridge.launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey];
- if ([userActivityDictionary[UIApplicationLaunchOptionsUserActivityTypeKey] isEqual:NSUserActivityTypeBrowsingWeb]) {
- initialURL = ((NSUserActivity *)userActivityDictionary[@"UIApplicationLaunchOptionsUserActivityKey"]).webpageURL;
- }
- }
- resolve(RCTNullIfNil(initialURL.absoluteString));
- }
- RCT_EXPORT_METHOD(openSettings:(RCTPromiseResolveBlock)resolve
- reject:(__unused RCTPromiseRejectBlock)reject)
- {
- NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
- [RCTSharedApplication() openURL:url options:@{} completionHandler:^(BOOL success) {
- if (success) {
- resolve(nil);
- } else {
- reject(RCTErrorUnspecified, @"Unable to open app settings", nil);
- }
- }];
- }
- RCT_EXPORT_METHOD(sendIntent:(NSString *)action
- extras:(NSArray *_Nullable)extras
- resolve:(RCTPromiseResolveBlock)resolve
- reject:(RCTPromiseRejectBlock)reject)
- {
- RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
- }
- - (std::shared_ptr<facebook::react::TurboModule>)
- getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
- nativeInvoker:(std::shared_ptr<facebook::react::CallInvoker>)nativeInvoker
- perfLogger:(id<RCTTurboModulePerformanceLogger>)perfLogger
- {
- return std::make_shared<facebook::react::NativeLinkingSpecJSI>(self, jsInvoker, nativeInvoker, perfLogger);
- }
- @end
- Class RCTLinkingManagerCls(void) {
- return RCTLinkingManager.class;
- }
|