expo-linking 2.3.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -1
- package/README.md +1 -1
- package/build/ExpoLinking.web.js +3 -3
- package/build/ExpoLinking.web.js.map +1 -1
- package/build/Linking.d.ts +58 -39
- package/build/Linking.js +79 -49
- package/build/Linking.js.map +1 -1
- package/build/Linking.types.d.ts +10 -0
- package/build/Linking.types.js.map +1 -1
- package/build/Schemes.js +12 -7
- package/build/Schemes.js.map +1 -1
- package/package.json +5 -5
- package/src/ExpoLinking.web.ts +3 -3
- package/src/Linking.ts +88 -59
- package/src/Linking.types.ts +19 -1
- package/src/Schemes.ts +15 -8
package/CHANGELOG.md
CHANGED
|
@@ -10,10 +10,27 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## 3.0.0 — 2021-12-03
|
|
14
|
+
|
|
15
|
+
### 🛠 Breaking changes
|
|
16
|
+
|
|
17
|
+
- Remove deprecated `useUrl` method. ([#15226](https://github.com/expo/expo/pull/15226) by [@Simek](https://github.com/Simek))
|
|
18
|
+
|
|
19
|
+
### 💡 Others
|
|
20
|
+
|
|
21
|
+
- Update `qs` dependency. ([#15069](https://github.com/expo/expo/pull/15069) by [@Simek](https://github.com/Simek))
|
|
22
|
+
- Extract `sendIntent` method `extras` parameter to the separate type named `SendIntentExtras`. ([#15226](https://github.com/expo/expo/pull/15226) by [@Simek](https://github.com/Simek))
|
|
23
|
+
|
|
24
|
+
## 2.4.1 — 2021-10-01
|
|
14
25
|
|
|
15
26
|
_This version does not introduce any user-facing changes._
|
|
16
27
|
|
|
28
|
+
## 2.4.0 — 2021-09-09
|
|
29
|
+
|
|
30
|
+
### 🎉 New features
|
|
31
|
+
|
|
32
|
+
- Update JS code to read manifest2 when manifest is not available. ([#13602](https://github.com/expo/expo/pull/13602) by [@wschurman](https://github.com/wschurman))
|
|
33
|
+
|
|
17
34
|
## 2.3.0 — 2021-06-16
|
|
18
35
|
|
|
19
36
|
### 🐛 Bug fixes
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ For managed [managed](https://docs.expo.io/versions/latest/introduction/managed-
|
|
|
13
13
|
|
|
14
14
|
# Installation in bare React Native projects
|
|
15
15
|
|
|
16
|
-
For bare React Native projects, you must ensure that you have [installed and configured the `
|
|
16
|
+
For bare React Native projects, you must ensure that you have [installed and configured the `expo` package](https://docs.expo.dev/bare/installing-expo-modules/) before continuing.
|
|
17
17
|
|
|
18
18
|
### Add the package to your npm dependencies
|
|
19
19
|
|
package/build/ExpoLinking.web.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { Platform } from '
|
|
1
|
+
import { Platform } from 'expo-modules-core';
|
|
2
2
|
import invariant from 'invariant';
|
|
3
3
|
const EventTypes = ['url'];
|
|
4
4
|
const listeners = [];
|
|
5
5
|
export default {
|
|
6
6
|
addEventListener(type, listener) {
|
|
7
7
|
invariant(EventTypes.indexOf(type) !== -1, `Linking.addEventListener(): ${type} is not a valid event`);
|
|
8
|
-
const nativeListener = nativeEvent => listener({ url: window.location.href, nativeEvent });
|
|
8
|
+
const nativeListener = (nativeEvent) => listener({ url: window.location.href, nativeEvent });
|
|
9
9
|
listeners.push({ listener, nativeListener });
|
|
10
10
|
window.addEventListener('message', nativeListener, false);
|
|
11
11
|
},
|
|
12
12
|
removeEventListener(type, listener) {
|
|
13
13
|
invariant(EventTypes.indexOf(type) !== -1, `Linking.removeEventListener(): ${type} is not a valid event.`);
|
|
14
|
-
const listenerIndex = listeners.findIndex(pair => pair.listener === listener);
|
|
14
|
+
const listenerIndex = listeners.findIndex((pair) => pair.listener === listener);
|
|
15
15
|
invariant(listenerIndex !== -1, 'Linking.removeEventListener(): cannot remove an unregistered event listener.');
|
|
16
16
|
const nativeListener = listeners[listenerIndex].nativeListener;
|
|
17
17
|
window.removeEventListener('message', nativeListener, false);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoLinking.web.js","sourceRoot":"","sources":["../src/ExpoLinking.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"ExpoLinking.web.js","sourceRoot":"","sources":["../src/ExpoLinking.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,SAAS,MAAM,WAAW,CAAC;AAIlC,MAAM,UAAU,GAAG,CAAC,KAAK,CAAC,CAAC;AAE3B,MAAM,SAAS,GAAmE,EAAE,CAAC;AAErF,eAAe;IACb,gBAAgB,CAAC,IAAW,EAAE,QAAqB;QACjD,SAAS,CACP,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAC/B,+BAA+B,IAAI,uBAAuB,CAC3D,CAAC;QACF,MAAM,cAAc,GAAsB,CAAC,WAAW,EAAE,EAAE,CACxD,QAAQ,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QACvD,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC;QAC7C,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,cAAc,EAAE,KAAK,CAAC,CAAC;IAC5D,CAAC;IAED,mBAAmB,CAAC,IAAW,EAAE,QAAqB;QACpD,SAAS,CACP,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAC/B,kCAAkC,IAAI,wBAAwB,CAC/D,CAAC;QACF,MAAM,aAAa,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;QAChF,SAAS,CACP,aAAa,KAAK,CAAC,CAAC,EACpB,8EAA8E,CAC/E,CAAC;QACF,MAAM,cAAc,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC,cAAc,CAAC;QAC/D,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,cAAc,EAAE,KAAK,CAAC,CAAC;QAC7D,SAAS,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,GAAW;QAC1B,uFAAuF;QACvF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,IAAI,CAAC,QAAQ,CAAC,cAAc;YAAE,OAAO,EAAE,CAAC;QACxC,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAW;QACvB,IAAI,QAAQ,CAAC,cAAc,EAAE;YAC3B,aAAa;YACb,MAAM,CAAC,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;SAC5D;IACH,CAAC;CACF,CAAC","sourcesContent":["import { Platform } from 'expo-modules-core';\nimport invariant from 'invariant';\n\nimport { NativeURLListener, URLListener } from './Linking.types';\n\nconst EventTypes = ['url'];\n\nconst listeners: { listener: URLListener; nativeListener: NativeURLListener }[] = [];\n\nexport default {\n addEventListener(type: 'url', listener: URLListener): void {\n invariant(\n EventTypes.indexOf(type) !== -1,\n `Linking.addEventListener(): ${type} is not a valid event`\n );\n const nativeListener: NativeURLListener = (nativeEvent) =>\n listener({ url: window.location.href, nativeEvent });\n listeners.push({ listener, nativeListener });\n window.addEventListener('message', nativeListener, false);\n },\n\n removeEventListener(type: 'url', listener: URLListener): void {\n invariant(\n EventTypes.indexOf(type) !== -1,\n `Linking.removeEventListener(): ${type} is not a valid event.`\n );\n const listenerIndex = listeners.findIndex((pair) => pair.listener === listener);\n invariant(\n listenerIndex !== -1,\n 'Linking.removeEventListener(): cannot remove an unregistered event listener.'\n );\n const nativeListener = listeners[listenerIndex].nativeListener;\n window.removeEventListener('message', nativeListener, false);\n listeners.splice(listenerIndex, 1);\n },\n\n async canOpenURL(url: string): Promise<boolean> {\n // In reality this should be able to return false for links like `chrome://` on chrome.\n return true;\n },\n\n async getInitialURL(): Promise<string> {\n if (!Platform.isDOMAvailable) return '';\n return window.location.href;\n },\n\n async openURL(url: string): Promise<void> {\n if (Platform.isDOMAvailable) {\n // @ts-ignore\n window.location = new URL(url, window.location).toString();\n }\n },\n};\n"]}
|
package/build/Linking.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { CreateURLOptions, ParsedURL, QueryParams, URLListener } from './Linking.types';
|
|
1
|
+
import { CreateURLOptions, ParsedURL, QueryParams, SendIntentExtras, URLListener } from './Linking.types';
|
|
2
2
|
/**
|
|
3
3
|
* Create a URL that works for the environment the app is currently running in.
|
|
4
4
|
* The scheme in bare and standalone must be defined in the app.json under `expo.scheme`.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* # Examples
|
|
8
7
|
* - Bare: empty string
|
|
9
8
|
* - Standalone, Custom: `yourscheme:///path`
|
|
10
9
|
* - Web (dev): `https://localhost:19006/path`
|
|
@@ -13,87 +12,107 @@ import { CreateURLOptions, ParsedURL, QueryParams, URLListener } from './Linking
|
|
|
13
12
|
* - Expo Client (prod): `exp://exp.host/@yourname/your-app/--/path`
|
|
14
13
|
*
|
|
15
14
|
* @param path addition path components to append to the base URL.
|
|
16
|
-
* @param queryParams An object of parameters
|
|
15
|
+
* @param queryParams An object with a set of query parameters. These will be merged with any
|
|
16
|
+
* Expo-specific parameters that are needed (e.g. release channel) and then appended to the URL
|
|
17
|
+
* as a query string.
|
|
18
|
+
* @param scheme Optional URI protocol to use in the URL `<scheme>:///`, when `undefined` the scheme
|
|
19
|
+
* will be chosen from the Expo config (`app.config.js` or `app.json`).
|
|
20
|
+
* @return A URL string which points to your app with the given deep link information.
|
|
21
|
+
* @deprecated An alias for [`createURL()`](#linkingcreateurlpath-namedparameters). This method is
|
|
22
|
+
* deprecated and will be removed in a future SDK version.
|
|
17
23
|
*/
|
|
18
24
|
export declare function makeUrl(path?: string, queryParams?: QueryParams, scheme?: string): string;
|
|
19
25
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
26
|
+
* Helper method for constructing a deep link into your app, given an optional path and set of query
|
|
27
|
+
* parameters. Creates a URI scheme with two slashes by default.
|
|
22
28
|
*
|
|
23
|
-
*
|
|
29
|
+
* The scheme in bare and standalone must be defined in the Expo config (`app.config.js` or `app.json`)
|
|
30
|
+
* under `expo.scheme`.
|
|
24
31
|
*
|
|
25
|
-
*
|
|
32
|
+
* # Examples
|
|
33
|
+
* - Bare: `<scheme>://path` - uses provided scheme or scheme from Expo config `scheme`.
|
|
26
34
|
* - Standalone, Custom: `yourscheme://path`
|
|
27
35
|
* - Web (dev): `https://localhost:19006/path`
|
|
28
36
|
* - Web (prod): `https://myapp.com/path`
|
|
29
37
|
* - Expo Client (dev): `exp://128.0.0.1:19000/--/path`
|
|
30
38
|
* - Expo Client (prod): `exp://exp.host/@yourname/your-app/--/path`
|
|
31
39
|
*
|
|
32
|
-
* @param path
|
|
33
|
-
* @param
|
|
34
|
-
* @
|
|
40
|
+
* @param path Addition path components to append to the base URL.
|
|
41
|
+
* @param namedParameters Additional options object.
|
|
42
|
+
* @return A URL string which points to your app with the given deep link information.
|
|
35
43
|
*/
|
|
36
44
|
export declare function createURL(path: string, { scheme, queryParams, isTripleSlashed }?: CreateURLOptions): string;
|
|
37
45
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* @
|
|
46
|
+
* Helper method for parsing out deep link information from a URL.
|
|
47
|
+
* @param url A URL that points to the currently running experience (e.g. an output of `Linking.createURL()`).
|
|
48
|
+
* @return A `ParsedURL` object.
|
|
41
49
|
*/
|
|
42
50
|
export declare function parse(url: string): ParsedURL;
|
|
43
51
|
/**
|
|
44
|
-
* Add a handler to Linking changes by listening to the `url` event type
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
52
|
+
* Add a handler to `Linking` changes by listening to the `url` event type and providing the handler.
|
|
53
|
+
* It is recommended to use the [`useURL()`](#useurl) hook instead.
|
|
54
|
+
* @param type The only valid type is `'url'`.
|
|
55
|
+
* @param handler An [`URLListener`](#urllistener) function that takes an `event` object of the type
|
|
56
|
+
* [`EventType`](#eventype).
|
|
57
|
+
* @see [React Native Docs Linking page](https://reactnative.dev/docs/linking#addeventlistener).
|
|
48
58
|
*/
|
|
49
59
|
export declare function addEventListener(type: string, handler: URLListener): void;
|
|
50
60
|
/**
|
|
51
61
|
* Remove a handler by passing the `url` event type and the handler.
|
|
52
|
-
*
|
|
53
|
-
*
|
|
62
|
+
* @param type The only valid type is `'url'`.
|
|
63
|
+
* @param handler An [`URLListener`](#urllistener) function that takes an `event` object of the type
|
|
64
|
+
* [`EventType`](#eventype).
|
|
65
|
+
* @see [React Native Docs Linking page](https://reactnative.dev/docs/linking#removeeventlistener).
|
|
54
66
|
*/
|
|
55
67
|
export declare function removeEventListener(type: string, handler: URLListener): void;
|
|
56
68
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
69
|
+
* Helper method which wraps React Native's `Linking.getInitialURL()` in `Linking.parse()`.
|
|
70
|
+
* Parses the deep link information out of the URL used to open the experience initially.
|
|
71
|
+
* If no link opened the app, all the fields will be `null`.
|
|
72
|
+
* > On the web it parses the current window URL.
|
|
73
|
+
* @return A promise that resolves with `ParsedURL` object.
|
|
59
74
|
*/
|
|
60
75
|
export declare function parseInitialURLAsync(): Promise<ParsedURL>;
|
|
61
76
|
/**
|
|
62
|
-
* Launch an Android intent with
|
|
63
|
-
*
|
|
77
|
+
* Launch an Android intent with extras.
|
|
78
|
+
* > Use [IntentLauncher](../intent-launcher) instead, `sendIntent` is only included in
|
|
79
|
+
* > `Linking` for API compatibility with React Native's Linking API.
|
|
64
80
|
* @platform android
|
|
65
81
|
*/
|
|
66
|
-
export declare function sendIntent(action: string, extras?:
|
|
67
|
-
key: string;
|
|
68
|
-
value: string | number | boolean;
|
|
69
|
-
}[]): Promise<void>;
|
|
82
|
+
export declare function sendIntent(action: string, extras?: SendIntentExtras[]): Promise<void>;
|
|
70
83
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
84
|
+
* Open the operating system settings app and displays the app’s custom settings, if it has any.
|
|
73
85
|
* @platform ios
|
|
74
86
|
*/
|
|
75
87
|
export declare function openSettings(): Promise<void>;
|
|
76
88
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
89
|
+
* Get the URL that was used to launch the app if it was launched by a link.
|
|
90
|
+
* @return The URL string that launched your app, or `null`.
|
|
79
91
|
*/
|
|
80
92
|
export declare function getInitialURL(): Promise<string | null>;
|
|
81
93
|
/**
|
|
82
|
-
*
|
|
94
|
+
* Attempt to open the given URL with an installed app. See the [Linking guide](/guides/linking)
|
|
95
|
+
* for more information.
|
|
96
|
+
* @param url A URL for the operating system to open, eg: `tel:5555555`, `exp://`.
|
|
97
|
+
* @return A `Promise` that is fulfilled with `true` if the link is opened operating system
|
|
98
|
+
* automatically or the user confirms the prompt to open the link. The `Promise` rejects if there
|
|
99
|
+
* are no applications registered for the URL or the user cancels the dialog.
|
|
83
100
|
*/
|
|
84
101
|
export declare function openURL(url: string): Promise<true>;
|
|
85
102
|
/**
|
|
86
103
|
* Determine whether or not an installed app can handle a given URL.
|
|
87
|
-
* On web this always returns true because there is no API for detecting what URLs can be opened.
|
|
104
|
+
* On web this always returns `true` because there is no API for detecting what URLs can be opened.
|
|
105
|
+
* @param url The URL that you want to test can be opened.
|
|
106
|
+
* @return A `Promise` object that is fulfilled with `true` if the URL can be handled, otherwise it
|
|
107
|
+
* `false` if not.
|
|
108
|
+
*
|
|
109
|
+
* The `Promise` will reject on Android if it was impossible to check if the URL can be opened, and
|
|
110
|
+
* on iOS if you didn't [add the specific scheme in the `LSApplicationQueriesSchemes` key inside **Info.plist**](/guides/linking#opening-links-to-other-apps).
|
|
88
111
|
*/
|
|
89
112
|
export declare function canOpenURL(url: string): Promise<boolean>;
|
|
90
113
|
/**
|
|
91
114
|
* Returns the initial URL followed by any subsequent changes to the URL.
|
|
115
|
+
* @return Returns the initial URL or `null`.
|
|
92
116
|
*/
|
|
93
117
|
export declare function useURL(): string | null;
|
|
94
|
-
/**
|
|
95
|
-
* Returns the initial URL followed by any subsequent changes to the URL.
|
|
96
|
-
* @deprecated Use `useURL` instead.
|
|
97
|
-
*/
|
|
98
|
-
export declare function useUrl(): string | null;
|
|
99
118
|
export * from './Linking.types';
|
package/build/Linking.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Platform, UnavailabilityError } from '@unimodules/core';
|
|
2
1
|
import Constants from 'expo-constants';
|
|
2
|
+
import { Platform, UnavailabilityError } from 'expo-modules-core';
|
|
3
3
|
import invariant from 'invariant';
|
|
4
4
|
import qs from 'qs';
|
|
5
5
|
import { useEffect, useState } from 'react';
|
|
@@ -14,7 +14,10 @@ function getHostUri() {
|
|
|
14
14
|
if (Constants.manifest?.hostUri) {
|
|
15
15
|
return Constants.manifest.hostUri;
|
|
16
16
|
}
|
|
17
|
-
else if (
|
|
17
|
+
else if (Constants.manifest2?.extra?.expoClient?.hostUri) {
|
|
18
|
+
return Constants.manifest2.extra.expoClient.hostUri;
|
|
19
|
+
}
|
|
20
|
+
else if (!hasCustomScheme()) {
|
|
18
21
|
// we're probably not using up-to-date xdl, so just fake it for now
|
|
19
22
|
// we have to remove the /--/ on the end since this will be inserted again later
|
|
20
23
|
return removeScheme(Constants.linkingUri).replace(/\/--($|\/.*$)/, '');
|
|
@@ -41,7 +44,7 @@ function removeLeadingSlash(url) {
|
|
|
41
44
|
function removeTrailingSlashAndQueryString(url) {
|
|
42
45
|
return url.replace(/\/?\?.*$/, '');
|
|
43
46
|
}
|
|
44
|
-
function
|
|
47
|
+
function ensureTrailingSlash(input, shouldAppend) {
|
|
45
48
|
const hasSlash = input.endsWith('/');
|
|
46
49
|
if (hasSlash && !shouldAppend) {
|
|
47
50
|
return input.substring(0, input.length - 1);
|
|
@@ -51,7 +54,7 @@ function ensureLeadingSlash(input, shouldAppend) {
|
|
|
51
54
|
}
|
|
52
55
|
return input;
|
|
53
56
|
}
|
|
54
|
-
function
|
|
57
|
+
function ensureLeadingSlash(input, shouldAppend) {
|
|
55
58
|
const hasSlash = input.startsWith('/');
|
|
56
59
|
if (hasSlash && !shouldAppend) {
|
|
57
60
|
return input.substring(1);
|
|
@@ -61,12 +64,12 @@ function ensureTrailingSlash(input, shouldAppend) {
|
|
|
61
64
|
}
|
|
62
65
|
return input;
|
|
63
66
|
}
|
|
67
|
+
// @needsAudit
|
|
64
68
|
/**
|
|
65
69
|
* Create a URL that works for the environment the app is currently running in.
|
|
66
70
|
* The scheme in bare and standalone must be defined in the app.json under `expo.scheme`.
|
|
67
71
|
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
72
|
+
* # Examples
|
|
70
73
|
* - Bare: empty string
|
|
71
74
|
* - Standalone, Custom: `yourscheme:///path`
|
|
72
75
|
* - Web (dev): `https://localhost:19006/path`
|
|
@@ -75,40 +78,50 @@ function ensureTrailingSlash(input, shouldAppend) {
|
|
|
75
78
|
* - Expo Client (prod): `exp://exp.host/@yourname/your-app/--/path`
|
|
76
79
|
*
|
|
77
80
|
* @param path addition path components to append to the base URL.
|
|
78
|
-
* @param queryParams An object of parameters
|
|
81
|
+
* @param queryParams An object with a set of query parameters. These will be merged with any
|
|
82
|
+
* Expo-specific parameters that are needed (e.g. release channel) and then appended to the URL
|
|
83
|
+
* as a query string.
|
|
84
|
+
* @param scheme Optional URI protocol to use in the URL `<scheme>:///`, when `undefined` the scheme
|
|
85
|
+
* will be chosen from the Expo config (`app.config.js` or `app.json`).
|
|
86
|
+
* @return A URL string which points to your app with the given deep link information.
|
|
87
|
+
* @deprecated An alias for [`createURL()`](#linkingcreateurlpath-namedparameters). This method is
|
|
88
|
+
* deprecated and will be removed in a future SDK version.
|
|
79
89
|
*/
|
|
80
90
|
export function makeUrl(path = '', queryParams, scheme) {
|
|
81
91
|
return createURL(path, { queryParams, scheme, isTripleSlashed: true });
|
|
82
92
|
}
|
|
93
|
+
// @needsAudit
|
|
83
94
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
95
|
+
* Helper method for constructing a deep link into your app, given an optional path and set of query
|
|
96
|
+
* parameters. Creates a URI scheme with two slashes by default.
|
|
86
97
|
*
|
|
87
|
-
*
|
|
98
|
+
* The scheme in bare and standalone must be defined in the Expo config (`app.config.js` or `app.json`)
|
|
99
|
+
* under `expo.scheme`.
|
|
88
100
|
*
|
|
89
|
-
*
|
|
101
|
+
* # Examples
|
|
102
|
+
* - Bare: `<scheme>://path` - uses provided scheme or scheme from Expo config `scheme`.
|
|
90
103
|
* - Standalone, Custom: `yourscheme://path`
|
|
91
104
|
* - Web (dev): `https://localhost:19006/path`
|
|
92
105
|
* - Web (prod): `https://myapp.com/path`
|
|
93
106
|
* - Expo Client (dev): `exp://128.0.0.1:19000/--/path`
|
|
94
107
|
* - Expo Client (prod): `exp://exp.host/@yourname/your-app/--/path`
|
|
95
108
|
*
|
|
96
|
-
* @param path
|
|
97
|
-
* @param
|
|
98
|
-
* @
|
|
109
|
+
* @param path Addition path components to append to the base URL.
|
|
110
|
+
* @param namedParameters Additional options object.
|
|
111
|
+
* @return A URL string which points to your app with the given deep link information.
|
|
99
112
|
*/
|
|
100
113
|
export function createURL(path, { scheme, queryParams = {}, isTripleSlashed = false } = {}) {
|
|
101
114
|
if (Platform.OS === 'web') {
|
|
102
115
|
if (!Platform.isDOMAvailable)
|
|
103
116
|
return '';
|
|
104
|
-
const origin =
|
|
117
|
+
const origin = ensureTrailingSlash(window.location.origin, false);
|
|
105
118
|
let queryString = qs.stringify(queryParams);
|
|
106
119
|
if (queryString) {
|
|
107
120
|
queryString = `?${queryString}`;
|
|
108
121
|
}
|
|
109
122
|
let outputPath = path;
|
|
110
123
|
if (outputPath)
|
|
111
|
-
outputPath =
|
|
124
|
+
outputPath = ensureLeadingSlash(path, true);
|
|
112
125
|
return encodeURI(`${origin}${outputPath}${queryString}`);
|
|
113
126
|
}
|
|
114
127
|
const resolvedScheme = resolveScheme({ scheme });
|
|
@@ -151,13 +164,14 @@ export function createURL(path, { scheme, queryParams = {}, isTripleSlashed = fa
|
|
|
151
164
|
if (queryString) {
|
|
152
165
|
queryString = `?${queryString}`;
|
|
153
166
|
}
|
|
154
|
-
hostUri =
|
|
167
|
+
hostUri = ensureLeadingSlash(hostUri, !isTripleSlashed);
|
|
155
168
|
return encodeURI(`${resolvedScheme}:${isTripleSlashed ? '/' : ''}/${hostUri}${path}${queryString}`);
|
|
156
169
|
}
|
|
170
|
+
// @needsAudit
|
|
157
171
|
/**
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* @
|
|
172
|
+
* Helper method for parsing out deep link information from a URL.
|
|
173
|
+
* @param url A URL that points to the currently running experience (e.g. an output of `Linking.createURL()`).
|
|
174
|
+
* @return A `ParsedURL` object.
|
|
161
175
|
*/
|
|
162
176
|
export function parse(url) {
|
|
163
177
|
validateURL(url);
|
|
@@ -180,10 +194,7 @@ export function parse(url) {
|
|
|
180
194
|
let expoPrefix = null;
|
|
181
195
|
if (hostUriStripped) {
|
|
182
196
|
const parts = hostUriStripped.split('/');
|
|
183
|
-
expoPrefix = parts
|
|
184
|
-
.slice(1)
|
|
185
|
-
.concat(['--/'])
|
|
186
|
-
.join('/');
|
|
197
|
+
expoPrefix = parts.slice(1).concat(['--/']).join('/');
|
|
187
198
|
}
|
|
188
199
|
if (isExpoHosted() && !hasCustomScheme() && expoPrefix && path.startsWith(expoPrefix)) {
|
|
189
200
|
path = path.substring(expoPrefix.length);
|
|
@@ -200,26 +211,35 @@ export function parse(url) {
|
|
|
200
211
|
scheme,
|
|
201
212
|
};
|
|
202
213
|
}
|
|
214
|
+
// @needsAudit
|
|
203
215
|
/**
|
|
204
|
-
* Add a handler to Linking changes by listening to the `url` event type
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
216
|
+
* Add a handler to `Linking` changes by listening to the `url` event type and providing the handler.
|
|
217
|
+
* It is recommended to use the [`useURL()`](#useurl) hook instead.
|
|
218
|
+
* @param type The only valid type is `'url'`.
|
|
219
|
+
* @param handler An [`URLListener`](#urllistener) function that takes an `event` object of the type
|
|
220
|
+
* [`EventType`](#eventype).
|
|
221
|
+
* @see [React Native Docs Linking page](https://reactnative.dev/docs/linking#addeventlistener).
|
|
208
222
|
*/
|
|
209
223
|
export function addEventListener(type, handler) {
|
|
210
224
|
NativeLinking.addEventListener(type, handler);
|
|
211
225
|
}
|
|
212
226
|
/**
|
|
213
227
|
* Remove a handler by passing the `url` event type and the handler.
|
|
214
|
-
*
|
|
215
|
-
*
|
|
228
|
+
* @param type The only valid type is `'url'`.
|
|
229
|
+
* @param handler An [`URLListener`](#urllistener) function that takes an `event` object of the type
|
|
230
|
+
* [`EventType`](#eventype).
|
|
231
|
+
* @see [React Native Docs Linking page](https://reactnative.dev/docs/linking#removeeventlistener).
|
|
216
232
|
*/
|
|
217
233
|
export function removeEventListener(type, handler) {
|
|
218
234
|
NativeLinking.removeEventListener(type, handler);
|
|
219
235
|
}
|
|
236
|
+
// @needsAudit
|
|
220
237
|
/**
|
|
221
|
-
*
|
|
222
|
-
*
|
|
238
|
+
* Helper method which wraps React Native's `Linking.getInitialURL()` in `Linking.parse()`.
|
|
239
|
+
* Parses the deep link information out of the URL used to open the experience initially.
|
|
240
|
+
* If no link opened the app, all the fields will be `null`.
|
|
241
|
+
* > On the web it parses the current window URL.
|
|
242
|
+
* @return A promise that resolves with `ParsedURL` object.
|
|
223
243
|
*/
|
|
224
244
|
export async function parseInitialURLAsync() {
|
|
225
245
|
const initialUrl = await NativeLinking.getInitialURL();
|
|
@@ -233,9 +253,11 @@ export async function parseInitialURLAsync() {
|
|
|
233
253
|
}
|
|
234
254
|
return parse(initialUrl);
|
|
235
255
|
}
|
|
256
|
+
// @needsAudit
|
|
236
257
|
/**
|
|
237
|
-
* Launch an Android intent with
|
|
238
|
-
*
|
|
258
|
+
* Launch an Android intent with extras.
|
|
259
|
+
* > Use [IntentLauncher](../intent-launcher) instead, `sendIntent` is only included in
|
|
260
|
+
* > `Linking` for API compatibility with React Native's Linking API.
|
|
239
261
|
* @platform android
|
|
240
262
|
*/
|
|
241
263
|
export async function sendIntent(action, extras) {
|
|
@@ -244,9 +266,9 @@ export async function sendIntent(action, extras) {
|
|
|
244
266
|
}
|
|
245
267
|
throw new UnavailabilityError('Linking', 'sendIntent');
|
|
246
268
|
}
|
|
269
|
+
// @needsAudit
|
|
247
270
|
/**
|
|
248
|
-
*
|
|
249
|
-
*
|
|
271
|
+
* Open the operating system settings app and displays the app’s custom settings, if it has any.
|
|
250
272
|
* @platform ios
|
|
251
273
|
*/
|
|
252
274
|
export async function openSettings() {
|
|
@@ -258,30 +280,46 @@ export async function openSettings() {
|
|
|
258
280
|
}
|
|
259
281
|
await openURL('app-settings:');
|
|
260
282
|
}
|
|
283
|
+
// @needsAudit
|
|
261
284
|
/**
|
|
262
|
-
*
|
|
263
|
-
*
|
|
285
|
+
* Get the URL that was used to launch the app if it was launched by a link.
|
|
286
|
+
* @return The URL string that launched your app, or `null`.
|
|
264
287
|
*/
|
|
265
288
|
export async function getInitialURL() {
|
|
266
289
|
return (await NativeLinking.getInitialURL()) ?? null;
|
|
267
290
|
}
|
|
291
|
+
// @needsAudit
|
|
268
292
|
/**
|
|
269
|
-
*
|
|
293
|
+
* Attempt to open the given URL with an installed app. See the [Linking guide](/guides/linking)
|
|
294
|
+
* for more information.
|
|
295
|
+
* @param url A URL for the operating system to open, eg: `tel:5555555`, `exp://`.
|
|
296
|
+
* @return A `Promise` that is fulfilled with `true` if the link is opened operating system
|
|
297
|
+
* automatically or the user confirms the prompt to open the link. The `Promise` rejects if there
|
|
298
|
+
* are no applications registered for the URL or the user cancels the dialog.
|
|
270
299
|
*/
|
|
271
300
|
export async function openURL(url) {
|
|
272
301
|
validateURL(url);
|
|
273
302
|
return await NativeLinking.openURL(url);
|
|
274
303
|
}
|
|
304
|
+
// @needsAudit
|
|
275
305
|
/**
|
|
276
306
|
* Determine whether or not an installed app can handle a given URL.
|
|
277
|
-
* On web this always returns true because there is no API for detecting what URLs can be opened.
|
|
307
|
+
* On web this always returns `true` because there is no API for detecting what URLs can be opened.
|
|
308
|
+
* @param url The URL that you want to test can be opened.
|
|
309
|
+
* @return A `Promise` object that is fulfilled with `true` if the URL can be handled, otherwise it
|
|
310
|
+
* `false` if not.
|
|
311
|
+
*
|
|
312
|
+
* The `Promise` will reject on Android if it was impossible to check if the URL can be opened, and
|
|
313
|
+
* on iOS if you didn't [add the specific scheme in the `LSApplicationQueriesSchemes` key inside **Info.plist**](/guides/linking#opening-links-to-other-apps).
|
|
278
314
|
*/
|
|
279
315
|
export async function canOpenURL(url) {
|
|
280
316
|
validateURL(url);
|
|
281
317
|
return await NativeLinking.canOpenURL(url);
|
|
282
318
|
}
|
|
319
|
+
// @needsAudit
|
|
283
320
|
/**
|
|
284
321
|
* Returns the initial URL followed by any subsequent changes to the URL.
|
|
322
|
+
* @return Returns the initial URL or `null`.
|
|
285
323
|
*/
|
|
286
324
|
export function useURL() {
|
|
287
325
|
const [url, setLink] = useState(null);
|
|
@@ -289,19 +327,11 @@ export function useURL() {
|
|
|
289
327
|
setLink(event.url);
|
|
290
328
|
}
|
|
291
329
|
useEffect(() => {
|
|
292
|
-
getInitialURL().then(url => setLink(url));
|
|
330
|
+
getInitialURL().then((url) => setLink(url));
|
|
293
331
|
addEventListener('url', onChange);
|
|
294
332
|
return () => removeEventListener('url', onChange);
|
|
295
333
|
}, []);
|
|
296
334
|
return url;
|
|
297
335
|
}
|
|
298
|
-
/**
|
|
299
|
-
* Returns the initial URL followed by any subsequent changes to the URL.
|
|
300
|
-
* @deprecated Use `useURL` instead.
|
|
301
|
-
*/
|
|
302
|
-
export function useUrl() {
|
|
303
|
-
console.warn(`Linking.useUrl has been deprecated in favor of Linking.useURL. This API will be removed in SDK 44.`);
|
|
304
|
-
return useURL();
|
|
305
|
-
}
|
|
306
336
|
export * from './Linking.types';
|
|
307
337
|
//# sourceMappingURL=Linking.js.map
|
package/build/Linking.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Linking.js","sourceRoot":"","sources":["../src/Linking.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform, UnavailabilityError } from '@unimodules/core';\nimport Constants from 'expo-constants';\nimport invariant from 'invariant';\nimport qs from 'qs';\nimport { useEffect, useState } from 'react';\nimport URL from 'url-parse';\n\nimport NativeLinking from './ExpoLinking';\nimport { CreateURLOptions, ParsedURL, QueryParams, URLListener } from './Linking.types';\nimport { hasCustomScheme, resolveScheme } from './Schemes';\n\nfunction validateURL(url: string): void {\n invariant(typeof url === 'string', 'Invalid URL: should be a string. Was: ' + url);\n invariant(url, 'Invalid URL: cannot be empty');\n}\n\nfunction getHostUri(): string | null {\n if (Constants.manifest?.hostUri) {\n return Constants.manifest.hostUri;\n } else if (!Constants.manifest?.hostUri && !hasCustomScheme()) {\n // we're probably not using up-to-date xdl, so just fake it for now\n // we have to remove the /--/ on the end since this will be inserted again later\n return removeScheme(Constants.linkingUri).replace(/\\/--($|\\/.*$)/, '');\n } else {\n return null;\n }\n}\n\nfunction isExpoHosted(): boolean {\n const hostUri = getHostUri();\n return !!(\n hostUri &&\n (/^(.*\\.)?(expo\\.io|exp\\.host|exp\\.direct|expo\\.test)(:.*)?(\\/.*)?$/.test(hostUri) ||\n Constants.manifest?.developer)\n );\n}\n\nfunction removeScheme(url: string): string {\n return url.replace(/^[a-zA-Z0-9+.-]+:\\/\\//, '');\n}\n\nfunction removePort(url: string): string {\n return url.replace(/(?=([a-zA-Z0-9+.-]+:\\/\\/)?[^/]):\\d+/, '');\n}\n\nfunction removeLeadingSlash(url: string): string {\n return url.replace(/^\\//, '');\n}\n\nfunction removeTrailingSlashAndQueryString(url: string): string {\n return url.replace(/\\/?\\?.*$/, '');\n}\n\nfunction ensureLeadingSlash(input: string, shouldAppend: boolean): string {\n const hasSlash = input.endsWith('/');\n if (hasSlash && !shouldAppend) {\n return input.substring(0, input.length - 1);\n } else if (!hasSlash && shouldAppend) {\n return `${input}/`;\n }\n return input;\n}\n\nfunction ensureTrailingSlash(input: string, shouldAppend: boolean): string {\n const hasSlash = input.startsWith('/');\n if (hasSlash && !shouldAppend) {\n return input.substring(1);\n } else if (!hasSlash && shouldAppend) {\n return `/${input}`;\n }\n return input;\n}\n\n/**\n * Create a URL that works for the environment the app is currently running in.\n * The scheme in bare and standalone must be defined in the app.json under `expo.scheme`.\n *\n * **Examples**\n *\n * - Bare: empty string\n * - Standalone, Custom: `yourscheme:///path`\n * - Web (dev): `https://localhost:19006/path`\n * - Web (prod): `https://myapp.com/path`\n * - Expo Client (dev): `exp://128.0.0.1:19000/--/path`\n * - Expo Client (prod): `exp://exp.host/@yourname/your-app/--/path`\n *\n * @param path addition path components to append to the base URL.\n * @param queryParams An object of parameters that will be converted into a query string.\n */\nexport function makeUrl(path: string = '', queryParams?: QueryParams, scheme?: string): string {\n return createURL(path, { queryParams, scheme, isTripleSlashed: true });\n}\n\n/**\n * Create a URL that works for the environment the app is currently running in.\n * The scheme in bare and standalone must be defined in the Expo config (app.config.js or app.json) under `expo.scheme`.\n *\n * **Examples**\n *\n * - Bare: `<scheme>://path` -- uses provided scheme or scheme from Expo config `scheme`.\n * - Standalone, Custom: `yourscheme://path`\n * - Web (dev): `https://localhost:19006/path`\n * - Web (prod): `https://myapp.com/path`\n * - Expo Client (dev): `exp://128.0.0.1:19000/--/path`\n * - Expo Client (prod): `exp://exp.host/@yourname/your-app/--/path`\n *\n * @param path addition path components to append to the base URL.\n * @param scheme URI protocol `<scheme>://` that must be built into your native app.\n * @param queryParams An object of parameters that will be converted into a query string.\n */\nexport function createURL(\n path: string,\n { scheme, queryParams = {}, isTripleSlashed = false }: CreateURLOptions = {}\n): string {\n if (Platform.OS === 'web') {\n if (!Platform.isDOMAvailable) return '';\n\n const origin = ensureLeadingSlash(window.location.origin, false);\n let queryString = qs.stringify(queryParams);\n if (queryString) {\n queryString = `?${queryString}`;\n }\n\n let outputPath = path;\n if (outputPath) outputPath = ensureTrailingSlash(path, true);\n\n return encodeURI(`${origin}${outputPath}${queryString}`);\n }\n\n const resolvedScheme = resolveScheme({ scheme });\n\n let hostUri = getHostUri() || '';\n\n if (hasCustomScheme() && isExpoHosted()) {\n hostUri = '';\n }\n\n if (path) {\n if (isExpoHosted() && hostUri) {\n path = `/--/${removeLeadingSlash(path)}`;\n }\n if (isTripleSlashed && !path.startsWith('/')) {\n path = `/${path}`;\n }\n } else {\n path = '';\n }\n\n // merge user-provided query params with any that were already in the hostUri\n // e.g. release-channel\n let queryString = '';\n const queryStringMatchResult = hostUri.match(/(.*)\\?(.+)/);\n if (queryStringMatchResult) {\n hostUri = queryStringMatchResult[1];\n queryString = queryStringMatchResult[2];\n let paramsFromHostUri = {};\n try {\n const parsedParams = qs.parse(queryString);\n if (typeof parsedParams === 'object') {\n paramsFromHostUri = parsedParams;\n }\n } catch (e) {}\n queryParams = {\n ...queryParams,\n ...paramsFromHostUri,\n };\n }\n queryString = qs.stringify(queryParams);\n if (queryString) {\n queryString = `?${queryString}`;\n }\n\n hostUri = ensureTrailingSlash(hostUri, !isTripleSlashed);\n\n return encodeURI(\n `${resolvedScheme}:${isTripleSlashed ? '/' : ''}/${hostUri}${path}${queryString}`\n );\n}\n\n/**\n * Returns the components and query parameters for a given URL.\n *\n * @param url Input URL to parse\n */\nexport function parse(url: string): ParsedURL {\n validateURL(url);\n\n const parsed = URL(url, /* parseQueryString */ true);\n\n for (const param in parsed.query) {\n parsed.query[param] = decodeURIComponent(parsed.query[param]!);\n }\n const queryParams = parsed.query;\n\n const hostUri = getHostUri() || '';\n const hostUriStripped = removePort(removeTrailingSlashAndQueryString(hostUri));\n\n let path = parsed.pathname || null;\n let hostname = parsed.hostname || null;\n let scheme = parsed.protocol || null;\n\n if (scheme) {\n // Remove colon at end\n scheme = scheme.substring(0, scheme.length - 1);\n }\n\n if (path) {\n path = removeLeadingSlash(path);\n\n let expoPrefix: string | null = null;\n if (hostUriStripped) {\n const parts = hostUriStripped.split('/');\n expoPrefix = parts\n .slice(1)\n .concat(['--/'])\n .join('/');\n }\n\n if (isExpoHosted() && !hasCustomScheme() && expoPrefix && path.startsWith(expoPrefix)) {\n path = path.substring(expoPrefix.length);\n hostname = null;\n } else if (path.indexOf('+') > -1) {\n path = path.substring(path.indexOf('+') + 1);\n }\n }\n\n return {\n hostname,\n path,\n queryParams,\n scheme,\n };\n}\n\n/**\n * Add a handler to Linking changes by listening to the `url` event type\n * and providing the handler\n *\n * See https://reactnative.dev/docs/linking.html#addeventlistener\n */\nexport function addEventListener(type: string, handler: URLListener) {\n NativeLinking.addEventListener(type, handler);\n}\n\n/**\n * Remove a handler by passing the `url` event type and the handler.\n *\n * See https://reactnative.dev/docs/linking.html#removeeventlistener\n */\nexport function removeEventListener(type: string, handler: URLListener) {\n NativeLinking.removeEventListener(type, handler);\n}\n\n/**\n * **Native:** Parses the link that opened the app. If no link opened the app, all the fields will be \\`null\\`.\n * **Web:** Parses the current window URL.\n */\nexport async function parseInitialURLAsync(): Promise<ParsedURL> {\n const initialUrl = await NativeLinking.getInitialURL();\n if (!initialUrl) {\n return {\n scheme: null,\n hostname: null,\n path: null,\n queryParams: null,\n };\n }\n\n return parse(initialUrl);\n}\n\n/**\n * Launch an Android intent with optional extras\n *\n * @platform android\n */\nexport async function sendIntent(\n action: string,\n extras?: { key: string; value: string | number | boolean }[]\n): Promise<void> {\n if (Platform.OS === 'android') {\n return await NativeLinking.sendIntent(action, extras);\n }\n throw new UnavailabilityError('Linking', 'sendIntent');\n}\n\n/**\n * Attempt to open the system settings for an the app.\n *\n * @platform ios\n */\nexport async function openSettings(): Promise<void> {\n if (Platform.OS === 'web') {\n throw new UnavailabilityError('Linking', 'openSettings');\n }\n if (NativeLinking.openSettings) {\n return await NativeLinking.openSettings();\n }\n await openURL('app-settings:');\n}\n\n/**\n * If the app launch was triggered by an app link,\n * it will give the link url, otherwise it will give `null`\n */\nexport async function getInitialURL(): Promise<string | null> {\n return (await NativeLinking.getInitialURL()) ?? null;\n}\n\n/**\n * Try to open the given `url` with any of the installed apps.\n */\nexport async function openURL(url: string): Promise<true> {\n validateURL(url);\n return await NativeLinking.openURL(url);\n}\n\n/**\n * Determine whether or not an installed app can handle a given URL.\n * On web this always returns true because there is no API for detecting what URLs can be opened.\n */\nexport async function canOpenURL(url: string): Promise<boolean> {\n validateURL(url);\n return await NativeLinking.canOpenURL(url);\n}\n\n/**\n * Returns the initial URL followed by any subsequent changes to the URL.\n */\nexport function useURL(): string | null {\n const [url, setLink] = useState<string | null>(null);\n\n function onChange(event: { url: string }) {\n setLink(event.url);\n }\n\n useEffect(() => {\n getInitialURL().then(url => setLink(url));\n addEventListener('url', onChange);\n return () => removeEventListener('url', onChange);\n }, []);\n\n return url;\n}\n\n/**\n * Returns the initial URL followed by any subsequent changes to the URL.\n * @deprecated Use `useURL` instead.\n */\nexport function useUrl(): string | null {\n console.warn(\n `Linking.useUrl has been deprecated in favor of Linking.useURL. This API will be removed in SDK 44.`\n );\n return useURL();\n}\n\nexport * from './Linking.types';\n"]}
|
|
1
|
+
{"version":3,"file":"Linking.js","sourceRoot":"","sources":["../src/Linking.ts"],"names":[],"mappings":"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","sourcesContent":["import Constants from 'expo-constants';\nimport { Platform, UnavailabilityError } from 'expo-modules-core';\nimport invariant from 'invariant';\nimport qs from 'qs';\nimport { useEffect, useState } from 'react';\nimport URL from 'url-parse';\n\nimport NativeLinking from './ExpoLinking';\nimport {\n CreateURLOptions,\n ParsedURL,\n QueryParams,\n SendIntentExtras,\n URLListener,\n} from './Linking.types';\nimport { hasCustomScheme, resolveScheme } from './Schemes';\n\nfunction validateURL(url: string): void {\n invariant(typeof url === 'string', 'Invalid URL: should be a string. Was: ' + url);\n invariant(url, 'Invalid URL: cannot be empty');\n}\n\nfunction getHostUri(): string | null {\n if (Constants.manifest?.hostUri) {\n return Constants.manifest.hostUri;\n } else if (Constants.manifest2?.extra?.expoClient?.hostUri) {\n return Constants.manifest2.extra.expoClient.hostUri;\n } else if (!hasCustomScheme()) {\n // we're probably not using up-to-date xdl, so just fake it for now\n // we have to remove the /--/ on the end since this will be inserted again later\n return removeScheme(Constants.linkingUri).replace(/\\/--($|\\/.*$)/, '');\n } else {\n return null;\n }\n}\n\nfunction isExpoHosted(): boolean {\n const hostUri = getHostUri();\n return !!(\n hostUri &&\n (/^(.*\\.)?(expo\\.io|exp\\.host|exp\\.direct|expo\\.test)(:.*)?(\\/.*)?$/.test(hostUri) ||\n Constants.manifest?.developer)\n );\n}\n\nfunction removeScheme(url: string): string {\n return url.replace(/^[a-zA-Z0-9+.-]+:\\/\\//, '');\n}\n\nfunction removePort(url: string): string {\n return url.replace(/(?=([a-zA-Z0-9+.-]+:\\/\\/)?[^/]):\\d+/, '');\n}\n\nfunction removeLeadingSlash(url: string): string {\n return url.replace(/^\\//, '');\n}\n\nfunction removeTrailingSlashAndQueryString(url: string): string {\n return url.replace(/\\/?\\?.*$/, '');\n}\n\nfunction ensureTrailingSlash(input: string, shouldAppend: boolean): string {\n const hasSlash = input.endsWith('/');\n if (hasSlash && !shouldAppend) {\n return input.substring(0, input.length - 1);\n } else if (!hasSlash && shouldAppend) {\n return `${input}/`;\n }\n return input;\n}\n\nfunction ensureLeadingSlash(input: string, shouldAppend: boolean): string {\n const hasSlash = input.startsWith('/');\n if (hasSlash && !shouldAppend) {\n return input.substring(1);\n } else if (!hasSlash && shouldAppend) {\n return `/${input}`;\n }\n return input;\n}\n\n// @needsAudit\n/**\n * Create a URL that works for the environment the app is currently running in.\n * The scheme in bare and standalone must be defined in the app.json under `expo.scheme`.\n *\n * # Examples\n * - Bare: empty string\n * - Standalone, Custom: `yourscheme:///path`\n * - Web (dev): `https://localhost:19006/path`\n * - Web (prod): `https://myapp.com/path`\n * - Expo Client (dev): `exp://128.0.0.1:19000/--/path`\n * - Expo Client (prod): `exp://exp.host/@yourname/your-app/--/path`\n *\n * @param path addition path components to append to the base URL.\n * @param queryParams An object with a set of query parameters. These will be merged with any\n * Expo-specific parameters that are needed (e.g. release channel) and then appended to the URL\n * as a query string.\n * @param scheme Optional URI protocol to use in the URL `<scheme>:///`, when `undefined` the scheme\n * will be chosen from the Expo config (`app.config.js` or `app.json`).\n * @return A URL string which points to your app with the given deep link information.\n * @deprecated An alias for [`createURL()`](#linkingcreateurlpath-namedparameters). This method is\n * deprecated and will be removed in a future SDK version.\n */\nexport function makeUrl(path: string = '', queryParams?: QueryParams, scheme?: string): string {\n return createURL(path, { queryParams, scheme, isTripleSlashed: true });\n}\n\n// @needsAudit\n/**\n * Helper method for constructing a deep link into your app, given an optional path and set of query\n * parameters. Creates a URI scheme with two slashes by default.\n *\n * The scheme in bare and standalone must be defined in the Expo config (`app.config.js` or `app.json`)\n * under `expo.scheme`.\n *\n * # Examples\n * - Bare: `<scheme>://path` - uses provided scheme or scheme from Expo config `scheme`.\n * - Standalone, Custom: `yourscheme://path`\n * - Web (dev): `https://localhost:19006/path`\n * - Web (prod): `https://myapp.com/path`\n * - Expo Client (dev): `exp://128.0.0.1:19000/--/path`\n * - Expo Client (prod): `exp://exp.host/@yourname/your-app/--/path`\n *\n * @param path Addition path components to append to the base URL.\n * @param namedParameters Additional options object.\n * @return A URL string which points to your app with the given deep link information.\n */\nexport function createURL(\n path: string,\n { scheme, queryParams = {}, isTripleSlashed = false }: CreateURLOptions = {}\n): string {\n if (Platform.OS === 'web') {\n if (!Platform.isDOMAvailable) return '';\n\n const origin = ensureTrailingSlash(window.location.origin, false);\n let queryString = qs.stringify(queryParams);\n if (queryString) {\n queryString = `?${queryString}`;\n }\n\n let outputPath = path;\n if (outputPath) outputPath = ensureLeadingSlash(path, true);\n\n return encodeURI(`${origin}${outputPath}${queryString}`);\n }\n\n const resolvedScheme = resolveScheme({ scheme });\n\n let hostUri = getHostUri() || '';\n\n if (hasCustomScheme() && isExpoHosted()) {\n hostUri = '';\n }\n\n if (path) {\n if (isExpoHosted() && hostUri) {\n path = `/--/${removeLeadingSlash(path)}`;\n }\n if (isTripleSlashed && !path.startsWith('/')) {\n path = `/${path}`;\n }\n } else {\n path = '';\n }\n\n // merge user-provided query params with any that were already in the hostUri\n // e.g. release-channel\n let queryString = '';\n const queryStringMatchResult = hostUri.match(/(.*)\\?(.+)/);\n if (queryStringMatchResult) {\n hostUri = queryStringMatchResult[1];\n queryString = queryStringMatchResult[2];\n let paramsFromHostUri = {};\n try {\n const parsedParams = qs.parse(queryString);\n if (typeof parsedParams === 'object') {\n paramsFromHostUri = parsedParams;\n }\n } catch (e) {}\n queryParams = {\n ...queryParams,\n ...paramsFromHostUri,\n };\n }\n queryString = qs.stringify(queryParams);\n if (queryString) {\n queryString = `?${queryString}`;\n }\n\n hostUri = ensureLeadingSlash(hostUri, !isTripleSlashed);\n\n return encodeURI(\n `${resolvedScheme}:${isTripleSlashed ? '/' : ''}/${hostUri}${path}${queryString}`\n );\n}\n\n// @needsAudit\n/**\n * Helper method for parsing out deep link information from a URL.\n * @param url A URL that points to the currently running experience (e.g. an output of `Linking.createURL()`).\n * @return A `ParsedURL` object.\n */\nexport function parse(url: string): ParsedURL {\n validateURL(url);\n\n const parsed = URL(url, /* parseQueryString */ true);\n\n for (const param in parsed.query) {\n parsed.query[param] = decodeURIComponent(parsed.query[param]!);\n }\n const queryParams = parsed.query;\n\n const hostUri = getHostUri() || '';\n const hostUriStripped = removePort(removeTrailingSlashAndQueryString(hostUri));\n\n let path = parsed.pathname || null;\n let hostname = parsed.hostname || null;\n let scheme = parsed.protocol || null;\n\n if (scheme) {\n // Remove colon at end\n scheme = scheme.substring(0, scheme.length - 1);\n }\n\n if (path) {\n path = removeLeadingSlash(path);\n\n let expoPrefix: string | null = null;\n if (hostUriStripped) {\n const parts = hostUriStripped.split('/');\n expoPrefix = parts.slice(1).concat(['--/']).join('/');\n }\n\n if (isExpoHosted() && !hasCustomScheme() && expoPrefix && path.startsWith(expoPrefix)) {\n path = path.substring(expoPrefix.length);\n hostname = null;\n } else if (path.indexOf('+') > -1) {\n path = path.substring(path.indexOf('+') + 1);\n }\n }\n\n return {\n hostname,\n path,\n queryParams,\n scheme,\n };\n}\n\n// @needsAudit\n/**\n * Add a handler to `Linking` changes by listening to the `url` event type and providing the handler.\n * It is recommended to use the [`useURL()`](#useurl) hook instead.\n * @param type The only valid type is `'url'`.\n * @param handler An [`URLListener`](#urllistener) function that takes an `event` object of the type\n * [`EventType`](#eventype).\n * @see [React Native Docs Linking page](https://reactnative.dev/docs/linking#addeventlistener).\n */\nexport function addEventListener(type: string, handler: URLListener): void {\n NativeLinking.addEventListener(type, handler);\n}\n\n/**\n * Remove a handler by passing the `url` event type and the handler.\n * @param type The only valid type is `'url'`.\n * @param handler An [`URLListener`](#urllistener) function that takes an `event` object of the type\n * [`EventType`](#eventype).\n * @see [React Native Docs Linking page](https://reactnative.dev/docs/linking#removeeventlistener).\n */\nexport function removeEventListener(type: string, handler: URLListener): void {\n NativeLinking.removeEventListener(type, handler);\n}\n\n// @needsAudit\n/**\n * Helper method which wraps React Native's `Linking.getInitialURL()` in `Linking.parse()`.\n * Parses the deep link information out of the URL used to open the experience initially.\n * If no link opened the app, all the fields will be `null`.\n * > On the web it parses the current window URL.\n * @return A promise that resolves with `ParsedURL` object.\n */\nexport async function parseInitialURLAsync(): Promise<ParsedURL> {\n const initialUrl = await NativeLinking.getInitialURL();\n if (!initialUrl) {\n return {\n scheme: null,\n hostname: null,\n path: null,\n queryParams: null,\n };\n }\n\n return parse(initialUrl);\n}\n\n// @needsAudit\n/**\n * Launch an Android intent with extras.\n * > Use [IntentLauncher](../intent-launcher) instead, `sendIntent` is only included in\n * > `Linking` for API compatibility with React Native's Linking API.\n * @platform android\n */\nexport async function sendIntent(action: string, extras?: SendIntentExtras[]): Promise<void> {\n if (Platform.OS === 'android') {\n return await NativeLinking.sendIntent(action, extras);\n }\n throw new UnavailabilityError('Linking', 'sendIntent');\n}\n\n// @needsAudit\n/**\n * Open the operating system settings app and displays the app’s custom settings, if it has any.\n * @platform ios\n */\nexport async function openSettings(): Promise<void> {\n if (Platform.OS === 'web') {\n throw new UnavailabilityError('Linking', 'openSettings');\n }\n if (NativeLinking.openSettings) {\n return await NativeLinking.openSettings();\n }\n await openURL('app-settings:');\n}\n\n// @needsAudit\n/**\n * Get the URL that was used to launch the app if it was launched by a link.\n * @return The URL string that launched your app, or `null`.\n */\nexport async function getInitialURL(): Promise<string | null> {\n return (await NativeLinking.getInitialURL()) ?? null;\n}\n\n// @needsAudit\n/**\n * Attempt to open the given URL with an installed app. See the [Linking guide](/guides/linking)\n * for more information.\n * @param url A URL for the operating system to open, eg: `tel:5555555`, `exp://`.\n * @return A `Promise` that is fulfilled with `true` if the link is opened operating system\n * automatically or the user confirms the prompt to open the link. The `Promise` rejects if there\n * are no applications registered for the URL or the user cancels the dialog.\n */\nexport async function openURL(url: string): Promise<true> {\n validateURL(url);\n return await NativeLinking.openURL(url);\n}\n\n// @needsAudit\n/**\n * Determine whether or not an installed app can handle a given URL.\n * On web this always returns `true` because there is no API for detecting what URLs can be opened.\n * @param url The URL that you want to test can be opened.\n * @return A `Promise` object that is fulfilled with `true` if the URL can be handled, otherwise it\n * `false` if not.\n *\n * The `Promise` will reject on Android if it was impossible to check if the URL can be opened, and\n * on iOS if you didn't [add the specific scheme in the `LSApplicationQueriesSchemes` key inside **Info.plist**](/guides/linking#opening-links-to-other-apps).\n */\nexport async function canOpenURL(url: string): Promise<boolean> {\n validateURL(url);\n return await NativeLinking.canOpenURL(url);\n}\n\n// @needsAudit\n/**\n * Returns the initial URL followed by any subsequent changes to the URL.\n * @return Returns the initial URL or `null`.\n */\nexport function useURL(): string | null {\n const [url, setLink] = useState<string | null>(null);\n\n function onChange(event: { url: string }) {\n setLink(event.url);\n }\n\n useEffect(() => {\n getInitialURL().then((url) => setLink(url));\n addEventListener('url', onChange);\n return () => removeEventListener('url', onChange);\n }, []);\n\n return url;\n}\n\nexport * from './Linking.types';\n"]}
|
package/build/Linking.types.d.ts
CHANGED
|
@@ -3,7 +3,13 @@ export declare type QueryParams = ParsedQs;
|
|
|
3
3
|
export declare type ParsedURL = {
|
|
4
4
|
scheme: string | null;
|
|
5
5
|
hostname: string | null;
|
|
6
|
+
/**
|
|
7
|
+
* The path into the app specified by the URL.
|
|
8
|
+
*/
|
|
6
9
|
path: string | null;
|
|
10
|
+
/**
|
|
11
|
+
* The set of query parameters specified by the query string of the url used to open the app.
|
|
12
|
+
*/
|
|
7
13
|
queryParams: QueryParams | null;
|
|
8
14
|
};
|
|
9
15
|
export declare type CreateURLOptions = {
|
|
@@ -26,3 +32,7 @@ export declare type EventType = {
|
|
|
26
32
|
};
|
|
27
33
|
export declare type URLListener = (event: EventType) => void;
|
|
28
34
|
export declare type NativeURLListener = (nativeEvent: MessageEvent) => void;
|
|
35
|
+
export declare type SendIntentExtras = {
|
|
36
|
+
key: string;
|
|
37
|
+
value: string | number | boolean;
|
|
38
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Linking.types.js","sourceRoot":"","sources":["../src/Linking.types.ts"],"names":[],"mappings":"","sourcesContent":["import { ParsedQs } from 'qs';\n\nexport type QueryParams = ParsedQs;\n\nexport type ParsedURL = {\n scheme: string | null;\n hostname: string | null;\n path: string | null;\n queryParams: QueryParams | null;\n};\n\nexport type CreateURLOptions = {\n /**\n * URI protocol `<scheme>://` that must be built into your native app.\n */\n scheme?: string;\n /**\n * An object of parameters that will be converted into a query string.\n */\n queryParams?: QueryParams;\n /**\n * Should the URI be triple slashed `scheme:///path` or double slashed `scheme://path`.\n */\n isTripleSlashed?: boolean;\n};\n\nexport type EventType = {
|
|
1
|
+
{"version":3,"file":"Linking.types.js","sourceRoot":"","sources":["../src/Linking.types.ts"],"names":[],"mappings":"","sourcesContent":["import { ParsedQs } from 'qs';\n\n// @docsMissing\nexport type QueryParams = ParsedQs;\n\n// @needsAudit @docsMissing\nexport type ParsedURL = {\n scheme: string | null;\n hostname: string | null;\n /**\n * The path into the app specified by the URL.\n */\n path: string | null;\n /**\n * The set of query parameters specified by the query string of the url used to open the app.\n */\n queryParams: QueryParams | null;\n};\n\n// @needsAudit\nexport type CreateURLOptions = {\n /**\n * URI protocol `<scheme>://` that must be built into your native app.\n */\n scheme?: string;\n /**\n * An object of parameters that will be converted into a query string.\n */\n queryParams?: QueryParams;\n /**\n * Should the URI be triple slashed `scheme:///path` or double slashed `scheme://path`.\n */\n isTripleSlashed?: boolean;\n};\n\n// @docsMissing\nexport type EventType = {\n url: string;\n nativeEvent?: MessageEvent;\n};\n\n// @docsMissing\nexport type URLListener = (event: EventType) => void;\n\n// @docsMissing\nexport type NativeURLListener = (nativeEvent: MessageEvent) => void;\n\n// @docsMissing\nexport type SendIntentExtras = { key: string; value: string | number | boolean };\n"]}
|
package/build/Schemes.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Platform } from '@unimodules/core';
|
|
2
1
|
import Constants, { ExecutionEnvironment } from 'expo-constants';
|
|
2
|
+
import { Platform } from 'expo-modules-core';
|
|
3
3
|
const LINKING_GUIDE_URL = `https://docs.expo.io/guides/linking/`;
|
|
4
4
|
export function hasCustomScheme() {
|
|
5
5
|
if (Constants.executionEnvironment === ExecutionEnvironment.Bare) {
|
|
@@ -56,15 +56,18 @@ export function collectManifestSchemes() {
|
|
|
56
56
|
// They'll be added when we drop support for `expo build` or decide
|
|
57
57
|
// to have them only work with `eas build`.
|
|
58
58
|
const platformManifest = Platform.select({
|
|
59
|
-
ios: Constants.manifest?.ios,
|
|
60
|
-
android: Constants.manifest?.android,
|
|
59
|
+
ios: Constants.manifest?.ios ?? Constants.manifest2?.extra?.expoClient?.ios,
|
|
60
|
+
android: Constants.manifest?.android ?? Constants.manifest2?.extra?.expoClient?.android,
|
|
61
61
|
web: {},
|
|
62
62
|
}) ?? {};
|
|
63
|
-
const schemes = getSchemes(Constants.manifest);
|
|
63
|
+
const schemes = getSchemes(Constants.manifest ?? Constants.manifest2?.extra?.expoClient);
|
|
64
64
|
// Add the detached scheme after the manifest scheme for legacy ExpoKit support.
|
|
65
65
|
if (Constants.manifest?.detach?.scheme) {
|
|
66
66
|
schemes.push(Constants.manifest.detach.scheme);
|
|
67
67
|
}
|
|
68
|
+
if (Constants.manifest2?.extra?.expoClient?.detach?.scheme) {
|
|
69
|
+
schemes.push(Constants.manifest2.extra.expoClient.detach.scheme);
|
|
70
|
+
}
|
|
68
71
|
// Add the unimplemented platform schemes last.
|
|
69
72
|
schemes.push(...getSchemes(platformManifest));
|
|
70
73
|
return schemes;
|
|
@@ -73,9 +76,11 @@ function getNativeAppIdScheme() {
|
|
|
73
76
|
// Add the native application identifier to the list of schemes for parity with `expo build`.
|
|
74
77
|
// The native app id has been added to builds for a long time to support Google Sign-In.
|
|
75
78
|
return (Platform.select({
|
|
76
|
-
ios: Constants.manifest?.ios?.bundleIdentifier
|
|
79
|
+
ios: Constants.manifest?.ios?.bundleIdentifier ??
|
|
80
|
+
Constants.manifest2?.extra?.expoClient?.ios?.bundleIdentifier,
|
|
77
81
|
// TODO: This may change to android.applicationId in the future.
|
|
78
|
-
android: Constants.manifest?.android?.package
|
|
82
|
+
android: Constants.manifest?.android?.package ??
|
|
83
|
+
Constants.manifest2?.extra?.expoClient?.android?.package,
|
|
79
84
|
}) ?? null);
|
|
80
85
|
}
|
|
81
86
|
export function hasConstantsManifest() {
|
|
@@ -120,7 +125,7 @@ export function resolveScheme(props) {
|
|
|
120
125
|
// TODO: Will this cause issues for things like Facebook or Google that use `reversed-client-id://` or `fb<FBID>:/`?
|
|
121
126
|
// Traditionally these APIs don't use the Linking API directly.
|
|
122
127
|
console.warn(`The provided Linking scheme '${props.scheme}' does not appear in the list of possible URI schemes in your Expo config. Expected one of: ${schemes
|
|
123
|
-
.map(scheme => `'${scheme}'`)
|
|
128
|
+
.map((scheme) => `'${scheme}'`)
|
|
124
129
|
.join(', ')}`);
|
|
125
130
|
}
|
|
126
131
|
}
|
package/build/Schemes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Schemes.js","sourceRoot":"","sources":["../src/Schemes.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from '@unimodules/core';\nimport Constants, { ExecutionEnvironment } from 'expo-constants';\n\nconst LINKING_GUIDE_URL = `https://docs.expo.io/guides/linking/`;\n\nexport function hasCustomScheme(): boolean {\n if (Constants.executionEnvironment === ExecutionEnvironment.Bare) {\n // Bare always uses a custom scheme.\n return true;\n } else if (Constants.executionEnvironment === ExecutionEnvironment.Standalone) {\n // Standalone uses a custom scheme when one is defined.\n const manifestSchemes = collectManifestSchemes();\n return !!manifestSchemes.length;\n }\n // Store client uses the default scheme.\n return false;\n}\n\ntype SchemeConfig = {\n scheme?: string | string[];\n};\n\nfunction getSchemes(config: SchemeConfig): string[] {\n if (config) {\n if (Array.isArray(config.scheme)) {\n const validate = (value: any): value is string => {\n return typeof value === 'string';\n };\n return config.scheme.filter<string>(validate);\n } else if (typeof config.scheme === 'string') {\n return [config.scheme];\n }\n }\n return [];\n}\n\n// Valid schemes for the Expo client.\nconst EXPO_CLIENT_SCHEMES = Platform.select({\n // Results from `npx uri-scheme list --info-path ios/Exponent/Supporting/Info.plist`\n ios: [\n 'exp',\n 'exps',\n 'fb1696089354000816',\n 'host.exp.exponent',\n 'com.googleusercontent.apps.603386649315-vp4revvrcgrcjme51ebuhbkbspl048l9',\n ],\n // Collected manually\n android: ['exp', 'exps'],\n});\n\n/**\n * Collect a list of platform schemes from the manifest.\n *\n * This method is based on the `Scheme` modules from `@expo/config-plugins`\n * which are used for collecting the schemes before prebuilding a native app.\n *\n * - iOS: scheme -> ios.scheme -> ios.bundleIdentifier\n * - Android: scheme -> android.scheme -> android.package\n */\nexport function collectManifestSchemes(): string[] {\n // ios.scheme, android.scheme, and scheme as an array are not yet added to the\n // Expo config spec, but there's no harm in adding them early.\n // They'll be added when we drop support for `expo build` or decide\n // to have them only work with `eas build`.\n const platformManifest =\n (Platform.select<any>({\n ios: Constants.manifest?.ios,\n android: Constants.manifest?.android,\n web: {},\n }) as SchemeConfig) ?? {};\n\n const schemes = getSchemes(Constants.manifest as any);\n\n // Add the detached scheme after the manifest scheme for legacy ExpoKit support.\n if (Constants.manifest?.detach?.scheme) {\n schemes.push(Constants.manifest.detach.scheme);\n }\n\n // Add the unimplemented platform schemes last.\n schemes.push(...getSchemes(platformManifest));\n\n return schemes;\n}\n\nfunction getNativeAppIdScheme(): string | null {\n // Add the native application identifier to the list of schemes for parity with `expo build`.\n // The native app id has been added to builds for a long time to support Google Sign-In.\n return (\n Platform.select({\n ios: Constants.manifest?.ios?.bundleIdentifier,\n // TODO: This may change to android.applicationId in the future.\n android: Constants.manifest?.android?.package,\n }) ?? null\n );\n}\n\nexport function hasConstantsManifest(): boolean {\n // Ensure the user has linked the expo-constants manifest in bare workflow.\n return (\n !!Object.keys(Constants.manifest ?? {}).length ||\n !!Object.keys(Constants.manifest2 ?? {}).length\n );\n}\n\nexport function resolveScheme(props: { scheme?: string; isSilent?: boolean }): string {\n if (\n Constants.executionEnvironment !== ExecutionEnvironment.StoreClient &&\n !hasConstantsManifest()\n ) {\n throw new Error(\n `expo-linking needs access to the expo-constants manifest (app.json or app.config.js) to determine what URI scheme to use. Setup the manifest and rebuild: https://github.com/expo/expo/blob/master/packages/expo-constants/README.md`\n );\n }\n\n const manifestSchemes = collectManifestSchemes();\n const nativeAppId = getNativeAppIdScheme();\n\n if (!manifestSchemes.length) {\n if (__DEV__ && !props.isSilent) {\n // Assert a config warning if no scheme is setup yet. `isSilent` is used for warnings, but we'll ignore it for exceptions.\n console.warn(\n `Linking requires a build-time setting \\`scheme\\` in the project's Expo config (app.config.js or app.json) for production apps, if it's left blank, your app may crash. The scheme does not apply to development in the Expo client but you should add it as soon as you start working with Linking to avoid creating a broken build. Learn more: ${LINKING_GUIDE_URL}`\n );\n } else if (!__DEV__ || Constants.executionEnvironment !== ExecutionEnvironment.StoreClient) {\n // Throw in production or when not in store client. Use the __DEV__ flag so users can test this functionality with `expo start --no-dev`,\n throw new Error(\n 'Cannot make a deep link into a standalone app with no custom scheme defined'\n );\n }\n }\n\n // In the Expo client...\n if (Constants.executionEnvironment === ExecutionEnvironment.StoreClient) {\n if (props.scheme) {\n // This enables users to use the fb or google redirects on iOS in the Expo client.\n if (EXPO_CLIENT_SCHEMES.includes(props.scheme)) {\n return props.scheme;\n }\n // Silently ignore to make bare workflow development easier.\n }\n // Fallback to the default client scheme.\n return 'exp';\n }\n\n const schemes = [...manifestSchemes, nativeAppId].filter(Boolean);\n\n if (props.scheme) {\n if (__DEV__) {\n // Bare workflow development assertion about the provided scheme matching the Expo config.\n if (!schemes.includes(props.scheme) && !props.isSilent) {\n // TODO: Will this cause issues for things like Facebook or Google that use `reversed-client-id://` or `fb<FBID>:/`?\n // Traditionally these APIs don't use the Linking API directly.\n console.warn(\n `The provided Linking scheme '${\n props.scheme\n }' does not appear in the list of possible URI schemes in your Expo config. Expected one of: ${schemes\n .map(scheme => `'${scheme}'`)\n .join(', ')}`\n );\n }\n }\n // Return the user provided value.\n return props.scheme;\n }\n // If no scheme is provided, we'll guess what the scheme is based on the manifest.\n // This is to attempt to keep managed apps working across expo build and EAS build.\n // EAS build ejects the app before building it so we can assume that the user will\n // be using one of defined schemes.\n\n // If the native app id is the only scheme,\n if (!!nativeAppId && !manifestSchemes.length && !props.isSilent) {\n // Assert a config warning if no scheme is setup yet.\n // This warning only applies to managed workflow EAS apps, as bare workflow\n console.warn(\n `Linking requires a build-time setting \\`scheme\\` in the project's Expo config (app.config.js or app.json) for bare or production apps. Manually providing a \\`scheme\\` property can circumvent this warning. Using native app identifier as the scheme '${nativeAppId}'. Learn more: ${LINKING_GUIDE_URL}`\n );\n return nativeAppId;\n }\n // When the native app id is defined, it'll be added to the list of schemes, for most\n // users this will be unexpected behavior and cause all apps to warn when the Linking API\n // is used without a predefined scheme. For now, if the native app id is defined, require\n // at least one more scheme to be added before throwing a warning.\n // i.e. `scheme: ['foo', 'bar']` (unimplemented functionality).\n const [scheme, ...extraSchemes] = manifestSchemes;\n\n if (!scheme) {\n const errorMessage = `Linking requires a build-time setting \\`scheme\\` in the project's Expo config (app.config.js or app.json) for bare or production apps. Manually providing a \\`scheme\\` property can circumvent this error. Learn more: ${LINKING_GUIDE_URL}`;\n // Throw in production, use the __DEV__ flag so users can test this functionality with `expo start --no-dev`\n throw new Error(errorMessage);\n }\n if (extraSchemes.length && !props.isSilent) {\n console.warn(\n `Linking found multiple possible URI schemes in your Expo config.\\nUsing '${scheme}'. Ignoring: ${[\n ...extraSchemes,\n nativeAppId,\n ]\n .filter(Boolean)\n .join(', ')}.\\nPlease supply the preferred URI scheme to the Linking API.`\n );\n }\n return scheme;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Schemes.js","sourceRoot":"","sources":["../src/Schemes.ts"],"names":[],"mappings":"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","sourcesContent":["import Constants, { ExecutionEnvironment } from 'expo-constants';\nimport { Platform } from 'expo-modules-core';\n\nconst LINKING_GUIDE_URL = `https://docs.expo.io/guides/linking/`;\n\nexport function hasCustomScheme(): boolean {\n if (Constants.executionEnvironment === ExecutionEnvironment.Bare) {\n // Bare always uses a custom scheme.\n return true;\n } else if (Constants.executionEnvironment === ExecutionEnvironment.Standalone) {\n // Standalone uses a custom scheme when one is defined.\n const manifestSchemes = collectManifestSchemes();\n return !!manifestSchemes.length;\n }\n // Store client uses the default scheme.\n return false;\n}\n\ntype SchemeConfig = {\n scheme?: string | string[];\n};\n\nfunction getSchemes(config: SchemeConfig | null | undefined): string[] {\n if (config) {\n if (Array.isArray(config.scheme)) {\n const validate = (value: any): value is string => {\n return typeof value === 'string';\n };\n return config.scheme.filter<string>(validate);\n } else if (typeof config.scheme === 'string') {\n return [config.scheme];\n }\n }\n return [];\n}\n\n// Valid schemes for the Expo client.\nconst EXPO_CLIENT_SCHEMES = Platform.select({\n // Results from `npx uri-scheme list --info-path ios/Exponent/Supporting/Info.plist`\n ios: [\n 'exp',\n 'exps',\n 'fb1696089354000816',\n 'host.exp.exponent',\n 'com.googleusercontent.apps.603386649315-vp4revvrcgrcjme51ebuhbkbspl048l9',\n ],\n // Collected manually\n android: ['exp', 'exps'],\n});\n\n/**\n * Collect a list of platform schemes from the manifest.\n *\n * This method is based on the `Scheme` modules from `@expo/config-plugins`\n * which are used for collecting the schemes before prebuilding a native app.\n *\n * - iOS: scheme -> ios.scheme -> ios.bundleIdentifier\n * - Android: scheme -> android.scheme -> android.package\n */\nexport function collectManifestSchemes(): string[] {\n // ios.scheme, android.scheme, and scheme as an array are not yet added to the\n // Expo config spec, but there's no harm in adding them early.\n // They'll be added when we drop support for `expo build` or decide\n // to have them only work with `eas build`.\n const platformManifest =\n (Platform.select<any>({\n ios: Constants.manifest?.ios ?? Constants.manifest2?.extra?.expoClient?.ios,\n android: Constants.manifest?.android ?? Constants.manifest2?.extra?.expoClient?.android,\n web: {},\n }) as SchemeConfig) ?? {};\n\n const schemes = getSchemes(Constants.manifest ?? Constants.manifest2?.extra?.expoClient);\n\n // Add the detached scheme after the manifest scheme for legacy ExpoKit support.\n if (Constants.manifest?.detach?.scheme) {\n schemes.push(Constants.manifest.detach.scheme);\n }\n if (Constants.manifest2?.extra?.expoClient?.detach?.scheme) {\n schemes.push(Constants.manifest2.extra.expoClient.detach.scheme);\n }\n\n // Add the unimplemented platform schemes last.\n schemes.push(...getSchemes(platformManifest));\n\n return schemes;\n}\n\nfunction getNativeAppIdScheme(): string | null {\n // Add the native application identifier to the list of schemes for parity with `expo build`.\n // The native app id has been added to builds for a long time to support Google Sign-In.\n return (\n Platform.select({\n ios:\n Constants.manifest?.ios?.bundleIdentifier ??\n Constants.manifest2?.extra?.expoClient?.ios?.bundleIdentifier,\n // TODO: This may change to android.applicationId in the future.\n android:\n Constants.manifest?.android?.package ??\n Constants.manifest2?.extra?.expoClient?.android?.package,\n }) ?? null\n );\n}\n\nexport function hasConstantsManifest(): boolean {\n // Ensure the user has linked the expo-constants manifest in bare workflow.\n return (\n !!Object.keys(Constants.manifest ?? {}).length ||\n !!Object.keys(Constants.manifest2 ?? {}).length\n );\n}\n\nexport function resolveScheme(props: { scheme?: string; isSilent?: boolean }): string {\n if (\n Constants.executionEnvironment !== ExecutionEnvironment.StoreClient &&\n !hasConstantsManifest()\n ) {\n throw new Error(\n `expo-linking needs access to the expo-constants manifest (app.json or app.config.js) to determine what URI scheme to use. Setup the manifest and rebuild: https://github.com/expo/expo/blob/master/packages/expo-constants/README.md`\n );\n }\n\n const manifestSchemes = collectManifestSchemes();\n const nativeAppId = getNativeAppIdScheme();\n\n if (!manifestSchemes.length) {\n if (__DEV__ && !props.isSilent) {\n // Assert a config warning if no scheme is setup yet. `isSilent` is used for warnings, but we'll ignore it for exceptions.\n console.warn(\n `Linking requires a build-time setting \\`scheme\\` in the project's Expo config (app.config.js or app.json) for production apps, if it's left blank, your app may crash. The scheme does not apply to development in the Expo client but you should add it as soon as you start working with Linking to avoid creating a broken build. Learn more: ${LINKING_GUIDE_URL}`\n );\n } else if (!__DEV__ || Constants.executionEnvironment !== ExecutionEnvironment.StoreClient) {\n // Throw in production or when not in store client. Use the __DEV__ flag so users can test this functionality with `expo start --no-dev`,\n throw new Error(\n 'Cannot make a deep link into a standalone app with no custom scheme defined'\n );\n }\n }\n\n // In the Expo client...\n if (Constants.executionEnvironment === ExecutionEnvironment.StoreClient) {\n if (props.scheme) {\n // This enables users to use the fb or google redirects on iOS in the Expo client.\n if (EXPO_CLIENT_SCHEMES.includes(props.scheme)) {\n return props.scheme;\n }\n // Silently ignore to make bare workflow development easier.\n }\n // Fallback to the default client scheme.\n return 'exp';\n }\n\n const schemes = [...manifestSchemes, nativeAppId].filter(Boolean);\n\n if (props.scheme) {\n if (__DEV__) {\n // Bare workflow development assertion about the provided scheme matching the Expo config.\n if (!schemes.includes(props.scheme) && !props.isSilent) {\n // TODO: Will this cause issues for things like Facebook or Google that use `reversed-client-id://` or `fb<FBID>:/`?\n // Traditionally these APIs don't use the Linking API directly.\n console.warn(\n `The provided Linking scheme '${\n props.scheme\n }' does not appear in the list of possible URI schemes in your Expo config. Expected one of: ${schemes\n .map((scheme) => `'${scheme}'`)\n .join(', ')}`\n );\n }\n }\n // Return the user provided value.\n return props.scheme;\n }\n // If no scheme is provided, we'll guess what the scheme is based on the manifest.\n // This is to attempt to keep managed apps working across expo build and EAS build.\n // EAS build ejects the app before building it so we can assume that the user will\n // be using one of defined schemes.\n\n // If the native app id is the only scheme,\n if (!!nativeAppId && !manifestSchemes.length && !props.isSilent) {\n // Assert a config warning if no scheme is setup yet.\n // This warning only applies to managed workflow EAS apps, as bare workflow\n console.warn(\n `Linking requires a build-time setting \\`scheme\\` in the project's Expo config (app.config.js or app.json) for bare or production apps. Manually providing a \\`scheme\\` property can circumvent this warning. Using native app identifier as the scheme '${nativeAppId}'. Learn more: ${LINKING_GUIDE_URL}`\n );\n return nativeAppId;\n }\n // When the native app id is defined, it'll be added to the list of schemes, for most\n // users this will be unexpected behavior and cause all apps to warn when the Linking API\n // is used without a predefined scheme. For now, if the native app id is defined, require\n // at least one more scheme to be added before throwing a warning.\n // i.e. `scheme: ['foo', 'bar']` (unimplemented functionality).\n const [scheme, ...extraSchemes] = manifestSchemes;\n\n if (!scheme) {\n const errorMessage = `Linking requires a build-time setting \\`scheme\\` in the project's Expo config (app.config.js or app.json) for bare or production apps. Manually providing a \\`scheme\\` property can circumvent this error. Learn more: ${LINKING_GUIDE_URL}`;\n // Throw in production, use the __DEV__ flag so users can test this functionality with `expo start --no-dev`\n throw new Error(errorMessage);\n }\n if (extraSchemes.length && !props.isSilent) {\n console.warn(\n `Linking found multiple possible URI schemes in your Expo config.\\nUsing '${scheme}'. Ignoring: ${[\n ...extraSchemes,\n nativeAppId,\n ]\n .filter(Boolean)\n .join(', ')}.\\nPlease supply the preferred URI scheme to the Linking API.`\n );\n }\n return scheme;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-linking",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Create and open deep links universally",
|
|
5
5
|
"main": "build/Linking.js",
|
|
6
6
|
"types": "build/Linking.d.ts",
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
},
|
|
29
29
|
"author": "650 Industries, Inc.",
|
|
30
30
|
"license": "MIT",
|
|
31
|
-
"homepage": "https://docs.expo.
|
|
31
|
+
"homepage": "https://docs.expo.dev/versions/latest/sdk/linking",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"expo-constants": "~
|
|
33
|
+
"expo-constants": "~13.0.0",
|
|
34
34
|
"invariant": "^2.2.4",
|
|
35
|
-
"qs": "^6.
|
|
35
|
+
"qs": "^6.9.1",
|
|
36
36
|
"url-parse": "^1.4.4"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"jest": {
|
|
43
43
|
"preset": "expo-module-scripts"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "2e5c6983b86d5ecfca028ba64002897d8adc2cc4"
|
|
46
46
|
}
|
package/src/ExpoLinking.web.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Platform } from '
|
|
1
|
+
import { Platform } from 'expo-modules-core';
|
|
2
2
|
import invariant from 'invariant';
|
|
3
3
|
|
|
4
4
|
import { NativeURLListener, URLListener } from './Linking.types';
|
|
@@ -13,7 +13,7 @@ export default {
|
|
|
13
13
|
EventTypes.indexOf(type) !== -1,
|
|
14
14
|
`Linking.addEventListener(): ${type} is not a valid event`
|
|
15
15
|
);
|
|
16
|
-
const nativeListener: NativeURLListener = nativeEvent =>
|
|
16
|
+
const nativeListener: NativeURLListener = (nativeEvent) =>
|
|
17
17
|
listener({ url: window.location.href, nativeEvent });
|
|
18
18
|
listeners.push({ listener, nativeListener });
|
|
19
19
|
window.addEventListener('message', nativeListener, false);
|
|
@@ -24,7 +24,7 @@ export default {
|
|
|
24
24
|
EventTypes.indexOf(type) !== -1,
|
|
25
25
|
`Linking.removeEventListener(): ${type} is not a valid event.`
|
|
26
26
|
);
|
|
27
|
-
const listenerIndex = listeners.findIndex(pair => pair.listener === listener);
|
|
27
|
+
const listenerIndex = listeners.findIndex((pair) => pair.listener === listener);
|
|
28
28
|
invariant(
|
|
29
29
|
listenerIndex !== -1,
|
|
30
30
|
'Linking.removeEventListener(): cannot remove an unregistered event listener.'
|
package/src/Linking.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import { Platform, UnavailabilityError } from '@unimodules/core';
|
|
2
1
|
import Constants from 'expo-constants';
|
|
2
|
+
import { Platform, UnavailabilityError } from 'expo-modules-core';
|
|
3
3
|
import invariant from 'invariant';
|
|
4
4
|
import qs from 'qs';
|
|
5
5
|
import { useEffect, useState } from 'react';
|
|
6
6
|
import URL from 'url-parse';
|
|
7
7
|
|
|
8
8
|
import NativeLinking from './ExpoLinking';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
CreateURLOptions,
|
|
11
|
+
ParsedURL,
|
|
12
|
+
QueryParams,
|
|
13
|
+
SendIntentExtras,
|
|
14
|
+
URLListener,
|
|
15
|
+
} from './Linking.types';
|
|
10
16
|
import { hasCustomScheme, resolveScheme } from './Schemes';
|
|
11
17
|
|
|
12
18
|
function validateURL(url: string): void {
|
|
@@ -17,7 +23,9 @@ function validateURL(url: string): void {
|
|
|
17
23
|
function getHostUri(): string | null {
|
|
18
24
|
if (Constants.manifest?.hostUri) {
|
|
19
25
|
return Constants.manifest.hostUri;
|
|
20
|
-
} else if (
|
|
26
|
+
} else if (Constants.manifest2?.extra?.expoClient?.hostUri) {
|
|
27
|
+
return Constants.manifest2.extra.expoClient.hostUri;
|
|
28
|
+
} else if (!hasCustomScheme()) {
|
|
21
29
|
// we're probably not using up-to-date xdl, so just fake it for now
|
|
22
30
|
// we have to remove the /--/ on the end since this will be inserted again later
|
|
23
31
|
return removeScheme(Constants.linkingUri).replace(/\/--($|\/.*$)/, '');
|
|
@@ -51,7 +59,7 @@ function removeTrailingSlashAndQueryString(url: string): string {
|
|
|
51
59
|
return url.replace(/\/?\?.*$/, '');
|
|
52
60
|
}
|
|
53
61
|
|
|
54
|
-
function
|
|
62
|
+
function ensureTrailingSlash(input: string, shouldAppend: boolean): string {
|
|
55
63
|
const hasSlash = input.endsWith('/');
|
|
56
64
|
if (hasSlash && !shouldAppend) {
|
|
57
65
|
return input.substring(0, input.length - 1);
|
|
@@ -61,7 +69,7 @@ function ensureLeadingSlash(input: string, shouldAppend: boolean): string {
|
|
|
61
69
|
return input;
|
|
62
70
|
}
|
|
63
71
|
|
|
64
|
-
function
|
|
72
|
+
function ensureLeadingSlash(input: string, shouldAppend: boolean): string {
|
|
65
73
|
const hasSlash = input.startsWith('/');
|
|
66
74
|
if (hasSlash && !shouldAppend) {
|
|
67
75
|
return input.substring(1);
|
|
@@ -71,12 +79,12 @@ function ensureTrailingSlash(input: string, shouldAppend: boolean): string {
|
|
|
71
79
|
return input;
|
|
72
80
|
}
|
|
73
81
|
|
|
82
|
+
// @needsAudit
|
|
74
83
|
/**
|
|
75
84
|
* Create a URL that works for the environment the app is currently running in.
|
|
76
85
|
* The scheme in bare and standalone must be defined in the app.json under `expo.scheme`.
|
|
77
86
|
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
87
|
+
* # Examples
|
|
80
88
|
* - Bare: empty string
|
|
81
89
|
* - Standalone, Custom: `yourscheme:///path`
|
|
82
90
|
* - Web (dev): `https://localhost:19006/path`
|
|
@@ -85,28 +93,38 @@ function ensureTrailingSlash(input: string, shouldAppend: boolean): string {
|
|
|
85
93
|
* - Expo Client (prod): `exp://exp.host/@yourname/your-app/--/path`
|
|
86
94
|
*
|
|
87
95
|
* @param path addition path components to append to the base URL.
|
|
88
|
-
* @param queryParams An object of parameters
|
|
96
|
+
* @param queryParams An object with a set of query parameters. These will be merged with any
|
|
97
|
+
* Expo-specific parameters that are needed (e.g. release channel) and then appended to the URL
|
|
98
|
+
* as a query string.
|
|
99
|
+
* @param scheme Optional URI protocol to use in the URL `<scheme>:///`, when `undefined` the scheme
|
|
100
|
+
* will be chosen from the Expo config (`app.config.js` or `app.json`).
|
|
101
|
+
* @return A URL string which points to your app with the given deep link information.
|
|
102
|
+
* @deprecated An alias for [`createURL()`](#linkingcreateurlpath-namedparameters). This method is
|
|
103
|
+
* deprecated and will be removed in a future SDK version.
|
|
89
104
|
*/
|
|
90
105
|
export function makeUrl(path: string = '', queryParams?: QueryParams, scheme?: string): string {
|
|
91
106
|
return createURL(path, { queryParams, scheme, isTripleSlashed: true });
|
|
92
107
|
}
|
|
93
108
|
|
|
109
|
+
// @needsAudit
|
|
94
110
|
/**
|
|
95
|
-
*
|
|
96
|
-
*
|
|
111
|
+
* Helper method for constructing a deep link into your app, given an optional path and set of query
|
|
112
|
+
* parameters. Creates a URI scheme with two slashes by default.
|
|
97
113
|
*
|
|
98
|
-
*
|
|
114
|
+
* The scheme in bare and standalone must be defined in the Expo config (`app.config.js` or `app.json`)
|
|
115
|
+
* under `expo.scheme`.
|
|
99
116
|
*
|
|
100
|
-
*
|
|
117
|
+
* # Examples
|
|
118
|
+
* - Bare: `<scheme>://path` - uses provided scheme or scheme from Expo config `scheme`.
|
|
101
119
|
* - Standalone, Custom: `yourscheme://path`
|
|
102
120
|
* - Web (dev): `https://localhost:19006/path`
|
|
103
121
|
* - Web (prod): `https://myapp.com/path`
|
|
104
122
|
* - Expo Client (dev): `exp://128.0.0.1:19000/--/path`
|
|
105
123
|
* - Expo Client (prod): `exp://exp.host/@yourname/your-app/--/path`
|
|
106
124
|
*
|
|
107
|
-
* @param path
|
|
108
|
-
* @param
|
|
109
|
-
* @
|
|
125
|
+
* @param path Addition path components to append to the base URL.
|
|
126
|
+
* @param namedParameters Additional options object.
|
|
127
|
+
* @return A URL string which points to your app with the given deep link information.
|
|
110
128
|
*/
|
|
111
129
|
export function createURL(
|
|
112
130
|
path: string,
|
|
@@ -115,14 +133,14 @@ export function createURL(
|
|
|
115
133
|
if (Platform.OS === 'web') {
|
|
116
134
|
if (!Platform.isDOMAvailable) return '';
|
|
117
135
|
|
|
118
|
-
const origin =
|
|
136
|
+
const origin = ensureTrailingSlash(window.location.origin, false);
|
|
119
137
|
let queryString = qs.stringify(queryParams);
|
|
120
138
|
if (queryString) {
|
|
121
139
|
queryString = `?${queryString}`;
|
|
122
140
|
}
|
|
123
141
|
|
|
124
142
|
let outputPath = path;
|
|
125
|
-
if (outputPath) outputPath =
|
|
143
|
+
if (outputPath) outputPath = ensureLeadingSlash(path, true);
|
|
126
144
|
|
|
127
145
|
return encodeURI(`${origin}${outputPath}${queryString}`);
|
|
128
146
|
}
|
|
@@ -170,17 +188,18 @@ export function createURL(
|
|
|
170
188
|
queryString = `?${queryString}`;
|
|
171
189
|
}
|
|
172
190
|
|
|
173
|
-
hostUri =
|
|
191
|
+
hostUri = ensureLeadingSlash(hostUri, !isTripleSlashed);
|
|
174
192
|
|
|
175
193
|
return encodeURI(
|
|
176
194
|
`${resolvedScheme}:${isTripleSlashed ? '/' : ''}/${hostUri}${path}${queryString}`
|
|
177
195
|
);
|
|
178
196
|
}
|
|
179
197
|
|
|
198
|
+
// @needsAudit
|
|
180
199
|
/**
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
* @
|
|
200
|
+
* Helper method for parsing out deep link information from a URL.
|
|
201
|
+
* @param url A URL that points to the currently running experience (e.g. an output of `Linking.createURL()`).
|
|
202
|
+
* @return A `ParsedURL` object.
|
|
184
203
|
*/
|
|
185
204
|
export function parse(url: string): ParsedURL {
|
|
186
205
|
validateURL(url);
|
|
@@ -210,10 +229,7 @@ export function parse(url: string): ParsedURL {
|
|
|
210
229
|
let expoPrefix: string | null = null;
|
|
211
230
|
if (hostUriStripped) {
|
|
212
231
|
const parts = hostUriStripped.split('/');
|
|
213
|
-
expoPrefix = parts
|
|
214
|
-
.slice(1)
|
|
215
|
-
.concat(['--/'])
|
|
216
|
-
.join('/');
|
|
232
|
+
expoPrefix = parts.slice(1).concat(['--/']).join('/');
|
|
217
233
|
}
|
|
218
234
|
|
|
219
235
|
if (isExpoHosted() && !hasCustomScheme() && expoPrefix && path.startsWith(expoPrefix)) {
|
|
@@ -232,28 +248,37 @@ export function parse(url: string): ParsedURL {
|
|
|
232
248
|
};
|
|
233
249
|
}
|
|
234
250
|
|
|
251
|
+
// @needsAudit
|
|
235
252
|
/**
|
|
236
|
-
* Add a handler to Linking changes by listening to the `url` event type
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
253
|
+
* Add a handler to `Linking` changes by listening to the `url` event type and providing the handler.
|
|
254
|
+
* It is recommended to use the [`useURL()`](#useurl) hook instead.
|
|
255
|
+
* @param type The only valid type is `'url'`.
|
|
256
|
+
* @param handler An [`URLListener`](#urllistener) function that takes an `event` object of the type
|
|
257
|
+
* [`EventType`](#eventype).
|
|
258
|
+
* @see [React Native Docs Linking page](https://reactnative.dev/docs/linking#addeventlistener).
|
|
240
259
|
*/
|
|
241
|
-
export function addEventListener(type: string, handler: URLListener) {
|
|
260
|
+
export function addEventListener(type: string, handler: URLListener): void {
|
|
242
261
|
NativeLinking.addEventListener(type, handler);
|
|
243
262
|
}
|
|
244
263
|
|
|
245
264
|
/**
|
|
246
265
|
* Remove a handler by passing the `url` event type and the handler.
|
|
247
|
-
*
|
|
248
|
-
*
|
|
266
|
+
* @param type The only valid type is `'url'`.
|
|
267
|
+
* @param handler An [`URLListener`](#urllistener) function that takes an `event` object of the type
|
|
268
|
+
* [`EventType`](#eventype).
|
|
269
|
+
* @see [React Native Docs Linking page](https://reactnative.dev/docs/linking#removeeventlistener).
|
|
249
270
|
*/
|
|
250
|
-
export function removeEventListener(type: string, handler: URLListener) {
|
|
271
|
+
export function removeEventListener(type: string, handler: URLListener): void {
|
|
251
272
|
NativeLinking.removeEventListener(type, handler);
|
|
252
273
|
}
|
|
253
274
|
|
|
275
|
+
// @needsAudit
|
|
254
276
|
/**
|
|
255
|
-
*
|
|
256
|
-
*
|
|
277
|
+
* Helper method which wraps React Native's `Linking.getInitialURL()` in `Linking.parse()`.
|
|
278
|
+
* Parses the deep link information out of the URL used to open the experience initially.
|
|
279
|
+
* If no link opened the app, all the fields will be `null`.
|
|
280
|
+
* > On the web it parses the current window URL.
|
|
281
|
+
* @return A promise that resolves with `ParsedURL` object.
|
|
257
282
|
*/
|
|
258
283
|
export async function parseInitialURLAsync(): Promise<ParsedURL> {
|
|
259
284
|
const initialUrl = await NativeLinking.getInitialURL();
|
|
@@ -269,24 +294,23 @@ export async function parseInitialURLAsync(): Promise<ParsedURL> {
|
|
|
269
294
|
return parse(initialUrl);
|
|
270
295
|
}
|
|
271
296
|
|
|
297
|
+
// @needsAudit
|
|
272
298
|
/**
|
|
273
|
-
* Launch an Android intent with
|
|
274
|
-
*
|
|
299
|
+
* Launch an Android intent with extras.
|
|
300
|
+
* > Use [IntentLauncher](../intent-launcher) instead, `sendIntent` is only included in
|
|
301
|
+
* > `Linking` for API compatibility with React Native's Linking API.
|
|
275
302
|
* @platform android
|
|
276
303
|
*/
|
|
277
|
-
export async function sendIntent(
|
|
278
|
-
action: string,
|
|
279
|
-
extras?: { key: string; value: string | number | boolean }[]
|
|
280
|
-
): Promise<void> {
|
|
304
|
+
export async function sendIntent(action: string, extras?: SendIntentExtras[]): Promise<void> {
|
|
281
305
|
if (Platform.OS === 'android') {
|
|
282
306
|
return await NativeLinking.sendIntent(action, extras);
|
|
283
307
|
}
|
|
284
308
|
throw new UnavailabilityError('Linking', 'sendIntent');
|
|
285
309
|
}
|
|
286
310
|
|
|
311
|
+
// @needsAudit
|
|
287
312
|
/**
|
|
288
|
-
*
|
|
289
|
-
*
|
|
313
|
+
* Open the operating system settings app and displays the app’s custom settings, if it has any.
|
|
290
314
|
* @platform ios
|
|
291
315
|
*/
|
|
292
316
|
export async function openSettings(): Promise<void> {
|
|
@@ -299,33 +323,49 @@ export async function openSettings(): Promise<void> {
|
|
|
299
323
|
await openURL('app-settings:');
|
|
300
324
|
}
|
|
301
325
|
|
|
326
|
+
// @needsAudit
|
|
302
327
|
/**
|
|
303
|
-
*
|
|
304
|
-
*
|
|
328
|
+
* Get the URL that was used to launch the app if it was launched by a link.
|
|
329
|
+
* @return The URL string that launched your app, or `null`.
|
|
305
330
|
*/
|
|
306
331
|
export async function getInitialURL(): Promise<string | null> {
|
|
307
332
|
return (await NativeLinking.getInitialURL()) ?? null;
|
|
308
333
|
}
|
|
309
334
|
|
|
335
|
+
// @needsAudit
|
|
310
336
|
/**
|
|
311
|
-
*
|
|
337
|
+
* Attempt to open the given URL with an installed app. See the [Linking guide](/guides/linking)
|
|
338
|
+
* for more information.
|
|
339
|
+
* @param url A URL for the operating system to open, eg: `tel:5555555`, `exp://`.
|
|
340
|
+
* @return A `Promise` that is fulfilled with `true` if the link is opened operating system
|
|
341
|
+
* automatically or the user confirms the prompt to open the link. The `Promise` rejects if there
|
|
342
|
+
* are no applications registered for the URL or the user cancels the dialog.
|
|
312
343
|
*/
|
|
313
344
|
export async function openURL(url: string): Promise<true> {
|
|
314
345
|
validateURL(url);
|
|
315
346
|
return await NativeLinking.openURL(url);
|
|
316
347
|
}
|
|
317
348
|
|
|
349
|
+
// @needsAudit
|
|
318
350
|
/**
|
|
319
351
|
* Determine whether or not an installed app can handle a given URL.
|
|
320
|
-
* On web this always returns true because there is no API for detecting what URLs can be opened.
|
|
352
|
+
* On web this always returns `true` because there is no API for detecting what URLs can be opened.
|
|
353
|
+
* @param url The URL that you want to test can be opened.
|
|
354
|
+
* @return A `Promise` object that is fulfilled with `true` if the URL can be handled, otherwise it
|
|
355
|
+
* `false` if not.
|
|
356
|
+
*
|
|
357
|
+
* The `Promise` will reject on Android if it was impossible to check if the URL can be opened, and
|
|
358
|
+
* on iOS if you didn't [add the specific scheme in the `LSApplicationQueriesSchemes` key inside **Info.plist**](/guides/linking#opening-links-to-other-apps).
|
|
321
359
|
*/
|
|
322
360
|
export async function canOpenURL(url: string): Promise<boolean> {
|
|
323
361
|
validateURL(url);
|
|
324
362
|
return await NativeLinking.canOpenURL(url);
|
|
325
363
|
}
|
|
326
364
|
|
|
365
|
+
// @needsAudit
|
|
327
366
|
/**
|
|
328
367
|
* Returns the initial URL followed by any subsequent changes to the URL.
|
|
368
|
+
* @return Returns the initial URL or `null`.
|
|
329
369
|
*/
|
|
330
370
|
export function useURL(): string | null {
|
|
331
371
|
const [url, setLink] = useState<string | null>(null);
|
|
@@ -335,7 +375,7 @@ export function useURL(): string | null {
|
|
|
335
375
|
}
|
|
336
376
|
|
|
337
377
|
useEffect(() => {
|
|
338
|
-
getInitialURL().then(url => setLink(url));
|
|
378
|
+
getInitialURL().then((url) => setLink(url));
|
|
339
379
|
addEventListener('url', onChange);
|
|
340
380
|
return () => removeEventListener('url', onChange);
|
|
341
381
|
}, []);
|
|
@@ -343,15 +383,4 @@ export function useURL(): string | null {
|
|
|
343
383
|
return url;
|
|
344
384
|
}
|
|
345
385
|
|
|
346
|
-
/**
|
|
347
|
-
* Returns the initial URL followed by any subsequent changes to the URL.
|
|
348
|
-
* @deprecated Use `useURL` instead.
|
|
349
|
-
*/
|
|
350
|
-
export function useUrl(): string | null {
|
|
351
|
-
console.warn(
|
|
352
|
-
`Linking.useUrl has been deprecated in favor of Linking.useURL. This API will be removed in SDK 44.`
|
|
353
|
-
);
|
|
354
|
-
return useURL();
|
|
355
|
-
}
|
|
356
|
-
|
|
357
386
|
export * from './Linking.types';
|
package/src/Linking.types.ts
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import { ParsedQs } from 'qs';
|
|
2
2
|
|
|
3
|
+
// @docsMissing
|
|
3
4
|
export type QueryParams = ParsedQs;
|
|
4
5
|
|
|
6
|
+
// @needsAudit @docsMissing
|
|
5
7
|
export type ParsedURL = {
|
|
6
8
|
scheme: string | null;
|
|
7
9
|
hostname: string | null;
|
|
10
|
+
/**
|
|
11
|
+
* The path into the app specified by the URL.
|
|
12
|
+
*/
|
|
8
13
|
path: string | null;
|
|
14
|
+
/**
|
|
15
|
+
* The set of query parameters specified by the query string of the url used to open the app.
|
|
16
|
+
*/
|
|
9
17
|
queryParams: QueryParams | null;
|
|
10
18
|
};
|
|
11
19
|
|
|
20
|
+
// @needsAudit
|
|
12
21
|
export type CreateURLOptions = {
|
|
13
22
|
/**
|
|
14
23
|
* URI protocol `<scheme>://` that must be built into your native app.
|
|
@@ -24,8 +33,17 @@ export type CreateURLOptions = {
|
|
|
24
33
|
isTripleSlashed?: boolean;
|
|
25
34
|
};
|
|
26
35
|
|
|
27
|
-
|
|
36
|
+
// @docsMissing
|
|
37
|
+
export type EventType = {
|
|
38
|
+
url: string;
|
|
39
|
+
nativeEvent?: MessageEvent;
|
|
40
|
+
};
|
|
28
41
|
|
|
42
|
+
// @docsMissing
|
|
29
43
|
export type URLListener = (event: EventType) => void;
|
|
30
44
|
|
|
45
|
+
// @docsMissing
|
|
31
46
|
export type NativeURLListener = (nativeEvent: MessageEvent) => void;
|
|
47
|
+
|
|
48
|
+
// @docsMissing
|
|
49
|
+
export type SendIntentExtras = { key: string; value: string | number | boolean };
|
package/src/Schemes.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Platform } from '@unimodules/core';
|
|
2
1
|
import Constants, { ExecutionEnvironment } from 'expo-constants';
|
|
2
|
+
import { Platform } from 'expo-modules-core';
|
|
3
3
|
|
|
4
4
|
const LINKING_GUIDE_URL = `https://docs.expo.io/guides/linking/`;
|
|
5
5
|
|
|
@@ -20,7 +20,7 @@ type SchemeConfig = {
|
|
|
20
20
|
scheme?: string | string[];
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
function getSchemes(config: SchemeConfig): string[] {
|
|
23
|
+
function getSchemes(config: SchemeConfig | null | undefined): string[] {
|
|
24
24
|
if (config) {
|
|
25
25
|
if (Array.isArray(config.scheme)) {
|
|
26
26
|
const validate = (value: any): value is string => {
|
|
@@ -64,17 +64,20 @@ export function collectManifestSchemes(): string[] {
|
|
|
64
64
|
// to have them only work with `eas build`.
|
|
65
65
|
const platformManifest =
|
|
66
66
|
(Platform.select<any>({
|
|
67
|
-
ios: Constants.manifest?.ios,
|
|
68
|
-
android: Constants.manifest?.android,
|
|
67
|
+
ios: Constants.manifest?.ios ?? Constants.manifest2?.extra?.expoClient?.ios,
|
|
68
|
+
android: Constants.manifest?.android ?? Constants.manifest2?.extra?.expoClient?.android,
|
|
69
69
|
web: {},
|
|
70
70
|
}) as SchemeConfig) ?? {};
|
|
71
71
|
|
|
72
|
-
const schemes = getSchemes(Constants.manifest
|
|
72
|
+
const schemes = getSchemes(Constants.manifest ?? Constants.manifest2?.extra?.expoClient);
|
|
73
73
|
|
|
74
74
|
// Add the detached scheme after the manifest scheme for legacy ExpoKit support.
|
|
75
75
|
if (Constants.manifest?.detach?.scheme) {
|
|
76
76
|
schemes.push(Constants.manifest.detach.scheme);
|
|
77
77
|
}
|
|
78
|
+
if (Constants.manifest2?.extra?.expoClient?.detach?.scheme) {
|
|
79
|
+
schemes.push(Constants.manifest2.extra.expoClient.detach.scheme);
|
|
80
|
+
}
|
|
78
81
|
|
|
79
82
|
// Add the unimplemented platform schemes last.
|
|
80
83
|
schemes.push(...getSchemes(platformManifest));
|
|
@@ -87,9 +90,13 @@ function getNativeAppIdScheme(): string | null {
|
|
|
87
90
|
// The native app id has been added to builds for a long time to support Google Sign-In.
|
|
88
91
|
return (
|
|
89
92
|
Platform.select({
|
|
90
|
-
ios:
|
|
93
|
+
ios:
|
|
94
|
+
Constants.manifest?.ios?.bundleIdentifier ??
|
|
95
|
+
Constants.manifest2?.extra?.expoClient?.ios?.bundleIdentifier,
|
|
91
96
|
// TODO: This may change to android.applicationId in the future.
|
|
92
|
-
android:
|
|
97
|
+
android:
|
|
98
|
+
Constants.manifest?.android?.package ??
|
|
99
|
+
Constants.manifest2?.extra?.expoClient?.android?.package,
|
|
93
100
|
}) ?? null
|
|
94
101
|
);
|
|
95
102
|
}
|
|
@@ -154,7 +161,7 @@ export function resolveScheme(props: { scheme?: string; isSilent?: boolean }): s
|
|
|
154
161
|
`The provided Linking scheme '${
|
|
155
162
|
props.scheme
|
|
156
163
|
}' does not appear in the list of possible URI schemes in your Expo config. Expected one of: ${schemes
|
|
157
|
-
.map(scheme => `'${scheme}'`)
|
|
164
|
+
.map((scheme) => `'${scheme}'`)
|
|
158
165
|
.join(', ')}`
|
|
159
166
|
);
|
|
160
167
|
}
|