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 { ...@@ -53,4 +53,5 @@ dependencies {
implementation 'androidx.browser:browser:1.0.0' implementation 'androidx.browser:browser:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'com.squareup.okhttp3:mockwebserver:3.11.0' 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 { ...@@ -76,6 +76,8 @@ public class InAppWebView extends WebView {
" }" + " }" +
"})();"; "})();";
static final String platformReadyJS = "window.dispatchEvent(new Event('flutterInAppBrowserPlatformReady'));";
public InAppWebView(Context context) { public InAppWebView(Context context) {
super(context); super(context);
} }
......
...@@ -11,6 +11,7 @@ import android.webkit.CookieManager; ...@@ -11,6 +11,7 @@ import android.webkit.CookieManager;
import android.webkit.CookieSyncManager; import android.webkit.CookieSyncManager;
import android.webkit.HttpAuthHandler; import android.webkit.HttpAuthHandler;
import android.webkit.SslErrorHandler; import android.webkit.SslErrorHandler;
import android.webkit.ValueCallback;
import android.webkit.WebResourceRequest; import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse; import android.webkit.WebResourceResponse;
import android.webkit.WebView; import android.webkit.WebView;
...@@ -195,7 +196,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -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); super.onPageFinished(view, url);
((inAppBrowserActivity != null) ? inAppBrowserActivity.webView : flutterWebView.webView).isLoading = false; ((inAppBrowserActivity != null) ? inAppBrowserActivity.webView : flutterWebView.webView).isLoading = false;
...@@ -213,11 +214,18 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -213,11 +214,18 @@ public class InAppWebViewClient extends WebViewClient {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
view.evaluateJavascript(InAppWebView.consoleLogJS, null); 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 { else {
view.loadUrl("javascript:"+InAppWebView.consoleLogJS); view.loadUrl("javascript:"+InAppWebView.consoleLogJS);
view.loadUrl("javascript:"+JavaScriptBridgeInterface.flutterInAppBroserJSClass); view.loadUrl("javascript:"+JavaScriptBridgeInterface.flutterInAppBroserJSClass);
view.loadUrl("javascript:"+InAppWebView.platformReadyJS);
} }
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
......
package com.pichillilorenzo.flutter_inappbrowser; package com.pichillilorenzo.flutter_inappbrowser;
import android.os.Build;
import android.util.Log;
import android.webkit.JavascriptInterface; import android.webkit.JavascriptInterface;
import com.google.gson.Gson;
import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebView;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -14,7 +19,11 @@ public class JavaScriptBridgeInterface { ...@@ -14,7 +19,11 @@ public class JavaScriptBridgeInterface {
private InAppBrowserActivity inAppBrowserActivity; private InAppBrowserActivity inAppBrowserActivity;
public static final String flutterInAppBroserJSClass = "window." + name + ".callHandler = function(handlerName, ...args) {" + 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) { public JavaScriptBridgeInterface(Object obj) {
...@@ -25,13 +34,35 @@ public class JavaScriptBridgeInterface { ...@@ -25,13 +34,35 @@ public class JavaScriptBridgeInterface {
} }
@JavascriptInterface @JavascriptInterface
public void _callHandler(String handlerName, String args) { public void _callHandler(String handlerName, final String _callHandlerID, String args) {
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null) if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid); obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("handlerName", handlerName); obj.put("handlerName", handlerName);
obj.put("args", args); 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() { private MethodChannel getChannel() {
......
...@@ -27,7 +27,14 @@ ...@@ -27,7 +27,14 @@
</div> </div>
</div> </div>
<script> <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> </script>
</div> </div>
</body> </body>
......
...@@ -41,6 +41,7 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> { ...@@ -41,6 +41,7 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
BoxDecoration(border: Border.all(color: Colors.blueAccent)), BoxDecoration(border: Border.all(color: Colors.blueAccent)),
child: InAppWebView( child: InAppWebView(
initialUrl: "https://flutter.dev/", initialUrl: "https://flutter.dev/",
//initialFile: "assets/index.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: { initialOptions: {
"useShouldOverrideUrlLoading": true, "useShouldOverrideUrlLoading": true,
...@@ -55,7 +56,7 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> { ...@@ -55,7 +56,7 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
this.url = url; this.url = url;
}); });
}, },
onLoadStop: (InAppWebViewController controller, String url) { onLoadStop: (InAppWebViewController controller, String url) async {
print("stopped $url"); print("stopped $url");
}, },
onProgressChanged: onProgressChanged:
...@@ -70,7 +71,10 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> { ...@@ -70,7 +71,10 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
}, },
onLoadResource: (InAppWebViewController controller, WebResourceResponse response, WebResourceRequest request) { onLoadResource: (InAppWebViewController controller, WebResourceResponse response, WebResourceRequest request) {
print("resource " + request.url); print("resource " + request.url);
} },
onConsoleMessage: (InAppWebViewController controller, ConsoleMessage consoleMessage) {
print(consoleMessage.message);
},
), ),
), ),
), ),
......
...@@ -20,8 +20,6 @@ ...@@ -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/.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/.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/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/App.framework/flutter_assets/packages" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/Flutter/flutter_assets/packages" /> <excludeFolder url="file://$MODULE_DIR$/example/ios/Flutter/flutter_assets/packages" />
</content> </content>
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
// Created by Lorenzo on 21/10/18. // Created by Lorenzo on 21/10/18.
// //
import Flutter
import Foundation import Foundation
import WebKit import WebKit
...@@ -71,10 +72,16 @@ let JAVASCRIPT_BRIDGE_NAME = "flutter_inappbrowser" ...@@ -71,10 +72,16 @@ let JAVASCRIPT_BRIDGE_NAME = "flutter_inappbrowser"
let javaScriptBridgeJS = """ let javaScriptBridgeJS = """
window.\(JAVASCRIPT_BRIDGE_NAME) = {}; window.\(JAVASCRIPT_BRIDGE_NAME) = {};
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler = function(handlerName, ...args) { 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 { public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler {
var IABController: InAppBrowserWebViewController? var IABController: InAppBrowserWebViewController?
...@@ -235,11 +242,13 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -235,11 +242,13 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
public func loadUrl(url: URL, headers: [String: String]?) { public func loadUrl(url: URL, headers: [String: String]?) {
var request = URLRequest(url: url) var request = URLRequest(url: url)
currentURL = url currentURL = url
if let mutableRequest = (request as NSURLRequest).mutableCopy() as? NSMutableURLRequest { if headers != nil {
for (key, value) in headers! { if let mutableRequest = (request as NSURLRequest).mutableCopy() as? NSMutableURLRequest {
mutableRequest.setValue(value, forHTTPHeaderField: key) for (key, value) in headers! {
mutableRequest.setValue(value, forHTTPHeaderField: key)
}
request = mutableRequest as URLRequest
} }
request = mutableRequest as URLRequest
} }
load(request) load(request)
} }
...@@ -581,6 +590,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -581,6 +590,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
self.WKNavigationMap = [:] self.WKNavigationMap = [:]
currentURL = url currentURL = url
onLoadStop(url: (currentURL?.absoluteString)!) onLoadStop(url: (currentURL?.absoluteString)!)
evaluateJavaScript(platformReadyJS, completionHandler: nil)
if IABController != nil { if IABController != nil {
IABController!.updateUrlTextField(url: (currentURL?.absoluteString)!) IABController!.updateUrlTextField(url: (currentURL?.absoluteString)!)
...@@ -698,12 +708,28 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -698,12 +708,28 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
getChannel().invokeMethod("onConsoleMessage", arguments: arguments) 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] var arguments: [String: Any] = ["handlerName": handlerName, "args": args]
if IABController != nil { if IABController != nil {
arguments["uuid"] = IABController!.uuid 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) { public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
...@@ -765,8 +791,9 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -765,8 +791,9 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
else if message.name == "callHandler" { else if message.name == "callHandler" {
let body = message.body as! [String: Any] let body = message.body as! [String: Any]
let handlerName = body["handlerName"] as! String let handlerName = body["handlerName"] as! String
let _callHandlerID = body["_callHandlerID"] as! Int64
let args = body["args"] as! String 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'; ...@@ -34,7 +34,7 @@ import 'package:uuid/uuid.dart';
import 'package:mime/mime.dart'; import 'package:mime/mime.dart';
typedef Future<dynamic> ListenerCallback(MethodCall call); typedef Future<dynamic> ListenerCallback(MethodCall call);
typedef Future<void> JavaScriptHandlerCallback(List<dynamic> arguments); typedef dynamic JavaScriptHandlerCallback(List<dynamic> arguments);
var _uuidGenerator = new Uuid(); var _uuidGenerator = new Uuid();
...@@ -112,7 +112,7 @@ class _ChannelManager { ...@@ -112,7 +112,7 @@ class _ChannelManager {
class InAppBrowser { class InAppBrowser {
String uuid; String uuid;
Map<String, List<JavaScriptHandlerCallback>> javaScriptHandlersMap = HashMap<String, List<JavaScriptHandlerCallback>>(); Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap = HashMap<String, JavaScriptHandlerCallback>();
bool _isOpened = false; bool _isOpened = false;
/// WebView Controller that can be used to access the [InAppWebView] API. /// WebView Controller that can be used to access the [InAppWebView] API.
InAppWebViewController webViewController; InAppWebViewController webViewController;
...@@ -735,7 +735,7 @@ class InAppWebViewController { ...@@ -735,7 +735,7 @@ class InAppWebViewController {
InAppWebView _widget; InAppWebView _widget;
MethodChannel _channel; MethodChannel _channel;
Map<String, List<JavaScriptHandlerCallback>> javaScriptHandlersMap = HashMap<String, List<JavaScriptHandlerCallback>>(); Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap = HashMap<String, JavaScriptHandlerCallback>();
bool _isOpened = false; bool _isOpened = false;
int _id; int _id;
String _inAppBrowserUuid; String _inAppBrowserUuid;
...@@ -849,9 +849,7 @@ class InAppWebViewController { ...@@ -849,9 +849,7 @@ class InAppWebViewController {
String handlerName = call.arguments["handlerName"]; String handlerName = call.arguments["handlerName"];
List<dynamic> args = jsonDecode(call.arguments["args"]); List<dynamic> args = jsonDecode(call.arguments["args"]);
if (javaScriptHandlersMap.containsKey(handlerName)) { if (javaScriptHandlersMap.containsKey(handlerName)) {
for (var handler in javaScriptHandlersMap[handlerName]) { return await javaScriptHandlersMap[handlerName](args);
handler(args);
}
} }
break; break;
default: default:
...@@ -1140,31 +1138,22 @@ class InAppWebViewController { ...@@ -1140,31 +1138,22 @@ class InAppWebViewController {
await _channel.invokeMethod('injectStyleFile', args); 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]. ///Adds 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.
/// ///
///The Android implementation uses [addJavascriptInterface](https://developer.android.com/reference/android/webkit/WebView#addJavascriptInterface(java.lang.Object,%20java.lang.String)). ///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 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 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. ///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) { void addJavaScriptHandler(String handlerName, JavaScriptHandlerCallback callback) {
this.javaScriptHandlersMap.putIfAbsent(handlerName, () => List<JavaScriptHandlerCallback>()); this.javaScriptHandlersMap[handlerName] = (callback);
this.javaScriptHandlersMap[handlerName].add(callback); }
return this.javaScriptHandlersMap[handlerName].indexOf(callback);
} ///Removes a JavaScript message handler previously added with the [addJavaScriptHandler()] associated to [handlerName] key.
///Returns the value associated with [handlerName] before it was removed.
///Removes a JavaScript message handler previously added with the [addJavaScriptHandler()] method in the [handlerName] list by its position [index]. ///Returns `null` if [handlerName] was not found.
///Returns `true` if the callback is removed, otherwise `false`. JavaScriptHandlerCallback removeJavaScriptHandler(String handlerName) {
bool removeJavaScriptHandler(String handlerName, int index) { return this.javaScriptHandlersMap.remove(handlerName);
try {
this.javaScriptHandlersMap[handlerName].removeAt(index);
return true;
}
on RangeError catch(e) {
print(e);
}
return false;
} }
///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. ///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 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). 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> author: Lorenzo Pichilli <pichillilorenzo@gmail.com>
homepage: https://github.com/pichillilorenzo/flutter_inappbrowser 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