Added requestPostMessageChannel, postMessage, isEngagementSignalsApiAvailable methods on ChromeSafariBrowser for Android, Added onMessageChannelReady, onPostMessage, onVerticalScrollEvent, onGreatestScrollPercentageIncreased, onSessionEnded events on ChromeSafariBrowser for Android
This commit is contained in:
parent
5009bf1fa4
commit
6a486b2fa9
|
@ -1,3 +1,8 @@
|
||||||
|
## 6.0.0-beta.27
|
||||||
|
|
||||||
|
- Added `requestPostMessageChannel`, `postMessage`, `isEngagementSignalsApiAvailable` methods on `ChromeSafariBrowser` for Android
|
||||||
|
- Added `onMessageChannelReady`, `onPostMessage`, `onVerticalScrollEvent`, `onGreatestScrollPercentageIncreased`, `onSessionEnded` events on `ChromeSafariBrowser` for Android
|
||||||
|
|
||||||
## 6.0.0-beta.26
|
## 6.0.0-beta.26
|
||||||
|
|
||||||
- Throw an error if any controller is used after being disposed
|
- Throw an error if any controller is used after being disposed
|
||||||
|
|
|
@ -9,6 +9,7 @@ import android.graphics.Color;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.RemoteException;
|
||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
|
|
||||||
import androidx.annotation.CallSuper;
|
import androidx.annotation.CallSuper;
|
||||||
|
@ -19,6 +20,7 @@ import androidx.browser.customtabs.CustomTabsCallback;
|
||||||
import androidx.browser.customtabs.CustomTabsIntent;
|
import androidx.browser.customtabs.CustomTabsIntent;
|
||||||
import androidx.browser.customtabs.CustomTabsService;
|
import androidx.browser.customtabs.CustomTabsService;
|
||||||
import androidx.browser.customtabs.CustomTabsSession;
|
import androidx.browser.customtabs.CustomTabsSession;
|
||||||
|
import androidx.browser.customtabs.EngagementSignalsCallback;
|
||||||
|
|
||||||
import com.pichillilorenzo.flutter_inappwebview.R;
|
import com.pichillilorenzo.flutter_inappwebview.R;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.AndroidResource;
|
import com.pichillilorenzo.flutter_inappwebview.types.AndroidResource;
|
||||||
|
@ -32,12 +34,13 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.flutter.Log;
|
||||||
import io.flutter.plugin.common.MethodChannel;
|
import io.flutter.plugin.common.MethodChannel;
|
||||||
|
|
||||||
public class ChromeCustomTabsActivity extends Activity implements Disposable {
|
public class ChromeCustomTabsActivity extends Activity implements Disposable {
|
||||||
protected static final String LOG_TAG = "CustomTabsActivity";
|
protected static final String LOG_TAG = "CustomTabsActivity";
|
||||||
public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_chromesafaribrowser_";
|
public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_chromesafaribrowser_";
|
||||||
|
|
||||||
public String id;
|
public String id;
|
||||||
@Nullable
|
@Nullable
|
||||||
public CustomTabsIntent.Builder builder;
|
public CustomTabsIntent.Builder builder;
|
||||||
|
@ -76,7 +79,7 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable {
|
||||||
|
|
||||||
Bundle b = getIntent().getExtras();
|
Bundle b = getIntent().getExtras();
|
||||||
if (b == null) return;
|
if (b == null) return;
|
||||||
|
|
||||||
id = b.getString("id");
|
id = b.getString("id");
|
||||||
|
|
||||||
String managerId = b.getString("managerId");
|
String managerId = b.getString("managerId");
|
||||||
|
@ -143,13 +146,22 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void extraCallback(@NonNull String callbackName, Bundle args) {}
|
public void extraCallback(@NonNull String callbackName, Bundle args) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessageChannelReady(Bundle extras) {}
|
public void onMessageChannelReady(Bundle extras) {
|
||||||
|
if (channelDelegate != null) {
|
||||||
|
channelDelegate.onMessageChannelReady();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPostMessage(@NonNull String message, Bundle extras) {}
|
public void onPostMessage(@NonNull String message, Bundle extras) {
|
||||||
|
if (channelDelegate != null) {
|
||||||
|
channelDelegate.onPostMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRelationshipValidationResult(@CustomTabsService.Relation int relation,
|
public void onRelationshipValidationResult(@CustomTabsService.Relation int relation,
|
||||||
|
@ -198,8 +210,41 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable {
|
||||||
return customTabActivityHelper.mayLaunchUrl(uri, null, bundleOtherLikelyURLs);
|
return customTabActivityHelper.mayLaunchUrl(uri, null, bundleOtherLikelyURLs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
public void customTabsConnected() {
|
public void customTabsConnected() {
|
||||||
customTabsSession = customTabActivityHelper.getSession();
|
customTabsSession = customTabActivityHelper.getSession();
|
||||||
|
|
||||||
|
if (customTabsSession != null) {
|
||||||
|
try {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
if (customTabsSession.isEngagementSignalsApiAvailable(bundle)) {
|
||||||
|
customTabsSession.setEngagementSignalsCallback(new EngagementSignalsCallback() {
|
||||||
|
@Override
|
||||||
|
public void onVerticalScrollEvent(boolean isDirectionUp, @NonNull Bundle extras) {
|
||||||
|
if (channelDelegate != null) {
|
||||||
|
channelDelegate.onVerticalScrollEvent(isDirectionUp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onGreatestScrollPercentageIncreased(int scrollPercentage, @NonNull Bundle extras) {
|
||||||
|
if (channelDelegate != null) {
|
||||||
|
channelDelegate.onGreatestScrollPercentageIncreased(scrollPercentage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSessionEnded(boolean didUserInteract, @NonNull Bundle extras) {
|
||||||
|
if (channelDelegate != null) {
|
||||||
|
channelDelegate.onSessionEnded(didUserInteract);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, bundle);
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// avoid webpage reopen if isBindSuccess is false: onServiceConnected->launchUrl
|
// avoid webpage reopen if isBindSuccess is false: onServiceConnected->launchUrl
|
||||||
if (isBindSuccess && initialUrl != null) {
|
if (isBindSuccess && initialUrl != null) {
|
||||||
launchUrl(initialUrl, initialHeaders, initialReferrer, initialOtherLikelyURLs);
|
launchUrl(initialUrl, initialHeaders, initialReferrer, initialOtherLikelyURLs);
|
||||||
|
@ -248,7 +293,7 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (CustomTabsMenuItem menuItem : menuItems) {
|
for (CustomTabsMenuItem menuItem : menuItems) {
|
||||||
builder.addMenuItem(menuItem.getLabel(),
|
builder.addMenuItem(menuItem.getLabel(),
|
||||||
createPendingIntent(menuItem.getId()));
|
createPendingIntent(menuItem.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,12 @@ package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.browser.customtabs.CustomTabsService;
|
||||||
|
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
|
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.CustomTabsActionButton;
|
import com.pichillilorenzo.flutter_inappwebview.types.CustomTabsActionButton;
|
||||||
|
@ -84,6 +87,35 @@ public class ChromeCustomTabsChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(false);
|
result.success(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "requestPostMessageChannel":
|
||||||
|
if (chromeCustomTabsActivity != null && chromeCustomTabsActivity.customTabsSession != null) {
|
||||||
|
String sourceOrigin = (String) call.argument("sourceOrigin");
|
||||||
|
String targetOrigin = (String) call.argument("targetOrigin");
|
||||||
|
result.success(chromeCustomTabsActivity.customTabsSession.requestPostMessageChannel(Uri.parse(sourceOrigin),
|
||||||
|
targetOrigin != null ? Uri.parse(targetOrigin) : null, new Bundle()));
|
||||||
|
} else {
|
||||||
|
result.success(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "postMessage":
|
||||||
|
if (chromeCustomTabsActivity != null && chromeCustomTabsActivity.customTabsSession != null) {
|
||||||
|
String message = (String) call.argument("message");
|
||||||
|
result.success(chromeCustomTabsActivity.customTabsSession.postMessage(message, new Bundle()));
|
||||||
|
} else {
|
||||||
|
result.success(CustomTabsService.RESULT_FAILURE_MESSAGING_ERROR);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "isEngagementSignalsApiAvailable":
|
||||||
|
if (chromeCustomTabsActivity != null && chromeCustomTabsActivity.customTabsSession != null) {
|
||||||
|
try {
|
||||||
|
result.success(chromeCustomTabsActivity.customTabsSession.isEngagementSignalsApiAvailable(new Bundle()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.success(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.success(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "close":
|
case "close":
|
||||||
if (chromeCustomTabsActivity != null) {
|
if (chromeCustomTabsActivity != null) {
|
||||||
chromeCustomTabsActivity.onStop();
|
chromeCustomTabsActivity.onStop();
|
||||||
|
@ -131,7 +163,7 @@ public class ChromeCustomTabsChannelDelegate extends ChannelDelegateImpl {
|
||||||
channel.invokeMethod("onCompletedInitialLoad", obj);
|
channel.invokeMethod("onCompletedInitialLoad", obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onNavigationEvent(int navigationEvent) {;
|
public void onNavigationEvent(int navigationEvent) {
|
||||||
MethodChannel channel = getChannel();
|
MethodChannel channel = getChannel();
|
||||||
if (channel == null) return;
|
if (channel == null) return;
|
||||||
Map<String, Object> obj = new HashMap<>();
|
Map<String, Object> obj = new HashMap<>();
|
||||||
|
@ -175,6 +207,45 @@ public class ChromeCustomTabsChannelDelegate extends ChannelDelegateImpl {
|
||||||
channel.invokeMethod("onRelationshipValidationResult", obj);
|
channel.invokeMethod("onRelationshipValidationResult", obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onMessageChannelReady() {
|
||||||
|
MethodChannel channel = getChannel();
|
||||||
|
if (channel == null) return;
|
||||||
|
Map<String, Object> obj = new HashMap<>();
|
||||||
|
channel.invokeMethod("onMessageChannelReady", obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPostMessage(@NonNull String message) {
|
||||||
|
MethodChannel channel = getChannel();
|
||||||
|
if (channel == null) return;
|
||||||
|
Map<String, Object> obj = new HashMap<>();
|
||||||
|
obj.put("message", message);
|
||||||
|
channel.invokeMethod("onPostMessage", obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onVerticalScrollEvent(boolean isDirectionUp) {
|
||||||
|
MethodChannel channel = getChannel();
|
||||||
|
if (channel == null) return;
|
||||||
|
Map<String, Object> obj = new HashMap<>();
|
||||||
|
obj.put("isDirectionUp", isDirectionUp);
|
||||||
|
channel.invokeMethod("onVerticalScrollEvent", obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onGreatestScrollPercentageIncreased(int scrollPercentage) {
|
||||||
|
MethodChannel channel = getChannel();
|
||||||
|
if (channel == null) return;
|
||||||
|
Map<String, Object> obj = new HashMap<>();
|
||||||
|
obj.put("scrollPercentage", scrollPercentage);
|
||||||
|
channel.invokeMethod("onGreatestScrollPercentageIncreased", obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSessionEnded(boolean didUserInteract) {
|
||||||
|
MethodChannel channel = getChannel();
|
||||||
|
if (channel == null) return;
|
||||||
|
Map<String, Object> obj = new HashMap<>();
|
||||||
|
obj.put("didUserInteract", didUserInteract);
|
||||||
|
channel.invokeMethod("onSessionEnded", obj);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
|
|
@ -41,14 +41,6 @@ public class TrustedWebActivity extends ChromeCustomTabsActivity {
|
||||||
referrer != null ? Uri.parse(referrer) : null, CHROME_CUSTOM_TAB_REQUEST_CODE);
|
referrer != null ? Uri.parse(referrer) : null, CHROME_CUSTOM_TAB_REQUEST_CODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void customTabsConnected() {
|
|
||||||
customTabsSession = customTabActivityHelper.getSession();
|
|
||||||
if (initialUrl != null) {
|
|
||||||
launchUrl(initialUrl, initialHeaders, initialReferrer, initialOtherLikelyURLs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void prepareCustomTabs() {
|
private void prepareCustomTabs() {
|
||||||
CustomTabColorSchemeParams.Builder defaultColorSchemeBuilder = new CustomTabColorSchemeParams.Builder();
|
CustomTabColorSchemeParams.Builder defaultColorSchemeBuilder = new CustomTabColorSchemeParams.Builder();
|
||||||
if (customSettings.toolbarBackgroundColor != null && !customSettings.toolbarBackgroundColor.isEmpty()) {
|
if (customSettings.toolbarBackgroundColor != null && !customSettings.toolbarBackgroundColor.isEmpty()) {
|
||||||
|
|
|
@ -93,6 +93,7 @@
|
||||||
android:name="io.flutter.embedded_views_preview"
|
android:name="io.flutter.embedded_views_preview"
|
||||||
android:value="true" />
|
android:value="true" />
|
||||||
|
|
||||||
|
<service android:name="androidx.browser.customtabs.PostMessageService"
|
||||||
|
android:exported="true"/>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -6,6 +6,12 @@
|
||||||
\"target\": {
|
\"target\": {
|
||||||
\"namespace\": \"web\",
|
\"namespace\": \"web\",
|
||||||
\"site\": \"https://flutter.dev\"}
|
\"site\": \"https://flutter.dev\"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\"relation\": [\"delegate_permission/common.handle_all_urls\"],
|
||||||
|
\"target\": {
|
||||||
|
\"namespace\": \"web\",
|
||||||
|
\"site\": \"https://inappwebview.dev\"}
|
||||||
}]
|
}]
|
||||||
</string>
|
</string>
|
||||||
</resources>
|
</resources>
|
|
@ -170,5 +170,52 @@ void customTabs() {
|
||||||
expect(await ChromeSafariBrowser.getMaxToolbarItems(),
|
expect(await ChromeSafariBrowser.getMaxToolbarItems(),
|
||||||
greaterThanOrEqualTo(0));
|
greaterThanOrEqualTo(0));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
skippableTest('request and send post messages', () async {
|
||||||
|
var chromeSafariBrowser = MyChromeSafariBrowser();
|
||||||
|
expect(chromeSafariBrowser.isOpened(), false);
|
||||||
|
|
||||||
|
await chromeSafariBrowser.open(
|
||||||
|
url: TEST_CUSTOM_TABS_POST_MESSAGE_URL,
|
||||||
|
settings: ChromeSafariBrowserSettings(isSingleInstance: true));
|
||||||
|
await expectLater(chromeSafariBrowser.opened.future, completes);
|
||||||
|
expect(chromeSafariBrowser.isOpened(), true);
|
||||||
|
|
||||||
|
await expectLater(
|
||||||
|
chromeSafariBrowser.navigationFinished.future, completes);
|
||||||
|
expect(
|
||||||
|
await chromeSafariBrowser.requestPostMessageChannel(
|
||||||
|
sourceOrigin: WebUri(TEST_CUSTOM_TABS_POST_MESSAGE_URL.origin)),
|
||||||
|
true);
|
||||||
|
await expectLater(
|
||||||
|
chromeSafariBrowser.messageChannelReady.future, completes);
|
||||||
|
expect(await chromeSafariBrowser.postMessage("Message from Flutter"),
|
||||||
|
CustomTabsPostMessageResultType.SUCCESS);
|
||||||
|
await expectLater(chromeSafariBrowser.postMessageReceived.future,
|
||||||
|
completion("Message from JavaScript"));
|
||||||
|
|
||||||
|
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
||||||
|
await chromeSafariBrowser.close();
|
||||||
|
await expectLater(chromeSafariBrowser.closed.future, completes);
|
||||||
|
expect(chromeSafariBrowser.isOpened(), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
skippableTest('Engagement Signals Api', () async {
|
||||||
|
var chromeSafariBrowser = MyChromeSafariBrowser();
|
||||||
|
expect(chromeSafariBrowser.isOpened(), false);
|
||||||
|
|
||||||
|
await chromeSafariBrowser.open(
|
||||||
|
url: TEST_URL_1,
|
||||||
|
settings: ChromeSafariBrowserSettings(isSingleInstance: true));
|
||||||
|
await expectLater(chromeSafariBrowser.opened.future, completes);
|
||||||
|
|
||||||
|
await expectLater(
|
||||||
|
chromeSafariBrowser.isEngagementSignalsApiAvailable(), completes);
|
||||||
|
|
||||||
|
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
||||||
|
await chromeSafariBrowser.close();
|
||||||
|
await expectLater(chromeSafariBrowser.closed.future, completes);
|
||||||
|
expect(chromeSafariBrowser.isOpened(), false);
|
||||||
|
});
|
||||||
}, skip: shouldSkip);
|
}, skip: shouldSkip);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,12 +13,12 @@ void trustedWebActivity() {
|
||||||
expect(chromeSafariBrowser.isOpened(), false);
|
expect(chromeSafariBrowser.isOpened(), false);
|
||||||
|
|
||||||
await chromeSafariBrowser.open(
|
await chromeSafariBrowser.open(
|
||||||
url: TEST_URL_1,
|
url: TEST_TWA_URL,
|
||||||
settings: ChromeSafariBrowserSettings(isTrustedWebActivity: true));
|
settings: ChromeSafariBrowserSettings(isTrustedWebActivity: true));
|
||||||
await chromeSafariBrowser.opened.future;
|
await chromeSafariBrowser.opened.future;
|
||||||
expect(chromeSafariBrowser.isOpened(), true);
|
expect(chromeSafariBrowser.isOpened(), true);
|
||||||
expect(() async {
|
expect(() async {
|
||||||
await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1);
|
await chromeSafariBrowser.open(url: TEST_TWA_URL);
|
||||||
}, throwsAssertionError);
|
}, throwsAssertionError);
|
||||||
|
|
||||||
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
||||||
|
@ -32,13 +32,13 @@ void trustedWebActivity() {
|
||||||
expect(chromeSafariBrowser.isOpened(), false);
|
expect(chromeSafariBrowser.isOpened(), false);
|
||||||
|
|
||||||
await chromeSafariBrowser.open(
|
await chromeSafariBrowser.open(
|
||||||
url: TEST_URL_1,
|
url: TEST_TWA_URL,
|
||||||
settings: ChromeSafariBrowserSettings(
|
settings: ChromeSafariBrowserSettings(
|
||||||
isTrustedWebActivity: true, isSingleInstance: true));
|
isTrustedWebActivity: true, isSingleInstance: true));
|
||||||
await chromeSafariBrowser.opened.future;
|
await chromeSafariBrowser.opened.future;
|
||||||
expect(chromeSafariBrowser.isOpened(), true);
|
expect(chromeSafariBrowser.isOpened(), true);
|
||||||
expect(() async {
|
expect(() async {
|
||||||
await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1);
|
await chromeSafariBrowser.open(url: TEST_TWA_URL);
|
||||||
}, throwsAssertionError);
|
}, throwsAssertionError);
|
||||||
|
|
||||||
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
||||||
|
@ -57,11 +57,11 @@ void trustedWebActivity() {
|
||||||
expect(
|
expect(
|
||||||
await chromeSafariBrowser.validateRelationship(
|
await chromeSafariBrowser.validateRelationship(
|
||||||
relation: CustomTabsRelationType.USE_AS_ORIGIN,
|
relation: CustomTabsRelationType.USE_AS_ORIGIN,
|
||||||
origin: TEST_CROSS_PLATFORM_URL_1),
|
origin: TEST_TWA_URL),
|
||||||
true);
|
true);
|
||||||
expect(
|
expect(
|
||||||
await chromeSafariBrowser.relationshipValidationResult.future, true);
|
await chromeSafariBrowser.relationshipValidationResult.future, true);
|
||||||
await chromeSafariBrowser.launchUrl(url: TEST_CROSS_PLATFORM_URL_1);
|
await chromeSafariBrowser.launchUrl(url: TEST_TWA_URL);
|
||||||
await chromeSafariBrowser.opened.future;
|
await chromeSafariBrowser.opened.future;
|
||||||
expect(chromeSafariBrowser.isOpened(), true);
|
expect(chromeSafariBrowser.isOpened(), true);
|
||||||
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
||||||
|
|
|
@ -28,3 +28,7 @@ final TEST_SERVICE_WORKER_URL = WebUri(
|
||||||
final TEST_WEBVIEW_ASSET_LOADER_DOMAIN = 'my.custom.domain.com';
|
final TEST_WEBVIEW_ASSET_LOADER_DOMAIN = 'my.custom.domain.com';
|
||||||
final TEST_WEBVIEW_ASSET_LOADER_URL = WebUri(
|
final TEST_WEBVIEW_ASSET_LOADER_URL = WebUri(
|
||||||
'https://$TEST_WEBVIEW_ASSET_LOADER_DOMAIN/assets/flutter_assets/test_assets/website/index.html');
|
'https://$TEST_WEBVIEW_ASSET_LOADER_DOMAIN/assets/flutter_assets/test_assets/website/index.html');
|
||||||
|
final TEST_TWA_URL =
|
||||||
|
WebUri('https://inappwebview.dev/test-twa-postmessage.html');
|
||||||
|
final TEST_CUSTOM_TABS_POST_MESSAGE_URL =
|
||||||
|
WebUri('https://inappwebview.dev/test-twa-postmessage.html');
|
||||||
|
|
|
@ -118,6 +118,9 @@ class MyChromeSafariBrowser extends ChromeSafariBrowser {
|
||||||
final Completer<void> closed = Completer<void>();
|
final Completer<void> closed = Completer<void>();
|
||||||
final Completer<CustomTabsNavigationEventType?> navigationEvent =
|
final Completer<CustomTabsNavigationEventType?> navigationEvent =
|
||||||
Completer<CustomTabsNavigationEventType?>();
|
Completer<CustomTabsNavigationEventType?>();
|
||||||
|
final Completer<void> navigationFinished = Completer<void>();
|
||||||
|
final Completer<void> messageChannelReady = Completer<void>();
|
||||||
|
final Completer<String> postMessageReceived = Completer<String>();
|
||||||
final Completer<bool> relationshipValidationResult = Completer<bool>();
|
final Completer<bool> relationshipValidationResult = Completer<bool>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -140,6 +143,24 @@ class MyChromeSafariBrowser extends ChromeSafariBrowser {
|
||||||
if (!navigationEvent.isCompleted) {
|
if (!navigationEvent.isCompleted) {
|
||||||
navigationEvent.complete(type);
|
navigationEvent.complete(type);
|
||||||
}
|
}
|
||||||
|
if (!navigationFinished.isCompleted &&
|
||||||
|
type == CustomTabsNavigationEventType.FINISHED) {
|
||||||
|
navigationFinished.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onMessageChannelReady() async {
|
||||||
|
if (!messageChannelReady.isCompleted) {
|
||||||
|
messageChannelReady.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onPostMessage(String message) {
|
||||||
|
if (!postMessageReceived.isCompleted) {
|
||||||
|
postMessageReceived.complete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -19,6 +19,21 @@ class MyChromeSafariBrowser extends ChromeSafariBrowser {
|
||||||
void onClosed() {
|
void onClosed() {
|
||||||
print("ChromeSafari browser closed");
|
print("ChromeSafari browser closed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onVerticalScrollEvent(bool isDirectionUp) {
|
||||||
|
print("onVerticalScrollEvent $isDirectionUp");
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onGreatestScrollPercentageIncreased(int scrollPercentage) {
|
||||||
|
print("onGreatestScrollPercentageIncreased $scrollPercentage");
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onSessionEnded(bool didUserInteract) {
|
||||||
|
print("onSessionEnded $didUserInteract");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChromeSafariBrowserExampleScreen extends StatefulWidget {
|
class ChromeSafariBrowserExampleScreen extends StatefulWidget {
|
||||||
|
@ -103,6 +118,8 @@ class _ChromeSafariBrowserExampleScreenState
|
||||||
dismissButtonStyle: DismissButtonStyle.CLOSE,
|
dismissButtonStyle: DismissButtonStyle.CLOSE,
|
||||||
presentationStyle:
|
presentationStyle:
|
||||||
ModalPresentationStyle.OVER_FULL_SCREEN));
|
ModalPresentationStyle.OVER_FULL_SCREEN));
|
||||||
|
await Future.delayed(Duration(seconds: 5));
|
||||||
|
widget.browser.close();
|
||||||
},
|
},
|
||||||
child: Text("Open Chrome Safari Browser")),
|
child: Text("Open Chrome Safari Browser")),
|
||||||
));
|
));
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'dart:typed_data';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import '../types/custom_tabs_navigation_event_type.dart';
|
import '../types/custom_tabs_navigation_event_type.dart';
|
||||||
|
import '../types/custom_tabs_post_message_result_type.dart';
|
||||||
import '../types/custom_tabs_relation_type.dart';
|
import '../types/custom_tabs_relation_type.dart';
|
||||||
import '../types/prewarming_token.dart';
|
import '../types/prewarming_token.dart';
|
||||||
import '../util.dart';
|
import '../util.dart';
|
||||||
|
@ -153,6 +154,25 @@ class ChromeSafariBrowser extends ChannelController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "onMessageChannelReady":
|
||||||
|
onMessageChannelReady();
|
||||||
|
break;
|
||||||
|
case "onPostMessage":
|
||||||
|
final String message = call.arguments["message"];
|
||||||
|
onPostMessage(message);
|
||||||
|
break;
|
||||||
|
case "onVerticalScrollEvent":
|
||||||
|
final bool isDirectionUp = call.arguments["isDirectionUp"];
|
||||||
|
onVerticalScrollEvent(isDirectionUp);
|
||||||
|
break;
|
||||||
|
case "onGreatestScrollPercentageIncreased":
|
||||||
|
final int scrollPercentage = call.arguments["scrollPercentage"];
|
||||||
|
onGreatestScrollPercentageIncreased(scrollPercentage);
|
||||||
|
break;
|
||||||
|
case "onSessionEnded":
|
||||||
|
final bool didUserInteract = call.arguments["didUserInteract"];
|
||||||
|
onSessionEnded(didUserInteract);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw UnimplementedError("Unimplemented ${call.method} method");
|
throw UnimplementedError("Unimplemented ${call.method} method");
|
||||||
}
|
}
|
||||||
|
@ -384,6 +404,67 @@ class ChromeSafariBrowser extends ChannelController {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///Sends a request to create a two way postMessage channel between the client
|
||||||
|
///and the browser.
|
||||||
|
///If you want to specifying the target origin to communicate with, set the [targetOrigin].
|
||||||
|
///
|
||||||
|
///[sourceOrigin] - A origin that the client is requesting to be
|
||||||
|
///identified as during the postMessage communication.
|
||||||
|
///It has to either start with http or https.
|
||||||
|
///
|
||||||
|
///[targetOrigin] - The target Origin to establish the postMessage communication with.
|
||||||
|
///This can be the app's package name, it has to either start with http or https.
|
||||||
|
///
|
||||||
|
///Returns whether the implementation accepted the request.
|
||||||
|
///Note that returning true here doesn't mean an origin has already been
|
||||||
|
///assigned as the validation is asynchronous.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android ([Official API - CustomTabsSession.requestPostMessageChannel](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsSession#requestPostMessageChannel(android.net.Uri,android.net.Uri,android.os.Bundle)))
|
||||||
|
Future<bool> requestPostMessageChannel(
|
||||||
|
{required WebUri sourceOrigin, WebUri? targetOrigin}) async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
args.putIfAbsent("sourceOrigin", () => sourceOrigin.toString());
|
||||||
|
args.putIfAbsent("targetOrigin", () => targetOrigin.toString());
|
||||||
|
return await channel?.invokeMethod<bool>(
|
||||||
|
"requestPostMessageChannel", args) ??
|
||||||
|
false;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Sends a postMessage request using the origin communicated via [requestPostMessageChannel].
|
||||||
|
///Fails when called before [onMessageChannelReady] event.
|
||||||
|
///
|
||||||
|
///[message] – The message that is being sent.
|
||||||
|
///
|
||||||
|
///Returns an integer constant about the postMessage request result.
|
||||||
|
///Will return CustomTabsService.RESULT_SUCCESS if successful.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android ([Official API - CustomTabsSession.postMessage](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsSession#postMessage(java.lang.String,android.os.Bundle)))
|
||||||
|
Future<CustomTabsPostMessageResultType> postMessage(String message) async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
args.putIfAbsent("message", () => message);
|
||||||
|
return CustomTabsPostMessageResultType.fromNativeValue(
|
||||||
|
await channel?.invokeMethod<int>("postMessage", args)) ??
|
||||||
|
CustomTabsPostMessageResultType.FAILURE_MESSAGING_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Returns whether the Engagement Signals API is available.
|
||||||
|
///The availability of the Engagement Signals API may change at runtime.
|
||||||
|
///If an EngagementSignalsCallback has been set, an [onSessionEnded]
|
||||||
|
///signal will be sent if the API becomes unavailable later.
|
||||||
|
///
|
||||||
|
///Returns whether the Engagement Signals API is available.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android ([Official API - CustomTabsSession.isEngagementSignalsApiAvailable](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsSession#isEngagementSignalsApiAvailable(android.os.Bundle)))
|
||||||
|
Future<bool> isEngagementSignalsApiAvailable() async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
return await channel?.invokeMethod<bool>(
|
||||||
|
"isEngagementSignalsApiAvailable", args) ??
|
||||||
|
false;
|
||||||
|
}
|
||||||
|
|
||||||
///On Android, returns `true` if Chrome Custom Tabs is available.
|
///On Android, returns `true` if Chrome Custom Tabs is available.
|
||||||
///On iOS, returns `true` if SFSafariViewController is available.
|
///On iOS, returns `true` if SFSafariViewController is available.
|
||||||
///Otherwise returns `false`.
|
///Otherwise returns `false`.
|
||||||
|
@ -393,7 +474,8 @@ class ChromeSafariBrowser extends ChannelController {
|
||||||
///- iOS
|
///- iOS
|
||||||
static Future<bool> isAvailable() async {
|
static Future<bool> isAvailable() async {
|
||||||
Map<String, dynamic> args = <String, dynamic>{};
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
return await _sharedChannel.invokeMethod("isAvailable", args);
|
return await _sharedChannel.invokeMethod<bool>("isAvailable", args) ??
|
||||||
|
false;
|
||||||
}
|
}
|
||||||
|
|
||||||
///The maximum number of allowed secondary toolbar items.
|
///The maximum number of allowed secondary toolbar items.
|
||||||
|
@ -515,6 +597,57 @@ class ChromeSafariBrowser extends ChannelController {
|
||||||
///- iOS ([Official API - SFSafariViewControllerDelegate.safariViewControllerWillOpenInBrowser](https://developer.apple.com/documentation/safariservices/sfsafariviewcontrollerdelegate/3650426-safariviewcontrollerwillopeninbr))
|
///- iOS ([Official API - SFSafariViewControllerDelegate.safariViewControllerWillOpenInBrowser](https://developer.apple.com/documentation/safariservices/sfsafariviewcontrollerdelegate/3650426-safariviewcontrollerwillopeninbr))
|
||||||
void onWillOpenInBrowser() {}
|
void onWillOpenInBrowser() {}
|
||||||
|
|
||||||
|
///Called when the [ChromeSafariBrowser] has requested a postMessage channel through
|
||||||
|
///[requestPostMessageChannel] and the channel is ready for sending and receiving messages on both ends.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android ([Official API - CustomTabsCallback.onMessageChannelReady](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsCallback#onMessageChannelReady(android.os.Bundle)))
|
||||||
|
void onMessageChannelReady() {}
|
||||||
|
|
||||||
|
///Called when a tab controlled by this [ChromeSafariBrowser] has sent a postMessage.
|
||||||
|
///If [postMessage] is called from a single thread, then the messages will be posted in the same order.
|
||||||
|
///When received on the client side, it is the client's responsibility to preserve the ordering further.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android ([Official API - CustomTabsCallback.onPostMessage](https://developer.android.com/reference/androidx/browser/customtabs/CustomTabsCallback#onPostMessage(java.lang.String,android.os.Bundle)))
|
||||||
|
void onPostMessage(String message) {}
|
||||||
|
|
||||||
|
///Called when a user scrolls the tab.
|
||||||
|
///
|
||||||
|
///[isDirectionUp] - `false` when the user scrolls farther down the page,
|
||||||
|
///and `true` when the user scrolls back up toward the top of the page.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only if [isEngagementSignalsApiAvailable] returns `true`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android ([Official API - EngagementSignalsCallback.onVerticalScrollEvent](https://developer.android.com/reference/androidx/browser/customtabs/EngagementSignalsCallback#onVerticalScrollEvent(boolean,android.os.Bundle)))
|
||||||
|
void onVerticalScrollEvent(bool isDirectionUp) {}
|
||||||
|
|
||||||
|
///Called when a user has reached a greater scroll percentage on the page. The greatest scroll
|
||||||
|
///percentage is reset if the user navigates to a different page. If the current page's total
|
||||||
|
///height changes, this method will be called again only if the scroll progress reaches a
|
||||||
|
///higher percentage based on the new and current height of the page.
|
||||||
|
///
|
||||||
|
///[scrollPercentage] - An integer indicating the percent of scrollable progress
|
||||||
|
///the user hasmade down the current page.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only if [isEngagementSignalsApiAvailable] returns `true`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android ([Official API - EngagementSignalsCallback.onGreatestScrollPercentageIncreased](https://developer.android.com/reference/androidx/browser/customtabs/EngagementSignalsCallback#onGreatestScrollPercentageIncreased(int,android.os.Bundle)))
|
||||||
|
void onGreatestScrollPercentageIncreased(int scrollPercentage) {}
|
||||||
|
|
||||||
|
///Called when a `CustomTabsSession` is ending or when no further Engagement Signals
|
||||||
|
///callbacks are expected to report whether any user action has occurred during the session.
|
||||||
|
///
|
||||||
|
///[didUserInteract] - Whether the user has interacted with the page in any way, e.g. scrolling.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only if [isEngagementSignalsApiAvailable] returns `true`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android ([Official API - EngagementSignalsCallback.onSessionEnded](https://developer.android.com/reference/androidx/browser/customtabs/EngagementSignalsCallback#onSessionEnded(boolean,android.os.Bundle)))
|
||||||
|
void onSessionEnded(bool didUserInteract) {}
|
||||||
|
|
||||||
///Event fired when the [ChromeSafariBrowser] is closed.
|
///Event fired when the [ChromeSafariBrowser] is closed.
|
||||||
///
|
///
|
||||||
///**Supported Platforms/Implementations**:
|
///**Supported Platforms/Implementations**:
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart';
|
||||||
|
|
||||||
|
part 'custom_tabs_post_message_result_type.g.dart';
|
||||||
|
|
||||||
|
///Custom Tabs postMessage result type.
|
||||||
|
@ExchangeableEnum()
|
||||||
|
class CustomTabsPostMessageResultType_ {
|
||||||
|
// ignore: unused_field
|
||||||
|
final int _value;
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final int? _nativeValue = null;
|
||||||
|
|
||||||
|
const CustomTabsPostMessageResultType_._internal(this._value);
|
||||||
|
|
||||||
|
///Indicates that the postMessage request was accepted.
|
||||||
|
@EnumSupportedPlatforms(platforms: [EnumAndroidPlatform(value: 0)])
|
||||||
|
static const SUCCESS = const CustomTabsPostMessageResultType_._internal(0);
|
||||||
|
|
||||||
|
///Indicates that the postMessage request was not allowed due to a bad argument
|
||||||
|
///or requesting at a disallowed time like when in background.
|
||||||
|
@EnumSupportedPlatforms(platforms: [EnumAndroidPlatform(value: -1)])
|
||||||
|
static const FAILURE_DISALLOWED =
|
||||||
|
const CustomTabsPostMessageResultType_._internal(-1);
|
||||||
|
|
||||||
|
///Indicates that the postMessage request has failed due to a `RemoteException`.
|
||||||
|
@EnumSupportedPlatforms(platforms: [EnumAndroidPlatform(value: -2)])
|
||||||
|
static const FAILURE_REMOTE_ERROR =
|
||||||
|
const CustomTabsPostMessageResultType_._internal(-2);
|
||||||
|
|
||||||
|
///Indicates that the postMessage request has failed due to an internal error on the browser message channel.
|
||||||
|
@EnumSupportedPlatforms(platforms: [EnumAndroidPlatform(value: -3)])
|
||||||
|
static const FAILURE_MESSAGING_ERROR =
|
||||||
|
const CustomTabsPostMessageResultType_._internal(-3);
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'custom_tabs_post_message_result_type.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// ExchangeableEnumGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
///Custom Tabs postMessage result type.
|
||||||
|
class CustomTabsPostMessageResultType {
|
||||||
|
final int _value;
|
||||||
|
final int? _nativeValue;
|
||||||
|
const CustomTabsPostMessageResultType._internal(
|
||||||
|
this._value, this._nativeValue);
|
||||||
|
// ignore: unused_element
|
||||||
|
factory CustomTabsPostMessageResultType._internalMultiPlatform(
|
||||||
|
int value, Function nativeValue) =>
|
||||||
|
CustomTabsPostMessageResultType._internal(value, nativeValue());
|
||||||
|
|
||||||
|
///Indicates that the postMessage request was not allowed due to a bad argument
|
||||||
|
///or requesting at a disallowed time like when in background.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
static final FAILURE_DISALLOWED =
|
||||||
|
CustomTabsPostMessageResultType._internalMultiPlatform(-1, () {
|
||||||
|
switch (defaultTargetPlatform) {
|
||||||
|
case TargetPlatform.android:
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
///Indicates that the postMessage request has failed due to an internal error on the browser message channel.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
static final FAILURE_MESSAGING_ERROR =
|
||||||
|
CustomTabsPostMessageResultType._internalMultiPlatform(-3, () {
|
||||||
|
switch (defaultTargetPlatform) {
|
||||||
|
case TargetPlatform.android:
|
||||||
|
return -3;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
///Indicates that the postMessage request has failed due to a `RemoteException`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
static final FAILURE_REMOTE_ERROR =
|
||||||
|
CustomTabsPostMessageResultType._internalMultiPlatform(-2, () {
|
||||||
|
switch (defaultTargetPlatform) {
|
||||||
|
case TargetPlatform.android:
|
||||||
|
return -2;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
///Indicates that the postMessage request was accepted.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
static final SUCCESS =
|
||||||
|
CustomTabsPostMessageResultType._internalMultiPlatform(0, () {
|
||||||
|
switch (defaultTargetPlatform) {
|
||||||
|
case TargetPlatform.android:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
///Set of all values of [CustomTabsPostMessageResultType].
|
||||||
|
static final Set<CustomTabsPostMessageResultType> values = [
|
||||||
|
CustomTabsPostMessageResultType.FAILURE_DISALLOWED,
|
||||||
|
CustomTabsPostMessageResultType.FAILURE_MESSAGING_ERROR,
|
||||||
|
CustomTabsPostMessageResultType.FAILURE_REMOTE_ERROR,
|
||||||
|
CustomTabsPostMessageResultType.SUCCESS,
|
||||||
|
].toSet();
|
||||||
|
|
||||||
|
///Gets a possible [CustomTabsPostMessageResultType] instance from [int] value.
|
||||||
|
static CustomTabsPostMessageResultType? fromValue(int? value) {
|
||||||
|
if (value != null) {
|
||||||
|
try {
|
||||||
|
return CustomTabsPostMessageResultType.values
|
||||||
|
.firstWhere((element) => element.toValue() == value);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Gets a possible [CustomTabsPostMessageResultType] instance from a native value.
|
||||||
|
static CustomTabsPostMessageResultType? fromNativeValue(int? value) {
|
||||||
|
if (value != null) {
|
||||||
|
try {
|
||||||
|
return CustomTabsPostMessageResultType.values
|
||||||
|
.firstWhere((element) => element.toNativeValue() == value);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Gets [int] value.
|
||||||
|
int toValue() => _value;
|
||||||
|
|
||||||
|
///Gets [int?] native value.
|
||||||
|
int? toNativeValue() => _nativeValue;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => _value.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(value) => value == _value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
switch (_value) {
|
||||||
|
case -1:
|
||||||
|
return 'FAILURE_DISALLOWED';
|
||||||
|
case -3:
|
||||||
|
return 'FAILURE_MESSAGING_ERROR';
|
||||||
|
case -2:
|
||||||
|
return 'FAILURE_REMOTE_ERROR';
|
||||||
|
case 0:
|
||||||
|
return 'SUCCESS';
|
||||||
|
}
|
||||||
|
return _value.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -223,3 +223,5 @@ export 'activity_button.dart' show ActivityButton;
|
||||||
export 'ui_event_attribution.dart' show UIEventAttribution;
|
export 'ui_event_attribution.dart' show UIEventAttribution;
|
||||||
export 'tracing_mode.dart' show TracingMode;
|
export 'tracing_mode.dart' show TracingMode;
|
||||||
export 'tracing_category.dart' show TracingCategory;
|
export 'tracing_category.dart' show TracingCategory;
|
||||||
|
export 'custom_tabs_post_message_result_type.dart'
|
||||||
|
show CustomTabsPostMessageResultType;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: flutter_inappwebview
|
name: flutter_inappwebview
|
||||||
description: A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window.
|
description: A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window.
|
||||||
version: 6.0.0-beta.26
|
version: 6.0.0-beta.27
|
||||||
homepage: https://inappwebview.dev/
|
homepage: https://inappwebview.dev/
|
||||||
repository: https://github.com/pichillilorenzo/flutter_inappwebview
|
repository: https://github.com/pichillilorenzo/flutter_inappwebview
|
||||||
issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues
|
issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues
|
||||||
|
|
Loading…
Reference in New Issue