1 | import { Constants } from 'expo-constants';
|
2 | import { Linking } from 'react-native';
|
3 | import qs from 'qs';
|
4 | const { manifest } = Constants;
|
5 | const USES_CUSTOM_SCHEME = Constants.appOwnership === 'standalone' && manifest.scheme;
|
6 | let HOST_URI = manifest.hostUri;
|
7 | if (!HOST_URI && !USES_CUSTOM_SCHEME) {
|
8 |
|
9 |
|
10 | HOST_URI = _removeScheme(Constants.linkingUri).replace(/\/--($|\/.*$)/, '');
|
11 | }
|
12 | const IS_EXPO_HOSTED = HOST_URI &&
|
13 | (/^(.*\.)?(expo\.io|exp\.host|exp\.direct|expo\.test)(:.*)?(\/.*)?$/.test(HOST_URI) ||
|
14 | manifest.developer);
|
15 | function _removeScheme(url) {
|
16 | return url.replace(/^[a-zA-Z0-9+.-]+:\/\//, '');
|
17 | }
|
18 | function _removePort(url) {
|
19 | return url.replace(/(?=([a-zA-Z0-9+.-]+:\/\/)?[^/]):\d+/, '');
|
20 | }
|
21 | function _removeLeadingSlash(url) {
|
22 | return url.replace(/^\//, '');
|
23 | }
|
24 | function _removeTrailingSlash(url) {
|
25 | return url.replace(/\/$/, '');
|
26 | }
|
27 | function _removeTrailingSlashAndQueryString(url) {
|
28 | return url.replace(/\/?\?.*$/, '');
|
29 | }
|
30 | function makeUrl(path = '', queryParams = {}) {
|
31 | let scheme = 'exp';
|
32 | if (Constants.appOwnership === 'standalone') {
|
33 | scheme = manifest.scheme || (manifest.detach && manifest.detach.scheme);
|
34 | }
|
35 | if (!scheme) {
|
36 | throw new Error('Cannot make a deep link into a standalone app with no custom scheme defined');
|
37 | }
|
38 | let hostUri = HOST_URI || '';
|
39 | if (USES_CUSTOM_SCHEME && IS_EXPO_HOSTED) {
|
40 | hostUri = '';
|
41 | }
|
42 | if (path) {
|
43 | if (IS_EXPO_HOSTED && hostUri) {
|
44 | path = `/--/${_removeLeadingSlash(path)}`;
|
45 | }
|
46 | if (!path.startsWith('/') && hostUri) {
|
47 | path = `/${path}`;
|
48 | }
|
49 | else if (path.startsWith('/') && !hostUri) {
|
50 | path = path.substr(1);
|
51 | }
|
52 | }
|
53 | else {
|
54 | path = '';
|
55 | }
|
56 |
|
57 |
|
58 | let queryString = '';
|
59 | let queryStringMatchResult = hostUri.match(/(.*)\?(.+)/);
|
60 | if (queryStringMatchResult) {
|
61 | hostUri = queryStringMatchResult[1];
|
62 | queryString = queryStringMatchResult[2];
|
63 | let paramsFromHostUri = {};
|
64 | try {
|
65 | let parsedParams = qs.parse(queryString);
|
66 | if (typeof parsedParams === 'object') {
|
67 | paramsFromHostUri = parsedParams;
|
68 | }
|
69 | }
|
70 | catch (e) { }
|
71 | queryParams = {
|
72 | ...queryParams,
|
73 | ...paramsFromHostUri,
|
74 | };
|
75 | }
|
76 | queryString = qs.stringify(queryParams);
|
77 | if (queryString) {
|
78 | queryString = `?${queryString}`;
|
79 | }
|
80 | hostUri = _removeTrailingSlash(hostUri);
|
81 | return encodeURI(`${scheme}://${hostUri}${path}${queryString}`);
|
82 | }
|
83 | function parse(url) {
|
84 | if (!url) {
|
85 | throw new Error('parse cannot be called with a null value');
|
86 | }
|
87 |
|
88 |
|
89 |
|
90 |
|
91 | let decodedUrl = _removePort(decodeURI(url));
|
92 | let path;
|
93 | let queryParams = {};
|
94 | let queryStringMatchResult = decodedUrl.match(/(.*)\?(.+)/);
|
95 | if (queryStringMatchResult) {
|
96 | decodedUrl = queryStringMatchResult[1];
|
97 | queryParams = qs.parse(queryStringMatchResult[2]);
|
98 | }
|
99 |
|
100 | let hostUri = HOST_URI || '';
|
101 | let hostUriStripped = _removePort(_removeTrailingSlashAndQueryString(hostUri));
|
102 | if (hostUriStripped && decodedUrl.indexOf(hostUriStripped) > -1) {
|
103 | path = decodedUrl.substr(decodedUrl.indexOf(hostUriStripped) + hostUriStripped.length);
|
104 | }
|
105 | else {
|
106 | path = _removeScheme(decodedUrl);
|
107 | }
|
108 | path = _removeLeadingSlash(path);
|
109 | if (IS_EXPO_HOSTED && !USES_CUSTOM_SCHEME && path.startsWith('--/')) {
|
110 | path = path.substr(3);
|
111 | }
|
112 | else if (path.indexOf('+') > -1) {
|
113 | path = path.substr(path.indexOf('+') + 1);
|
114 | }
|
115 | return { path, queryParams };
|
116 | }
|
117 | async function parseInitialURLAsync() {
|
118 | const initialUrl = await Linking.getInitialURL();
|
119 | return parse(initialUrl);
|
120 | }
|
121 |
|
122 | let newLinking = new Linking.constructor();
|
123 | newLinking.makeUrl = makeUrl;
|
124 | newLinking.parse = parse;
|
125 | newLinking.parseInitialURLAsync = parseInitialURLAsync;
|
126 | export default newLinking;
|
127 |
|
\ | No newline at end of file |