1import { UnavailabilityError } from 'expo-modules-core'; 2import { useEffect, useState } from 'react'; 3import { EmitterSubscription, Platform } from 'react-native'; 4 5import NativeLinking from './ExpoLinking'; 6import { ParsedURL, SendIntentExtras, URLListener } from './Linking.types'; 7import { parse } from './createURL'; 8import { validateURL } from './validateURL'; 9 10// @needsAudit 11/** 12 * Add a handler to `Linking` changes by listening to the `url` event type and providing the handler. 13 * It is recommended to use the [`useURL()`](#useurl) hook instead. 14 * @param type The only valid type is `'url'`. 15 * @param handler An [`URLListener`](#urllistener) function that takes an `event` object of the type 16 * [`EventType`](#eventype). 17 * @return An EmitterSubscription that has the remove method from EventSubscription 18 * @see [React Native Docs Linking page](https://reactnative.dev/docs/linking#addeventlistener). 19 */ 20export function addEventListener(type: 'url', handler: URLListener): EmitterSubscription { 21 return NativeLinking.addEventListener(type, handler); 22} 23 24// @needsAudit 25/** 26 * Helper method which wraps React Native's `Linking.getInitialURL()` in `Linking.parse()`. 27 * Parses the deep link information out of the URL used to open the experience initially. 28 * If no link opened the app, all the fields will be `null`. 29 * > On the web it parses the current window URL. 30 * @return A promise that resolves with `ParsedURL` object. 31 */ 32export async function parseInitialURLAsync(): Promise<ParsedURL> { 33 const initialUrl = await NativeLinking.getInitialURL(); 34 if (!initialUrl) { 35 return { 36 scheme: null, 37 hostname: null, 38 path: null, 39 queryParams: null, 40 }; 41 } 42 43 return parse(initialUrl); 44} 45 46// @needsAudit 47/** 48 * Launch an Android intent with extras. 49 * > Use [IntentLauncher](./intent-launcher) instead, `sendIntent` is only included in 50 * > `Linking` for API compatibility with React Native's Linking API. 51 * @platform android 52 */ 53export async function sendIntent(action: string, extras?: SendIntentExtras[]): Promise<void> { 54 if (Platform.OS === 'android') { 55 return await NativeLinking.sendIntent(action, extras); 56 } 57 throw new UnavailabilityError('Linking', 'sendIntent'); 58} 59 60// @needsAudit 61/** 62 * Open the operating system settings app and displays the app’s custom settings, if it has any. 63 */ 64export async function openSettings(): Promise<void> { 65 if (Platform.OS === 'web') { 66 throw new UnavailabilityError('Linking', 'openSettings'); 67 } 68 if (NativeLinking.openSettings) { 69 return await NativeLinking.openSettings(); 70 } 71 await openURL('app-settings:'); 72} 73 74// @needsAudit 75/** 76 * Get the URL that was used to launch the app if it was launched by a link. 77 * @return The URL string that launched your app, or `null`. 78 */ 79export async function getInitialURL(): Promise<string | null> { 80 return (await NativeLinking.getInitialURL()) ?? null; 81} 82 83// @needsAudit 84/** 85 * Attempt to open the given URL with an installed app. See the [Linking guide](/guides/linking) 86 * for more information. 87 * @param url A URL for the operating system to open, eg: `tel:5555555`, `exp://`. 88 * @return A `Promise` that is fulfilled with `true` if the link is opened operating system 89 * automatically or the user confirms the prompt to open the link. The `Promise` rejects if there 90 * are no applications registered for the URL or the user cancels the dialog. 91 */ 92export async function openURL(url: string): Promise<true> { 93 validateURL(url); 94 return await NativeLinking.openURL(url); 95} 96 97// @needsAudit 98/** 99 * Determine whether or not an installed app can handle a given URL. 100 * On web this always returns `true` because there is no API for detecting what URLs can be opened. 101 * @param url The URL that you want to test can be opened. 102 * @return A `Promise` object that is fulfilled with `true` if the URL can be handled, otherwise it 103 * `false` if not. 104 * 105 * The `Promise` will reject on Android if it was impossible to check if the URL can be opened, and 106 * on iOS if you didn't [add the specific scheme in the `LSApplicationQueriesSchemes` key inside **Info.plist**](/guides/linking#linking-from-your-app). 107 */ 108export async function canOpenURL(url: string): Promise<boolean> { 109 validateURL(url); 110 return await NativeLinking.canOpenURL(url); 111} 112 113// @needsAudit 114/** 115 * Returns the initial URL followed by any subsequent changes to the URL. 116 * @return Returns the initial URL or `null`. 117 */ 118export function useURL(): string | null { 119 const [url, setLink] = useState<string | null>(null); 120 121 function onChange(event: { url: string }) { 122 setLink(event.url); 123 } 124 125 useEffect(() => { 126 getInitialURL().then((url) => setLink(url)); 127 const subscription = addEventListener('url', onChange); 128 return () => subscription.remove(); 129 }, []); 130 131 return url; 132} 133 134export * from './Linking.types'; 135export * from './Schemes'; 136export { parse, createURL } from './createURL'; 137