1 | import { UnavailabilityError } from '@unimodules/core';
|
2 | import { AppState, Linking, Platform } from 'react-native';
|
3 | import ExponentWebBrowser from './ExpoWebBrowser';
|
4 | import { WebBrowserResultType, } from './WebBrowser.types';
|
5 | export { WebBrowserResultType, };
|
6 | const emptyCustomTabsPackages = {
|
7 | defaultBrowserPackage: undefined,
|
8 | preferredBrowserPackage: undefined,
|
9 | browserPackages: [],
|
10 | servicePackages: [],
|
11 | };
|
12 | export async function getCustomTabsSupportingBrowsersAsync() {
|
13 | if (!ExponentWebBrowser.getCustomTabsSupportingBrowsersAsync) {
|
14 | throw new UnavailabilityError('WebBrowser', 'getCustomTabsSupportingBrowsersAsync');
|
15 | }
|
16 | if (Platform.OS !== 'android') {
|
17 | return emptyCustomTabsPackages;
|
18 | }
|
19 | else {
|
20 | return await ExponentWebBrowser.getCustomTabsSupportingBrowsersAsync();
|
21 | }
|
22 | }
|
23 | export async function warmUpAsync(browserPackage) {
|
24 | if (!ExponentWebBrowser.warmUpAsync) {
|
25 | throw new UnavailabilityError('WebBrowser', 'warmUpAsync');
|
26 | }
|
27 | if (Platform.OS !== 'android') {
|
28 | return {};
|
29 | }
|
30 | else {
|
31 | return await ExponentWebBrowser.warmUpAsync(browserPackage);
|
32 | }
|
33 | }
|
34 | export async function mayInitWithUrlAsync(url, browserPackage) {
|
35 | if (!ExponentWebBrowser.mayInitWithUrlAsync) {
|
36 | throw new UnavailabilityError('WebBrowser', 'mayInitWithUrlAsync');
|
37 | }
|
38 | if (Platform.OS !== 'android') {
|
39 | return {};
|
40 | }
|
41 | else {
|
42 | return await ExponentWebBrowser.mayInitWithUrlAsync(url, browserPackage);
|
43 | }
|
44 | }
|
45 | export async function coolDownAsync(browserPackage) {
|
46 | if (!ExponentWebBrowser.coolDownAsync) {
|
47 | throw new UnavailabilityError('WebBrowser', 'coolDownAsync');
|
48 | }
|
49 | if (Platform.OS !== 'android') {
|
50 | return {};
|
51 | }
|
52 | else {
|
53 | return await ExponentWebBrowser.coolDownAsync(browserPackage);
|
54 | }
|
55 | }
|
56 | export async function openBrowserAsync(url, browserParams = {}) {
|
57 | if (!ExponentWebBrowser.openBrowserAsync) {
|
58 | throw new UnavailabilityError('WebBrowser', 'openBrowserAsync');
|
59 | }
|
60 | return await ExponentWebBrowser.openBrowserAsync(url, browserParams);
|
61 | }
|
62 | export function dismissBrowser() {
|
63 | if (!ExponentWebBrowser.dismissBrowser) {
|
64 | throw new UnavailabilityError('WebBrowser', 'dismissBrowser');
|
65 | }
|
66 | ExponentWebBrowser.dismissBrowser();
|
67 | }
|
68 | export async function openAuthSessionAsync(url, redirectUrl, browserParams = {}) {
|
69 | if (_authSessionIsNativelySupported()) {
|
70 | if (!ExponentWebBrowser.openAuthSessionAsync) {
|
71 | throw new UnavailabilityError('WebBrowser', 'openAuthSessionAsync');
|
72 | }
|
73 | return ExponentWebBrowser.openAuthSessionAsync(url, redirectUrl);
|
74 | }
|
75 | else {
|
76 | return _openAuthSessionPolyfillAsync(url, redirectUrl, browserParams);
|
77 | }
|
78 | }
|
79 | export function dismissAuthSession() {
|
80 | if (_authSessionIsNativelySupported()) {
|
81 | if (!ExponentWebBrowser.dismissAuthSession) {
|
82 | throw new UnavailabilityError('WebBrowser', 'dismissAuthSession');
|
83 | }
|
84 | ExponentWebBrowser.dismissAuthSession();
|
85 | }
|
86 | else {
|
87 | if (!ExponentWebBrowser.dismissBrowser) {
|
88 | throw new UnavailabilityError('WebBrowser', 'dismissAuthSession');
|
89 | }
|
90 | ExponentWebBrowser.dismissBrowser();
|
91 | }
|
92 | }
|
93 |
|
94 | function _authSessionIsNativelySupported() {
|
95 | if (Platform.OS === 'android') {
|
96 | return false;
|
97 | }
|
98 | const versionNumber = parseInt(String(Platform.Version), 10);
|
99 | return versionNumber >= 11;
|
100 | }
|
101 | let _redirectHandler = null;
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 | let _onWebBrowserCloseAndroid = null;
|
109 | function _onAppStateChangeAndroid(state) {
|
110 | if (state === 'active' && _onWebBrowserCloseAndroid) {
|
111 | _onWebBrowserCloseAndroid();
|
112 | }
|
113 | }
|
114 | async function _openBrowserAndWaitAndroidAsync(startUrl, browserParams = {}) {
|
115 | let appStateChangedToActive = new Promise(resolve => {
|
116 | _onWebBrowserCloseAndroid = resolve;
|
117 | AppState.addEventListener('change', _onAppStateChangeAndroid);
|
118 | });
|
119 | let result = { type: 'cancel' };
|
120 | let { type } = await openBrowserAsync(startUrl, browserParams);
|
121 | if (type === 'opened') {
|
122 | await appStateChangedToActive;
|
123 | result = { type: 'dismiss' };
|
124 | }
|
125 | AppState.removeEventListener('change', _onAppStateChangeAndroid);
|
126 | _onWebBrowserCloseAndroid = null;
|
127 | return result;
|
128 | }
|
129 | async function _openAuthSessionPolyfillAsync(startUrl, returnUrl, browserParams = {}) {
|
130 | if (_redirectHandler) {
|
131 | throw new Error(`The WebBrowser's auth session is in an invalid state with a redirect handler set when it should not be`);
|
132 | }
|
133 | if (_onWebBrowserCloseAndroid) {
|
134 | throw new Error(`WebBrowser is already open, only one can be open at a time`);
|
135 | }
|
136 | try {
|
137 | if (Platform.OS === 'android') {
|
138 | return await Promise.race([
|
139 | _openBrowserAndWaitAndroidAsync(startUrl, browserParams),
|
140 | _waitForRedirectAsync(returnUrl),
|
141 | ]);
|
142 | }
|
143 | else {
|
144 | return await Promise.race([
|
145 | openBrowserAsync(startUrl, browserParams),
|
146 | _waitForRedirectAsync(returnUrl),
|
147 | ]);
|
148 | }
|
149 | }
|
150 | finally {
|
151 |
|
152 |
|
153 | if (ExponentWebBrowser.dismissBrowser) {
|
154 | ExponentWebBrowser.dismissBrowser();
|
155 | }
|
156 | _stopWaitingForRedirect();
|
157 | }
|
158 | }
|
159 | function _stopWaitingForRedirect() {
|
160 | if (!_redirectHandler) {
|
161 | throw new Error(`The WebBrowser auth session is in an invalid state with no redirect handler when one should be set`);
|
162 | }
|
163 | Linking.removeEventListener('url', _redirectHandler);
|
164 | _redirectHandler = null;
|
165 | }
|
166 | function _waitForRedirectAsync(returnUrl) {
|
167 | return new Promise(resolve => {
|
168 | _redirectHandler = (event) => {
|
169 | if (event.url.startsWith(returnUrl)) {
|
170 | resolve({ url: event.url, type: 'success' });
|
171 | }
|
172 | };
|
173 | Linking.addEventListener('url', _redirectHandler);
|
174 | });
|
175 | }
|
176 |
|
\ | No newline at end of file |