From 8e9c10246aa18e833be590b467eab828465c56f4 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Tue, 25 Oct 2022 11:18:53 +0200 Subject: [PATCH] Added startAnimations, exitAnimations, navigationBarColor, navigationBarDividerColor, secondaryToolbarColor ChromeSafariBrowser settings for Android, Added getVariationsHeader WebView static method, All ChromeSafariBrowserSettings properties are optionals --- CHANGELOG.md | 5 +- .../InAppWebViewStatic.java | 8 + .../ChromeCustomTabsActivity.java | 49 ++- .../ChromeCustomTabsChannelDelegate.java | 13 +- .../ChromeCustomTabsSettings.java | 39 +++ .../CustomTabActivityHelper.java | 19 + .../TrustedWebActivity.java | 6 +- .../types/AndroidResource.java | 103 ++++++ .../custom_action_button.dart | 11 +- .../custom_menu_item.dart | 4 +- .../chrome_safari_browser/custom_tabs.dart | 40 ++- .../chrome_safari_browser/main.dart | 2 + .../chrome_safari_browser/open_and_close.dart | 33 +- .../sf_safari_view_controller.dart | 43 +++ .../trusted_web_activity.dart | 26 +- example/integration_test/util.dart | 38 +- .../SafariBrowserSettings.swift | 2 +- lib/src/android/webview_feature.dart | 5 + lib/src/android/webview_feature.g.dart | 5 + .../chrome_safari_browser.dart | 26 +- .../chrome_safari_browser_settings.dart | 207 +++++------ .../chrome_safari_browser_settings.g.dart | 330 ++++++++++++++++++ lib/src/chrome_safari_browser/main.dart | 6 +- .../in_app_webview_controller.dart | 18 + lib/src/types/android_resource.dart | 33 ++ lib/src/types/android_resource.g.dart | 66 ++++ lib/src/types/main.dart | 3 +- scripts/test.sh | 6 +- test_node_server/index.js | 13 + 29 files changed, 990 insertions(+), 169 deletions(-) create mode 100644 android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/AndroidResource.java create mode 100644 example/integration_test/chrome_safari_browser/sf_safari_view_controller.dart create mode 100644 lib/src/chrome_safari_browser/chrome_safari_browser_settings.g.dart create mode 100644 lib/src/types/android_resource.dart create mode 100644 lib/src/types/android_resource.g.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 857d4841..a5e6418d 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,13 +3,16 @@ - Added `headers`, `otherLikelyURLs` arguments on `ChromeSafariBrowser.open` method for Android - Added `onNavigationEvent`, `onServiceConnected`, `onRelationshipValidationResult` events on `ChromeSafariBrowser` for Android - Added `mayLaunchUrl`, `launchUrl`, `updateActionButton`, `validateRelationship` methods on `ChromeSafariBrowser` for Android +- Added `startAnimations`, `exitAnimations`, `navigationBarColor`, `navigationBarDividerColor`, `secondaryToolbarColor` ChromeSafariBrowser settings for Android - Added `didLoadSuccessfully` optional argument on `ChromeSafariBrowser.onCompletedInitialLoad` event for iOS - Added `onInitialLoadDidRedirect`, `onWillOpenInBrowser` events on `ChromeSafariBrowser` for iOS - Added `clearWebsiteData`, `prewarmConnections`, `invalidatePrewarmingToken` static methods on `ChromeSafariBrowser` for iOS +- Added `getVariationsHeader` WebView static method ### BREAKING CHANGES - `ChromeSafariBrowser.onCompletedInitialLoad` event has an optional argument +- All `ChromeSafariBrowserSettings` properties are optionals ## 6.0.0-beta.8 @@ -78,7 +81,7 @@ - Added `PullToRefreshController.isEnabled` method - Updated `getMetaThemeColor` on iOS 15.0+ - Deprecated `onLoadError` for `onReceivedError`. `onReceivedError` will be called also for subframes -- Deprecated `onLoadHttpError` for `onReceivedError`. `onReceivedHttpError` will be called also for subframes +- Deprecated `onLoadHttpError` for `onReceivedHttpError`. `onReceivedHttpError` will be called also for subframes ### BREAKING CHANGES diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java index 816adb88..8ceea978 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java @@ -114,6 +114,14 @@ public class InAppWebViewStatic extends ChannelDelegateImpl { } result.success(true); break; + case "getVariationsHeader": + if (WebViewFeature.isFeatureSupported(WebViewFeature.GET_VARIATIONS_HEADER)) { + result.success(WebViewCompat.getVariationsHeader()); + } + else { + result.success(null); + } + break; default: result.notImplemented(); } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsActivity.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsActivity.java index 9b8908e6..0216c3a5 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsActivity.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsActivity.java @@ -21,6 +21,7 @@ import androidx.browser.customtabs.CustomTabsService; import androidx.browser.customtabs.CustomTabsSession; import com.pichillilorenzo.flutter_inappwebview.R; +import com.pichillilorenzo.flutter_inappwebview.types.AndroidResource; import com.pichillilorenzo.flutter_inappwebview.types.CustomTabsActionButton; import com.pichillilorenzo.flutter_inappwebview.types.CustomTabsMenuItem; import com.pichillilorenzo.flutter_inappwebview.types.Disposable; @@ -156,35 +157,27 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable { public void launchUrl(@NonNull String url, @Nullable Map headers, @Nullable List otherLikelyURLs) { - Uri uri = mayLaunchUrl(url, headers, otherLikelyURLs); + mayLaunchUrl(url, otherLikelyURLs); builder = new CustomTabsIntent.Builder(customTabsSession); prepareCustomTabs(); CustomTabsIntent customTabsIntent = builder.build(); prepareCustomTabsIntent(customTabsIntent); - CustomTabActivityHelper.openCustomTab(this, customTabsIntent, uri, CHROME_CUSTOM_TAB_REQUEST_CODE); + CustomTabActivityHelper.openCustomTab(this, customTabsIntent, Uri.parse(url), headers, CHROME_CUSTOM_TAB_REQUEST_CODE); } - public Uri mayLaunchUrl(@NonNull String url, - @Nullable Map headers, - @Nullable List otherLikelyURLs) { - Uri uri = Uri.parse(url); - Bundle bundleHeaders = new Bundle(); - if (headers != null) { - for (Map.Entry header : headers.entrySet()) { - bundleHeaders.putString(header.getKey(), header.getValue()); - } - } + public boolean mayLaunchUrl(@Nullable String url, @Nullable List otherLikelyURLs) { + Uri uri = url != null ? Uri.parse(url) : null; + List bundleOtherLikelyURLs = new ArrayList<>(); if (otherLikelyURLs != null) { + Bundle bundleOtherLikelyURL = new Bundle(); for (String otherLikelyURL : otherLikelyURLs) { - Bundle bundleOtherLikelyURL = new Bundle(); bundleOtherLikelyURL.putString(CustomTabsService.KEY_URL, otherLikelyURL); } } - customTabActivityHelper.mayLaunchUrl(uri, bundleHeaders, bundleOtherLikelyURLs); - return uri; + return customTabActivityHelper.mayLaunchUrl(uri, null, bundleOtherLikelyURLs); } public void customTabsConnected() { @@ -206,16 +199,34 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable { builder.setShareState(customSettings.shareState); } + CustomTabColorSchemeParams.Builder defaultColorSchemeBuilder = new CustomTabColorSchemeParams.Builder(); if (customSettings.toolbarBackgroundColor != null && !customSettings.toolbarBackgroundColor.isEmpty()) { - CustomTabColorSchemeParams.Builder defaultColorSchemeBuilder = new CustomTabColorSchemeParams.Builder(); - builder.setDefaultColorSchemeParams(defaultColorSchemeBuilder - .setToolbarColor(Color.parseColor(customSettings.toolbarBackgroundColor)) - .build()); + defaultColorSchemeBuilder.setToolbarColor(Color.parseColor(customSettings.toolbarBackgroundColor)); } + if (customSettings.navigationBarColor != null && !customSettings.navigationBarColor.isEmpty()) { + defaultColorSchemeBuilder.setNavigationBarColor(Color.parseColor(customSettings.navigationBarColor)); + } + if (customSettings.navigationBarDividerColor != null && !customSettings.navigationBarDividerColor.isEmpty()) { + defaultColorSchemeBuilder.setNavigationBarDividerColor(Color.parseColor(customSettings.navigationBarDividerColor)); + } + if (customSettings.secondaryToolbarColor != null && !customSettings.secondaryToolbarColor.isEmpty()) { + defaultColorSchemeBuilder.setSecondaryToolbarColor(Color.parseColor(customSettings.secondaryToolbarColor)); + } + builder.setDefaultColorSchemeParams(defaultColorSchemeBuilder.build()); builder.setShowTitle(customSettings.showTitle); builder.setUrlBarHidingEnabled(customSettings.enableUrlBarHiding); builder.setInstantAppsEnabled(customSettings.instantAppsEnabled); + if (customSettings.startAnimations.size() == 2) { + builder.setStartAnimations(this, + customSettings.startAnimations.get(0).getIdentifier(this), + customSettings.startAnimations.get(1).getIdentifier(this)); + } + if (customSettings.exitAnimations.size() == 2) { + builder.setExitAnimations(this, + customSettings.exitAnimations.get(0).getIdentifier(this), + customSettings.exitAnimations.get(1).getIdentifier(this)); + } for (CustomTabsMenuItem menuItem : menuItems) { builder.addMenuItem(menuItem.getLabel(), diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsChannelDelegate.java index 22160e97..1af27d3b 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsChannelDelegate.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsChannelDelegate.java @@ -48,14 +48,8 @@ public class ChromeCustomTabsChannelDelegate extends ChannelDelegateImpl { case "mayLaunchUrl": if (chromeCustomTabsActivity != null) { String url = (String) call.argument("url"); - if (url != null) { - Map headers = (Map) call.argument("headers"); - List otherLikelyURLs = (List) call.argument("otherLikelyURLs"); - chromeCustomTabsActivity.mayLaunchUrl(url, headers, otherLikelyURLs); - result.success(true); - } else { - result.success(false); - } + List otherLikelyURLs = (List) call.argument("otherLikelyURLs"); + result.success(chromeCustomTabsActivity.mayLaunchUrl(url, otherLikelyURLs)); } else { result.success(false); } @@ -74,8 +68,7 @@ public class ChromeCustomTabsChannelDelegate extends ChannelDelegateImpl { if (chromeCustomTabsActivity != null && chromeCustomTabsActivity.customTabsSession != null) { Integer relation = (Integer) call.argument("relation"); String origin = (String) call.argument("origin"); - chromeCustomTabsActivity.customTabsSession.validateRelationship(relation, Uri.parse(origin), null); - result.success(true); + result.success(chromeCustomTabsActivity.customTabsSession.validateRelationship(relation, Uri.parse(origin), null)); } else { result.success(false); } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsSettings.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsSettings.java index 3867020e..10f3e707 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsSettings.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsSettings.java @@ -9,6 +9,7 @@ import androidx.browser.trusted.ScreenOrientation; import androidx.browser.trusted.TrustedWebActivityDisplayMode; import com.pichillilorenzo.flutter_inappwebview.ISettings; +import com.pichillilorenzo.flutter_inappwebview.types.AndroidResource; import java.util.ArrayList; import java.util.HashMap; @@ -25,6 +26,12 @@ public class ChromeCustomTabsSettings implements ISettings additionalTrustedOrigins = new ArrayList<>(); public TrustedWebActivityDisplayMode displayMode = null; public Integer screenOrientation = ScreenOrientation.DEFAULT; + public List startAnimations = new ArrayList<>(); + public List exitAnimations = new ArrayList<>(); @NonNull @Override @@ -59,6 +68,15 @@ public class ChromeCustomTabsSettings implements ISettings> startAnimationsList = (List>) value; + for (Map startAnimation : startAnimationsList) { + AndroidResource androidResource = AndroidResource.fromMap(startAnimation); + if (androidResource != null) { + startAnimations.add(AndroidResource.fromMap(startAnimation)); + } + } + break; + case "exitAnimations": + List> exitAnimationsList = (List>) value; + for (Map exitAnimation : exitAnimationsList) { + AndroidResource androidResource = AndroidResource.fromMap(exitAnimation); + if (androidResource != null) { + exitAnimations.add(AndroidResource.fromMap(exitAnimation)); + } + } + break; } } @@ -115,6 +151,9 @@ public class ChromeCustomTabsSettings implements ISettings headers, int requestCode) { customTabsIntent.intent.setData(uri); + if (headers != null) { + Bundle bundleHeaders = new Bundle(); + for (Map.Entry header : headers.entrySet()) { + bundleHeaders.putString(header.getKey(), header.getValue()); + } + customTabsIntent.intent.putExtra(Browser.EXTRA_HEADERS, bundleHeaders); + } activity.startActivityForResult(customTabsIntent.intent, requestCode); } public static void openCustomTab(Activity activity, TrustedWebActivityIntent trustedWebActivityIntent, Uri uri, + @Nullable Map headers, int requestCode) { trustedWebActivityIntent.getIntent().setData(uri); + if (headers != null) { + Bundle bundleHeaders = new Bundle(); + for (Map.Entry header : headers.entrySet()) { + bundleHeaders.putString(header.getKey(), header.getValue()); + } + trustedWebActivityIntent.getIntent().putExtra(Browser.EXTRA_HEADERS, bundleHeaders); + } activity.startActivityForResult(trustedWebActivityIntent.getIntent(), requestCode); } + public static boolean isAvailable(Activity activity) { return CustomTabsHelper.getPackageNameToUse(activity) != null; diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/TrustedWebActivity.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/TrustedWebActivity.java index cd8721e2..b86578a0 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/TrustedWebActivity.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/TrustedWebActivity.java @@ -31,15 +31,16 @@ public class TrustedWebActivity extends ChromeCustomTabsActivity { if (customTabsSession == null) { return; } + Uri uri = Uri.parse(url); - Uri uri = mayLaunchUrl(url, headers, otherLikelyURLs); + mayLaunchUrl(url, otherLikelyURLs); builder = new TrustedWebActivityIntentBuilder(uri); prepareCustomTabs(); TrustedWebActivityIntent trustedWebActivityIntent = builder.build(customTabsSession); prepareCustomTabsIntent(trustedWebActivityIntent); - CustomTabActivityHelper.openCustomTab(this, trustedWebActivityIntent, uri, CHROME_CUSTOM_TAB_REQUEST_CODE); + CustomTabActivityHelper.openCustomTab(this, trustedWebActivityIntent, uri, headers, CHROME_CUSTOM_TAB_REQUEST_CODE); } @Override @@ -48,7 +49,6 @@ public class TrustedWebActivity extends ChromeCustomTabsActivity { if (initialUrl != null) { launchUrl(initialUrl, initialHeaders, initialOtherLikelyURLs); } - } private void prepareCustomTabs() { diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/AndroidResource.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/AndroidResource.java new file mode 100644 index 00000000..ba145359 --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/AndroidResource.java @@ -0,0 +1,103 @@ +package com.pichillilorenzo.flutter_inappwebview.types; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.HashMap; +import java.util.Map; + +public class AndroidResource { + @NonNull + String name; + @Nullable + String defType; + @Nullable + String defPackage; + + public AndroidResource(@NonNull String name, @Nullable String defType, @Nullable String defPackage) { + this.name = name; + this.defType = defType; + this.defPackage = defPackage; + } + + @Nullable + public static AndroidResource fromMap(@Nullable Map map) { + if (map == null) { + return null; + } + String name = (String) map.get("name"); + String defType = (String) map.get("defType"); + String defPackage = (String) map.get("defPackage"); + return new AndroidResource(name, defType, defPackage); + } + + public Map toMap() { + Map urlRequestMap = new HashMap<>(); + urlRequestMap.put("name", name); + urlRequestMap.put("defType", defType); + urlRequestMap.put("defPackage", defPackage); + return urlRequestMap; + } + + @NonNull + public String getName() { + return name; + } + + public void setName(@NonNull String name) { + this.name = name; + } + + @Nullable + public String getDefType() { + return defType; + } + + public void setDefType(@Nullable String defType) { + this.defType = defType; + } + + @Nullable + public String getDefPackage() { + return defPackage; + } + + public void setDefPackage(@Nullable String defPackage) { + this.defPackage = defPackage; + } + + public int getIdentifier(@NonNull Context ctx) { + return ctx.getResources().getIdentifier(name, defType, defPackage); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + AndroidResource that = (AndroidResource) o; + + if (!name.equals(that.name)) return false; + if (defType != null ? !defType.equals(that.defType) : that.defType != null) return false; + return defPackage != null ? defPackage.equals(that.defPackage) : that.defPackage == null; + } + + @Override + public int hashCode() { + int result = name.hashCode(); + result = 31 * result + (defType != null ? defType.hashCode() : 0); + result = 31 * result + (defPackage != null ? defPackage.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "AndroidResource{" + + "name='" + name + '\'' + + ", type='" + defType + '\'' + + ", defPackage='" + defPackage + '\'' + + '}'; + } +} diff --git a/example/integration_test/chrome_safari_browser/custom_action_button.dart b/example/integration_test/chrome_safari_browser/custom_action_button.dart index 7b771231..db3ffa47 100644 --- a/example/integration_test/chrome_safari_browser/custom_action_button.dart +++ b/example/integration_test/chrome_safari_browser/custom_action_button.dart @@ -13,10 +13,12 @@ void customActionButton() { TargetPlatform.android, ].contains(defaultTargetPlatform); - test('add custom action button', () async { + test('add custom action button and update icon', () async { var chromeSafariBrowser = MyChromeSafariBrowser(); var actionButtonIcon = await rootBundle.load('test_assets/images/flutter-logo.png'); + var actionButtonIcon2 = + await rootBundle.load('test_assets/images/flutter-logo.jpg'); chromeSafariBrowser.setActionButton(ChromeSafariBrowserActionButton( id: 1, description: 'Action Button description', @@ -25,15 +27,18 @@ void customActionButton() { expect(chromeSafariBrowser.isOpened(), false); await chromeSafariBrowser.open(url: TEST_URL_1); - await chromeSafariBrowser.browserCreated.future; + await chromeSafariBrowser.opened.future; expect(chromeSafariBrowser.isOpened(), true); expect(() async { await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1); }, throwsA(isInstanceOf())); await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); + await chromeSafariBrowser.updateActionButton( + icon: actionButtonIcon2.buffer.asUint8List(), + description: 'New Action Button description'); await chromeSafariBrowser.close(); - await chromeSafariBrowser.browserClosed.future; + await chromeSafariBrowser.closed.future; expect(chromeSafariBrowser.isOpened(), false); }, skip: shouldSkip); } diff --git a/example/integration_test/chrome_safari_browser/custom_menu_item.dart b/example/integration_test/chrome_safari_browser/custom_menu_item.dart index 3f002f76..02bc4350 100644 --- a/example/integration_test/chrome_safari_browser/custom_menu_item.dart +++ b/example/integration_test/chrome_safari_browser/custom_menu_item.dart @@ -18,7 +18,7 @@ void customMenuItem() { expect(chromeSafariBrowser.isOpened(), false); await chromeSafariBrowser.open(url: TEST_URL_1); - await chromeSafariBrowser.browserCreated.future; + await chromeSafariBrowser.opened.future; expect(chromeSafariBrowser.isOpened(), true); expect(() async { await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1); @@ -26,7 +26,7 @@ void customMenuItem() { await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); await chromeSafariBrowser.close(); - await chromeSafariBrowser.browserClosed.future; + await chromeSafariBrowser.closed.future; expect(chromeSafariBrowser.isOpened(), false); }, skip: shouldSkip); } diff --git a/example/integration_test/chrome_safari_browser/custom_tabs.dart b/example/integration_test/chrome_safari_browser/custom_tabs.dart index fbfe5496..dd1a419c 100644 --- a/example/integration_test/chrome_safari_browser/custom_tabs.dart +++ b/example/integration_test/chrome_safari_browser/custom_tabs.dart @@ -20,7 +20,7 @@ void customTabs() { await chromeSafariBrowser.open( url: TEST_URL_1, settings: ChromeSafariBrowserSettings(isSingleInstance: true)); - await chromeSafariBrowser.browserCreated.future; + await expectLater(chromeSafariBrowser.opened.future, completes); expect(chromeSafariBrowser.isOpened(), true); expect(() async { await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1); @@ -28,7 +28,43 @@ void customTabs() { await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); await chromeSafariBrowser.close(); - await chromeSafariBrowser.browserClosed.future; + await expectLater(chromeSafariBrowser.closed.future, completes); + expect(chromeSafariBrowser.isOpened(), false); + }); + + test('mayLaunchUrl and launchUrl', () async { + var chromeSafariBrowser = MyChromeSafariBrowser(); + expect(chromeSafariBrowser.isOpened(), false); + + await chromeSafariBrowser.open(); + await expectLater(chromeSafariBrowser.serviceConnected.future, completes); + expect(chromeSafariBrowser.isOpened(), true); + expect( + await chromeSafariBrowser.mayLaunchUrl( + url: TEST_URL_1, otherLikelyURLs: [TEST_CROSS_PLATFORM_URL_1]), + true); + await chromeSafariBrowser.launchUrl( + url: TEST_URL_1, + headers: {'accept-language': 'it-IT'}, + otherLikelyURLs: [TEST_CROSS_PLATFORM_URL_1]); + await expectLater(chromeSafariBrowser.opened.future, completes); + await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); + await chromeSafariBrowser.close(); + await expectLater(chromeSafariBrowser.closed.future, completes); + expect(chromeSafariBrowser.isOpened(), false); + }); + + test('onNavigationEvent', () async { + var chromeSafariBrowser = MyChromeSafariBrowser(); + expect(chromeSafariBrowser.isOpened(), false); + + await chromeSafariBrowser.open(url: TEST_URL_1); + await expectLater(chromeSafariBrowser.opened.future, completes); + expect(chromeSafariBrowser.isOpened(), true); + await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); + expect(await chromeSafariBrowser.navigationEvent.future, isNotNull); + await chromeSafariBrowser.close(); + await expectLater(chromeSafariBrowser.closed.future, completes); expect(chromeSafariBrowser.isOpened(), false); }); }, skip: shouldSkip); diff --git a/example/integration_test/chrome_safari_browser/main.dart b/example/integration_test/chrome_safari_browser/main.dart index a3cd7c44..9acbe741 100644 --- a/example/integration_test/chrome_safari_browser/main.dart +++ b/example/integration_test/chrome_safari_browser/main.dart @@ -6,6 +6,7 @@ import 'custom_menu_item.dart'; import 'custom_tabs.dart'; import 'open_and_close.dart'; import 'trusted_web_activity.dart'; +import 'sf_safari_view_controller.dart'; void main() { final shouldSkip = @@ -17,5 +18,6 @@ void main() { customActionButton(); customTabs(); trustedWebActivity(); + sfSafariViewController(); }, skip: shouldSkip); } diff --git a/example/integration_test/chrome_safari_browser/open_and_close.dart b/example/integration_test/chrome_safari_browser/open_and_close.dart index 7ebdb5dd..02d34976 100644 --- a/example/integration_test/chrome_safari_browser/open_and_close.dart +++ b/example/integration_test/chrome_safari_browser/open_and_close.dart @@ -15,8 +15,35 @@ void openAndClose() { var chromeSafariBrowser = MyChromeSafariBrowser(); expect(chromeSafariBrowser.isOpened(), false); - await chromeSafariBrowser.open(url: TEST_URL_1); - await chromeSafariBrowser.browserCreated.future; + await chromeSafariBrowser.open( + url: TEST_URL_1, + settings: ChromeSafariBrowserSettings( + shareState: CustomTabsShareState.SHARE_STATE_OFF, + startAnimations: [ + AndroidResource( + name: "slide_in_left", + defType: "anim", + defPackage: "android"), + AndroidResource( + name: "slide_out_right", + defType: "anim", + defPackage: "android") + ], + exitAnimations: [ + AndroidResource( + name: "abc_slide_in_top", + defType: "anim", + defPackage: + "com.pichillilorenzo.flutter_inappwebviewexample"), + AndroidResource( + name: "abc_slide_out_top", + defType: "anim", + defPackage: "com.pichillilorenzo.flutter_inappwebviewexample") + ], + keepAliveEnabled: true, + dismissButtonStyle: DismissButtonStyle.CLOSE, + presentationStyle: ModalPresentationStyle.OVER_FULL_SCREEN)); + await chromeSafariBrowser.opened.future; expect(chromeSafariBrowser.isOpened(), true); expect(() async { await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1); @@ -24,7 +51,7 @@ void openAndClose() { await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); await chromeSafariBrowser.close(); - await chromeSafariBrowser.browserClosed.future; + await chromeSafariBrowser.closed.future; expect(chromeSafariBrowser.isOpened(), false); }, skip: shouldSkip); } diff --git a/example/integration_test/chrome_safari_browser/sf_safari_view_controller.dart b/example/integration_test/chrome_safari_browser/sf_safari_view_controller.dart new file mode 100644 index 00000000..fc8ff915 --- /dev/null +++ b/example/integration_test/chrome_safari_browser/sf_safari_view_controller.dart @@ -0,0 +1,43 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../constants.dart'; +import '../util.dart'; + +void sfSafariViewController() { + final shouldSkip = kIsWeb + ? true + : ![ + TargetPlatform.android, + ].contains(defaultTargetPlatform); + + group('SF Safari View Controller', () { + test('onCompletedInitialLoad did load successfully', () async { + var chromeSafariBrowser = MyChromeSafariBrowser(); + expect(chromeSafariBrowser.isOpened(), false); + + await chromeSafariBrowser.open(url: TEST_URL_1); + await expectLater(chromeSafariBrowser.opened.future, completes); + expect(chromeSafariBrowser.isOpened(), true); + expect(() async { + await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1); + }, throwsA(isInstanceOf())); + + expect(await chromeSafariBrowser.firstPageLoaded.future, true); + await chromeSafariBrowser.close(); + await expectLater(chromeSafariBrowser.closed.future, completes); + expect(chromeSafariBrowser.isOpened(), false); + }); + + test('clearWebsiteData', () async { + await expectLater(ChromeSafariBrowser.clearWebsiteData(), completes); + }); + + test('create and invalidate Prewarming Token', () async { + final prewarmingToken = await ChromeSafariBrowser.prewarmConnections([TEST_URL_1]); + expect(prewarmingToken, isNotNull); + await expectLater(ChromeSafariBrowser.invalidatePrewarmingToken(prewarmingToken!), completes); + }); + }, skip: shouldSkip); +} diff --git a/example/integration_test/chrome_safari_browser/trusted_web_activity.dart b/example/integration_test/chrome_safari_browser/trusted_web_activity.dart index 99b23b27..09cc6e08 100644 --- a/example/integration_test/chrome_safari_browser/trusted_web_activity.dart +++ b/example/integration_test/chrome_safari_browser/trusted_web_activity.dart @@ -20,7 +20,7 @@ void trustedWebActivity() { await chromeSafariBrowser.open( url: TEST_URL_1, settings: ChromeSafariBrowserSettings(isTrustedWebActivity: true)); - await chromeSafariBrowser.browserCreated.future; + await chromeSafariBrowser.opened.future; expect(chromeSafariBrowser.isOpened(), true); expect(() async { await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1); @@ -28,7 +28,7 @@ void trustedWebActivity() { await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); await chromeSafariBrowser.close(); - await chromeSafariBrowser.browserClosed.future; + await chromeSafariBrowser.closed.future; expect(chromeSafariBrowser.isOpened(), false); }); @@ -40,7 +40,7 @@ void trustedWebActivity() { url: TEST_URL_1, settings: ChromeSafariBrowserSettings( isTrustedWebActivity: true, isSingleInstance: true)); - await chromeSafariBrowser.browserCreated.future; + await chromeSafariBrowser.opened.future; expect(chromeSafariBrowser.isOpened(), true); expect(() async { await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1); @@ -48,7 +48,25 @@ void trustedWebActivity() { await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); await chromeSafariBrowser.close(); - await chromeSafariBrowser.browserClosed.future; + await chromeSafariBrowser.closed.future; + expect(chromeSafariBrowser.isOpened(), false); + }); + + test('validate relationship', () async { + var chromeSafariBrowser = MyChromeSafariBrowser(); + expect(chromeSafariBrowser.isOpened(), false); + + await chromeSafariBrowser.open( + settings: ChromeSafariBrowserSettings(isTrustedWebActivity: true)); + await chromeSafariBrowser.serviceConnected.future; + expect(await chromeSafariBrowser.validateRelationship(relation: CustomTabsRelationType.USE_AS_ORIGIN, origin: TEST_CROSS_PLATFORM_URL_1), true); + expect(await chromeSafariBrowser.relationshipValidationResult.future, true); + await chromeSafariBrowser.launchUrl(url: TEST_CROSS_PLATFORM_URL_1); + await chromeSafariBrowser.opened.future; + expect(chromeSafariBrowser.isOpened(), true); + await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); + await chromeSafariBrowser.close(); + await chromeSafariBrowser.closed.future; expect(chromeSafariBrowser.isOpened(), false); }); }, skip: shouldSkip); diff --git a/example/integration_test/util.dart b/example/integration_test/util.dart index 530cadf2..5188d75f 100644 --- a/example/integration_test/util.dart +++ b/example/integration_test/util.dart @@ -54,22 +54,44 @@ class MyInAppBrowser extends InAppBrowser { } class MyChromeSafariBrowser extends ChromeSafariBrowser { - final Completer browserCreated = Completer(); - final Completer firstPageLoaded = Completer(); - final Completer browserClosed = Completer(); + final Completer serviceConnected = Completer(); + final Completer opened = Completer(); + final Completer firstPageLoaded = Completer(); + final Completer closed = Completer(); + final Completer navigationEvent = Completer(); + final Completer relationshipValidationResult = Completer(); @override - void onOpened() { - browserCreated.complete(); + void onServiceConnected() { + serviceConnected.complete(); } @override - void onCompletedInitialLoad() { - firstPageLoaded.complete(); + void onOpened() { + opened.complete(); + } + + @override + void onCompletedInitialLoad(didLoadSuccessfully) { + firstPageLoaded.complete(didLoadSuccessfully); + } + + @override + void onNavigationEvent(CustomTabsNavigationEventType? type) { + if (!navigationEvent.isCompleted) { + navigationEvent.complete(type); + } + } + + + @override + void onRelationshipValidationResult( + CustomTabsRelationType? relation, Uri? requestedOrigin, bool result) { + relationshipValidationResult.complete(result); } @override void onClosed() { - browserClosed.complete(); + closed.complete(); } } diff --git a/ios/Classes/SafariViewController/SafariBrowserSettings.swift b/ios/Classes/SafariViewController/SafariBrowserSettings.swift index dd9d1f8a..3ff9c07c 100755 --- a/ios/Classes/SafariViewController/SafariBrowserSettings.swift +++ b/ios/Classes/SafariViewController/SafariBrowserSettings.swift @@ -17,7 +17,7 @@ public class SafariBrowserSettings: ISettings { var preferredBarTintColor: String? var preferredControlTintColor: String? var presentationStyle = 0 //fullscreen - var transitionStyle = 0 //crossDissolve + var transitionStyle = 0 //coverVertical override init(){ super.init() diff --git a/lib/src/android/webview_feature.dart b/lib/src/android/webview_feature.dart index 64510f7c..1b6e30e2 100644 --- a/lib/src/android/webview_feature.dart +++ b/lib/src/android/webview_feature.dart @@ -217,6 +217,11 @@ class WebViewFeature_ { const WebViewFeature_._internal( "ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY"); + ///This feature covers [InAppWebViewController.getVariationsHeader]. + static const GET_VARIATIONS_HEADER = + const WebViewFeature_._internal( + "GET_VARIATIONS_HEADER"); + ///Return whether a feature is supported at run-time. On devices running Android version `Build.VERSION_CODES.LOLLIPOP` and higher, ///this will check whether a feature is supported, depending on the combination of the desired feature, the Android version of device, ///and the WebView APK on the device. If running on a device with a lower API level, this will always return `false`. diff --git a/lib/src/android/webview_feature.g.dart b/lib/src/android/webview_feature.g.dart index 77964d4f..0ca4c03e 100644 --- a/lib/src/android/webview_feature.g.dart +++ b/lib/src/android/webview_feature.g.dart @@ -217,6 +217,10 @@ class WebViewFeature { WebViewFeature._internal('ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY', 'ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY'); + ///This feature covers [InAppWebViewController.getVariationsHeader]. + static const GET_VARIATIONS_HEADER = WebViewFeature._internal( + 'GET_VARIATIONS_HEADER', 'GET_VARIATIONS_HEADER'); + ///Set of all values of [WebViewFeature]. static final Set values = [ WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL, @@ -266,6 +270,7 @@ class WebViewFeature { WebViewFeature.ALGORITHMIC_DARKENING, WebViewFeature.REQUESTED_WITH_HEADER_CONTROL, WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, + WebViewFeature.GET_VARIATIONS_HEADER, ].toSet(); ///Gets a possible [WebViewFeature] instance from [String] value. diff --git a/lib/src/chrome_safari_browser/chrome_safari_browser.dart b/lib/src/chrome_safari_browser/chrome_safari_browser.dart index 4ee837c0..cea4f634 100755 --- a/lib/src/chrome_safari_browser/chrome_safari_browser.dart +++ b/lib/src/chrome_safari_browser/chrome_safari_browser.dart @@ -143,7 +143,9 @@ class ChromeSafariBrowser { /// ///[url] - The [url] to load. On iOS, the [url] is required and must use the `http` or `https` scheme. /// - ///[headers] - extra request headers. Supported only on Android. + ///[headers] (Supported only on Android) - [whitelisted](https://fetch.spec.whatwg.org/#cors-safelisted-request-header) cross-origin request headers. + ///It is possible to attach non-whitelisted headers to cross-origin requests, when the server and client are related using a + ///[digital asset link](https://developers.google.com/digital-asset-links/v1/getting-started). /// ///[otherLikelyURLs] - Other likely destinations, sorted in decreasing likelihood order. Supported only on Android. /// @@ -199,7 +201,9 @@ class ChromeSafariBrowser { /// ///[url] - initial url. /// - ///[headers] - extra request headers. + ///[headers] (Supported only on Android) - [whitelisted](https://fetch.spec.whatwg.org/#cors-safelisted-request-header) cross-origin request headers. + ///It is possible to attach non-whitelisted headers to cross-origin requests, when the server and client are related using a + ///[digital asset link](https://developers.google.com/digital-asset-links/v1/getting-started). /// ///[otherLikelyURLs] - Other likely destinations, sorted in decreasing likelihood order. /// @@ -225,22 +229,18 @@ class ChromeSafariBrowser { /// ///[url] - Most likely URL, may be null if otherLikelyBundles is provided. /// - ///[headers] - extra request headers. - /// ///[otherLikelyURLs] - Other likely destinations, sorted in decreasing likelihood order. /// ///**Supported Platforms/Implementations**: ///- Android ([Official API - CustomTabsSession.mayLaunchUrl](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsSession#mayLaunchUrl(android.net.Uri,android.os.Bundle,java.util.List%3Candroid.os.Bundle%3E))) - Future mayLaunchUrl( + Future mayLaunchUrl( {Uri? url, - Map? headers, List? otherLikelyURLs}) async { Map args = {}; args.putIfAbsent('url', () => url?.toString()); - args.putIfAbsent('headers', () => headers); args.putIfAbsent('otherLikelyURLs', () => otherLikelyURLs?.map((e) => e.toString()).toList()); - await _channel.invokeMethod("mayLaunchUrl", args); + return await _channel.invokeMethod("mayLaunchUrl", args); } ///Requests to validate a relationship between the application and an origin. @@ -251,14 +251,20 @@ class ChromeSafariBrowser { ///If this method returns `true`, the validation result will be provided through [onRelationshipValidationResult]. ///Otherwise the request didn't succeed. /// + ///[relation] – Relation to check, must be one of the [CustomTabsRelationType] constants. + /// + ///[origin] – Origin. + /// + ///[extras] – Reserved for future use. + /// ///**Supported Platforms/Implementations**: ///- Android ([Official API - CustomTabsSession.validateRelationship](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsSession#validateRelationship(int,android.net.Uri,android.os.Bundle))) - Future validateRelationship( + Future validateRelationship( {required CustomTabsRelationType relation, required Uri origin}) async { Map args = {}; args.putIfAbsent('relation', () => relation.toNativeValue()); args.putIfAbsent('origin', () => origin.toString()); - await _channel.invokeMethod("validateRelationship", args); + return await _channel.invokeMethod("validateRelationship", args); } ///Closes the [ChromeSafariBrowser] instance. diff --git a/lib/src/chrome_safari_browser/chrome_safari_browser_settings.dart b/lib/src/chrome_safari_browser/chrome_safari_browser_settings.dart index 3794f710..0127849a 100755 --- a/lib/src/chrome_safari_browser/chrome_safari_browser_settings.dart +++ b/lib/src/chrome_safari_browser/chrome_safari_browser_settings.dart @@ -1,11 +1,35 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import '../types/android_resource.dart'; +import '../types/custom_tabs_share_state.dart'; +import '../types/dismiss_button_style.dart'; +import '../types/main.dart'; +import '../types/modal_presentation_style.dart'; +import '../types/modal_transition_style.dart'; +import '../types/trusted_web_activity_display_mode.dart'; +import '../types/trusted_web_activity_screen_orientation.dart'; import '../util.dart'; import 'android/chrome_custom_tabs_options.dart'; import 'apple/safari_options.dart'; -import '../types/main.dart'; + +part 'chrome_safari_browser_settings.g.dart'; + +TrustedWebActivityDisplayMode? _deserializeDisplayMode( + Map? displayMode) { + if (displayMode == null) { + return null; + } + switch (displayMode["type"]) { + case "IMMERSIVE_MODE": + return TrustedWebActivityImmersiveDisplayMode.fromMap(displayMode); + case "DEFAULT_MODE": + default: + return TrustedWebActivityDefaultDisplayMode(); + } +} class ChromeSafariBrowserOptions { Map toMap() { @@ -31,14 +55,15 @@ class ChromeSafariBrowserOptions { } ///Class that represents the settings that can be used for an [ChromeSafariBrowser] window. -class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions { +@ExchangeableObject(copyMethod: true) +class ChromeSafariBrowserSettings_ implements ChromeSafariBrowserOptions { ///The share state that should be applied to the custom tab. The default value is [CustomTabsShareState.SHARE_STATE_DEFAULT]. /// ///**NOTE**: Not available in a Trusted Web Activity. /// ///**Supported Platforms/Implementations**: ///- Android - CustomTabsShareState shareState; + CustomTabsShareState_? shareState; ///Set to `false` if the title shouldn't be shown in the custom tab. The default value is `true`. /// @@ -46,7 +71,7 @@ class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions { /// ///**Supported Platforms/Implementations**: ///- Android - bool showTitle; + bool? showTitle; ///Set the custom background color of the toolbar. /// @@ -54,13 +79,31 @@ class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions { ///- Android Color? toolbarBackgroundColor; + ///Sets the navigation bar color. Has no effect on Android API versions below L. + /// + ///**Supported Platforms/Implementations**: + ///- Android + Color? navigationBarColor; + + ///Sets the navigation bar divider color. Has no effect on Android API versions below P. + /// + ///**Supported Platforms/Implementations**: + ///- Android + Color? navigationBarDividerColor; + + ///Sets the color of the secondary toolbar. + /// + ///**Supported Platforms/Implementations**: + ///- Android + Color? secondaryToolbarColor; + ///Set to `true` to enable the url bar to hide as the user scrolls down on the page. The default value is `false`. /// ///**NOTE**: Not available in a Trusted Web Activity. /// ///**Supported Platforms/Implementations**: ///- Android - bool enableUrlBarHiding; + bool? enableUrlBarHiding; ///Set to `true` to enable Instant Apps. The default value is `false`. /// @@ -68,7 +111,7 @@ class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions { /// ///**Supported Platforms/Implementations**: ///- Android - bool instantAppsEnabled; + bool? instantAppsEnabled; ///Set an explicit application package name that limits ///the components this Intent will resolve to. If left to the default @@ -84,25 +127,25 @@ class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions { /// ///**Supported Platforms/Implementations**: ///- Android - bool keepAliveEnabled; + bool? keepAliveEnabled; ///Set to `true` to launch the Android activity in `singleInstance` mode. The default value is `false`. /// ///**Supported Platforms/Implementations**: ///- Android - bool isSingleInstance; + bool? isSingleInstance; ///Set to `true` to launch the Android intent with the flag `FLAG_ACTIVITY_NO_HISTORY`. The default value is `false`. /// ///**Supported Platforms/Implementations**: ///- Android - bool noHistory; + bool? noHistory; ///Set to `true` to launch the Custom Tab as a Trusted Web Activity. The default value is `false`. /// ///**Supported Platforms/Implementations**: ///- Android - bool isTrustedWebActivity; + bool? isTrustedWebActivity; ///Sets a list of additional trusted origins that the user may navigate or be redirected to from the starting uri. /// @@ -110,7 +153,7 @@ class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions { /// ///**Supported Platforms/Implementations**: ///- Android - List additionalTrustedOrigins; + List? additionalTrustedOrigins; ///Sets a display mode of a Trusted Web Activity. /// @@ -118,7 +161,8 @@ class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions { /// ///**Supported Platforms/Implementations**: ///- Android - TrustedWebActivityDisplayMode? displayMode; + @ExchangeableObjectProperty(deserializer: _deserializeDisplayMode) + TrustedWebActivityDisplayMode_? displayMode; ///Sets a screen orientation. This can be used e.g. to enable the locking of an orientation lock type. /// @@ -126,19 +170,35 @@ class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions { /// ///**Supported Platforms/Implementations**: ///- Android - TrustedWebActivityScreenOrientation screenOrientation; + TrustedWebActivityScreenOrientation_? screenOrientation; + + ///Sets the start animations. + ///It must contain 2 [AndroidResource], where the first one represents the "enter" animation for the browser + ///and the second one represents the "exit" animation for the application. + /// + ///**Supported Platforms/Implementations**: + ///- Android + List? startAnimations; + + ///Sets the exit animations. + ///It must contain 2 [AndroidResource], where the first one represents the "enter" animation for the application + ///and the second one represents the "exit" animation for the browser. + /// + ///**Supported Platforms/Implementations**: + ///- Android + List? exitAnimations; ///Set to `true` if Reader mode should be entered automatically when it is available for the webpage. The default value is `false`. /// ///**Supported Platforms/Implementations**: ///- iOS - bool entersReaderIfAvailable; + bool? entersReaderIfAvailable; ///Set to `true` to enable bar collapsing. The default value is `false`. /// ///**Supported Platforms/Implementations**: ///- iOS - bool barCollapsingEnabled; + bool? barCollapsingEnabled; ///Set the custom style for the dismiss button. The default value is [DismissButtonStyle.DONE]. /// @@ -146,7 +206,7 @@ class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions { /// ///**Supported Platforms/Implementations**: ///- iOS - DismissButtonStyle dismissButtonStyle; + DismissButtonStyle_? dismissButtonStyle; ///Set the custom background color of the navigation bar and the toolbar. /// @@ -168,18 +228,22 @@ class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions { /// ///**Supported Platforms/Implementations**: ///- iOS - ModalPresentationStyle presentationStyle; + ModalPresentationStyle_? presentationStyle; ///Set to the custom transition style when presenting the WebView. The default value is [ModalTransitionStyle.COVER_VERTICAL]. /// ///**Supported Platforms/Implementations**: ///- iOS - ModalTransitionStyle transitionStyle; + ModalTransitionStyle_? transitionStyle; - ChromeSafariBrowserSettings( - {this.shareState = CustomTabsShareState.SHARE_STATE_DEFAULT, + @ExchangeableObjectConstructor() + ChromeSafariBrowserSettings_( + {this.shareState = CustomTabsShareState_.SHARE_STATE_DEFAULT, this.showTitle = true, this.toolbarBackgroundColor, + this.navigationBarColor, + this.navigationBarDividerColor, + this.secondaryToolbarColor, this.enableUrlBarHiding = false, this.instantAppsEnabled = false, this.packageName, @@ -189,99 +253,42 @@ class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions { this.isTrustedWebActivity = false, this.additionalTrustedOrigins = const [], this.displayMode, - this.screenOrientation = TrustedWebActivityScreenOrientation.DEFAULT, + this.screenOrientation = TrustedWebActivityScreenOrientation_.DEFAULT, + this.startAnimations, + this.exitAnimations, this.entersReaderIfAvailable = false, this.barCollapsingEnabled = false, - this.dismissButtonStyle = DismissButtonStyle.DONE, + this.dismissButtonStyle = DismissButtonStyle_.DONE, this.preferredBarTintColor, this.preferredControlTintColor, - this.presentationStyle = ModalPresentationStyle.FULL_SCREEN, - this.transitionStyle = ModalTransitionStyle.COVER_VERTICAL}); - - @override - Map toMap() { - return { - "shareState": shareState.toNativeValue(), - "showTitle": showTitle, - "toolbarBackgroundColor": toolbarBackgroundColor?.toHex(), - "enableUrlBarHiding": enableUrlBarHiding, - "instantAppsEnabled": instantAppsEnabled, - "packageName": packageName, - "keepAliveEnabled": keepAliveEnabled, - "isSingleInstance": isSingleInstance, - "noHistory": noHistory, - "isTrustedWebActivity": isTrustedWebActivity, - "additionalTrustedOrigins": additionalTrustedOrigins, - "displayMode": displayMode?.toMap(), - "screenOrientation": screenOrientation.toNativeValue(), - "entersReaderIfAvailable": entersReaderIfAvailable, - "barCollapsingEnabled": barCollapsingEnabled, - "dismissButtonStyle": dismissButtonStyle.toNativeValue(), - "preferredBarTintColor": preferredBarTintColor?.toHex(), - "preferredControlTintColor": preferredControlTintColor?.toHex(), - "presentationStyle": presentationStyle.toNativeValue(), - "transitionStyle": transitionStyle.toNativeValue() - }; - } - - static ChromeSafariBrowserSettings fromMap(Map map) { - ChromeSafariBrowserSettings settings = new ChromeSafariBrowserSettings(); - if (defaultTargetPlatform == TargetPlatform.android) { - settings.shareState = map["shareState"]; - settings.showTitle = map["showTitle"]; - settings.toolbarBackgroundColor = - UtilColor.fromHex(map["toolbarBackgroundColor"]); - settings.enableUrlBarHiding = map["enableUrlBarHiding"]; - settings.instantAppsEnabled = map["instantAppsEnabled"]; - settings.packageName = map["packageName"]; - settings.keepAliveEnabled = map["keepAliveEnabled"]; - settings.isSingleInstance = map["isSingleInstance"]; - settings.noHistory = map["noHistory"]; - settings.isTrustedWebActivity = map["isTrustedWebActivity"]; - settings.additionalTrustedOrigins = map["additionalTrustedOrigins"]; - switch (map["displayMode"]["type"]) { - case "IMMERSIVE_MODE": - settings.displayMode = TrustedWebActivityImmersiveDisplayMode.fromMap( - map["displayMode"]); - break; - case "DEFAULT_MODE": - default: - settings.displayMode = TrustedWebActivityDefaultDisplayMode(); - break; - } - settings.screenOrientation = map["screenOrientation"]; + this.presentationStyle = ModalPresentationStyle_.FULL_SCREEN, + this.transitionStyle = ModalTransitionStyle_.COVER_VERTICAL}) { + if (startAnimations != null) { + assert(startAnimations!.length == 2, + "start animations must be have 2 android resources"); } - if (defaultTargetPlatform == TargetPlatform.iOS || - defaultTargetPlatform == TargetPlatform.macOS) { - settings.entersReaderIfAvailable = map["entersReaderIfAvailable"]; - settings.barCollapsingEnabled = map["barCollapsingEnabled"]; - settings.dismissButtonStyle = - DismissButtonStyle.fromNativeValue(map["dismissButtonStyle"])!; - settings.preferredBarTintColor = - UtilColor.fromHex(map["preferredBarTintColor"]); - settings.preferredControlTintColor = - UtilColor.fromHex(map["preferredControlTintColor"]); - settings.presentationStyle = - ModalPresentationStyle.fromNativeValue(map["presentationStyle"])!; - settings.transitionStyle = - ModalTransitionStyle.fromNativeValue(map["transitionStyle"])!; + if (exitAnimations != null) { + assert(exitAnimations!.length == 2, + "exit animations must be have 2 android resources"); } - return settings; } @override + @ExchangeableObjectMethod(ignore: true) + ChromeSafariBrowserSettings_ copy() { + throw UnimplementedError(); + } + + @override + @ExchangeableObjectMethod(ignore: true) Map toJson() { - return this.toMap(); + throw UnimplementedError(); } @override - String toString() { - return toMap().toString(); - } - - @override - ChromeSafariBrowserSettings copy() { - return ChromeSafariBrowserSettings.fromMap(this.toMap()); + @ExchangeableObjectMethod(ignore: true) + Map toMap() { + throw UnimplementedError(); } } diff --git a/lib/src/chrome_safari_browser/chrome_safari_browser_settings.g.dart b/lib/src/chrome_safari_browser/chrome_safari_browser_settings.g.dart new file mode 100644 index 00000000..8db91d41 --- /dev/null +++ b/lib/src/chrome_safari_browser/chrome_safari_browser_settings.g.dart @@ -0,0 +1,330 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'chrome_safari_browser_settings.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Class that represents the settings that can be used for an [ChromeSafariBrowser] window. +class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions { + ///The share state that should be applied to the custom tab. The default value is [CustomTabsShareState.SHARE_STATE_DEFAULT]. + /// + ///**NOTE**: Not available in a Trusted Web Activity. + /// + ///**Supported Platforms/Implementations**: + ///- Android + CustomTabsShareState? shareState; + + ///Set to `false` if the title shouldn't be shown in the custom tab. The default value is `true`. + /// + ///**NOTE**: Not available in a Trusted Web Activity. + /// + ///**Supported Platforms/Implementations**: + ///- Android + bool? showTitle; + + ///Set the custom background color of the toolbar. + /// + ///**Supported Platforms/Implementations**: + ///- Android + Color? toolbarBackgroundColor; + + ///Sets the navigation bar color. Has no effect on Android API versions below L. + /// + ///**Supported Platforms/Implementations**: + ///- Android + Color? navigationBarColor; + + ///Sets the navigation bar divider color. Has no effect on Android API versions below P. + /// + ///**Supported Platforms/Implementations**: + ///- Android + Color? navigationBarDividerColor; + + ///Sets the color of the secondary toolbar. + /// + ///**Supported Platforms/Implementations**: + ///- Android + Color? secondaryToolbarColor; + + ///Set to `true` to enable the url bar to hide as the user scrolls down on the page. The default value is `false`. + /// + ///**NOTE**: Not available in a Trusted Web Activity. + /// + ///**Supported Platforms/Implementations**: + ///- Android + bool? enableUrlBarHiding; + + ///Set to `true` to enable Instant Apps. The default value is `false`. + /// + ///**NOTE**: Not available in a Trusted Web Activity. + /// + ///**Supported Platforms/Implementations**: + ///- Android + bool? instantAppsEnabled; + + ///Set an explicit application package name that limits + ///the components this Intent will resolve to. If left to the default + ///value of null, all components in all applications will considered. + ///If non-null, the Intent can only match the components in the given + ///application package. + /// + ///**Supported Platforms/Implementations**: + ///- Android + String? packageName; + + ///Set to `true` to enable Keep Alive. The default value is `false`. + /// + ///**Supported Platforms/Implementations**: + ///- Android + bool? keepAliveEnabled; + + ///Set to `true` to launch the Android activity in `singleInstance` mode. The default value is `false`. + /// + ///**Supported Platforms/Implementations**: + ///- Android + bool? isSingleInstance; + + ///Set to `true` to launch the Android intent with the flag `FLAG_ACTIVITY_NO_HISTORY`. The default value is `false`. + /// + ///**Supported Platforms/Implementations**: + ///- Android + bool? noHistory; + + ///Set to `true` to launch the Custom Tab as a Trusted Web Activity. The default value is `false`. + /// + ///**Supported Platforms/Implementations**: + ///- Android + bool? isTrustedWebActivity; + + ///Sets a list of additional trusted origins that the user may navigate or be redirected to from the starting uri. + /// + ///**NOTE**: Available only in a Trusted Web Activity. + /// + ///**Supported Platforms/Implementations**: + ///- Android + List? additionalTrustedOrigins; + + ///Sets a display mode of a Trusted Web Activity. + /// + ///**NOTE**: Available only in a Trusted Web Activity. + /// + ///**Supported Platforms/Implementations**: + ///- Android + TrustedWebActivityDisplayMode? displayMode; + + ///Sets a screen orientation. This can be used e.g. to enable the locking of an orientation lock type. + /// + ///**NOTE**: Available only in a Trusted Web Activity. + /// + ///**Supported Platforms/Implementations**: + ///- Android + TrustedWebActivityScreenOrientation? screenOrientation; + + ///Sets the start animations. + ///It must contain 2 [AndroidResource], where the first one represents the "enter" animation for the browser + ///and the second one represents the "exit" animation for the application. + /// + ///**Supported Platforms/Implementations**: + ///- Android + List? startAnimations; + + ///Sets the exit animations. + ///It must contain 2 [AndroidResource], where the first one represents the "enter" animation for the application + ///and the second one represents the "exit" animation for the browser. + /// + ///**Supported Platforms/Implementations**: + ///- Android + List? exitAnimations; + + ///Set to `true` if Reader mode should be entered automatically when it is available for the webpage. The default value is `false`. + /// + ///**Supported Platforms/Implementations**: + ///- iOS + bool? entersReaderIfAvailable; + + ///Set to `true` to enable bar collapsing. The default value is `false`. + /// + ///**Supported Platforms/Implementations**: + ///- iOS + bool? barCollapsingEnabled; + + ///Set the custom style for the dismiss button. The default value is [DismissButtonStyle.DONE]. + /// + ///**NOTE**: available on iOS 11.0+. + /// + ///**Supported Platforms/Implementations**: + ///- iOS + DismissButtonStyle? dismissButtonStyle; + + ///Set the custom background color of the navigation bar and the toolbar. + /// + ///**NOTE**: available on iOS 10.0+. + /// + ///**Supported Platforms/Implementations**: + ///- iOS + Color? preferredBarTintColor; + + ///Set the custom color of the control buttons on the navigation bar and the toolbar. + /// + ///**NOTE**: available on iOS 10.0+. + /// + ///**Supported Platforms/Implementations**: + ///- iOS + Color? preferredControlTintColor; + + ///Set the custom modal presentation style when presenting the WebView. The default value is [ModalPresentationStyle.FULL_SCREEN]. + /// + ///**Supported Platforms/Implementations**: + ///- iOS + ModalPresentationStyle? presentationStyle; + + ///Set to the custom transition style when presenting the WebView. The default value is [ModalTransitionStyle.COVER_VERTICAL]. + /// + ///**Supported Platforms/Implementations**: + ///- iOS + ModalTransitionStyle? transitionStyle; + ChromeSafariBrowserSettings( + {this.shareState = CustomTabsShareState.SHARE_STATE_DEFAULT, + this.showTitle = true, + this.toolbarBackgroundColor, + this.navigationBarColor, + this.navigationBarDividerColor, + this.secondaryToolbarColor, + this.enableUrlBarHiding = false, + this.instantAppsEnabled = false, + this.packageName, + this.keepAliveEnabled = false, + this.isSingleInstance = false, + this.noHistory = false, + this.isTrustedWebActivity = false, + this.additionalTrustedOrigins = const [], + this.displayMode, + this.screenOrientation = TrustedWebActivityScreenOrientation.DEFAULT, + this.startAnimations, + this.exitAnimations, + this.entersReaderIfAvailable = false, + this.barCollapsingEnabled = false, + this.dismissButtonStyle = DismissButtonStyle.DONE, + this.preferredBarTintColor, + this.preferredControlTintColor, + this.presentationStyle = ModalPresentationStyle.FULL_SCREEN, + this.transitionStyle = ModalTransitionStyle.COVER_VERTICAL}) { + if (startAnimations != null) { + assert(startAnimations!.length == 2, + "start animations must be have 2 android resources"); + } + if (exitAnimations != null) { + assert(exitAnimations!.length == 2, + "exit animations must be have 2 android resources"); + } + } + + ///Gets a possible [ChromeSafariBrowserSettings] instance from a [Map] value. + static ChromeSafariBrowserSettings? fromMap(Map? map) { + if (map == null) { + return null; + } + final instance = ChromeSafariBrowserSettings( + toolbarBackgroundColor: map['toolbarBackgroundColor'] != null + ? UtilColor.fromStringRepresentation(map['toolbarBackgroundColor']) + : null, + navigationBarColor: map['navigationBarColor'] != null + ? UtilColor.fromStringRepresentation(map['navigationBarColor']) + : null, + navigationBarDividerColor: map['navigationBarDividerColor'] != null + ? UtilColor.fromStringRepresentation(map['navigationBarDividerColor']) + : null, + secondaryToolbarColor: map['secondaryToolbarColor'] != null + ? UtilColor.fromStringRepresentation(map['secondaryToolbarColor']) + : null, + packageName: map['packageName'], + displayMode: _deserializeDisplayMode(map['displayMode']), + startAnimations: map['startAnimations'] != null + ? List.from(map['startAnimations'] + .map((e) => AndroidResource.fromMap(e?.cast())!)) + : null, + exitAnimations: map['exitAnimations'] != null + ? List.from(map['exitAnimations'] + .map((e) => AndroidResource.fromMap(e?.cast())!)) + : null, + preferredBarTintColor: map['preferredBarTintColor'] != null + ? UtilColor.fromStringRepresentation(map['preferredBarTintColor']) + : null, + preferredControlTintColor: map['preferredControlTintColor'] != null + ? UtilColor.fromStringRepresentation(map['preferredControlTintColor']) + : null, + ); + instance.shareState = + CustomTabsShareState.fromNativeValue(map['shareState']); + instance.showTitle = map['showTitle']; + instance.enableUrlBarHiding = map['enableUrlBarHiding']; + instance.instantAppsEnabled = map['instantAppsEnabled']; + instance.keepAliveEnabled = map['keepAliveEnabled']; + instance.isSingleInstance = map['isSingleInstance']; + instance.noHistory = map['noHistory']; + instance.isTrustedWebActivity = map['isTrustedWebActivity']; + instance.additionalTrustedOrigins = + map['additionalTrustedOrigins']?.cast(); + instance.screenOrientation = + TrustedWebActivityScreenOrientation.fromNativeValue( + map['screenOrientation']); + instance.entersReaderIfAvailable = map['entersReaderIfAvailable']; + instance.barCollapsingEnabled = map['barCollapsingEnabled']; + instance.dismissButtonStyle = + DismissButtonStyle.fromNativeValue(map['dismissButtonStyle']); + instance.presentationStyle = + ModalPresentationStyle.fromNativeValue(map['presentationStyle']); + instance.transitionStyle = + ModalTransitionStyle.fromNativeValue(map['transitionStyle']); + return instance; + } + + ///Converts instance to a map. + Map toMap() { + return { + "shareState": shareState?.toNativeValue(), + "showTitle": showTitle, + "toolbarBackgroundColor": toolbarBackgroundColor?.toHex(), + "navigationBarColor": navigationBarColor?.toHex(), + "navigationBarDividerColor": navigationBarDividerColor?.toHex(), + "secondaryToolbarColor": secondaryToolbarColor?.toHex(), + "enableUrlBarHiding": enableUrlBarHiding, + "instantAppsEnabled": instantAppsEnabled, + "packageName": packageName, + "keepAliveEnabled": keepAliveEnabled, + "isSingleInstance": isSingleInstance, + "noHistory": noHistory, + "isTrustedWebActivity": isTrustedWebActivity, + "additionalTrustedOrigins": additionalTrustedOrigins, + "displayMode": displayMode?.toMap(), + "screenOrientation": screenOrientation?.toNativeValue(), + "startAnimations": startAnimations?.map((e) => e.toMap()).toList(), + "exitAnimations": exitAnimations?.map((e) => e.toMap()).toList(), + "entersReaderIfAvailable": entersReaderIfAvailable, + "barCollapsingEnabled": barCollapsingEnabled, + "dismissButtonStyle": dismissButtonStyle?.toNativeValue(), + "preferredBarTintColor": preferredBarTintColor?.toHex(), + "preferredControlTintColor": preferredControlTintColor?.toHex(), + "presentationStyle": presentationStyle?.toNativeValue(), + "transitionStyle": transitionStyle?.toNativeValue(), + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + ///Returns a copy of ChromeSafariBrowserSettings. + ChromeSafariBrowserSettings copy() { + return ChromeSafariBrowserSettings.fromMap(toMap()) ?? + ChromeSafariBrowserSettings(); + } + + @override + String toString() { + return 'ChromeSafariBrowserSettings{shareState: $shareState, showTitle: $showTitle, toolbarBackgroundColor: $toolbarBackgroundColor, navigationBarColor: $navigationBarColor, navigationBarDividerColor: $navigationBarDividerColor, secondaryToolbarColor: $secondaryToolbarColor, enableUrlBarHiding: $enableUrlBarHiding, instantAppsEnabled: $instantAppsEnabled, packageName: $packageName, keepAliveEnabled: $keepAliveEnabled, isSingleInstance: $isSingleInstance, noHistory: $noHistory, isTrustedWebActivity: $isTrustedWebActivity, additionalTrustedOrigins: $additionalTrustedOrigins, displayMode: $displayMode, screenOrientation: $screenOrientation, startAnimations: $startAnimations, exitAnimations: $exitAnimations, entersReaderIfAvailable: $entersReaderIfAvailable, barCollapsingEnabled: $barCollapsingEnabled, dismissButtonStyle: $dismissButtonStyle, preferredBarTintColor: $preferredBarTintColor, preferredControlTintColor: $preferredControlTintColor, presentationStyle: $presentationStyle, transitionStyle: $transitionStyle}'; + } +} diff --git a/lib/src/chrome_safari_browser/main.dart b/lib/src/chrome_safari_browser/main.dart index c11753f1..9d23040d 100644 --- a/lib/src/chrome_safari_browser/main.dart +++ b/lib/src/chrome_safari_browser/main.dart @@ -1,4 +1,8 @@ export 'chrome_safari_browser.dart'; -export 'chrome_safari_browser_settings.dart'; +export 'chrome_safari_browser_settings.dart' + show + ChromeSafariBrowserOptions, + ChromeSafariBrowserSettings, + ChromeSafariBrowserClassOptions; export 'android/main.dart'; export 'apple/main.dart'; diff --git a/lib/src/in_app_webview/in_app_webview_controller.dart b/lib/src/in_app_webview/in_app_webview_controller.dart index 7cff2139..4bd7e244 100644 --- a/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/lib/src/in_app_webview/in_app_webview_controller.dart @@ -3683,6 +3683,24 @@ class InAppWebViewController { 'setWebContentsDebuggingEnabled', args); } + ///Gets the WebView variations encoded to be used as the X-Client-Data HTTP header. + /// + ///The app is responsible for adding the X-Client-Data header to any request + ///that may use variations metadata, such as requests to Google web properties. + ///The returned string will be a base64 encoded ClientVariations proto: + ///https://source.chromium.org/chromium/chromium/src/+/main:components/variations/proto/client_variations.proto + /// + ///The string may be empty if the header is not available. + /// + ///**NOTE for Android native WebView**: This method should only be called if [WebViewFeature.isFeatureSupported] returns `true` for [WebViewFeature.GET_VARIATIONS_HEADER]. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebViewCompat.getVariationsHeader](https://developer.android.com/reference/androidx/webkit/WebViewCompat#getVariationsHeader())) + static Future getVariationsHeader() async { + Map args = {}; + return await _staticChannel.invokeMethod('getVariationsHeader', args); + } + ///Returns a Boolean value that indicates whether WebKit natively supports resources with the specified URL scheme. /// ///[urlScheme] represents the URL scheme associated with the resource. diff --git a/lib/src/types/android_resource.dart b/lib/src/types/android_resource.dart new file mode 100644 index 00000000..27907ad1 --- /dev/null +++ b/lib/src/types/android_resource.dart @@ -0,0 +1,33 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +part 'android_resource.g.dart'; + +///Class that represents an android resource. +@ExchangeableObject() +class AndroidResource_ { + ///Android resource name. + /// + ///A list of available `android.R.anim` can be found + ///[here](https://developer.android.com/reference/android/R.anim). + /// + ///A list of available `androidx.appcompat.R.anim` can be found + ///[here](https://android.googlesource.com/platform/frameworks/support/+/HEAD/appcompat/appcompat/src/main/res/anim/) + ///(abc_*.xml files). + ///In this case, [defPackage] must match your App Android package name. + String name; + + ///Optional default resource type to find, if "type/" is not included in the name. + ///Can be `null` to require an explicit type. + /// + ///Example: "anim" + String? defType; + + ///Optional default package to find, if "package:" is not included in the name. + ///Can be `null` to require an explicit package. + /// + ///Example: "android" if you want use resources from `android.R.` + String? defPackage; + + AndroidResource_({required this.name, + this.defType, this.defPackage}); +} \ No newline at end of file diff --git a/lib/src/types/android_resource.g.dart b/lib/src/types/android_resource.g.dart new file mode 100644 index 00000000..6c48d8ff --- /dev/null +++ b/lib/src/types/android_resource.g.dart @@ -0,0 +1,66 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'android_resource.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Class that represents an android resource. +class AndroidResource { + ///Android resource name. + /// + ///A list of available `android.R.anim` can be found + ///[here](https://developer.android.com/reference/android/R.anim). + /// + ///A list of available `androidx.appcompat.R.anim` can be found + ///[here](https://android.googlesource.com/platform/frameworks/support/+/HEAD/appcompat/appcompat/src/main/res/anim/) + ///(abc_*.xml files). + ///In this case, [defPackage] must match your App Android package name. + String name; + + ///Optional default resource type to find, if "type/" is not included in the name. + ///Can be `null` to require an explicit type. + /// + ///Example: "anim" + String? defType; + + ///Optional default package to find, if "package:" is not included in the name. + ///Can be `null` to require an explicit package. + /// + ///Example: "android" if you want use resources from `android.R.` + String? defPackage; + AndroidResource({required this.name, this.defType, this.defPackage}); + + ///Gets a possible [AndroidResource] instance from a [Map] value. + static AndroidResource? fromMap(Map? map) { + if (map == null) { + return null; + } + final instance = AndroidResource( + name: map['name'], + defType: map['defType'], + defPackage: map['defPackage'], + ); + return instance; + } + + ///Converts instance to a map. + Map toMap() { + return { + "name": name, + "defType": defType, + "defPackage": defPackage, + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'AndroidResource{name: $name, defType: $defType, defPackage: $defPackage}'; + } +} diff --git a/lib/src/types/main.dart b/lib/src/types/main.dart index 29e25979..72f077a4 100644 --- a/lib/src/types/main.dart +++ b/lib/src/types/main.dart @@ -217,4 +217,5 @@ export 'window_style_mask.dart' show WindowStyleMask; export 'window_titlebar_separator_style.dart' show WindowTitlebarSeparatorStyle; export 'custom_tabs_navigation_event_type.dart' show CustomTabsNavigationEventType; export 'custom_tabs_relation_type.dart' show CustomTabsRelationType; -export 'prewarming_token.dart' show PrewarmingToken; \ No newline at end of file +export 'prewarming_token.dart' show PrewarmingToken; +export 'android_resource.dart' show AndroidResource; \ No newline at end of file diff --git a/scripts/test.sh b/scripts/test.sh index e38cca11..dcbb98c7 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -34,13 +34,17 @@ dart $PROJECT_DIR/tool/env.dart cd $PROJECT_DIR/test_node_server node index.js & +# Only for Android +# Open Chrome on the development device, navigate to chrome://flags, search for an item called Enable command line on non-rooted devices and change it to ENABLED and then restart the browser. +adb shell "echo '_ --disable-digital-asset-link-verification-for-url=\"https://flutter.dev\"' > /data/local/tmp/chrome-command-line" || true + flutter --version flutter clean flutter pub get cd $PROJECT_DIR/example flutter clean if [ ! -z "$2" ] && [ $PLATFORM = "web" ]; then - flutter driver --driver=test_driver/integration_test.dart --target=integration_test/webview_flutter_test.dart --device-id=chrome + flutter driver --driver=test_driver/integration_test.dart --target=integration_test/webview_flutter_test.dart --device-id=chrome else flutter driver --driver=test_driver/integration_test.dart --target=integration_test/webview_flutter_test.dart fi diff --git a/test_node_server/index.js b/test_node_server/index.js index 820dfa4b..aeb07c7d 100755 --- a/test_node_server/index.js +++ b/test_node_server/index.js @@ -153,6 +153,19 @@ app.get("/", (req, res) => { res.end() }) +app.get("/echo-headers", (req, res) => { + res.send(` + + + + +
${JSON.stringify(req.headers)}
+ + + `); + res.end() +}) + app.get('/test-index', (req, res) => { res.sendFile(__dirname + '/public/index.html'); })