import Constants, { ExecutionEnvironment } from '../constants' import * as Linking from 'expo-linking' import URL from 'url-parse' // This is only run on native. function extractExactPathFromURL(url: string): string { if ( // If a universal link / app link / web URL is used, we should use the path // from the URL, while stripping the origin. url.match(/^https?:\/\//) ) { const { origin, href } = new URL(url) return href.replace(origin, '') } // Handle special URLs used in Expo Go: `/--/pathname` -> `pathname` if ( Constants.executionEnvironment === ExecutionEnvironment.StoreClient && // while not exhaustive, `exp` and `exps` are the only two schemes which // are passed through to other apps in Expo Go. url.match(/^exp(s)?:\/\//) ) { const pathname = url.match(/exps?:\/\/.*?\/--\/(.*)/)?.[1] if (pathname) { return fromDeepLink('a://' + pathname) } const res = Linking.parse(url) const qs = !res.queryParams ? '' : Object.entries(res.queryParams) .map(([k, v]) => `${k}=${v}`) .join('&') return ( adjustPathname({ hostname: res.hostname, pathname: res.path || '' }) + (qs ? '?' + qs : '') ) } // TODO: Support dev client URLs return fromDeepLink(url) } /** Major hack to support the makeshift expo-development-client system. */ function isExpoDevelopmentClient(url: URL>): boolean { return !!url.hostname.match(/^expo-development-client$/) } function fromDeepLink(url: string): string { // This is for all standard deep links, e.g. `foobar://` where everything // after the `://` is the path. const res = new URL(url, true) if (isExpoDevelopmentClient(res)) { if (!res.query || !res.query.url) { return '' } const incomingUrl = res.query.url return extractExactPathFromURL(decodeURI(incomingUrl)) } const qs = !res.query ? '' : Object.entries(res.query as Record) .map(([k, v]) => `${k}=${decodeURIComponent(v)}`) .join('&') let results = '' if (res.host) { results += res.host } if (res.pathname) { results += res.pathname } if (qs) { results += '?' + qs } return results } export function extractExpoPathFromURL(url = '') { // TODO: We should get rid of this, dropping specificities is not good return extractExactPathFromURL(url).replace(/^\//, '') } export function adjustPathname(url: { hostname?: string | null; pathname: string }) { if (url.hostname === 'exp.host' || url.hostname === 'u.expo.dev') { // drop the first two segments from pathname: return url.pathname.split('/').slice(2).join('/') } return url.pathname }