Commit a480ebf6 authored by pichillilorenzo's avatar pichillilorenzo

added return value for JavaScriptHandlerCallback, added...

added return value for JavaScriptHandlerCallback, added flutterInAppBrowserPlatformReady event for javascript, breaking change: javaScriptHandlersMap contains only one callback
parent f3f0876f
This diff is collapsed.
......@@ -53,4 +53,5 @@ dependencies {
implementation 'androidx.browser:browser:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'com.squareup.okhttp3:mockwebserver:3.11.0'
implementation 'com.google.code.gson:gson:2.8.5'
}
......@@ -76,6 +76,8 @@ public class InAppWebView extends WebView {
" }" +
"})();";
static final String platformReadyJS = "window.dispatchEvent(new Event('flutterInAppBrowserPlatformReady'));";
public InAppWebView(Context context) {
super(context);
}
......
......@@ -11,6 +11,7 @@ import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.HttpAuthHandler;
import android.webkit.SslErrorHandler;
import android.webkit.ValueCallback;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
......@@ -195,7 +196,7 @@ public class InAppWebViewClient extends WebViewClient {
}
public void onPageFinished(WebView view, String url) {
public void onPageFinished(final WebView view, String url) {
super.onPageFinished(view, url);
((inAppBrowserActivity != null) ? inAppBrowserActivity.webView : flutterWebView.webView).isLoading = false;
......@@ -213,11 +214,18 @@ public class InAppWebViewClient extends WebViewClient {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
view.evaluateJavascript(InAppWebView.consoleLogJS, null);
view.evaluateJavascript(JavaScriptBridgeInterface.flutterInAppBroserJSClass, null);
view.evaluateJavascript(JavaScriptBridgeInterface.flutterInAppBroserJSClass, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
view.evaluateJavascript(InAppWebView.platformReadyJS, null);
}
});
}
else {
view.loadUrl("javascript:"+InAppWebView.consoleLogJS);
view.loadUrl("javascript:"+JavaScriptBridgeInterface.flutterInAppBroserJSClass);
view.loadUrl("javascript:"+InAppWebView.platformReadyJS);
}
Map<String, Object> obj = new HashMap<>();
......
package com.pichillilorenzo.flutter_inappbrowser;
import android.os.Build;
import android.util.Log;
import android.webkit.JavascriptInterface;
import com.google.gson.Gson;
import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebView;
import java.util.HashMap;
import java.util.Map;
......@@ -14,7 +19,11 @@ public class JavaScriptBridgeInterface {
private InAppBrowserActivity inAppBrowserActivity;
public static final String flutterInAppBroserJSClass = "window." + name + ".callHandler = function(handlerName, ...args) {" +
"window." + name + "._callHandler(handlerName, JSON.stringify(args));" +
"var _callHandlerID = setTimeout(function(){});" +
"window." + name + "._callHandler(handlerName, _callHandlerID, JSON.stringify(args));" +
"return new Promise(function(resolve, reject) {" +
" window." + name + "[_callHandlerID] = resolve;" +
"});" +
"}";
public JavaScriptBridgeInterface(Object obj) {
......@@ -25,13 +34,35 @@ public class JavaScriptBridgeInterface {
}
@JavascriptInterface
public void _callHandler(String handlerName, String args) {
public void _callHandler(String handlerName, final String _callHandlerID, String args) {
Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("handlerName", handlerName);
obj.put("args", args);
getChannel().invokeMethod("onCallJsHandler", obj);
getChannel().invokeMethod("onCallJsHandler", obj, new MethodChannel.Result() {
@Override
public void success(Object o) {
String json = new Gson().toJson(o);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
flutterWebView.webView.evaluateJavascript("window." + name + "[" + _callHandlerID + "](" + json + ");", null);
}
else {
flutterWebView.webView.loadUrl("javascript:window." + name + "[" + _callHandlerID + "](" + json + ");");
}
}
@Override
public void error(String s, String s1, Object o) {
Log.d(LOG_TAG, "ERROR: " + s + " " + s1);
}
@Override
public void notImplemented() {
}
});
}
private MethodChannel getChannel() {
......
......@@ -27,7 +27,14 @@
</div>
</div>
<script>
console.log("hello");
window.addEventListener("flutterInAppBrowserPlatformReady", function(event) {
console.log("ready");
window.flutter_inappbrowser.callHandler('handlerTest', 1).then(function(result) {
console.log(result, typeof result);
});
});
</script>
</div>
</body>
......
......@@ -41,6 +41,7 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
BoxDecoration(border: Border.all(color: Colors.blueAccent)),
child: InAppWebView(
initialUrl: "https://flutter.dev/",
//initialFile: "assets/index.html",
initialHeaders: {},
initialOptions: {
"useShouldOverrideUrlLoading": true,
......@@ -55,7 +56,7 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
this.url = url;
});
},
onLoadStop: (InAppWebViewController controller, String url) {
onLoadStop: (InAppWebViewController controller, String url) async {
print("stopped $url");
},
onProgressChanged:
......@@ -70,7 +71,10 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
},
onLoadResource: (InAppWebViewController controller, WebResourceResponse response, WebResourceRequest request) {
print("resource " + request.url);
}
},
onConsoleMessage: (InAppWebViewController controller, ConsoleMessage consoleMessage) {
print(consoleMessage.message);
},
),
),
),
......
......@@ -20,8 +20,6 @@
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/example/build" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/example/ios/Flutter/App.framework/flutter_assets/packages" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/example/ios/Flutter/flutter_assets/packages" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/Flutter/App.framework/flutter_assets/packages" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/Flutter/flutter_assets/packages" />
</content>
......
......@@ -5,6 +5,7 @@
// Created by Lorenzo on 21/10/18.
//
import Flutter
import Foundation
import WebKit
......@@ -71,10 +72,16 @@ let JAVASCRIPT_BRIDGE_NAME = "flutter_inappbrowser"
let javaScriptBridgeJS = """
window.\(JAVASCRIPT_BRIDGE_NAME) = {};
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler = function(handlerName, ...args) {
window.webkit.messageHandlers['callHandler'].postMessage( {'handlerName': handlerName, 'args': JSON.stringify(args)} );
var _callHandlerID = setTimeout(function(){});
window.webkit.messageHandlers['callHandler'].postMessage( {'handlerName': handlerName, '_callHandlerID': _callHandlerID, 'args': JSON.stringify(args)} );
return new Promise(function(resolve, reject) {
window.\(JAVASCRIPT_BRIDGE_NAME)[_callHandlerID] = resolve;
});
}
"""
let platformReadyJS = "window.dispatchEvent(new Event('flutterInAppBrowserPlatformReady'));";
public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler {
var IABController: InAppBrowserWebViewController?
......@@ -235,12 +242,14 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
public func loadUrl(url: URL, headers: [String: String]?) {
var request = URLRequest(url: url)
currentURL = url
if headers != nil {
if let mutableRequest = (request as NSURLRequest).mutableCopy() as? NSMutableURLRequest {
for (key, value) in headers! {
mutableRequest.setValue(value, forHTTPHeaderField: key)
}
request = mutableRequest as URLRequest
}
}
load(request)
}
......@@ -581,6 +590,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
self.WKNavigationMap = [:]
currentURL = url
onLoadStop(url: (currentURL?.absoluteString)!)
evaluateJavaScript(platformReadyJS, completionHandler: nil)
if IABController != nil {
IABController!.updateUrlTextField(url: (currentURL?.absoluteString)!)
......@@ -698,12 +708,28 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
getChannel().invokeMethod("onConsoleMessage", arguments: arguments)
}
public func onCallJsHandler(handlerName: String, args: String) {
public func onCallJsHandler(handlerName: String, _callHandlerID: Int64, args: String) {
var arguments: [String: Any] = ["handlerName": handlerName, "args": args]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
getChannel().invokeMethod("onCallJsHandler", arguments: arguments)
getChannel().invokeMethod("onCallJsHandler", arguments: arguments, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
}
else if (result as? NSObject) == FlutterMethodNotImplemented {}
else {
var json = "null"
if let r = result {
json = JSONSerializer.toJson(r)
if json == "{}" {
json = "\(r)"
}
}
self.evaluateJavaScript("window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)](\(json));", completionHandler: nil)
}
})
}
public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
......@@ -765,8 +791,9 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
else if message.name == "callHandler" {
let body = message.body as! [String: Any]
let handlerName = body["handlerName"] as! String
let _callHandlerID = body["_callHandlerID"] as! Int64
let args = body["args"] as! String
onCallJsHandler(handlerName: handlerName, args: args)
onCallJsHandler(handlerName: handlerName, _callHandlerID: _callHandlerID, args: args)
}
}
......
This diff is collapsed.
......@@ -34,7 +34,7 @@ import 'package:uuid/uuid.dart';
import 'package:mime/mime.dart';
typedef Future<dynamic> ListenerCallback(MethodCall call);
typedef Future<void> JavaScriptHandlerCallback(List<dynamic> arguments);
typedef dynamic JavaScriptHandlerCallback(List<dynamic> arguments);
var _uuidGenerator = new Uuid();
......@@ -112,7 +112,7 @@ class _ChannelManager {
class InAppBrowser {
String uuid;
Map<String, List<JavaScriptHandlerCallback>> javaScriptHandlersMap = HashMap<String, List<JavaScriptHandlerCallback>>();
Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap = HashMap<String, JavaScriptHandlerCallback>();
bool _isOpened = false;
/// WebView Controller that can be used to access the [InAppWebView] API.
InAppWebViewController webViewController;
......@@ -735,7 +735,7 @@ class InAppWebViewController {
InAppWebView _widget;
MethodChannel _channel;
Map<String, List<JavaScriptHandlerCallback>> javaScriptHandlersMap = HashMap<String, List<JavaScriptHandlerCallback>>();
Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap = HashMap<String, JavaScriptHandlerCallback>();
bool _isOpened = false;
int _id;
String _inAppBrowserUuid;
......@@ -849,9 +849,7 @@ class InAppWebViewController {
String handlerName = call.arguments["handlerName"];
List<dynamic> args = jsonDecode(call.arguments["args"]);
if (javaScriptHandlersMap.containsKey(handlerName)) {
for (var handler in javaScriptHandlersMap[handlerName]) {
handler(args);
}
return await javaScriptHandlersMap[handlerName](args);
}
break;
default:
......@@ -1140,31 +1138,22 @@ class InAppWebViewController {
await _channel.invokeMethod('injectStyleFile', args);
}
///Adds/Appends a JavaScript message handler [callback] ([JavaScriptHandlerCallback]) that listen to post messages sent from JavaScript by the handler with name [handlerName].
///Returns the position `index` of the handler that can be used to remove it with the [removeJavaScriptHandler()] method.
///Adds a JavaScript message handler [callback] ([JavaScriptHandlerCallback]) that listen to post messages sent from JavaScript by the handler with name [handlerName].
///
///The Android implementation uses [addJavascriptInterface](https://developer.android.com/reference/android/webkit/WebView#addJavascriptInterface(java.lang.Object,%20java.lang.String)).
///The iOS implementation uses [addScriptMessageHandler](https://developer.apple.com/documentation/webkit/wkusercontentcontroller/1537172-addscriptmessagehandler?language=objc)
///
///The JavaScript function that can be used to call the handler is `window.flutter_inappbrowser.callHandler(handlerName <String>, ...args);`, where `args` are [rest parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters).
///The `args` will be stringified automatically using `JSON.stringify(args)` method and then they will be decoded on the Dart side.
int addJavaScriptHandler(String handlerName, JavaScriptHandlerCallback callback) {
this.javaScriptHandlersMap.putIfAbsent(handlerName, () => List<JavaScriptHandlerCallback>());
this.javaScriptHandlersMap[handlerName].add(callback);
return this.javaScriptHandlersMap[handlerName].indexOf(callback);
void addJavaScriptHandler(String handlerName, JavaScriptHandlerCallback callback) {
this.javaScriptHandlersMap[handlerName] = (callback);
}
///Removes a JavaScript message handler previously added with the [addJavaScriptHandler()] method in the [handlerName] list by its position [index].
///Returns `true` if the callback is removed, otherwise `false`.
bool removeJavaScriptHandler(String handlerName, int index) {
try {
this.javaScriptHandlersMap[handlerName].removeAt(index);
return true;
}
on RangeError catch(e) {
print(e);
}
return false;
///Removes a JavaScript message handler previously added with the [addJavaScriptHandler()] associated to [handlerName] key.
///Returns the value associated with [handlerName] before it was removed.
///Returns `null` if [handlerName] was not found.
JavaScriptHandlerCallback removeJavaScriptHandler(String handlerName) {
return this.javaScriptHandlersMap.remove(handlerName);
}
///Takes a screenshot (in PNG format) of the WebView's visible viewport and returns a `Uint8List`. Returns `null` if it wasn't be able to take it.
......
name: flutter_inappbrowser
description: A Flutter plugin that allows you to add an inline webview or open an in-app browser window (inspired by the popular cordova-plugin-inappbrowser).
version: 1.0.1
version: 1.1.0
author: Lorenzo Pichilli <pichillilorenzo@gmail.com>
homepage: https://github.com/pichillilorenzo/flutter_inappbrowser
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment