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
|
||||
|
||||
- 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.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
|
@ -19,6 +20,7 @@ import androidx.browser.customtabs.CustomTabsCallback;
|
|||
import androidx.browser.customtabs.CustomTabsIntent;
|
||||
import androidx.browser.customtabs.CustomTabsService;
|
||||
import androidx.browser.customtabs.CustomTabsSession;
|
||||
import androidx.browser.customtabs.EngagementSignalsCallback;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.R;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.AndroidResource;
|
||||
|
@ -32,12 +34,13 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.flutter.Log;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
|
||||
public class ChromeCustomTabsActivity extends Activity implements Disposable {
|
||||
protected static final String LOG_TAG = "CustomTabsActivity";
|
||||
public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_chromesafaribrowser_";
|
||||
|
||||
|
||||
public String id;
|
||||
@Nullable
|
||||
public CustomTabsIntent.Builder builder;
|
||||
|
@ -76,7 +79,7 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable {
|
|||
|
||||
Bundle b = getIntent().getExtras();
|
||||
if (b == null) return;
|
||||
|
||||
|
||||
id = b.getString("id");
|
||||
|
||||
String managerId = b.getString("managerId");
|
||||
|
@ -143,13 +146,22 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void extraCallback(@NonNull String callbackName, Bundle args) {}
|
||||
public void extraCallback(@NonNull String callbackName, Bundle args) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageChannelReady(Bundle extras) {}
|
||||
public void onMessageChannelReady(Bundle extras) {
|
||||
if (channelDelegate != null) {
|
||||
channelDelegate.onMessageChannelReady();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostMessage(@NonNull String message, Bundle extras) {}
|
||||
public void onPostMessage(@NonNull String message, Bundle extras) {
|
||||
if (channelDelegate != null) {
|
||||
channelDelegate.onPostMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelationshipValidationResult(@CustomTabsService.Relation int relation,
|
||||
|
@ -198,8 +210,41 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable {
|
|||
return customTabActivityHelper.mayLaunchUrl(uri, null, bundleOtherLikelyURLs);
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
public void customTabsConnected() {
|
||||
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
|
||||
if (isBindSuccess && initialUrl != null) {
|
||||
launchUrl(initialUrl, initialHeaders, initialReferrer, initialOtherLikelyURLs);
|
||||
|
@ -248,7 +293,7 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable {
|
|||
}
|
||||
|
||||
for (CustomTabsMenuItem menuItem : menuItems) {
|
||||
builder.addMenuItem(menuItem.getLabel(),
|
||||
builder.addMenuItem(menuItem.getLabel(),
|
||||
createPendingIntent(menuItem.getId()));
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,12 @@ package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
|
|||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.browser.customtabs.CustomTabsService;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.CustomTabsActionButton;
|
||||
|
@ -84,6 +87,35 @@ public class ChromeCustomTabsChannelDelegate extends ChannelDelegateImpl {
|
|||
result.success(false);
|
||||
}
|
||||
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":
|
||||
if (chromeCustomTabsActivity != null) {
|
||||
chromeCustomTabsActivity.onStop();
|
||||
|
@ -131,7 +163,7 @@ public class ChromeCustomTabsChannelDelegate extends ChannelDelegateImpl {
|
|||
channel.invokeMethod("onCompletedInitialLoad", obj);
|
||||
}
|
||||
|
||||
public void onNavigationEvent(int navigationEvent) {;
|
||||
public void onNavigationEvent(int navigationEvent) {
|
||||
MethodChannel channel = getChannel();
|
||||
if (channel == null) return;
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
|
@ -175,6 +207,45 @@ public class ChromeCustomTabsChannelDelegate extends ChannelDelegateImpl {
|
|||
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
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
|
|
|
@ -41,14 +41,6 @@ public class TrustedWebActivity extends ChromeCustomTabsActivity {
|
|||
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() {
|
||||
CustomTabColorSchemeParams.Builder defaultColorSchemeBuilder = new CustomTabColorSchemeParams.Builder();
|
||||
if (customSettings.toolbarBackgroundColor != null && !customSettings.toolbarBackgroundColor.isEmpty()) {
|
||||
|
|
|
@ -93,6 +93,7 @@
|
|||
android:name="io.flutter.embedded_views_preview"
|
||||
android:value="true" />
|
||||
|
||||
|
||||
<service android:name="androidx.browser.customtabs.PostMessageService"
|
||||
android:exported="true"/>
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
\"target\": {
|
||||
\"namespace\": \"web\",
|
||||
\"site\": \"https://flutter.dev\"}
|
||||
},
|
||||
{
|
||||
\"relation\": [\"delegate_permission/common.handle_all_urls\"],
|
||||
\"target\": {
|
||||
\"namespace\": \"web\",
|
||||
\"site\": \"https://inappwebview.dev\"}
|
||||
}]
|
||||
</string>
|
||||
</resources>
|
|
@ -170,5 +170,52 @@ void customTabs() {
|
|||
expect(await ChromeSafariBrowser.getMaxToolbarItems(),
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -13,12 +13,12 @@ void trustedWebActivity() {
|
|||
expect(chromeSafariBrowser.isOpened(), false);
|
||||
|
||||
await chromeSafariBrowser.open(
|
||||
url: TEST_URL_1,
|
||||
url: TEST_TWA_URL,
|
||||
settings: ChromeSafariBrowserSettings(isTrustedWebActivity: true));
|
||||
await chromeSafariBrowser.opened.future;
|
||||
expect(chromeSafariBrowser.isOpened(), true);
|
||||
expect(() async {
|
||||
await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1);
|
||||
await chromeSafariBrowser.open(url: TEST_TWA_URL);
|
||||
}, throwsAssertionError);
|
||||
|
||||
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
||||
|
@ -32,13 +32,13 @@ void trustedWebActivity() {
|
|||
expect(chromeSafariBrowser.isOpened(), false);
|
||||
|
||||
await chromeSafariBrowser.open(
|
||||
url: TEST_URL_1,
|
||||
url: TEST_TWA_URL,
|
||||
settings: ChromeSafariBrowserSettings(
|
||||
isTrustedWebActivity: true, isSingleInstance: true));
|
||||
await chromeSafariBrowser.opened.future;
|
||||
expect(chromeSafariBrowser.isOpened(), true);
|
||||
expect(() async {
|
||||
await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1);
|
||||
await chromeSafariBrowser.open(url: TEST_TWA_URL);
|
||||
}, throwsAssertionError);
|
||||
|
||||
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
||||
|
@ -57,11 +57,11 @@ void trustedWebActivity() {
|
|||
expect(
|
||||
await chromeSafariBrowser.validateRelationship(
|
||||
relation: CustomTabsRelationType.USE_AS_ORIGIN,
|
||||
origin: TEST_CROSS_PLATFORM_URL_1),
|
||||
origin: TEST_TWA_URL),
|
||||
true);
|
||||
expect(
|
||||
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;
|
||||
expect(chromeSafariBrowser.isOpened(), true);
|
||||
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_URL = WebUri(
|
||||
'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<CustomTabsNavigationEventType?> navigationEvent =
|
||||
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>();
|
||||
|
||||
@override
|
||||
|
@ -140,6 +143,24 @@ class MyChromeSafariBrowser extends ChromeSafariBrowser {
|
|||
if (!navigationEvent.isCompleted) {
|
||||
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
|
||||
|
|
|
@ -19,6 +19,21 @@ class MyChromeSafariBrowser extends ChromeSafariBrowser {
|
|||
void onClosed() {
|
||||
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 {
|
||||
|
@ -103,6 +118,8 @@ class _ChromeSafariBrowserExampleScreenState
|
|||
dismissButtonStyle: DismissButtonStyle.CLOSE,
|
||||
presentationStyle:
|
||||
ModalPresentationStyle.OVER_FULL_SCREEN));
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
widget.browser.close();
|
||||
},
|
||||
child: Text("Open Chrome Safari Browser")),
|
||||
));
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'dart:typed_data';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.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/prewarming_token.dart';
|
||||
import '../util.dart';
|
||||
|
@ -153,6 +154,25 @@ class ChromeSafariBrowser extends ChannelController {
|
|||
}
|
||||
}
|
||||
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:
|
||||
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 iOS, returns `true` if SFSafariViewController is available.
|
||||
///Otherwise returns `false`.
|
||||
|
@ -393,7 +474,8 @@ class ChromeSafariBrowser extends ChannelController {
|
|||
///- iOS
|
||||
static Future<bool> isAvailable() async {
|
||||
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.
|
||||
|
@ -515,6 +597,57 @@ class ChromeSafariBrowser extends ChannelController {
|
|||
///- iOS ([Official API - SFSafariViewControllerDelegate.safariViewControllerWillOpenInBrowser](https://developer.apple.com/documentation/safariservices/sfsafariviewcontrollerdelegate/3650426-safariviewcontrollerwillopeninbr))
|
||||
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.
|
||||
///
|
||||
///**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 'tracing_mode.dart' show TracingMode;
|
||||
export 'tracing_category.dart' show TracingCategory;
|
||||
export 'custom_tabs_post_message_result_type.dart'
|
||||
show CustomTabsPostMessageResultType;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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.
|
||||
version: 6.0.0-beta.26
|
||||
version: 6.0.0-beta.27
|
||||
homepage: https://inappwebview.dev/
|
||||
repository: https://github.com/pichillilorenzo/flutter_inappwebview
|
||||
issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues
|
||||
|
|
Loading…
Reference in New Issue