Skip to content

Commit 5aa3d35

Browse files
authored
[webview_flutter_android] Add javascript panel interface for android (flutter#5796)
* There are cases where Web calls System Popup with javascript on webview_flutter * Android has a interface on WebChromeClient * https://developer.android.com/reference/android/webkit/WebChromeClient#onJsAlert(android.webkit.WebView,%20java.lang.String,%20java.lang.String,%20android.webkit.JsResult) * Related issue: flutter#30358 (comment) * Related Interface PR: flutter/packages#5670 * The PR that contains all changes can be found at flutter/packages#4704
1 parent dced730 commit 5aa3d35

20 files changed

+1358
-4
lines changed

packages/webview_flutter/webview_flutter_android/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 3.14.0
2+
3+
* Adds support to show JavaScript dialog. See `AndroidWebViewController.setOnJavaScriptAlertDialog`, `AndroidWebViewController.setOnJavaScriptConfirmDialog` and `AndroidWebViewController.setOnJavaScriptTextInputDialog`.
4+
15
## 3.13.2
26

37
* Fixes new lint warnings.

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2643,6 +2643,12 @@ void setSynchronousReturnValueForOnShowFileChooser(
26432643
void setSynchronousReturnValueForOnConsoleMessage(
26442644
@NonNull Long instanceId, @NonNull Boolean value);
26452645

2646+
void setSynchronousReturnValueForOnJsAlert(@NonNull Long instanceId, @NonNull Boolean value);
2647+
2648+
void setSynchronousReturnValueForOnJsConfirm(@NonNull Long instanceId, @NonNull Boolean value);
2649+
2650+
void setSynchronousReturnValueForOnJsPrompt(@NonNull Long instanceId, @NonNull Boolean value);
2651+
26462652
/** The codec used by WebChromeClientHostApi. */
26472653
static @NonNull MessageCodec<Object> getCodec() {
26482654
return new StandardMessageCodec();
@@ -2732,6 +2738,87 @@ static void setup(
27322738
channel.setMessageHandler(null);
27332739
}
27342740
}
2741+
{
2742+
BasicMessageChannel<Object> channel =
2743+
new BasicMessageChannel<>(
2744+
binaryMessenger,
2745+
"dev.flutter.pigeon.webview_flutter_android.WebChromeClientHostApi.setSynchronousReturnValueForOnJsAlert",
2746+
getCodec());
2747+
if (api != null) {
2748+
channel.setMessageHandler(
2749+
(message, reply) -> {
2750+
ArrayList<Object> wrapped = new ArrayList<Object>();
2751+
ArrayList<Object> args = (ArrayList<Object>) message;
2752+
Number instanceIdArg = (Number) args.get(0);
2753+
Boolean valueArg = (Boolean) args.get(1);
2754+
try {
2755+
api.setSynchronousReturnValueForOnJsAlert(
2756+
(instanceIdArg == null) ? null : instanceIdArg.longValue(), valueArg);
2757+
wrapped.add(0, null);
2758+
} catch (Throwable exception) {
2759+
ArrayList<Object> wrappedError = wrapError(exception);
2760+
wrapped = wrappedError;
2761+
}
2762+
reply.reply(wrapped);
2763+
});
2764+
} else {
2765+
channel.setMessageHandler(null);
2766+
}
2767+
}
2768+
{
2769+
BasicMessageChannel<Object> channel =
2770+
new BasicMessageChannel<>(
2771+
binaryMessenger,
2772+
"dev.flutter.pigeon.webview_flutter_android.WebChromeClientHostApi.setSynchronousReturnValueForOnJsConfirm",
2773+
getCodec());
2774+
if (api != null) {
2775+
channel.setMessageHandler(
2776+
(message, reply) -> {
2777+
ArrayList<Object> wrapped = new ArrayList<Object>();
2778+
ArrayList<Object> args = (ArrayList<Object>) message;
2779+
Number instanceIdArg = (Number) args.get(0);
2780+
Boolean valueArg = (Boolean) args.get(1);
2781+
try {
2782+
api.setSynchronousReturnValueForOnJsConfirm(
2783+
(instanceIdArg == null) ? null : instanceIdArg.longValue(), valueArg);
2784+
wrapped.add(0, null);
2785+
} catch (Throwable exception) {
2786+
ArrayList<Object> wrappedError = wrapError(exception);
2787+
wrapped = wrappedError;
2788+
}
2789+
reply.reply(wrapped);
2790+
});
2791+
} else {
2792+
channel.setMessageHandler(null);
2793+
}
2794+
}
2795+
{
2796+
BasicMessageChannel<Object> channel =
2797+
new BasicMessageChannel<>(
2798+
binaryMessenger,
2799+
"dev.flutter.pigeon.webview_flutter_android.WebChromeClientHostApi.setSynchronousReturnValueForOnJsPrompt",
2800+
getCodec());
2801+
if (api != null) {
2802+
channel.setMessageHandler(
2803+
(message, reply) -> {
2804+
ArrayList<Object> wrapped = new ArrayList<Object>();
2805+
ArrayList<Object> args = (ArrayList<Object>) message;
2806+
Number instanceIdArg = (Number) args.get(0);
2807+
Boolean valueArg = (Boolean) args.get(1);
2808+
try {
2809+
api.setSynchronousReturnValueForOnJsPrompt(
2810+
(instanceIdArg == null) ? null : instanceIdArg.longValue(), valueArg);
2811+
wrapped.add(0, null);
2812+
} catch (Throwable exception) {
2813+
ArrayList<Object> wrappedError = wrapError(exception);
2814+
wrapped = wrappedError;
2815+
}
2816+
reply.reply(wrapped);
2817+
});
2818+
} else {
2819+
channel.setMessageHandler(null);
2820+
}
2821+
}
27352822
}
27362823
}
27372824
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
@@ -2967,6 +3054,60 @@ public void onConsoleMessage(
29673054
new ArrayList<Object>(Arrays.asList(instanceIdArg, messageArg)),
29683055
channelReply -> callback.reply(null));
29693056
}
3057+
3058+
public void onJsAlert(
3059+
@NonNull Long instanceIdArg,
3060+
@NonNull String urlArg,
3061+
@NonNull String messageArg,
3062+
@NonNull Reply<Void> callback) {
3063+
BasicMessageChannel<Object> channel =
3064+
new BasicMessageChannel<>(
3065+
binaryMessenger,
3066+
"dev.flutter.pigeon.webview_flutter_android.WebChromeClientFlutterApi.onJsAlert",
3067+
getCodec());
3068+
channel.send(
3069+
new ArrayList<Object>(Arrays.asList(instanceIdArg, urlArg, messageArg)),
3070+
channelReply -> callback.reply(null));
3071+
}
3072+
3073+
public void onJsConfirm(
3074+
@NonNull Long instanceIdArg,
3075+
@NonNull String urlArg,
3076+
@NonNull String messageArg,
3077+
@NonNull Reply<Boolean> callback) {
3078+
BasicMessageChannel<Object> channel =
3079+
new BasicMessageChannel<>(
3080+
binaryMessenger,
3081+
"dev.flutter.pigeon.webview_flutter_android.WebChromeClientFlutterApi.onJsConfirm",
3082+
getCodec());
3083+
channel.send(
3084+
new ArrayList<Object>(Arrays.asList(instanceIdArg, urlArg, messageArg)),
3085+
channelReply -> {
3086+
@SuppressWarnings("ConstantConditions")
3087+
Boolean output = (Boolean) channelReply;
3088+
callback.reply(output);
3089+
});
3090+
}
3091+
3092+
public void onJsPrompt(
3093+
@NonNull Long instanceIdArg,
3094+
@NonNull String urlArg,
3095+
@NonNull String messageArg,
3096+
@NonNull String defaultValueArg,
3097+
@NonNull Reply<String> callback) {
3098+
BasicMessageChannel<Object> channel =
3099+
new BasicMessageChannel<>(
3100+
binaryMessenger,
3101+
"dev.flutter.pigeon.webview_flutter_android.WebChromeClientFlutterApi.onJsPrompt",
3102+
getCodec());
3103+
channel.send(
3104+
new ArrayList<Object>(Arrays.asList(instanceIdArg, urlArg, messageArg, defaultValueArg)),
3105+
channelReply -> {
3106+
@SuppressWarnings("ConstantConditions")
3107+
String output = (String) channelReply;
3108+
callback.reply(output);
3109+
});
3110+
}
29703111
}
29713112
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
29723113
public interface WebStorageHostApi {

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientFlutterApiImpl.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,56 @@ public void onConsoleMessage(
187187
callback);
188188
}
189189

190+
/**
191+
* Sends a message to Dart to call `WebChromeClient.onJsAlert` on the Dart object representing
192+
* `instance`.
193+
*/
194+
public void onJsAlert(
195+
@NonNull WebChromeClient instance,
196+
@NonNull String url,
197+
@NonNull String message,
198+
@NonNull WebChromeClientFlutterApi.Reply<Void> callback) {
199+
super.onJsAlert(
200+
Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(instance)),
201+
url,
202+
message,
203+
callback);
204+
}
205+
206+
/**
207+
* Sends a message to Dart to call `WebChromeClient.onJsConfirm` on the Dart object representing
208+
* `instance`.
209+
*/
210+
public void onJsConfirm(
211+
@NonNull WebChromeClient instance,
212+
@NonNull String url,
213+
@NonNull String message,
214+
@NonNull WebChromeClientFlutterApi.Reply<Boolean> callback) {
215+
super.onJsConfirm(
216+
Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(instance)),
217+
url,
218+
message,
219+
callback);
220+
}
221+
222+
/**
223+
* Sends a message to Dart to call `WebChromeClient.onJsPrompt` on the Dart object representing
224+
* `instance`.
225+
*/
226+
public void onJsPrompt(
227+
@NonNull WebChromeClient instance,
228+
@NonNull String url,
229+
@NonNull String message,
230+
@NonNull String defaultValue,
231+
@NonNull WebChromeClientFlutterApi.Reply<String> callback) {
232+
super.onJsPrompt(
233+
Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(instance)),
234+
url,
235+
message,
236+
defaultValue,
237+
callback);
238+
}
239+
190240
private long getIdentifierForClient(WebChromeClient webChromeClient) {
191241
final Long identifier = instanceManager.getIdentifierForStrongReference(webChromeClient);
192242
if (identifier == null) {

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import android.view.View;
1212
import android.webkit.ConsoleMessage;
1313
import android.webkit.GeolocationPermissions;
14+
import android.webkit.JsPromptResult;
15+
import android.webkit.JsResult;
1416
import android.webkit.PermissionRequest;
1517
import android.webkit.ValueCallback;
1618
import android.webkit.WebChromeClient;
@@ -43,6 +45,10 @@ public static class WebChromeClientImpl extends SecureWebChromeClient {
4345
private boolean returnValueForOnShowFileChooser = false;
4446
private boolean returnValueForOnConsoleMessage = false;
4547

48+
private boolean returnValueForOnJsAlert = false;
49+
private boolean returnValueForOnJsConfirm = false;
50+
private boolean returnValueForOnJsPrompt = false;
51+
4652
/**
4753
* Creates a {@link WebChromeClient} that passes arguments of callbacks methods to Dart.
4854
*
@@ -124,6 +130,77 @@ public void setReturnValueForOnShowFileChooser(boolean value) {
124130
public void setReturnValueForOnConsoleMessage(boolean value) {
125131
returnValueForOnConsoleMessage = value;
126132
}
133+
134+
public void setReturnValueForOnJsAlert(boolean value) {
135+
returnValueForOnJsAlert = value;
136+
}
137+
138+
public void setReturnValueForOnJsConfirm(boolean value) {
139+
returnValueForOnJsConfirm = value;
140+
}
141+
142+
public void setReturnValueForOnJsPrompt(boolean value) {
143+
returnValueForOnJsPrompt = value;
144+
}
145+
146+
@Override
147+
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
148+
if (returnValueForOnJsAlert) {
149+
flutterApi.onJsAlert(
150+
this,
151+
url,
152+
message,
153+
reply -> {
154+
result.confirm();
155+
});
156+
return true;
157+
} else {
158+
return false;
159+
}
160+
}
161+
162+
@Override
163+
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
164+
if (returnValueForOnJsConfirm) {
165+
flutterApi.onJsConfirm(
166+
this,
167+
url,
168+
message,
169+
reply -> {
170+
if (reply) {
171+
result.confirm();
172+
} else {
173+
result.cancel();
174+
}
175+
});
176+
return true;
177+
} else {
178+
return false;
179+
}
180+
}
181+
182+
@Override
183+
public boolean onJsPrompt(
184+
WebView view, String url, String message, String defaultValue, JsPromptResult result) {
185+
if (returnValueForOnJsPrompt) {
186+
flutterApi.onJsPrompt(
187+
this,
188+
url,
189+
message,
190+
defaultValue,
191+
reply -> {
192+
@Nullable String inputMessage = reply;
193+
if (inputMessage != null) {
194+
result.confirm(inputMessage);
195+
} else {
196+
result.cancel();
197+
}
198+
});
199+
return true;
200+
} else {
201+
return false;
202+
}
203+
}
127204
}
128205

129206
/**
@@ -267,4 +344,28 @@ public void setSynchronousReturnValueForOnConsoleMessage(
267344
Objects.requireNonNull(instanceManager.getInstance(instanceId));
268345
webChromeClient.setReturnValueForOnConsoleMessage(value);
269346
}
347+
348+
@Override
349+
public void setSynchronousReturnValueForOnJsAlert(
350+
@NonNull Long instanceId, @NonNull Boolean value) {
351+
final WebChromeClientImpl webChromeClient =
352+
Objects.requireNonNull(instanceManager.getInstance(instanceId));
353+
webChromeClient.setReturnValueForOnJsAlert(value);
354+
}
355+
356+
@Override
357+
public void setSynchronousReturnValueForOnJsConfirm(
358+
@NonNull Long instanceId, @NonNull Boolean value) {
359+
final WebChromeClientImpl webChromeClient =
360+
Objects.requireNonNull(instanceManager.getInstance(instanceId));
361+
webChromeClient.setReturnValueForOnJsConfirm(value);
362+
}
363+
364+
@Override
365+
public void setSynchronousReturnValueForOnJsPrompt(
366+
@NonNull Long instanceId, @NonNull Boolean value) {
367+
final WebChromeClientImpl webChromeClient =
368+
Objects.requireNonNull(instanceManager.getInstance(instanceId));
369+
webChromeClient.setReturnValueForOnJsPrompt(value);
370+
}
270371
}

0 commit comments

Comments
 (0)