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 | let browserLocked = false;
|
57 | export async function openBrowserAsync(url, browserParams = {}) {
|
58 | if (!ExponentWebBrowser.openBrowserAsync) {
|
59 | throw new UnavailabilityError('WebBrowser', 'openBrowserAsync');
|
60 | }
|
61 | if (browserLocked) {
|
62 |
|
63 |
|
64 | if (__DEV__) {
|
65 | console.warn('Attempted to call WebBrowser.openBrowserAsync multiple times while already active. Only one WebBrowser controller can be active at any given time.');
|
66 | }
|
67 | return { type: WebBrowserResultType.LOCKED };
|
68 | }
|
69 | browserLocked = true;
|
70 | let result;
|
71 | try {
|
72 | result = await ExponentWebBrowser.openBrowserAsync(url, browserParams);
|
73 | }
|
74 | finally {
|
75 |
|
76 | browserLocked = false;
|
77 | }
|
78 | return result;
|
79 | }
|
80 | export function dismissBrowser() {
|
81 | if (!ExponentWebBrowser.dismissBrowser) {
|
82 | throw new UnavailabilityError('WebBrowser', 'dismissBrowser');
|
83 | }
|
84 | ExponentWebBrowser.dismissBrowser();
|
85 | }
|
86 | export async function openAuthSessionAsync(url, redirectUrl, browserParams = {}) {
|
87 | if (_authSessionIsNativelySupported()) {
|
88 | if (!ExponentWebBrowser.openAuthSessionAsync) {
|
89 | throw new UnavailabilityError('WebBrowser', 'openAuthSessionAsync');
|
90 | }
|
91 | if (Platform.OS === 'web') {
|
92 | return ExponentWebBrowser.openAuthSessionAsync(url, redirectUrl, browserParams);
|
93 | }
|
94 | return ExponentWebBrowser.openAuthSessionAsync(url, redirectUrl);
|
95 | }
|
96 | else {
|
97 | return _openAuthSessionPolyfillAsync(url, redirectUrl, browserParams);
|
98 | }
|
99 | }
|
100 | export function dismissAuthSession() {
|
101 | if (_authSessionIsNativelySupported()) {
|
102 | if (!ExponentWebBrowser.dismissAuthSession) {
|
103 | throw new UnavailabilityError('WebBrowser', 'dismissAuthSession');
|
104 | }
|
105 | ExponentWebBrowser.dismissAuthSession();
|
106 | }
|
107 | else {
|
108 | if (!ExponentWebBrowser.dismissBrowser) {
|
109 | throw new UnavailabilityError('WebBrowser', 'dismissAuthSession');
|
110 | }
|
111 | ExponentWebBrowser.dismissBrowser();
|
112 | }
|
113 | }
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 | export function maybeCompleteAuthSession(options = {}) {
|
120 | if (ExponentWebBrowser.maybeCompleteAuthSession) {
|
121 | return ExponentWebBrowser.maybeCompleteAuthSession(options);
|
122 | }
|
123 | return { type: 'failed', message: 'Not supported on this platform' };
|
124 | }
|
125 |
|
126 | function _authSessionIsNativelySupported() {
|
127 | if (Platform.OS === 'android') {
|
128 | return false;
|
129 | }
|
130 | else if (Platform.OS === 'web') {
|
131 | return true;
|
132 | }
|
133 | const versionNumber = parseInt(String(Platform.Version), 10);
|
134 | return versionNumber >= 11;
|
135 | }
|
136 | let _redirectHandler = null;
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 | let _onWebBrowserCloseAndroid = null;
|
144 |
|
145 |
|
146 |
|
147 |
|
148 | let _isAppStateAvailable = AppState.currentState !== null;
|
149 | function _onAppStateChangeAndroid(state) {
|
150 | if (!_isAppStateAvailable) {
|
151 | _isAppStateAvailable = true;
|
152 | return;
|
153 | }
|
154 | if (state === 'active' && _onWebBrowserCloseAndroid) {
|
155 | _onWebBrowserCloseAndroid();
|
156 | }
|
157 | }
|
158 | async function _openBrowserAndWaitAndroidAsync(startUrl, browserParams = {}) {
|
159 | const appStateChangedToActive = new Promise(resolve => {
|
160 | _onWebBrowserCloseAndroid = resolve;
|
161 | AppState.addEventListener('change', _onAppStateChangeAndroid);
|
162 | });
|
163 | let result = { type: WebBrowserResultType.CANCEL };
|
164 | const { type } = await openBrowserAsync(startUrl, browserParams);
|
165 | if (type === 'opened') {
|
166 | await appStateChangedToActive;
|
167 | result = { type: WebBrowserResultType.DISMISS };
|
168 | }
|
169 | AppState.removeEventListener('change', _onAppStateChangeAndroid);
|
170 | _onWebBrowserCloseAndroid = null;
|
171 | return result;
|
172 | }
|
173 | async function _openAuthSessionPolyfillAsync(startUrl, returnUrl, browserParams = {}) {
|
174 | if (_redirectHandler) {
|
175 | throw new Error(`The WebBrowser's auth session is in an invalid state with a redirect handler set when it should not be`);
|
176 | }
|
177 | if (_onWebBrowserCloseAndroid) {
|
178 | throw new Error(`WebBrowser is already open, only one can be open at a time`);
|
179 | }
|
180 | try {
|
181 | if (Platform.OS === 'android') {
|
182 | return await Promise.race([
|
183 | _openBrowserAndWaitAndroidAsync(startUrl, browserParams),
|
184 | _waitForRedirectAsync(returnUrl),
|
185 | ]);
|
186 | }
|
187 | else {
|
188 | return await Promise.race([
|
189 | openBrowserAsync(startUrl, browserParams),
|
190 | _waitForRedirectAsync(returnUrl),
|
191 | ]);
|
192 | }
|
193 | }
|
194 | finally {
|
195 |
|
196 |
|
197 | if (ExponentWebBrowser.dismissBrowser) {
|
198 | ExponentWebBrowser.dismissBrowser();
|
199 | }
|
200 | _stopWaitingForRedirect();
|
201 | }
|
202 | }
|
203 | function _stopWaitingForRedirect() {
|
204 | if (!_redirectHandler) {
|
205 | throw new Error(`The WebBrowser auth session is in an invalid state with no redirect handler when one should be set`);
|
206 | }
|
207 | Linking.removeEventListener('url', _redirectHandler);
|
208 | _redirectHandler = null;
|
209 | }
|
210 | function _waitForRedirectAsync(returnUrl) {
|
211 | return new Promise(resolve => {
|
212 | _redirectHandler = (event) => {
|
213 | if (event.url.startsWith(returnUrl)) {
|
214 | resolve({ url: event.url, type: 'success' });
|
215 | }
|
216 | };
|
217 | Linking.addEventListener('url', _redirectHandler);
|
218 | });
|
219 | }
|
220 |
|
\ | No newline at end of file |