expo-web-browser 10.2.1 → 12.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 +32 -0
- package/android/build.gradle +3 -2
- package/android/src/main/java/expo/modules/webbrowser/CustomTabsActivitiesHelper.kt +123 -0
- package/android/src/main/java/expo/modules/webbrowser/CustomTabsConnectionHelper.kt +97 -0
- package/android/src/main/java/expo/modules/webbrowser/DeferredClientActionsQueue.kt +45 -0
- package/android/src/main/java/expo/modules/webbrowser/WebBrowserExceptions.kt +13 -0
- package/android/src/main/java/expo/modules/webbrowser/WebBrowserModule.kt +164 -0
- package/android/src/main/java/expo/modules/webbrowser/WebBrowserOptions.kt +15 -0
- package/build/ExpoWebBrowser.web.js +5 -5
- package/build/ExpoWebBrowser.web.js.map +1 -1
- package/build/WebBrowser.d.ts +6 -6
- package/build/WebBrowser.d.ts.map +1 -1
- package/build/WebBrowser.js +25 -16
- package/build/WebBrowser.js.map +1 -1
- package/build/WebBrowser.types.d.ts +3 -3
- package/build/WebBrowser.types.js.map +1 -1
- package/expo-module.config.json +3 -0
- package/ios/ExpoWebBrowser.podspec +1 -1
- package/ios/WebAuthSession.swift +2 -2
- package/ios/WebBrowserModule.swift +9 -9
- package/package.json +3 -3
- package/src/ExpoWebBrowser.web.ts +6 -6
- package/src/WebBrowser.ts +38 -19
- package/src/WebBrowser.types.ts +3 -3
- package/tsconfig.json +1 -1
- package/android/src/main/java/expo/modules/webbrowser/CustomTabsActivitiesHelper.java +0 -33
- package/android/src/main/java/expo/modules/webbrowser/CustomTabsConnectionHelper.java +0 -13
- package/android/src/main/java/expo/modules/webbrowser/DeferredClientActionsQueue.java +0 -50
- package/android/src/main/java/expo/modules/webbrowser/InternalCustomTabsActivitiesHelper.java +0 -127
- package/android/src/main/java/expo/modules/webbrowser/InternalCustomTabsConnectionHelper.java +0 -126
- package/android/src/main/java/expo/modules/webbrowser/WebBrowserModule.java +0 -218
- package/android/src/main/java/expo/modules/webbrowser/WebBrowserPackage.java +0 -27
- package/android/src/main/java/expo/modules/webbrowser/error/NoPreferredPackageFound.java +0 -15
- package/android/src/main/java/expo/modules/webbrowser/error/PackageManagerNotFoundException.java +0 -10
package/src/WebBrowser.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { UnavailabilityError } from 'expo-modules-core';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
AppState,
|
|
4
|
+
AppStateStatus,
|
|
5
|
+
Linking,
|
|
6
|
+
Platform,
|
|
7
|
+
EmitterSubscription,
|
|
8
|
+
processColor,
|
|
9
|
+
} from 'react-native';
|
|
3
10
|
|
|
4
11
|
import ExponentWebBrowser from './ExpoWebBrowser';
|
|
5
12
|
import {
|
|
@@ -177,7 +184,7 @@ export async function openBrowserAsync(
|
|
|
177
184
|
|
|
178
185
|
let result: WebBrowserResult;
|
|
179
186
|
try {
|
|
180
|
-
result = await ExponentWebBrowser.openBrowserAsync(url, browserParams);
|
|
187
|
+
result = await ExponentWebBrowser.openBrowserAsync(url, _processOptions(browserParams));
|
|
181
188
|
} finally {
|
|
182
189
|
// WebBrowser session complete, unset lock
|
|
183
190
|
browserLocked = false;
|
|
@@ -203,9 +210,8 @@ export function dismissBrowser(): void {
|
|
|
203
210
|
// @needsAudit
|
|
204
211
|
/**
|
|
205
212
|
* # On iOS:
|
|
206
|
-
* Opens the url with Safari in a modal using `
|
|
207
|
-
*
|
|
208
|
-
* to authenticate using the given url.
|
|
213
|
+
* Opens the url with Safari in a modal using `ASWebAuthenticationSession`. The user will be asked
|
|
214
|
+
* whether to allow the app to authenticate using the given url.
|
|
209
215
|
*
|
|
210
216
|
* # On Android:
|
|
211
217
|
* This will be done using a "custom Chrome tabs" browser, [AppState](../react-native/appstate/),
|
|
@@ -220,7 +226,7 @@ export function dismissBrowser(): void {
|
|
|
220
226
|
*
|
|
221
227
|
* How this works on web:
|
|
222
228
|
* - A crypto state will be created for verifying the redirect.
|
|
223
|
-
* - This means you need to run with `expo start
|
|
229
|
+
* - This means you need to run with `npx expo start --https`
|
|
224
230
|
* - The state will be added to the window's `localstorage`. This ensures that auth cannot complete
|
|
225
231
|
* unless it's done from a page running with the same origin as it was started.
|
|
226
232
|
* Ex: if `openAuthSessionAsync` is invoked on `https://localhost:19006`, then `maybeCompleteAuthSession`
|
|
@@ -234,7 +240,8 @@ export function dismissBrowser(): void {
|
|
|
234
240
|
* after a user interaction. If the event is blocked, an error with code [`ERR_WEB_BROWSER_BLOCKED`](#errwebbrowserblocked) will be thrown.
|
|
235
241
|
*
|
|
236
242
|
* @param url The url to open in the web browser. This should be a login page.
|
|
237
|
-
* @param redirectUrl _Optional_ - The url to deep link back into your app.
|
|
243
|
+
* @param redirectUrl _Optional_ - The url to deep link back into your app.
|
|
244
|
+
* On web, this defaults to the output of [`Linking.createURL("")`](./linking/#linkingcreateurlpath-namedparameters).
|
|
238
245
|
* @param options _Optional_ - An object extending the [`WebBrowserOpenOptions`](#webbrowseropenoptions).
|
|
239
246
|
* If there is no native AuthSession implementation available (which is the case on Android)
|
|
240
247
|
* these params will be used in the browser polyfill. If there is a native AuthSession implementation,
|
|
@@ -248,7 +255,7 @@ export function dismissBrowser(): void {
|
|
|
248
255
|
*/
|
|
249
256
|
export async function openAuthSessionAsync(
|
|
250
257
|
url: string,
|
|
251
|
-
redirectUrl
|
|
258
|
+
redirectUrl?: string | null,
|
|
252
259
|
options: AuthSessionOpenOptions = {}
|
|
253
260
|
): Promise<WebBrowserAuthSessionResult> {
|
|
254
261
|
if (_authSessionIsNativelySupported()) {
|
|
@@ -256,7 +263,7 @@ export async function openAuthSessionAsync(
|
|
|
256
263
|
throw new UnavailabilityError('WebBrowser', 'openAuthSessionAsync');
|
|
257
264
|
}
|
|
258
265
|
if (['ios', 'web'].includes(Platform.OS)) {
|
|
259
|
-
return ExponentWebBrowser.openAuthSessionAsync(url, redirectUrl, options);
|
|
266
|
+
return ExponentWebBrowser.openAuthSessionAsync(url, redirectUrl, _processOptions(options));
|
|
260
267
|
}
|
|
261
268
|
return ExponentWebBrowser.openAuthSessionAsync(url, redirectUrl);
|
|
262
269
|
} else {
|
|
@@ -317,6 +324,15 @@ export function maybeCompleteAuthSession(
|
|
|
317
324
|
return { type: 'failed', message: 'Not supported on this platform' };
|
|
318
325
|
}
|
|
319
326
|
|
|
327
|
+
function _processOptions(options: WebBrowserOpenOptions) {
|
|
328
|
+
return {
|
|
329
|
+
...options,
|
|
330
|
+
controlsColor: processColor(options.controlsColor),
|
|
331
|
+
toolbarColor: processColor(options.toolbarColor),
|
|
332
|
+
secondaryToolbarColor: processColor(options.secondaryToolbarColor),
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
320
336
|
/* iOS <= 10 and Android polyfill for SFAuthenticationSession flow */
|
|
321
337
|
|
|
322
338
|
function _authSessionIsNativelySupported(): boolean {
|
|
@@ -330,7 +346,7 @@ function _authSessionIsNativelySupported(): boolean {
|
|
|
330
346
|
return versionNumber >= 11;
|
|
331
347
|
}
|
|
332
348
|
|
|
333
|
-
let
|
|
349
|
+
let _redirectSubscription: EmitterSubscription | null = null;
|
|
334
350
|
|
|
335
351
|
/*
|
|
336
352
|
* openBrowserAsync on Android doesn't wait until closed, so we need to polyfill
|
|
@@ -389,10 +405,10 @@ async function _openBrowserAndWaitAndroidAsync(
|
|
|
389
405
|
|
|
390
406
|
async function _openAuthSessionPolyfillAsync(
|
|
391
407
|
startUrl: string,
|
|
392
|
-
returnUrl: string,
|
|
408
|
+
returnUrl: string | null | undefined,
|
|
393
409
|
browserParams: WebBrowserOpenOptions = {}
|
|
394
410
|
): Promise<WebBrowserAuthSessionResult> {
|
|
395
|
-
if (
|
|
411
|
+
if (_redirectSubscription) {
|
|
396
412
|
throw new Error(
|
|
397
413
|
`The WebBrowser's auth session is in an invalid state with a redirect handler set when it should not be`
|
|
398
414
|
);
|
|
@@ -426,24 +442,27 @@ async function _openAuthSessionPolyfillAsync(
|
|
|
426
442
|
}
|
|
427
443
|
|
|
428
444
|
function _stopWaitingForRedirect() {
|
|
429
|
-
if (!
|
|
445
|
+
if (!_redirectSubscription) {
|
|
430
446
|
throw new Error(
|
|
431
447
|
`The WebBrowser auth session is in an invalid state with no redirect handler when one should be set`
|
|
432
448
|
);
|
|
433
449
|
}
|
|
434
450
|
|
|
435
|
-
|
|
436
|
-
|
|
451
|
+
_redirectSubscription.remove();
|
|
452
|
+
_redirectSubscription = null;
|
|
437
453
|
}
|
|
438
454
|
|
|
439
|
-
function _waitForRedirectAsync(
|
|
455
|
+
function _waitForRedirectAsync(
|
|
456
|
+
returnUrl: string | null | undefined
|
|
457
|
+
): Promise<WebBrowserRedirectResult> {
|
|
458
|
+
// Note that this Promise never resolves when `returnUrl` is nullish
|
|
440
459
|
return new Promise((resolve) => {
|
|
441
|
-
|
|
442
|
-
if (event.url.startsWith(returnUrl)) {
|
|
460
|
+
const redirectHandler = (event: RedirectEvent) => {
|
|
461
|
+
if (returnUrl && event.url.startsWith(returnUrl)) {
|
|
443
462
|
resolve({ url: event.url, type: 'success' });
|
|
444
463
|
}
|
|
445
464
|
};
|
|
446
465
|
|
|
447
|
-
Linking.addEventListener('url',
|
|
466
|
+
_redirectSubscription = Linking.addEventListener('url', redirectHandler);
|
|
448
467
|
});
|
|
449
468
|
}
|
package/src/WebBrowser.types.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type WebBrowserWindowFeatures = Record<string, number | boolean | string>
|
|
|
8
8
|
// @needsAudit
|
|
9
9
|
export type WebBrowserOpenOptions = {
|
|
10
10
|
/**
|
|
11
|
-
* Color of the toolbar
|
|
11
|
+
* Color of the toolbar. Supports React Native [color formats](https://reactnative.dev/docs/colors).
|
|
12
12
|
*/
|
|
13
13
|
toolbarColor?: string;
|
|
14
14
|
/**
|
|
@@ -22,7 +22,7 @@ export type WebBrowserOpenOptions = {
|
|
|
22
22
|
*/
|
|
23
23
|
enableBarCollapsing?: boolean;
|
|
24
24
|
/**
|
|
25
|
-
* Color of the secondary toolbar
|
|
25
|
+
* Color of the secondary toolbar. Supports React Native [color formats](https://reactnative.dev/docs/colors).
|
|
26
26
|
* @platform android
|
|
27
27
|
*/
|
|
28
28
|
secondaryToolbarColor?: string;
|
|
@@ -51,7 +51,7 @@ export type WebBrowserOpenOptions = {
|
|
|
51
51
|
*/
|
|
52
52
|
createTask?: boolean;
|
|
53
53
|
/**
|
|
54
|
-
* Tint color for controls in SKSafariViewController
|
|
54
|
+
* Tint color for controls in SKSafariViewController. Supports React Native [color formats](https://reactnative.dev/docs/colors).
|
|
55
55
|
* @platform ios
|
|
56
56
|
*/
|
|
57
57
|
controlsColor?: string;
|
package/tsconfig.json
CHANGED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
package expo.modules.webbrowser;
|
|
2
|
-
|
|
3
|
-
import android.content.Intent;
|
|
4
|
-
import android.content.pm.ResolveInfo;
|
|
5
|
-
|
|
6
|
-
import expo.modules.core.errors.CurrentActivityNotFoundException;
|
|
7
|
-
import expo.modules.core.interfaces.InternalModule;
|
|
8
|
-
|
|
9
|
-
import java.util.ArrayList;
|
|
10
|
-
import java.util.List;
|
|
11
|
-
|
|
12
|
-
import androidx.annotation.NonNull;
|
|
13
|
-
import androidx.annotation.Nullable;
|
|
14
|
-
import expo.modules.webbrowser.error.PackageManagerNotFoundException;
|
|
15
|
-
|
|
16
|
-
public interface CustomTabsActivitiesHelper extends InternalModule {
|
|
17
|
-
|
|
18
|
-
@NonNull
|
|
19
|
-
ArrayList<String> getCustomTabsResolvingActivities() throws PackageManagerNotFoundException, CurrentActivityNotFoundException;
|
|
20
|
-
|
|
21
|
-
@NonNull
|
|
22
|
-
ArrayList<String> getCustomTabsResolvingServices() throws PackageManagerNotFoundException, CurrentActivityNotFoundException;
|
|
23
|
-
|
|
24
|
-
@Nullable
|
|
25
|
-
String getPreferredCustomTabsResolvingActivity(@Nullable List<String> packages) throws PackageManagerNotFoundException, CurrentActivityNotFoundException;
|
|
26
|
-
|
|
27
|
-
@Nullable
|
|
28
|
-
String getDefaultCustomTabsResolvingActivity() throws PackageManagerNotFoundException, CurrentActivityNotFoundException;
|
|
29
|
-
|
|
30
|
-
void startCustomTabs(Intent intent) throws CurrentActivityNotFoundException;
|
|
31
|
-
|
|
32
|
-
boolean canResolveIntent(Intent intent) throws PackageManagerNotFoundException, CurrentActivityNotFoundException;
|
|
33
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
package expo.modules.webbrowser;
|
|
2
|
-
|
|
3
|
-
import android.net.Uri;
|
|
4
|
-
|
|
5
|
-
import expo.modules.core.interfaces.InternalModule;
|
|
6
|
-
|
|
7
|
-
public interface CustomTabsConnectionHelper extends InternalModule {
|
|
8
|
-
void warmUp(String packageName);
|
|
9
|
-
|
|
10
|
-
void mayInitWithUrl(String packageName, Uri uri);
|
|
11
|
-
|
|
12
|
-
boolean coolDown(String packageName);
|
|
13
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
package expo.modules.webbrowser;
|
|
2
|
-
|
|
3
|
-
import expo.modules.core.interfaces.Consumer;
|
|
4
|
-
|
|
5
|
-
import java.util.LinkedList;
|
|
6
|
-
import java.util.Queue;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
public class DeferredClientActionsQueue<T> {
|
|
10
|
-
|
|
11
|
-
private Queue<Consumer<T>> actions = new LinkedList<>();
|
|
12
|
-
private T client;
|
|
13
|
-
|
|
14
|
-
public void executeOrQueueAction(Consumer<T> action) {
|
|
15
|
-
if (client != null) {
|
|
16
|
-
action.apply(client);
|
|
17
|
-
} else {
|
|
18
|
-
addActionToQueue(action);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
public void setClient(T client) {
|
|
23
|
-
this.client = client;
|
|
24
|
-
executeQueuedActions();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
public void clear() {
|
|
28
|
-
this.client = null;
|
|
29
|
-
this.actions.clear();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
public boolean hasClient() {
|
|
33
|
-
return client != null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
private void executeQueuedActions() {
|
|
37
|
-
if (client != null) {
|
|
38
|
-
Consumer<T> action = actions.poll();
|
|
39
|
-
while (action != null) {
|
|
40
|
-
action.apply(client);
|
|
41
|
-
action = actions.poll();
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
private void addActionToQueue(Consumer<T> consumer) {
|
|
47
|
-
actions.add(consumer);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
}
|
package/android/src/main/java/expo/modules/webbrowser/InternalCustomTabsActivitiesHelper.java
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
package expo.modules.webbrowser;
|
|
2
|
-
|
|
3
|
-
import android.app.Activity;
|
|
4
|
-
import android.content.Intent;
|
|
5
|
-
import android.content.pm.PackageManager;
|
|
6
|
-
import android.content.pm.ResolveInfo;
|
|
7
|
-
import android.net.Uri;
|
|
8
|
-
|
|
9
|
-
import expo.modules.core.ModuleRegistry;
|
|
10
|
-
import expo.modules.core.errors.CurrentActivityNotFoundException;
|
|
11
|
-
import expo.modules.core.interfaces.ActivityProvider;
|
|
12
|
-
import expo.modules.core.interfaces.Function;
|
|
13
|
-
import expo.modules.core.interfaces.InternalModule;
|
|
14
|
-
|
|
15
|
-
import java.util.ArrayList;
|
|
16
|
-
import java.util.Collection;
|
|
17
|
-
import java.util.Collections;
|
|
18
|
-
import java.util.LinkedHashSet;
|
|
19
|
-
import java.util.List;
|
|
20
|
-
|
|
21
|
-
import androidx.annotation.NonNull;
|
|
22
|
-
import androidx.annotation.Nullable;
|
|
23
|
-
import androidx.browser.customtabs.CustomTabsClient;
|
|
24
|
-
import androidx.browser.customtabs.CustomTabsIntent;
|
|
25
|
-
import expo.modules.webbrowser.error.PackageManagerNotFoundException;
|
|
26
|
-
|
|
27
|
-
import static androidx.browser.customtabs.CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION;
|
|
28
|
-
|
|
29
|
-
class InternalCustomTabsActivitiesHelper implements CustomTabsActivitiesHelper {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
private final static String DUMMY_URL = "https://expo.io";
|
|
33
|
-
|
|
34
|
-
private ModuleRegistry mModuleRegistry;
|
|
35
|
-
|
|
36
|
-
@NonNull
|
|
37
|
-
public static <T, R> ArrayList<R> mapCollectionToDistinctArrayList(Collection<? extends T> toMap, Function<T, R> mapper) {
|
|
38
|
-
LinkedHashSet<R> resultSet = new LinkedHashSet<>();
|
|
39
|
-
for (T element : toMap) {
|
|
40
|
-
resultSet.add(mapper.apply(element));
|
|
41
|
-
}
|
|
42
|
-
return new ArrayList<>(resultSet);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
@Override
|
|
46
|
-
public void onCreate(ModuleRegistry moduleRegistry) {
|
|
47
|
-
this.mModuleRegistry = moduleRegistry;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
@Override
|
|
51
|
-
@NonNull
|
|
52
|
-
public ArrayList<String> getCustomTabsResolvingActivities() throws PackageManagerNotFoundException, CurrentActivityNotFoundException {
|
|
53
|
-
return mapCollectionToDistinctArrayList(getResolvingActivities(createDefaultCustomTabsIntent()), resolveInfo -> resolveInfo.activityInfo.packageName);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
@Override
|
|
57
|
-
@NonNull
|
|
58
|
-
public ArrayList<String> getCustomTabsResolvingServices() throws PackageManagerNotFoundException, CurrentActivityNotFoundException {
|
|
59
|
-
return mapCollectionToDistinctArrayList(getPackageManager().queryIntentServices(createDefaultCustomTabsServiceIntent(), 0), resolveInfo -> resolveInfo.serviceInfo.packageName);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
@Override
|
|
63
|
-
@Nullable
|
|
64
|
-
public String getPreferredCustomTabsResolvingActivity(@Nullable List<String> packages) throws PackageManagerNotFoundException, CurrentActivityNotFoundException {
|
|
65
|
-
if (packages == null) packages = getCustomTabsResolvingActivities();
|
|
66
|
-
return CustomTabsClient.getPackageName(getCurrentActivity(), packages);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
@Override
|
|
70
|
-
@Nullable
|
|
71
|
-
public String getDefaultCustomTabsResolvingActivity() throws PackageManagerNotFoundException, CurrentActivityNotFoundException {
|
|
72
|
-
ResolveInfo info = getPackageManager().resolveActivity(createDefaultCustomTabsIntent(), 0);
|
|
73
|
-
return info == null ? null : info.activityInfo.packageName;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
@Override
|
|
77
|
-
public boolean canResolveIntent(@NonNull Intent intent) throws PackageManagerNotFoundException, CurrentActivityNotFoundException {
|
|
78
|
-
return getResolvingActivities(intent).size() > 0;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
public void startCustomTabs(Intent intent) throws CurrentActivityNotFoundException {
|
|
82
|
-
getCurrentActivity().startActivity(intent);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
private List<ResolveInfo> getResolvingActivities(@NonNull Intent intent) throws PackageManagerNotFoundException, CurrentActivityNotFoundException {
|
|
86
|
-
return getPackageManager().queryIntentActivities(intent, 0);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
private PackageManager getPackageManager() throws PackageManagerNotFoundException, CurrentActivityNotFoundException {
|
|
90
|
-
PackageManager pm = getCurrentActivity().getPackageManager();
|
|
91
|
-
if (pm == null) throw new PackageManagerNotFoundException();
|
|
92
|
-
else return pm;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
private Activity getCurrentActivity() throws CurrentActivityNotFoundException {
|
|
96
|
-
ActivityProvider activityProvider = mModuleRegistry.getModule(ActivityProvider.class);
|
|
97
|
-
if (activityProvider == null || activityProvider.getCurrentActivity() == null) {
|
|
98
|
-
throw new CurrentActivityNotFoundException();
|
|
99
|
-
}
|
|
100
|
-
return activityProvider.getCurrentActivity();
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
private Intent createDefaultCustomTabsIntent() {
|
|
104
|
-
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
|
|
105
|
-
CustomTabsIntent customTabsIntent = builder.build();
|
|
106
|
-
|
|
107
|
-
Intent intent = customTabsIntent.intent;
|
|
108
|
-
intent.setData(Uri.parse(DUMMY_URL));
|
|
109
|
-
return intent;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
private Intent createDefaultCustomTabsServiceIntent() {
|
|
113
|
-
Intent serviceIntent = new Intent();
|
|
114
|
-
serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION);
|
|
115
|
-
return serviceIntent;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
@Override
|
|
119
|
-
public void onDestroy() {
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
@Override
|
|
124
|
-
public List<? extends Class> getExportedInterfaces() {
|
|
125
|
-
return Collections.singletonList(CustomTabsActivitiesHelper.class);
|
|
126
|
-
}
|
|
127
|
-
}
|
package/android/src/main/java/expo/modules/webbrowser/InternalCustomTabsConnectionHelper.java
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
package expo.modules.webbrowser;
|
|
2
|
-
|
|
3
|
-
import android.content.ComponentName;
|
|
4
|
-
import android.content.Context;
|
|
5
|
-
import android.net.Uri;
|
|
6
|
-
import androidx.browser.customtabs.CustomTabsClient;
|
|
7
|
-
import androidx.browser.customtabs.CustomTabsServiceConnection;
|
|
8
|
-
import androidx.browser.customtabs.CustomTabsSession;
|
|
9
|
-
|
|
10
|
-
import expo.modules.core.interfaces.InternalModule;
|
|
11
|
-
import expo.modules.core.interfaces.LifecycleEventListener;
|
|
12
|
-
|
|
13
|
-
import java.util.Collections;
|
|
14
|
-
import java.util.List;
|
|
15
|
-
|
|
16
|
-
public class InternalCustomTabsConnectionHelper extends CustomTabsServiceConnection implements LifecycleEventListener, CustomTabsConnectionHelper {
|
|
17
|
-
|
|
18
|
-
private Context mContext;
|
|
19
|
-
private String mPackageName;
|
|
20
|
-
private DeferredClientActionsQueue<CustomTabsClient> clientActions = new DeferredClientActionsQueue<>();
|
|
21
|
-
private DeferredClientActionsQueue<CustomTabsSession> sessionActions = new DeferredClientActionsQueue<>();
|
|
22
|
-
|
|
23
|
-
InternalCustomTabsConnectionHelper(Context context) {
|
|
24
|
-
this.mContext = context;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
@Override
|
|
28
|
-
public void warmUp(String packageName) {
|
|
29
|
-
clientActions.executeOrQueueAction(client -> client.warmup(0));
|
|
30
|
-
ensureConnection(packageName);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
@Override
|
|
34
|
-
public void mayInitWithUrl(String packageName, Uri uri) {
|
|
35
|
-
sessionActions.executeOrQueueAction(session -> session.mayLaunchUrl(uri, null, null));
|
|
36
|
-
ensureConnection(packageName);
|
|
37
|
-
ensureSession();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
private void ensureSession() {
|
|
41
|
-
if (!sessionActions.hasClient()) {
|
|
42
|
-
clientActions.executeOrQueueAction(
|
|
43
|
-
client ->
|
|
44
|
-
sessionActions.setClient(client.newSession(null)));
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
@Override
|
|
49
|
-
public boolean coolDown(String packageName) {
|
|
50
|
-
if (packageName.equals(this.mPackageName)) {
|
|
51
|
-
unbindService();
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
private void ensureConnection(String packageName) {
|
|
58
|
-
if (this.mPackageName != null && !this.mPackageName.equals(packageName)) {
|
|
59
|
-
clearConnection();
|
|
60
|
-
}
|
|
61
|
-
if (!connectionStarted(packageName)) {
|
|
62
|
-
CustomTabsClient.bindCustomTabsService(getContext(), packageName, this);
|
|
63
|
-
this.mPackageName = packageName;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
private boolean connectionStarted(String packageName) {
|
|
68
|
-
return packageName.equals(this.mPackageName);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
@Override
|
|
72
|
-
public void onBindingDied(ComponentName componentName) {
|
|
73
|
-
if (componentName.getPackageName().equals(this.mPackageName)) {
|
|
74
|
-
clearConnection();
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
@Override
|
|
79
|
-
public void onCustomTabsServiceConnected(ComponentName componentName, CustomTabsClient client) {
|
|
80
|
-
if (componentName.getPackageName().equals(mPackageName)) {
|
|
81
|
-
clientActions.setClient(client);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
@Override
|
|
86
|
-
public void onServiceDisconnected(ComponentName componentName) {
|
|
87
|
-
if (componentName.getPackageName().equals(this.mPackageName)) {
|
|
88
|
-
clearConnection();
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
@Override
|
|
93
|
-
public void onHostResume() {
|
|
94
|
-
// do nothing
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
@Override
|
|
98
|
-
public void onHostPause() {
|
|
99
|
-
// do nothing
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
@Override
|
|
103
|
-
public void onHostDestroy() {
|
|
104
|
-
unbindService();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
private void unbindService() {
|
|
108
|
-
getContext().unbindService(this);
|
|
109
|
-
clearConnection();
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
private void clearConnection() {
|
|
113
|
-
this.mPackageName = null;
|
|
114
|
-
clientActions.clear();
|
|
115
|
-
sessionActions.clear();
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
private Context getContext() {
|
|
119
|
-
return mContext;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
@Override
|
|
123
|
-
public List<? extends Class> getExportedInterfaces() {
|
|
124
|
-
return Collections.singletonList(CustomTabsConnectionHelper.class);
|
|
125
|
-
}
|
|
126
|
-
}
|