Added support for Android TWA (Trusted Web Activity)
This commit is contained in:
parent
c61019058c
commit
5510fd342f
@ -6,6 +6,7 @@
|
|||||||
- Added `singleInstance` option for Android `ChromeSafariBrowser` implementation
|
- Added `singleInstance` option for Android `ChromeSafariBrowser` implementation
|
||||||
- Added `onDownloadStartRequest` event and deprecated old `onDownloadStart` event
|
- Added `onDownloadStartRequest` event and deprecated old `onDownloadStart` event
|
||||||
- Added `shareState` Android option for `ChromeSafariBrowser` class
|
- Added `shareState` Android option for `ChromeSafariBrowser` class
|
||||||
|
- Added support for Android TWA (Trusted Web Activity)
|
||||||
- Fixed missing `onZoomScaleChanged` call for `InAppBrowser` class
|
- Fixed missing `onZoomScaleChanged` call for `InAppBrowser` class
|
||||||
- Fixed `requestImageRef` method always `null` on iOS
|
- Fixed `requestImageRef` method always `null` on iOS
|
||||||
- Fixed "applicationNameForUserAgent is not work in ios" [#525](https://github.com/pichillilorenzo/flutter_inappwebview/issues/525)
|
- Fixed "applicationNameForUserAgent is not work in ios" [#525](https://github.com/pichillilorenzo/flutter_inappwebview/issues/525)
|
||||||
|
@ -46,8 +46,8 @@ android {
|
|||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'androidx.webkit:webkit:1.4.0'
|
implementation 'androidx.webkit:webkit:1.4.0'
|
||||||
implementation 'androidx.browser:browser:1.3.0'
|
implementation 'androidx.browser:browser:1.4.0'
|
||||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||||
implementation 'com.squareup.okhttp3:okhttp:3.14.9'
|
implementation 'com.squareup.okhttp3:okhttp:3.14.9'
|
||||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,20 @@
|
|||||||
android:theme="@style/ThemeTransparent"
|
android:theme="@style/ThemeTransparent"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:name="com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.ChromeCustomTabsActivity" />
|
android:name="com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.ChromeCustomTabsActivity" />
|
||||||
|
<activity
|
||||||
|
android:theme="@style/ThemeTransparent"
|
||||||
|
android:exported="true"
|
||||||
|
android:name="com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.TrustedWebActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:theme="@style/ThemeTransparent"
|
android:theme="@style/ThemeTransparent"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:name="com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.ChromeCustomTabsActivitySingleInstance"
|
android:name="com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.ChromeCustomTabsActivitySingleInstance"
|
||||||
android:launchMode="singleInstance"/>
|
android:launchMode="singleInstance"/>
|
||||||
|
<activity
|
||||||
|
android:theme="@style/ThemeTransparent"
|
||||||
|
android:exported="true"
|
||||||
|
android:name="com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.TrustedWebActivitySingleInstance"
|
||||||
|
android:launchMode="singleInstance"/>
|
||||||
<receiver android:name="com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.ActionBroadcastReceiver" />
|
<receiver android:name="com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.ActionBroadcastReceiver" />
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="io.flutter.embedded_views_preview"
|
android:name="io.flutter.embedded_views_preview"
|
||||||
|
@ -67,17 +67,7 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
|
|||||||
customTabActivityHelper.setConnectionCallback(new CustomTabActivityHelper.ConnectionCallback() {
|
customTabActivityHelper.setConnectionCallback(new CustomTabActivityHelper.ConnectionCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onCustomTabsConnected() {
|
public void onCustomTabsConnected() {
|
||||||
customTabsSession = customTabActivityHelper.getSession();
|
customTabsConnected(url, menuItemList);
|
||||||
Uri uri = Uri.parse(url);
|
|
||||||
customTabActivityHelper.mayLaunchUrl(uri, null, null);
|
|
||||||
|
|
||||||
builder = new CustomTabsIntent.Builder(customTabsSession);
|
|
||||||
prepareCustomTabs(menuItemList);
|
|
||||||
|
|
||||||
CustomTabsIntent customTabsIntent = builder.build();
|
|
||||||
prepareCustomTabsIntent(customTabsIntent);
|
|
||||||
|
|
||||||
CustomTabActivityHelper.openCustomTab(chromeCustomTabsActivity, customTabsIntent, uri, CHROME_CUSTOM_TAB_REQUEST_CODE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -149,6 +139,20 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void customTabsConnected (String url, List<HashMap<String, Object>> menuItemList) {
|
||||||
|
customTabsSession = customTabActivityHelper.getSession();
|
||||||
|
Uri uri = Uri.parse(url);
|
||||||
|
customTabActivityHelper.mayLaunchUrl(uri, null, null);
|
||||||
|
|
||||||
|
builder = new CustomTabsIntent.Builder(customTabsSession);
|
||||||
|
prepareCustomTabs(menuItemList);
|
||||||
|
|
||||||
|
CustomTabsIntent customTabsIntent = builder.build();
|
||||||
|
prepareCustomTabsIntent(customTabsIntent);
|
||||||
|
|
||||||
|
CustomTabActivityHelper.openCustomTab(this, customTabsIntent, uri, CHROME_CUSTOM_TAB_REQUEST_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
private void prepareCustomTabs(List<HashMap<String, Object>> menuItemList) {
|
private void prepareCustomTabs(List<HashMap<String, Object>> menuItemList) {
|
||||||
if (options.addDefaultShareMenuItem != null) {
|
if (options.addDefaultShareMenuItem != null) {
|
||||||
builder.setShareState(options.addDefaultShareMenuItem ?
|
builder.setShareState(options.addDefaultShareMenuItem ?
|
||||||
|
@ -4,10 +4,14 @@ import android.content.Intent;
|
|||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.browser.customtabs.CustomTabsIntent;
|
import androidx.browser.customtabs.CustomTabsIntent;
|
||||||
|
import androidx.browser.trusted.ScreenOrientation;
|
||||||
|
import androidx.browser.trusted.TrustedWebActivityDisplayMode;
|
||||||
|
|
||||||
import com.pichillilorenzo.flutter_inappwebview.Options;
|
import com.pichillilorenzo.flutter_inappwebview.Options;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ChromeCustomTabsOptions implements Options<ChromeCustomTabsActivity> {
|
public class ChromeCustomTabsOptions implements Options<ChromeCustomTabsActivity> {
|
||||||
@ -24,8 +28,12 @@ public class ChromeCustomTabsOptions implements Options<ChromeCustomTabsActivity
|
|||||||
public Boolean instantAppsEnabled = false;
|
public Boolean instantAppsEnabled = false;
|
||||||
public String packageName;
|
public String packageName;
|
||||||
public Boolean keepAliveEnabled = false;
|
public Boolean keepAliveEnabled = false;
|
||||||
public Boolean singleInstance = false;
|
public Boolean isSingleInstance = false;
|
||||||
public Boolean noHistory = false;
|
public Boolean noHistory = false;
|
||||||
|
public Boolean isTrustedWebActivity = false;
|
||||||
|
public List<String> additionalTrustedOrigins = new ArrayList<>();
|
||||||
|
public TrustedWebActivityDisplayMode displayMode = null;
|
||||||
|
public Integer screenOrientation = ScreenOrientation.DEFAULT;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ChromeCustomTabsOptions parse(Map<String, Object> options) {
|
public ChromeCustomTabsOptions parse(Map<String, Object> options) {
|
||||||
@ -61,12 +69,35 @@ public class ChromeCustomTabsOptions implements Options<ChromeCustomTabsActivity
|
|||||||
case "keepAliveEnabled":
|
case "keepAliveEnabled":
|
||||||
keepAliveEnabled = (Boolean) value;
|
keepAliveEnabled = (Boolean) value;
|
||||||
break;
|
break;
|
||||||
case "singleInstance":
|
case "isSingleInstance":
|
||||||
singleInstance = (Boolean) value;
|
isSingleInstance = (Boolean) value;
|
||||||
break;
|
break;
|
||||||
case "noHistory":
|
case "noHistory":
|
||||||
noHistory = (Boolean) value;
|
noHistory = (Boolean) value;
|
||||||
break;
|
break;
|
||||||
|
case "isTrustedWebActivity":
|
||||||
|
isTrustedWebActivity = (Boolean) value;
|
||||||
|
break;
|
||||||
|
case "additionalTrustedOrigins":
|
||||||
|
additionalTrustedOrigins = (List<String>) value;
|
||||||
|
break;
|
||||||
|
case "displayMode":
|
||||||
|
Map<String, Object> displayModeMap = (Map<String, Object>) value;
|
||||||
|
String displayModeType = (String) displayModeMap.get("type");
|
||||||
|
if (displayModeType != null) {
|
||||||
|
switch (displayModeType) {
|
||||||
|
case "IMMERSIVE_MODE":
|
||||||
|
boolean isSticky = (boolean) displayModeMap.get("isSticky");
|
||||||
|
int layoutInDisplayCutoutMode = (int) displayModeMap.get("layoutInDisplayCutoutMode");
|
||||||
|
displayMode = new TrustedWebActivityDisplayMode.ImmersiveMode(isSticky, layoutInDisplayCutoutMode);
|
||||||
|
case "DEFAULT_MODE":
|
||||||
|
displayMode = new TrustedWebActivityDisplayMode.DefaultMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "screenOrientation":
|
||||||
|
screenOrientation = (Integer) value;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,8 +114,11 @@ public class ChromeCustomTabsOptions implements Options<ChromeCustomTabsActivity
|
|||||||
options.put("instantAppsEnabled", instantAppsEnabled);
|
options.put("instantAppsEnabled", instantAppsEnabled);
|
||||||
options.put("packageName", packageName);
|
options.put("packageName", packageName);
|
||||||
options.put("keepAliveEnabled", keepAliveEnabled);
|
options.put("keepAliveEnabled", keepAliveEnabled);
|
||||||
options.put("singleInstance", singleInstance);
|
options.put("isSingleInstance", isSingleInstance);
|
||||||
options.put("noHistory", noHistory);
|
options.put("noHistory", noHistory);
|
||||||
|
options.put("isTrustedWebActivity", isTrustedWebActivity);
|
||||||
|
options.put("additionalTrustedOrigins", additionalTrustedOrigins);
|
||||||
|
options.put("screenOrientation", screenOrientation);
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,11 +68,15 @@ public class ChromeSafariBrowserManager implements MethodChannel.MethodCallHandl
|
|||||||
extras.putSerializable("options", options);
|
extras.putSerializable("options", options);
|
||||||
extras.putSerializable("menuItemList", (Serializable) menuItemList);
|
extras.putSerializable("menuItemList", (Serializable) menuItemList);
|
||||||
|
|
||||||
Boolean isSingleInstance = (Boolean) options.get("singleInstance");
|
Boolean isSingleInstance = (Boolean) Util.getOrDefault(options, "isSingleInstance", false);
|
||||||
|
Boolean isTrustedWebActivity = (Boolean) Util.getOrDefault(options, "isTrustedWebActivity", false);
|
||||||
if (CustomTabActivityHelper.isAvailable(activity)) {
|
if (CustomTabActivityHelper.isAvailable(activity)) {
|
||||||
intent = new Intent(activity, !isSingleInstance ? ChromeCustomTabsActivity.class : ChromeCustomTabsActivitySingleInstance.class);
|
intent = new Intent(activity, !isSingleInstance ?
|
||||||
|
(!isTrustedWebActivity ? ChromeCustomTabsActivity.class : TrustedWebActivity.class) :
|
||||||
|
(!isTrustedWebActivity ? ChromeCustomTabsActivitySingleInstance.class : TrustedWebActivitySingleInstance.class));
|
||||||
intent.putExtras(extras);
|
intent.putExtras(extras);
|
||||||
if ((Boolean) options.get("noHistory")) {
|
Boolean noHistory = (Boolean) Util.getOrDefault(options, "noHistory", false);
|
||||||
|
if (noHistory) {
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
|
||||||
}
|
}
|
||||||
activity.startActivity(intent);
|
activity.startActivity(intent);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
|
package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ import androidx.browser.customtabs.CustomTabsClient;
|
|||||||
import androidx.browser.customtabs.CustomTabsIntent;
|
import androidx.browser.customtabs.CustomTabsIntent;
|
||||||
import androidx.browser.customtabs.CustomTabsServiceConnection;
|
import androidx.browser.customtabs.CustomTabsServiceConnection;
|
||||||
import androidx.browser.customtabs.CustomTabsSession;
|
import androidx.browser.customtabs.CustomTabsSession;
|
||||||
|
import androidx.browser.trusted.TrustedWebActivityIntent;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -37,6 +39,14 @@ public class CustomTabActivityHelper implements ServiceConnectionCallback {
|
|||||||
activity.startActivityForResult(customTabsIntent.intent, requestCode);
|
activity.startActivityForResult(customTabsIntent.intent, requestCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void openCustomTab(Activity activity,
|
||||||
|
TrustedWebActivityIntent trustedWebActivityIntent,
|
||||||
|
Uri uri,
|
||||||
|
int requestCode) {
|
||||||
|
trustedWebActivityIntent.getIntent().setData(uri);
|
||||||
|
activity.startActivityForResult(trustedWebActivityIntent.getIntent(), requestCode);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isAvailable(Activity activity) {
|
public static boolean isAvailable(Activity activity) {
|
||||||
return CustomTabsHelper.getPackageNameToUse(activity) != null;
|
return CustomTabsHelper.getPackageNameToUse(activity) != null;
|
||||||
}
|
}
|
||||||
@ -135,5 +145,4 @@ public class CustomTabActivityHelper implements ServiceConnectionCallback {
|
|||||||
*/
|
*/
|
||||||
void onCustomTabsDisconnected();
|
void onCustomTabsDisconnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import androidx.browser.customtabs.CustomTabColorSchemeParams;
|
||||||
|
import androidx.browser.trusted.TrustedWebActivityIntent;
|
||||||
|
import androidx.browser.trusted.TrustedWebActivityIntentBuilder;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TrustedWebActivity extends ChromeCustomTabsActivity {
|
||||||
|
|
||||||
|
protected static final String LOG_TAG = "TrustedWebActivity";
|
||||||
|
|
||||||
|
public TrustedWebActivityIntentBuilder builder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void customTabsConnected (String url, List<HashMap<String, Object>> menuItemList) {
|
||||||
|
customTabsSession = customTabActivityHelper.getSession();
|
||||||
|
Uri uri = Uri.parse(url);
|
||||||
|
customTabActivityHelper.mayLaunchUrl(uri, null, null);
|
||||||
|
|
||||||
|
builder = new TrustedWebActivityIntentBuilder(uri);
|
||||||
|
prepareCustomTabs();
|
||||||
|
|
||||||
|
TrustedWebActivityIntent trustedWebActivityIntent = builder.build(customTabsSession);
|
||||||
|
prepareCustomTabsIntent(trustedWebActivityIntent);
|
||||||
|
|
||||||
|
CustomTabActivityHelper.openCustomTab(this, trustedWebActivityIntent, uri, CHROME_CUSTOM_TAB_REQUEST_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareCustomTabs() {
|
||||||
|
if (options.toolbarBackgroundColor != null && !options.toolbarBackgroundColor.isEmpty()) {
|
||||||
|
CustomTabColorSchemeParams.Builder defaultColorSchemeBuilder = new CustomTabColorSchemeParams.Builder();
|
||||||
|
builder.setDefaultColorSchemeParams(defaultColorSchemeBuilder
|
||||||
|
.setToolbarColor(Color.parseColor(options.toolbarBackgroundColor))
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.additionalTrustedOrigins != null && !options.additionalTrustedOrigins.isEmpty()) {
|
||||||
|
builder.setAdditionalTrustedOrigins(options.additionalTrustedOrigins);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.displayMode != null) {
|
||||||
|
builder.setDisplayMode(options.displayMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.setScreenOrientation(options.screenOrientation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareCustomTabsIntent(TrustedWebActivityIntent trustedWebActivityIntent) {
|
||||||
|
Intent intent = trustedWebActivityIntent.getIntent();
|
||||||
|
if (options.packageName != null)
|
||||||
|
intent.setPackage(options.packageName);
|
||||||
|
else
|
||||||
|
intent.setPackage(CustomTabsHelper.getPackageNameToUse(this));
|
||||||
|
|
||||||
|
if (options.keepAliveEnabled)
|
||||||
|
CustomTabsHelper.addKeepAliveExtra(this, intent);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
|
||||||
|
|
||||||
|
public class TrustedWebActivitySingleInstance extends TrustedWebActivity {
|
||||||
|
|
||||||
|
protected static final String LOG_TAG = "TrustedWebActivitySingleInstance";
|
||||||
|
|
||||||
|
}
|
@ -30,6 +30,10 @@
|
|||||||
android:label="flutter_inappwebview_example"
|
android:label="flutter_inappwebview_example"
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
|
<meta-data
|
||||||
|
android:name="asset_statements"
|
||||||
|
android:resource="@string/asset_statements" />
|
||||||
|
|
||||||
<!-- Don't delete the meta-data below.
|
<!-- Don't delete the meta-data below.
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
<meta-data
|
<meta-data
|
||||||
|
11
example/android/app/src/main/res/values/strings.xml
Executable file
11
example/android/app/src/main/res/values/strings.xml
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="app_name">Flutter Trusted Web Activity</string>
|
||||||
|
<string name="asset_statements">
|
||||||
|
[{
|
||||||
|
\"relation\": [\"delegate_permission/common.handle_all_urls\"],
|
||||||
|
\"target\": {
|
||||||
|
\"namespace\": \"web\",
|
||||||
|
\"site\": \"https://flutter.dev\"}
|
||||||
|
}]
|
||||||
|
</string>
|
||||||
|
</resources>
|
@ -67,7 +67,8 @@ class _ChromeSafariBrowserExampleScreenState
|
|||||||
options: ChromeSafariBrowserClassOptions(
|
options: ChromeSafariBrowserClassOptions(
|
||||||
android: AndroidChromeCustomTabsOptions(
|
android: AndroidChromeCustomTabsOptions(
|
||||||
shareState: CustomTabsShareState.SHARE_STATE_OFF,
|
shareState: CustomTabsShareState.SHARE_STATE_OFF,
|
||||||
singleInstance: false,
|
isSingleInstance: false,
|
||||||
|
isTrustedWebActivity: false,
|
||||||
keepAliveEnabled: true),
|
keepAliveEnabled: true),
|
||||||
ios: IOSSafariOptions(
|
ios: IOSSafariOptions(
|
||||||
dismissButtonStyle:
|
dismissButtonStyle:
|
||||||
|
@ -11,23 +11,31 @@ import '../../in_app_webview/android/in_app_webview_options.dart';
|
|||||||
///This class represents all the Android-only [ChromeSafariBrowser] options available.
|
///This class represents all the Android-only [ChromeSafariBrowser] options available.
|
||||||
class AndroidChromeCustomTabsOptions
|
class AndroidChromeCustomTabsOptions
|
||||||
implements ChromeSafariBrowserOptions, AndroidOptions {
|
implements ChromeSafariBrowserOptions, AndroidOptions {
|
||||||
///Set to `false` if you don't want the default share item to the menu. The default value is `true`.
|
///Use `shareState` instead.
|
||||||
@Deprecated('Use `shareState` instead')
|
@Deprecated('Use `shareState` instead')
|
||||||
bool? addDefaultShareMenuItem;
|
bool? addDefaultShareMenuItem;
|
||||||
|
|
||||||
///The share state that should be applied to the custom tab. The default value is [CustomTabsShareState.SHARE_STATE_DEFAULT].
|
///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.
|
||||||
CustomTabsShareState shareState;
|
CustomTabsShareState shareState;
|
||||||
|
|
||||||
///Set to `false` if the title shouldn't be shown in the custom tab. The default value is `true`.
|
///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.
|
||||||
bool showTitle;
|
bool showTitle;
|
||||||
|
|
||||||
///Set the custom background color of the toolbar.
|
///Set the custom background color of the toolbar.
|
||||||
Color? toolbarBackgroundColor;
|
Color? toolbarBackgroundColor;
|
||||||
|
|
||||||
///Set to `true` to enable the url bar to hide as the user scrolls down on the page. The default value is `false`.
|
///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.
|
||||||
bool enableUrlBarHiding;
|
bool enableUrlBarHiding;
|
||||||
|
|
||||||
///Set to `true` to enable Instant Apps. The default value is `false`.
|
///Set to `true` to enable Instant Apps. The default value is `false`.
|
||||||
|
///
|
||||||
|
///**NOTE**: Not available in a Trusted Web Activity.
|
||||||
bool instantAppsEnabled;
|
bool instantAppsEnabled;
|
||||||
|
|
||||||
///Set an explicit application package name that limits
|
///Set an explicit application package name that limits
|
||||||
@ -41,11 +49,29 @@ class AndroidChromeCustomTabsOptions
|
|||||||
bool keepAliveEnabled;
|
bool keepAliveEnabled;
|
||||||
|
|
||||||
///Set to `true` to launch the Android activity in `singleInstance` mode. The default value is `false`.
|
///Set to `true` to launch the Android activity in `singleInstance` mode. The default value is `false`.
|
||||||
bool singleInstance;
|
bool isSingleInstance;
|
||||||
|
|
||||||
///Set to `true` to launch the Android intent with the flag `FLAG_ACTIVITY_NO_HISTORY`. The default value is `false`.
|
///Set to `true` to launch the Android intent with the flag `FLAG_ACTIVITY_NO_HISTORY`. The default value is `false`.
|
||||||
bool noHistory;
|
bool noHistory;
|
||||||
|
|
||||||
|
///Set to `true` to launch the Custom Tab as a Trusted Web Activity. The default value is `false`.
|
||||||
|
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.
|
||||||
|
List<String> additionalTrustedOrigins;
|
||||||
|
|
||||||
|
///Sets a display mode of a Trusted Web Activity.
|
||||||
|
///
|
||||||
|
///**NOTE**: Available only in a Trusted Web Activity.
|
||||||
|
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.
|
||||||
|
TrustedWebActivityScreenOrientation screenOrientation;
|
||||||
|
|
||||||
AndroidChromeCustomTabsOptions(
|
AndroidChromeCustomTabsOptions(
|
||||||
{@Deprecated('Use `shareState` instead') this.addDefaultShareMenuItem,
|
{@Deprecated('Use `shareState` instead') this.addDefaultShareMenuItem,
|
||||||
this.shareState = CustomTabsShareState.SHARE_STATE_DEFAULT,
|
this.shareState = CustomTabsShareState.SHARE_STATE_DEFAULT,
|
||||||
@ -55,8 +81,12 @@ class AndroidChromeCustomTabsOptions
|
|||||||
this.instantAppsEnabled = false,
|
this.instantAppsEnabled = false,
|
||||||
this.packageName,
|
this.packageName,
|
||||||
this.keepAliveEnabled = false,
|
this.keepAliveEnabled = false,
|
||||||
this.singleInstance = false,
|
this.isSingleInstance = false,
|
||||||
this.noHistory = false});
|
this.noHistory = false,
|
||||||
|
this.isTrustedWebActivity = false,
|
||||||
|
this.additionalTrustedOrigins = const [],
|
||||||
|
this.displayMode,
|
||||||
|
this.screenOrientation = TrustedWebActivityScreenOrientation.DEFAULT});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, dynamic> toMap() {
|
Map<String, dynamic> toMap() {
|
||||||
@ -70,8 +100,12 @@ class AndroidChromeCustomTabsOptions
|
|||||||
"instantAppsEnabled": instantAppsEnabled,
|
"instantAppsEnabled": instantAppsEnabled,
|
||||||
"packageName": packageName,
|
"packageName": packageName,
|
||||||
"keepAliveEnabled": keepAliveEnabled,
|
"keepAliveEnabled": keepAliveEnabled,
|
||||||
"singleInstance": singleInstance,
|
"isSingleInstance": isSingleInstance,
|
||||||
"noHistory": noHistory
|
"noHistory": noHistory,
|
||||||
|
"isTrustedWebActivity": isTrustedWebActivity,
|
||||||
|
"additionalTrustedOrigins": additionalTrustedOrigins,
|
||||||
|
"displayMode": displayMode?.toMap(),
|
||||||
|
"screenOrientation": screenOrientation.toValue()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,8 +122,20 @@ class AndroidChromeCustomTabsOptions
|
|||||||
options.instantAppsEnabled = map["instantAppsEnabled"];
|
options.instantAppsEnabled = map["instantAppsEnabled"];
|
||||||
options.packageName = map["packageName"];
|
options.packageName = map["packageName"];
|
||||||
options.keepAliveEnabled = map["keepAliveEnabled"];
|
options.keepAliveEnabled = map["keepAliveEnabled"];
|
||||||
options.singleInstance = map["singleInstance"];
|
options.isSingleInstance = map["isSingleInstance"];
|
||||||
options.noHistory = map["noHistory"];
|
options.noHistory = map["noHistory"];
|
||||||
|
options.isTrustedWebActivity = map["isTrustedWebActivity"];
|
||||||
|
options.additionalTrustedOrigins = map["additionalTrustedOrigins"];
|
||||||
|
switch(map["displayMode"]["type"]) {
|
||||||
|
case "IMMERSIVE_MODE":
|
||||||
|
options.displayMode = TrustedWebActivityImmersiveDisplayMode.fromMap(map["displayMode"]);
|
||||||
|
break;
|
||||||
|
case "DEFAULT_MODE":
|
||||||
|
default:
|
||||||
|
options.displayMode = TrustedWebActivityDefaultDisplayMode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
options.screenOrientation = map["screenOrientation"];
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7012,6 +7012,264 @@ class CustomTabsShareState {
|
|||||||
|
|
||||||
bool operator ==(value) => value == _value;
|
bool operator ==(value) => value == _value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => _value.hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Android-class that represents display mode of a Trusted Web Activity.
|
||||||
|
abstract class TrustedWebActivityDisplayMode {
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return this.toMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return toMap().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///Android-class that represents the default display mode of a Trusted Web Activity.
|
||||||
|
///The system UI (status bar, navigation bar) is shown, and the browser toolbar is hidden while the user is on a verified origin.
|
||||||
|
class TrustedWebActivityDefaultDisplayMode implements TrustedWebActivityDisplayMode {
|
||||||
|
|
||||||
|
String _type = "DEFAULT_MODE";
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
return {
|
||||||
|
"type": _type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return this.toMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return toMap().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///Android-class that represents the default display mode of a Trusted Web Activity.
|
||||||
|
///The system UI (status bar, navigation bar) is shown, and the browser toolbar is hidden while the user is on a verified origin.
|
||||||
|
class TrustedWebActivityImmersiveDisplayMode implements TrustedWebActivityDisplayMode {
|
||||||
|
///Whether the Trusted Web Activity should be in sticky immersive mode.
|
||||||
|
bool isSticky;
|
||||||
|
|
||||||
|
///The constant defining how to deal with display cutouts.
|
||||||
|
AndroidLayoutInDisplayCutoutMode layoutInDisplayCutoutMode;
|
||||||
|
|
||||||
|
String _type = "IMMERSIVE_MODE";
|
||||||
|
|
||||||
|
TrustedWebActivityImmersiveDisplayMode(
|
||||||
|
{required this.isSticky,
|
||||||
|
required this.layoutInDisplayCutoutMode});
|
||||||
|
|
||||||
|
static TrustedWebActivityImmersiveDisplayMode? fromMap(Map<String, dynamic>? map) {
|
||||||
|
if (map == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TrustedWebActivityImmersiveDisplayMode(
|
||||||
|
isSticky: map["isSticky"],
|
||||||
|
layoutInDisplayCutoutMode: map["layoutInDisplayCutoutMode"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
return {
|
||||||
|
"isSticky": isSticky,
|
||||||
|
"layoutInDisplayCutoutMode": layoutInDisplayCutoutMode.toValue(),
|
||||||
|
"type": _type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return this.toMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return toMap().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///Android-specific class representing the share state that should be applied to the custom tab.
|
||||||
|
///
|
||||||
|
///**NOTE**: available on Android 28+.
|
||||||
|
class AndroidLayoutInDisplayCutoutMode {
|
||||||
|
final int _value;
|
||||||
|
|
||||||
|
const AndroidLayoutInDisplayCutoutMode._internal(this._value);
|
||||||
|
|
||||||
|
static final Set<AndroidLayoutInDisplayCutoutMode> values = [
|
||||||
|
AndroidLayoutInDisplayCutoutMode.DEFAULT,
|
||||||
|
AndroidLayoutInDisplayCutoutMode.SHORT_EDGES,
|
||||||
|
AndroidLayoutInDisplayCutoutMode.NEVER,
|
||||||
|
AndroidLayoutInDisplayCutoutMode.ALWAYS
|
||||||
|
].toSet();
|
||||||
|
|
||||||
|
static AndroidLayoutInDisplayCutoutMode? fromValue(int? value) {
|
||||||
|
if (value != null) {
|
||||||
|
try {
|
||||||
|
return AndroidLayoutInDisplayCutoutMode.values
|
||||||
|
.firstWhere((element) => element.toValue() == value);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int toValue() => _value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
switch (_value) {
|
||||||
|
case 1:
|
||||||
|
return "SHORT_EDGES";
|
||||||
|
case 2:
|
||||||
|
return "NEVER";
|
||||||
|
case 3:
|
||||||
|
return "ALWAYS";
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
return "DEFAULT";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///With this default setting, content renders into the cutout area when displayed in portrait mode, but content is letterboxed when displayed in landscape mode.
|
||||||
|
///
|
||||||
|
///**NOTE**: available on Android 28+.
|
||||||
|
static const DEFAULT = const AndroidLayoutInDisplayCutoutMode._internal(0);
|
||||||
|
|
||||||
|
///Content renders into the cutout area in both portrait and landscape modes.
|
||||||
|
///
|
||||||
|
///**NOTE**: available on Android 28+.
|
||||||
|
static const SHORT_EDGES = const AndroidLayoutInDisplayCutoutMode._internal(1);
|
||||||
|
|
||||||
|
///Content never renders into the cutout area.
|
||||||
|
///
|
||||||
|
///**NOTE**: available on Android 28+.
|
||||||
|
static const NEVER = const AndroidLayoutInDisplayCutoutMode._internal(2);
|
||||||
|
|
||||||
|
///The window is always allowed to extend into the DisplayCutout areas on the all edges of the screen.
|
||||||
|
///
|
||||||
|
///**NOTE**: available on Android 30+.
|
||||||
|
static const ALWAYS = const AndroidLayoutInDisplayCutoutMode._internal(3);
|
||||||
|
|
||||||
|
bool operator ==(value) => value == _value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => _value.hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Android-specific class representing Screen Orientation Lock type value of a Trusted Web Activity:
|
||||||
|
/// https://www.w3.org/TR/screen-orientation/#screenorientation-interface
|
||||||
|
class TrustedWebActivityScreenOrientation {
|
||||||
|
final int _value;
|
||||||
|
|
||||||
|
const TrustedWebActivityScreenOrientation._internal(this._value);
|
||||||
|
|
||||||
|
static final Set<TrustedWebActivityScreenOrientation> values = [
|
||||||
|
TrustedWebActivityScreenOrientation.DEFAULT,
|
||||||
|
TrustedWebActivityScreenOrientation.PORTRAIT_PRIMARY,
|
||||||
|
TrustedWebActivityScreenOrientation.PORTRAIT_SECONDARY,
|
||||||
|
TrustedWebActivityScreenOrientation.LANDSCAPE_PRIMARY,
|
||||||
|
TrustedWebActivityScreenOrientation.LANDSCAPE_SECONDARY,
|
||||||
|
TrustedWebActivityScreenOrientation.ANY,
|
||||||
|
TrustedWebActivityScreenOrientation.LANDSCAPE,
|
||||||
|
TrustedWebActivityScreenOrientation.PORTRAIT,
|
||||||
|
TrustedWebActivityScreenOrientation.NATURAL,
|
||||||
|
].toSet();
|
||||||
|
|
||||||
|
static TrustedWebActivityScreenOrientation? fromValue(int? value) {
|
||||||
|
if (value != null) {
|
||||||
|
try {
|
||||||
|
return TrustedWebActivityScreenOrientation.values
|
||||||
|
.firstWhere((element) => element.toValue() == value);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int toValue() => _value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
switch (_value) {
|
||||||
|
case 1:
|
||||||
|
return "PORTRAIT_PRIMARY";
|
||||||
|
case 2:
|
||||||
|
return "PORTRAIT_SECONDARY";
|
||||||
|
case 3:
|
||||||
|
return "LANDSCAPE_PRIMARY";
|
||||||
|
case 4:
|
||||||
|
return "LANDSCAPE_SECONDARY";
|
||||||
|
case 5:
|
||||||
|
return "ANY";
|
||||||
|
case 6:
|
||||||
|
return "LANDSCAPE";
|
||||||
|
case 7:
|
||||||
|
return "PORTRAIT";
|
||||||
|
case 8:
|
||||||
|
return "NATURAL";
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
return "DEFAULT";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The default screen orientation is the set of orientations to which the screen is locked when
|
||||||
|
/// there is no current orientation lock.
|
||||||
|
static const DEFAULT = const TrustedWebActivityScreenOrientation._internal(0);
|
||||||
|
|
||||||
|
/// Portrait-primary is an orientation where the screen width is less than or equal to the
|
||||||
|
/// screen height. If the device's natural orientation is portrait, then it is in
|
||||||
|
/// portrait-primary when held in that position.
|
||||||
|
static const PORTRAIT_PRIMARY = const TrustedWebActivityScreenOrientation._internal(1);
|
||||||
|
|
||||||
|
/// Portrait-secondary is an orientation where the screen width is less than or equal to the
|
||||||
|
/// screen height. If the device's natural orientation is portrait, then it is in
|
||||||
|
/// portrait-secondary when rotated 180° from its natural position.
|
||||||
|
static const PORTRAIT_SECONDARY = const TrustedWebActivityScreenOrientation._internal(2);
|
||||||
|
|
||||||
|
/// Landscape-primary is an orientation where the screen width is greater than the screen height.
|
||||||
|
/// If the device's natural orientation is landscape, then it is in landscape-primary when held
|
||||||
|
/// in that position.
|
||||||
|
static const LANDSCAPE_PRIMARY = const TrustedWebActivityScreenOrientation._internal(3);
|
||||||
|
|
||||||
|
/// Landscape-secondary is an orientation where the screen width is greater than the
|
||||||
|
/// screen height. If the device's natural orientation is landscape, it is in
|
||||||
|
/// landscape-secondary when rotated 180° from its natural orientation.
|
||||||
|
static const LANDSCAPE_SECONDARY = const TrustedWebActivityScreenOrientation._internal(4);
|
||||||
|
|
||||||
|
/// Any is an orientation that means the screen can be locked to any one of portrait-primary,
|
||||||
|
/// portrait-secondary, landscape-primary and landscape-secondary.
|
||||||
|
static const ANY = const TrustedWebActivityScreenOrientation._internal(5);
|
||||||
|
|
||||||
|
/// Landscape is an orientation where the screen width is greater than the screen height and
|
||||||
|
/// depending on platform convention locking the screen to landscape can represent
|
||||||
|
/// landscape-primary, landscape-secondary or both.
|
||||||
|
static const LANDSCAPE = const TrustedWebActivityScreenOrientation._internal(6);
|
||||||
|
|
||||||
|
/// Portrait is an orientation where the screen width is less than or equal to the screen height
|
||||||
|
/// and depending on platform convention locking the screen to portrait can represent
|
||||||
|
/// portrait-primary, portrait-secondary or both.
|
||||||
|
static const PORTRAIT = const TrustedWebActivityScreenOrientation._internal(7);
|
||||||
|
|
||||||
|
/// Natural is an orientation that refers to either portrait-primary or landscape-primary
|
||||||
|
/// depending on the device's usual orientation. This orientation is usually provided by
|
||||||
|
/// the underlying operating system.
|
||||||
|
static const NATURAL = const TrustedWebActivityScreenOrientation._internal(8);
|
||||||
|
|
||||||
|
bool operator ==(value) => value == _value;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => _value.hashCode;
|
int get hashCode => _value.hashCode;
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user