diff --git a/CHANGELOG.md b/CHANGELOG.md index 79915a8..fc8142b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,10 +25,11 @@ in case of vulnerabilities. ### Added - Add custom size option to iOS formSheet Modal by [@ShaneMckenna23](https://github.com/ShaneMckenna23) ([#91](https://github.com/proyecto26/nativescript-inappbrowser/pull/91)). - Add `includeReferrer` to allow adding android package name as referrer for website to track by [@vincent-paing](https://github.com/vincent-paing) ([#95](https://github.com/proyecto26/nativescript-inappbrowser/pull/95)). +- Add `warmup` and `mayLaunchUrl` functions for optimization in Android by [@vincent-paing](https://github.com/vincent-paing) ([#97](https://github.com/proyecto26/nativescript-inappbrowser/pull/97)). ### Fixed - Complete migration to ns8 and fix build issues by [@rigor789](https://github.com/rigor789) ([#92](https://github.com/proyecto26/nativescript-inappbrowser/pull/92)). -- Fix support `Metadata Filtering` for Android by [@jcassidyav](https://github.com/jcassidyav) ([#93](https://github.com/proyecto26/nativescript-inappbrowser/pull/93)). +- Fix support for `Metadata Filtering` from Android by [@jcassidyav](https://github.com/jcassidyav) ([#93](https://github.com/proyecto26/nativescript-inappbrowser/pull/93)). ### Removed - Remove `QUERY_ALL_PACKAGES` permission by [@edusperoni](https://github.com/edusperoni) ([#87](https://github.com/proyecto26/nativescript-inappbrowser/pull/87)). diff --git a/README.md b/README.md index 3b6796b..8263c91 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,9 @@ Methods | Action `openAuth` | Opens the url with Safari in a modal on iOS using **SFAuthenticationSession/ASWebAuthenticationSession**, and Chrome in a new custom tab on Android. On iOS, the user will be asked whether to allow the app to authenticate using the given url **(OAuth flow with deep linking redirection)**. `closeAuth` | Dismisses the current authentication session. `isAvailable` | Detect if the device supports this plugin. +`onStart` | Initialize a bound background service so the application can communicate its intention to the browser. After the service is connected, the client can be used to Warms up the browser to make navigation faster and indicates that a given URL may be loaded in the future. - Android Only. +`warmup` | Warm up the browser process - Android Only. +`mayLaunchUrl` | Tells the browser of a likely future navigation to a URL. The most likely URL has to be specified first. Optionally, a list of other likely URLs can be provided. They are treated as less likely than the first one, and have to be sorted in decreasing priority order. These additional URLs may be ignored. All previous calls to this method will be deprioritized - Android Only. ### iOS Options @@ -194,6 +197,36 @@ import { InAppBrowser } from 'nativescript-inappbrowser'; ... ``` +### Android Optimizations + +On Android, you can warmup the in app browser client to make it launch siginificantly faster. To do so, add the following to your [Custom Android Activity](https://docs.nativescript.org/advanced-concepts.html#extending-android-activity). + +```ts +import { InAppBrowser } from "nativescript-inappbrowser"; +@NativeClass() +@JavaProxy("org.nativescript.demo.MainActivity") +export class Activity extends androidx.appcompat.app.AppCompatActivity { + public onCreate(): void { + // InAppBrowser initialization for CustomTabsServiceConnection + InAppBrowser.onStart(); + } +} +``` + +You can further optimize performance and pre-render pages [by providing the urls that the user is likely to open](https://developer.chrome.com/docs/android/custom-tabs/best-practices/#pre-render-content). + +```ts +constructor() { + super(); + // Do not call this every time the component render + InAppBrowser.mayLaunchUrl(this._url, [ + "https://twitter.com/NativeScript", + "https://github.com/NativeScript/NativeScript", + "https://openjsf.org" + ]); +} +``` + ### Authentication Flow using Deep Linking In order to redirect back to your application from a web browser, you must specify a unique URI to your app. To do this, diff --git a/demo/App_Resources/Android/src/main/AndroidManifest.xml b/demo/App_Resources/Android/src/main/AndroidManifest.xml index 8b4b9c8..9e9b2a6 100644 --- a/demo/App_Resources/Android/src/main/AndroidManifest.xml +++ b/demo/App_Resources/Android/src/main/AndroidManifest.xml @@ -27,7 +27,7 @@ android:launchMode="singleTask"> , + grantResults: Array + ): void { + this._callbacks.onRequestPermissionsResult( + this, + requestCode, + permissions, + grantResults, + undefined /*TODO: Enable if needed*/ + ); + } + + public onActivityResult( + requestCode: number, + resultCode: number, + data: android.content.Intent + ): void { + this._callbacks.onActivityResult( + this, + requestCode, + resultCode, + data, + super.onActivityResult + ); + } +} diff --git a/demo/app/home/home-view-model.ts b/demo/app/home/home-view-model.ts index d8d524a..7b5f8cc 100644 --- a/demo/app/home/home-view-model.ts +++ b/demo/app/home/home-view-model.ts @@ -11,6 +11,16 @@ export class HelloWorldModel extends Observable { // Initialize default values. this._url = "https://nativescript.org"; + if (InAppBrowser.warmup()) { + console.log("Warmup successful!"); + InAppBrowser.mayLaunchUrl(this._url, [ + "https://twitter.com/NativeScript", + "https://github.com/NativeScript/NativeScript", + "https://openjsf.org" + ]); + } else { + console.log("Warmup failed :("); + } } get url(): string { diff --git a/demo/webpack.config.js b/demo/webpack.config.js index 67fb28f..29f3fda 100644 --- a/demo/webpack.config.js +++ b/demo/webpack.config.js @@ -5,6 +5,10 @@ module.exports = (env) => { webpack.init(env); webpack.useConfig("typescript"); + env.appComponents = (env.appComponents || []).concat([ + "./app/activity.android", + ]); + webpack.chainWebpack((config) => { // shared demo code config.resolve.alias.set( diff --git a/src/ChromeTabsManagerActivity.ts b/src/ChromeTabsManagerActivity.ts index 7cbfc9e..9c203a6 100644 --- a/src/ChromeTabsManagerActivity.ts +++ b/src/ChromeTabsManagerActivity.ts @@ -7,13 +7,13 @@ import { BROWSER_TYPES } from "./InAppBrowser.common"; import { DISMISSED_EVENT } from "./utils.android"; import { log } from "./utils.common"; -export class ChromeTabsEvent extends Observable { +class ChromeTabsEvent extends Observable { public message: string; public resultType: string; public isError: boolean; } -export const BROWSER_ACTIVITY_EVENTS = new ChromeTabsEvent(); +const BROWSER_ACTIVITY_EVENTS = new ChromeTabsEvent(); const KEY_BROWSER_INTENT = "browserIntent"; const BROWSER_RESULT_TYPE = "browserResultType"; @@ -39,7 +39,7 @@ const notifyMessage = ( */ @NativeClass() @JavaProxy("com.proyecto26.inappbrowser.ChromeTabsManagerActivity") -export class ChromeTabsManagerActivity extends android.app.Activity { +class ChromeTabsManagerActivity extends android.app.Activity { private mOpened = false; private resultType = null; private isError = false; @@ -131,21 +131,27 @@ export class ChromeTabsManagerActivity extends android.app.Activity { } } -export const createStartIntent = ( - context: Context, - authIntent: Intent -): Intent => { +const createStartIntent = (context: Context, authIntent: Intent): Intent => { let intent = createBaseIntent(context); intent.putExtra(KEY_BROWSER_INTENT, authIntent); return intent; }; -export const createDismissIntent = (context: Context): Intent => { +const createDismissIntent = (context: Context): Intent => { let intent = createBaseIntent(context); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); return intent; }; -export const createBaseIntent = (context: Context): Intent => { +const createBaseIntent = (context: Context): Intent => { return new Intent(context, ChromeTabsManagerActivity.class); }; + +export { + BROWSER_ACTIVITY_EVENTS, + ChromeTabsEvent, + createStartIntent, + createDismissIntent, + createBaseIntent, + ChromeTabsManagerActivity, +}; diff --git a/src/CustomTabsServiceConnection.ts b/src/CustomTabsServiceConnection.ts new file mode 100644 index 0000000..faeee3f --- /dev/null +++ b/src/CustomTabsServiceConnection.ts @@ -0,0 +1,37 @@ +import Context = android.content.Context; +import ComponentName = android.content.ComponentName; +import CustomTabsClient = androidx.browser.customtabs.CustomTabsClient; +import Log = android.util.Log; + +import { CustomTabsServiceConnection } from "./utils.android"; +import { log } from "./utils.common"; + +@NativeClass() +class CustomTabsController extends CustomTabsServiceConnection { + private static readonly TAG = "CustomTabsController"; + private readonly context: WeakRef; + public static customTabsClient: CustomTabsClient; + constructor(context: Context) { + super(); + this.context = new WeakRef(context); + + return global.__native(this); + } + + onCustomTabsServiceConnected(_: ComponentName, client: CustomTabsClient) { + CustomTabsController.customTabsClient = client; + if (!client.warmup(long(0))) { + Log.e(CustomTabsController.TAG, "Couldn't warmup custom tabs client"); + } + const context = this.context.get(); + context.unbindService(this); + log("Custom tabs service connected"); + } + + onServiceDisconnected(_: ComponentName) { + CustomTabsController.customTabsClient = null; + log("Custom tabs service disconnected"); + } +} + +export { CustomTabsController }; diff --git a/src/InAppBrowser.android.ts b/src/InAppBrowser.android.ts index b51bea9..97cd2ef 100644 --- a/src/InAppBrowser.android.ts +++ b/src/InAppBrowser.android.ts @@ -7,42 +7,46 @@ import Context = android.content.Context; import BitmapFactory = android.graphics.BitmapFactory; import Browser = android.provider.Browser; import Pattern = java.util.regex.Pattern; +import ArrayList = java.util.ArrayList; +import Log = android.util.Log; import { Application, EventData, Utils } from "@nativescript/core"; import { - ChromeTabsEvent, BROWSER_ACTIVITY_EVENTS, - createStartIntent, + ChromeTabsEvent, createDismissIntent, + createStartIntent, } from "./ChromeTabsManagerActivity"; +import { CustomTabsController } from "./CustomTabsServiceConnection"; import { Animations, BrowserResult, + BROWSER_TYPES, getDefaultOptions, - InAppBrowserOptions, InAppBrowserClassMethods, - RedirectResolve, + InAppBrowserOptions, RedirectReject, - BROWSER_TYPES, + RedirectResolve, } from "./InAppBrowser.common"; import { + ARROW_BACK_BLACK, + ARROW_BACK_WHITE, Builder, - getDrawableId, - toolbarIsLight, + closeAuthSessionPolyfillAsync, + CustomTabsCallback, + CustomTabsClient, CustomTabsIntent, + CustomTabsService, DISMISSED_EVENT, - ARROW_BACK_WHITE, - ARROW_BACK_BLACK, + getDefaultBrowser, + getDrawableId, getPreferredPackages, openAuthSessionPolyfillAsync, - closeAuthSessionPolyfillAsync, + toolbarIsLight, } from "./utils.android"; - import { tryParseColor } from "./utils.common"; -declare let global: any; - -let InAppBrowserModuleInstance: InAppBrowserClassMethods; +let InAppBrowserModuleInstance: any; function setup() { @NativeClass() @@ -223,8 +227,7 @@ function setup() { intent.setPackage(packageName); } } else { - const packageName = - inAppBrowserOptions[InAppBrowserModule.KEY_BROWSER_PACKAGE]; + const packageName = getDefaultBrowser(context); intent.setPackage(packageName); } } catch (error) { @@ -412,6 +415,55 @@ function setup() { InAppBrowserModule.redirectResolve = null; InAppBrowserModule.redirectReject = null; } + + public onStart(): void { + const context = Utils.android.getApplicationContext() as Context; + const connection = new CustomTabsController(context); + const packageName = getDefaultBrowser(context); + if (packageName) { + CustomTabsClient.bindCustomTabsService( + context, + packageName, + connection + ); + } else { + Log.e(InAppBrowserModule.ERROR_CODE, "No browser supported to bind custom tab service"); + } + } + + public warmup(): boolean { + const customTabsClient = CustomTabsController.customTabsClient; + if (customTabsClient) { + return customTabsClient.warmup(long(0)); + } + return false; + } + + public mayLaunchUrl(mostLikelyUrl: string, otherUrls: Array): void { + const customTabsClient = CustomTabsController.customTabsClient; + if (customTabsClient) { + const customTabsSession = customTabsClient.newSession( + new CustomTabsCallback() + ); + if (customTabsSession != null) { + const otherUrlBundles = new ArrayList(otherUrls.length); + for (let index = 0; index < otherUrls.length; index++) { + const link = otherUrls[index]; + if (link) { + const bundle = new Bundle(); + bundle.putParcelable(CustomTabsService.KEY_URL, Uri.parse(link)); + otherUrlBundles.add(bundle); + } + } + + customTabsSession.mayLaunchUrl( + Uri.parse(mostLikelyUrl), + null, + otherUrlBundles + ); + } + } + } } return new InAppBrowserModule(); diff --git a/src/InAppBrowser.common.ts b/src/InAppBrowser.common.ts index ee3473a..da6ad21 100644 --- a/src/InAppBrowser.common.ts +++ b/src/InAppBrowser.common.ts @@ -77,15 +77,81 @@ export type OpenBrowserAsync = ( ) => Promise; export interface InAppBrowserClassMethods { + /** + * Opens the url with Safari in a modal on iOS using [`SFSafariViewController`](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller), + * or Chrome in a new [custom tab](https://developer.chrome.com/multidevice/android/customtabs) on Android. + * + * @param url The url to open in the web browser. + * @param options A dictionary of key-value pairs. + * + * @return The promise behaves differently based on the platform: + * - If the user closed the web browser, the Promise resolves with `{ type: 'cancel' }`. + * - If the browser is closed using `close`, the Promise resolves with `{ type: 'dismiss' }`. + */ open: OpenBrowserAsync; + /** + * Dismisses the presented web browser. + */ close: () => void; + /** + * # On iOS: + * Opens the url with Safari in a modal using `ASWebAuthenticationSession`. The user will be asked + * whether to allow the app to authenticate using the given url. + * + * # On Android: + * This will be done using a "custom Chrome tabs" browser and [activityResumedEvent](https://docs.nativescript.org/api-reference/classes/androidapplication#activityresumedevent), + * + * @param url The url to open in the web browser. This should be a login page. + * @param redirectUrl _Optional_ - The url to deep link back into your app. + * @param options _Optional_ - An object extending the InAppBrowser Options. + * + * @return + * - If the user does not permit the application to authenticate with the given url, the Promise fulfills with `{ type: 'cancel' }` object. + * - If the user closed the web browser, the Promise fulfills with `{ type: 'cancel' }` object. + * - If the browser is closed using `dismissBrowser`, the Promise fulfills with `{ type: 'dismiss' }` object. + */ openAuth: ( url: string, redirectUrl: string, options?: InAppBrowserOptions ) => Promise; + /** + * Dismisses the current authentication session + */ closeAuth: () => void; + /** + * Detect if the device supports this plugin. + */ isAvailable: () => Promise; + /** + * Initialize a bound background service so the application can communicate its intention to the browser. + * After the service is connected, the client can be used to warms up the browser to make navigation faster and indicates that a given URL may be loaded in the future. + * + * @platform android + */ + onStart(): void; + /** + * Warm up the browser process. + * Allows the browser application to pre-initialize itself in the background. + * Significantly speeds up URL opening in the browser. + * This is synchronous and can be called several times. + * + * @platform android + */ + warmup: () => boolean; + /** + * Tells the browser of a likely future navigation to a URL. + * The most likely URL has to be specified first. + * Optionally, a list of other likely URLs can be provided. + * They are treated as less likely than the first one, and have to be sorted in decreasing priority order. + * These additional URLs may be ignored. + * + * @param mostLikelyUrl Most likely URL, may be null if otherUrls is provided. + * @param otherUrls Other likely destinations, sorted in decreasing likelihood order. + * + * @platform android + */ + mayLaunchUrl: (mostLikelyUrl: string, otherUrls: Array) => void; } export type RedirectResolve = ( diff --git a/src/InAppBrowser.ios.ts b/src/InAppBrowser.ios.ts index e3aa018..f138869 100644 --- a/src/InAppBrowser.ios.ts +++ b/src/InAppBrowser.ios.ts @@ -303,6 +303,13 @@ function setup() { this.redirectResolve = null; this.redirectReject = null; } + onStart() {} + warmup() { + return false; + } + mayLaunchUrl(url: string, otherUrls: Array) { + log(`mayLaunchUrl is not supported on iOS. url: ${url}, otherUrls: ${otherUrls}`); + } } return InAppBrowserModule.new(); diff --git a/src/platforms/android/native-api-usage.json b/src/platforms/android/native-api-usage.json index 8bd939a..caf0225 100644 --- a/src/platforms/android/native-api-usage.json +++ b/src/platforms/android/native-api-usage.json @@ -2,32 +2,49 @@ "uses": [ "com.proyecto26*:*", "android.app:Activity*", + "android.app:Service*", "android.content:Context*", + "android.content:ComponentCallbacks2*", + "android.content:ComponentName*", "android.content:Intent*", + "android.content:ServiceConnection*", "android.content.pm:ResolveInfo*", "android.content.pm:PackageManager*", "android.content.res:Resources*", "android.graphics:BitmapFactory*", "android.graphics:Color*", + "android.graphics:Bitmap*", + "android.util:Log*", "android.net:Uri*", "android.os:Build*", "android.os:Bundle*", + "android.os:Parcelable*", "android.provider:Browser*", "android.text:TextUtils*", "android.nfc:NfcAdapter*", + "androidx.browser.customtabs:CustomTabsCallback*", "androidx.browser.customtabs:CustomTabsClient*", "androidx.browser.customtabs:CustomTabsIntent*", "androidx.browser.customtabs.CustomTabsIntent:Builder*", + "androidx.browser.customtabs:CustomTabsService*", + "androidx.browser.customtabs:CustomTabsServiceConnection*", + "androidx.browser.customtabs:CustomTabsSession*", "androidx.core.graphics:ColorUtils*", + "android.support.customtabs:CustomTabsCallback*", "android.support.customtabs:CustomTabsClient*", "android.support.customtabs:CustomTabsIntent*", "android.support.customtabs.CustomTabsIntent:Builder*", + "android.support.customtabs:CustomTabsService*", + "android.support.customtabs:CustomTabsServiceConnection*", + "android.support.customtabs:CustomTabsSession*", "android.support.customtabs.action:CustomTabsService*", "android.support.v4.graphics:ColorUtils*", "java.lang:Object*", + "java.lang:Long*", "java.lang.reflect:Method*", "java.util:List*", "java.util:Arrays*", + "java.util:ArrayList*", "java.util.regex:Pattern*", "java.util.regex:Matcher*" ] diff --git a/src/types/android.d.ts b/src/types/android.d.ts index 25ee076..a20ba4f 100644 --- a/src/types/android.d.ts +++ b/src/types/android.d.ts @@ -1,10 +1,28 @@ declare namespace android { export namespace support { export namespace customtabs { - export class CustomTabsClient { - static getPackageName(context: android.content.Context, list: java.util.List): string; + export class CustomTabsCallback extends java.lang.Object {} + export class CustomTabsSession extends java.lang.Object { + mayLaunchUrl( + url: android.net.Uri, + extras: android.os.Bundle, + otherLikelyBundles: java.util.List + ): boolean; } - export class CustomTabsIntent { + export class CustomTabsClient extends java.lang.Object { + static getPackageName( + context: android.content.Context, + packages: java.util.List + ): string; + static bindCustomTabsService( + context: android.content.Context, + packageName: string, + connection: CustomTabsServiceConnection + ): CustomTabsClient; + warmup(flags: java.lang.Long): boolean; + newSession(callback: CustomTabsCallback): CustomTabsSession; + } + export class CustomTabsIntent extends java.lang.Object { launchUrl(context: android.content.Context, url: android.net.Uri): void; intent: android.content.Intent; static NO_TITLE: number; @@ -13,9 +31,8 @@ declare namespace android { startAnimationBundle: android.os.Bundle; } namespace CustomTabsIntent { - export class Builder { - constructor(); - build(): android.support.customtabs.CustomTabsIntent; + export class Builder extends java.lang.Object { + build(): CustomTabsIntent; setShowTitle(showTitle: boolean): this; setToolbarColor(color: number): this; setSecondaryToolbarColor(color: number): this; @@ -23,11 +40,29 @@ declare namespace android { setNavigationBarDividerColor(color: number): this; addDefaultShareMenuItem(): this; enableUrlBarHiding(): this; - setStartAnimations(context: android.content.Context, enterResId: number, exitResId: number): this; - setExitAnimations(context: android.content.Context, enterResId: number, exitResId: number): this; + setStartAnimations( + context: android.content.Context, + enterResId: number, + exitResId: number + ): this; + setExitAnimations( + context: android.content.Context, + enterResId: number, + exitResId: number + ): this; setCloseButtonIcon(icon: android.graphics.Bitmap): this; } } + export class CustomTabsService extends android.app.Service { + static KEY_URL: string; + } + export class CustomTabsServiceConnection extends android.content + .ServiceConnection { + onCustomTabsServiceConnected( + name: android.content.ComponentName, + client: CustomTabsClient + ): void; + } } } } @@ -35,10 +70,28 @@ declare namespace android { declare namespace androidx { export namespace browser { export namespace customtabs { - export class CustomTabsClient { - static getPackageName(context: android.content.Context, list: java.util.List): string; + export class CustomTabsCallback extends java.lang.Object {} + export class CustomTabsSession extends java.lang.Object { + mayLaunchUrl( + url: android.net.Uri, + extras: android.os.Bundle, + otherLikelyBundles: java.util.List + ): boolean; + } + export class CustomTabsClient extends java.lang.Object { + static getPackageName( + context: android.content.Context, + packages: java.util.List + ): string; + static bindCustomTabsService( + context: android.content.Context, + packageName: string, + connection: CustomTabsServiceConnection + ): void; + warmup(flags: java.lang.Long): boolean; + newSession(callback: CustomTabsCallback): CustomTabsSession; } - export class CustomTabsIntent { + export class CustomTabsIntent extends java.lang.Object { launchUrl(context: android.content.Context, url: android.net.Uri): void; intent: android.content.Intent; static NO_TITLE: number; @@ -47,9 +100,8 @@ declare namespace androidx { startAnimationBundle: android.os.Bundle; } namespace CustomTabsIntent { - export class Builder { - constructor(); - build(): android.support.customtabs.CustomTabsIntent; + export class Builder extends java.lang.Object { + build(): CustomTabsIntent; setShowTitle(showTitle: boolean): this; setToolbarColor(color: number): this; setSecondaryToolbarColor(color: number): this; @@ -57,11 +109,29 @@ declare namespace androidx { setNavigationBarDividerColor(color: number): this; addDefaultShareMenuItem(): this; enableUrlBarHiding(): this; - setStartAnimations(context: android.content.Context, enterResId: number, exitResId: number): this; - setExitAnimations(context: android.content.Context, enterResId: number, exitResId: number): this; + setStartAnimations( + context: android.content.Context, + enterResId: number, + exitResId: number + ): this; + setExitAnimations( + context: android.content.Context, + enterResId: number, + exitResId: number + ): this; setCloseButtonIcon(icon: android.graphics.Bitmap): this; } } + export class CustomTabsService extends android.app.Service { + static KEY_URL: string; + } + export class CustomTabsServiceConnection extends android.content + .ServiceConnection { + onCustomTabsServiceConnected( + name: android.content.ComponentName, + client: CustomTabsClient + ): void; + } } } -} \ No newline at end of file +} diff --git a/src/utils.android.ts b/src/utils.android.ts index d525bde..55910dc 100644 --- a/src/utils.android.ts +++ b/src/utils.android.ts @@ -8,20 +8,24 @@ import List = java.util.List; import Arrays = java.util.Arrays; import { - Utils, + AndroidActivityEventData, + AndroidApplication, Application, ApplicationEventData, - AndroidApplication, - AndroidActivityEventData, + Utils, } from "@nativescript/core"; import { - RedirectResult, - OpenBrowserAsync, AuthSessionResult, BROWSER_TYPES, InAppBrowserOptions, + OpenBrowserAsync, + RedirectResult, } from "./InAppBrowser.common"; +export function useAndroidX() { + return global.androidx && global.androidx.browser; +} + export type Builder = androidx.browser.customtabs.CustomTabsIntent.Builder; export const CustomTabsIntent = ( useAndroidX() ? androidx.browser : android.support @@ -29,9 +33,20 @@ export const CustomTabsIntent = ( export const CustomTabsClient = ( useAndroidX() ? androidx.browser : android.support ).customtabs.CustomTabsClient; +export const CustomTabsServiceConnection = ( + useAndroidX() ? androidx.browser : android.support +).customtabs.CustomTabsServiceConnection; +export const CustomTabsService = ( + useAndroidX() ? androidx.browser : android.support +).customtabs.CustomTabsService; +export const CustomTabsCallback = ( + useAndroidX() ? androidx.browser : android.support +).customtabs.CustomTabsCallback; + export const ColorUtils: typeof androidx.core.graphics.ColorUtils = ( useAndroidX() ? androidx.core.graphics : (android.support.v4.graphics as any) ).ColorUtils; + export const CHROME_PACKAGE_STABLE = "com.android.chrome"; export const CHROME_PACKAGE_BETA = "com.chrome.beta"; export const CHROME_PACKAGE_DEV = "com.chrome.dev"; @@ -53,10 +68,6 @@ let initialUrl = ""; export const getDrawableId = Utils.ad.resources.getDrawableId; -export function useAndroidX() { - return global.androidx && global.androidx.browser; -} - /** * Get the url when the app is opened and clear the data for security concerns. * @param activity - Current Android Activity.