Commit a6590903 authored by Lorenzo Pichilli's avatar Lorenzo Pichilli

fixed ajax interceptor javascript code, re-added...

fixed ajax interceptor javascript code, re-added flutterInAppBrowserPlatformReady javascript for the window object, tests moved inside example folder using flutter driver
parent 8894ae1b
This diff is collapsed.
...@@ -45,7 +45,6 @@ ...@@ -45,7 +45,6 @@
- Renamed `injectScriptCode` to `evaluateJavascript` - Renamed `injectScriptCode` to `evaluateJavascript`
- Renamed `injectStyleCode` to `injectCSSCode` - Renamed `injectStyleCode` to `injectCSSCode`
- Renamed `injectStyleFile` to `injectCSSFileFromUrl` - Renamed `injectStyleFile` to `injectCSSFileFromUrl`
- No need to listen to `window.addEventListener("flutterInAppBrowserPlatformReady", fuction(){ })` javascript event anymore to call `window.flutter_inappbrowser.callHandler(handlerName <String>, ...args)` to use the JavaScript message handlers
## 1.2.1 ## 1.2.1
......
...@@ -85,6 +85,8 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -85,6 +85,8 @@ final public class InAppWebView extends InputAwareWebView {
" }" + " }" +
"})(window.console);"; "})(window.console);";
static final String platformReadyJS = "window.dispatchEvent(new Event('flutterInAppBrowserPlatformReady'));";
static final String variableForOnLoadResourceJS = "window._flutter_inappbrowser_useOnLoadResource"; static final String variableForOnLoadResourceJS = "window._flutter_inappbrowser_useOnLoadResource";
static final String enableVariableForOnLoadResourceJS = variableForOnLoadResourceJS + " = $PLACEHOLDER_VALUE;"; static final String enableVariableForOnLoadResourceJS = variableForOnLoadResourceJS + " = $PLACEHOLDER_VALUE;";
...@@ -148,7 +150,6 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -148,7 +150,6 @@ final public class InAppWebView extends InputAwareWebView {
" };" + " };" +
" ajax.prototype.setRequestHeader = function(header, value) {" + " ajax.prototype.setRequestHeader = function(header, value) {" +
" this._flutter_inappbrowser_request_headers[header] = value;" + " this._flutter_inappbrowser_request_headers[header] = value;" +
" setRequestHeader.call(this, header, value);" +
" };" + " };" +
" function handleEvent(e) {" + " function handleEvent(e) {" +
" var self = this;" + " var self = this;" +
...@@ -289,7 +290,11 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -289,7 +290,11 @@ final public class InAppWebView extends InputAwareWebView {
" };" + " };" +
" for (var header in result.headers) {" + " for (var header in result.headers) {" +
" var value = result.headers[header];" + " var value = result.headers[header];" +
" self.setRequestHeader(header, value);" + " self._flutter_inappbrowser_request_headers[header] = value;" +
" };" +
" for (var header in self._flutter_inappbrowser_request_headers) {" +
" var value = self._flutter_inappbrowser_request_headers[header];" +
" setRequestHeader.call(self, header, value);" +
" };" + " };" +
" if ((self._flutter_inappbrowser_method != result.method && result.method != null) || (self._flutter_inappbrowser_url != result.url && result.url != null)) {" + " if ((self._flutter_inappbrowser_method != result.method && result.method != null) || (self._flutter_inappbrowser_url != result.url && result.url != null)) {" +
" self.abort();" + " self.abort();" +
......
...@@ -136,16 +136,23 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -136,16 +136,23 @@ public class InAppWebViewClient extends WebViewClient {
InAppWebView webView = (InAppWebView) view; InAppWebView webView = (InAppWebView) view;
webView.loadUrl("javascript:" + InAppWebView.consoleLogJS.replaceAll("[\r\n]+", "")); String js = InAppWebView.consoleLogJS.replaceAll("[\r\n]+", "");
webView.loadUrl("javascript:" + JavaScriptBridgeInterface.flutterInAppBroserJSClass.replaceAll("[\r\n]+", "")); js += JavaScriptBridgeInterface.flutterInAppBroserJSClass.replaceAll("[\r\n]+", "");
if (webView.options.useShouldInterceptAjaxRequest) { if (webView.options.useShouldInterceptAjaxRequest) {
webView.loadUrl("javascript:" + InAppWebView.interceptAjaxRequestsJS.replaceAll("[\r\n]+", "")); js += InAppWebView.interceptAjaxRequestsJS.replaceAll("[\r\n]+", "");
} }
if (webView.options.useShouldInterceptFetchRequest) { if (webView.options.useShouldInterceptFetchRequest) {
webView.loadUrl("javascript:" + InAppWebView.interceptFetchRequestsJS.replaceAll("[\r\n]+", "")); js += InAppWebView.interceptFetchRequestsJS.replaceAll("[\r\n]+", "");
} }
if (webView.options.useOnLoadResource) { if (webView.options.useOnLoadResource) {
webView.loadUrl("javascript:" + InAppWebView.resourceObserverJS.replaceAll("[\r\n]+", "")); js += InAppWebView.resourceObserverJS.replaceAll("[\r\n]+", "");
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript(js, (ValueCallback<String>) null);
} else {
webView.loadUrl("javascript:" + js);
} }
onPageStartedURL = url; onPageStartedURL = url;
...@@ -184,6 +191,14 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -184,6 +191,14 @@ public class InAppWebViewClient extends WebViewClient {
view.clearFocus(); view.clearFocus();
view.requestFocus(); view.requestFocus();
String js = InAppWebView.platformReadyJS.replaceAll("[\r\n]+", "");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript(js, (ValueCallback<String>) null);
} else {
webView.loadUrl("javascript:" + js);
}
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);
......
...@@ -28,7 +28,7 @@ public class JavaScriptBridgeInterface { ...@@ -28,7 +28,7 @@ public class JavaScriptBridgeInterface {
"return new Promise(function(resolve, reject) {" + "return new Promise(function(resolve, reject) {" +
" window." + name + "[_callHandlerID] = resolve;" + " window." + name + "[_callHandlerID] = resolve;" +
"});" + "});" +
"}"; "};";
public JavaScriptBridgeInterface(Object obj) { public JavaScriptBridgeInterface(Object obj) {
if (obj instanceof InAppBrowserActivity) if (obj instanceof InAppBrowserActivity)
......
...@@ -77,6 +77,7 @@ ...@@ -77,6 +77,7 @@
window.location = "#foo-" + randomNumber; window.location = "#foo-" + randomNumber;
} }
window.addEventListener("flutterInAppBrowserPlatformReady", function(event) {
window.flutter_inappbrowser.callHandler('handlerFoo').then(function(result) { window.flutter_inappbrowser.callHandler('handlerFoo').then(function(result) {
console.log(result, typeof result); console.log(result, typeof result);
console.log(JSON.stringify(result), result.bar); console.log(JSON.stringify(result), result.bar);
...@@ -86,6 +87,7 @@ ...@@ -86,6 +87,7 @@
console.log(result, typeof result); console.log(result, typeof result);
console.log(JSON.stringify(result)); console.log(JSON.stringify(result));
}); });
});
$(document).ready(function() { $(document).ready(function() {
......
...@@ -289,9 +289,10 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> { ...@@ -289,9 +289,10 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
print("Current highlighted: $activeMatchOrdinal, Number of matches found: $numberOfMatches, find operation completed: $isDoneCounting"); print("Current highlighted: $activeMatchOrdinal, Number of matches found: $numberOfMatches, find operation completed: $isDoneCounting");
}, },
shouldInterceptAjaxRequest: (InAppWebViewController controller, AjaxRequest ajaxRequest) async { shouldInterceptAjaxRequest: (InAppWebViewController controller, AjaxRequest ajaxRequest) async {
print("AJAX REQUEST: ${ajaxRequest.method} - ${ajaxRequest.url}, DATA: ${ajaxRequest.data}"); print("AJAX REQUEST: ${ajaxRequest.method} - ${ajaxRequest.url}, DATA: ${ajaxRequest.data}, headers: ${ajaxRequest.headers}");
if (ajaxRequest.url == "http://192.168.1.20:8082/test-ajax-post") { if (ajaxRequest.url == "http://192.168.1.20:8082/test-ajax-post") {
ajaxRequest.responseType = 'json'; ajaxRequest.responseType = 'json';
ajaxRequest.data = "firstname=Lorenzo&lastname=Pichilli";
} }
// ajaxRequest.method = "GET"; // ajaxRequest.method = "GET";
// ajaxRequest.url = "http://192.168.1.20:8082/test-download-file"; // ajaxRequest.url = "http://192.168.1.20:8082/test-download-file";
......
...@@ -22,14 +22,13 @@ dependencies: ...@@ -22,14 +22,13 @@ dependencies:
flutter_downloader: ^1.3.2 flutter_downloader: ^1.3.2
path_provider: ^1.4.0 path_provider: ^1.4.0
permission_handler: ^3.3.0 permission_handler: ^3.3.0
flutter_inappbrowser:
path: ../
dev_dependencies: dev_dependencies:
flutter_test: flutter_driver:
sdk: flutter sdk: flutter
ansicolor: 1.0.2 test: any
flutter_inappbrowser:
path: ../
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec # following page: https://www.dartlang.org/tools/pub/pubspec
...@@ -50,6 +49,14 @@ flutter: ...@@ -50,6 +49,14 @@ flutter:
- assets/css/ - assets/css/
- assets/images/ - assets/images/
- assets/favicon.ico - assets/favicon.ico
- test_assets/certificate.pfx
- test_assets/in_app_webview_initial_file_test.html
- test_assets/in_app_webview_on_load_resource_test.html
- test_assets/in_app_webview_javascript_handler_test.html
- test_assets/in_app_webview_ajax_test.html
- test_assets/css/
- test_assets/images/
- test_assets/favicon.ico
# To add assets to your application, add an assets section, like this: # To add assets to your application, add an assets section, like this:
# assets: # assets:
......
import 'package:ansicolor/ansicolor.dart';
import 'package:flutter/widgets.dart';
class WidgetTest extends StatefulWidget {
final String name;
WidgetTest({this.name, Key key}): super(key: key) {
AnsiPen pen = new AnsiPen()..white()..rgb(r: 1.0, g: 0.8, b: 0.2);
print("\n");
print(pen("'" + this.name + "' test loading..."));
print("\n");
}
@override
State<StatefulWidget> createState() {
return null;
}
}
\ No newline at end of file
import 'package:ansicolor/ansicolor.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'custom_widget_test.dart';
int countTestPassed = 0;
int countTestFailed = 0;
int currentTest = 0;
List<String> testRoutes = [
'/',
'/InAppWebViewInitialFileTest',
'/InAppWebViewOnLoadResourceTest'
];
void nextTest({@required BuildContext context}) {
if (currentTest + 1 < testRoutes.length) {
currentTest++;
String nextRoute = testRoutes[currentTest];
Navigator.pushReplacementNamed(context, nextRoute);
} else {
AnsiPen penError = new AnsiPen()..white()..rgb(r: 1.0, g: 0.0, b: 0.0);
AnsiPen penSuccess = new AnsiPen()..white()..rgb(r: 0.0, g: 1.0, b: 0.0);
if (countTestFailed > 0)
print("\n" + penError("Total tests failed $countTestFailed.") + "\n");
if (countTestPassed > 0)
print("\n" + penSuccess("Total tests passed $countTestPassed.") + "\n");
}
}
bool customAssert({WidgetTest widget, String name, @required bool value}) {
try {
assert(value);
} catch (e, stackTrace) {
String message = "${widget != null ? "'" + widget.name + "' - " : ""} ERROR - Failed assertion: ";
List<String> stakTraceSplitted = stackTrace.toString().split("\n");
String lineCallingAssert = stakTraceSplitted[3].trim().substring(2).trim();
AnsiPen penError = new AnsiPen()..white()..rgb(r: 1.0, g: 0.0, b: 0.0);
print("\n" + penError(message + lineCallingAssert) + "\n");
countTestFailed++;
return false;
}
countTestPassed++;
try {
throw Exception();
} on Exception catch(e, stackTrace) {
String message = "${widget != null ? "'" + widget.name + "' - " : ""} Test ";
message += (name != null) ? "'$name' " : "";
message += "passed!";
List<String> stakTraceSplitted = stackTrace.toString().split("\n");
String lineCallingAssert = stakTraceSplitted[1].trim().substring(2).trim();
message += " $lineCallingAssert";
AnsiPen pen = new AnsiPen()..white()..rgb(r: 1.0, g: 0.8, b: 0.2);
print("\n" + pen(message) + "\n");
}
return true;
}
\ No newline at end of file
/*
* Globals
*/
/* Links */
a,
a:focus,
a:hover {
color: #fff;
}
/* Custom default button */
.btn-secondary,
.btn-secondary:hover,
.btn-secondary:focus {
color: #333;
text-shadow: none; /* Prevent inheritance from `body` */
background-color: #fff;
border: .05rem solid #fff;
}
/*
* Base structure
*/
html,
body {
height: 100%;
background-color: #333;
}
body {
display: -ms-flexbox;
display: flex;
color: #fff;
text-shadow: 0 .05rem .1rem rgba(0, 0, 0, .5);
box-shadow: inset 0 0 5rem rgba(0, 0, 0, .5);
}
.cover-container {
max-width: 42em;
}
/*
* Header
*/
.masthead {
margin-bottom: 2rem;
}
.masthead-brand {
margin-bottom: 0;
}
.nav-masthead .nav-link {
padding: .25rem 0;
font-weight: 700;
color: rgba(255, 255, 255, .5);
background-color: transparent;
border-bottom: .25rem solid transparent;
}
.nav-masthead .nav-link:hover,
.nav-masthead .nav-link:focus {
border-bottom-color: rgba(255, 255, 255, .25);
}
.nav-masthead .nav-link + .nav-link {
margin-left: 1rem;
}
.nav-masthead .active {
color: #fff;
border-bottom-color: #fff;
}
@media (min-width: 48em) {
.masthead-brand {
float: left;
}
.nav-masthead {
float: right;
}
}
/*
* Cover
*/
.cover {
padding: 0 1.5rem;
}
.cover .btn-lg {
padding: .75rem 1.25rem;
font-weight: 700;
}
/*
* Footer
*/
.mastfoot {
color: rgba(255, 255, 255, .5);
}
\ No newline at end of file
This diff is collapsed.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>InAppWebViewAjaxTest</title>
</head>
<body>
<h1>InAppWebViewAjaxTest</h1>
<script>
window.addEventListener('flutterInAppBrowserPlatformReady', function(event) {
var xhttp = new XMLHttpRequest();
xhttp.open("POST", "http://192.168.1.20:8082/test-ajax-post");
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send("firstname=Foo&lastname=Bar");
var xhttp2 = new XMLHttpRequest();
xhttp2.open("GET", "http://192.168.1.20:8082/test-download-file");
xhttp2.send();
});
</script>
</body>
</html>
\ No newline at end of file
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>InAppWebViewInitialFileTest</title>
<link rel="stylesheet" href="https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<link rel="shortcut icon" href="favicon.ico">
</head>
<body class="text-center">
<div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
<header class="masthead mb-auto">
<div class="inner">
<h3 class="masthead-brand">InAppWebViewInitialFileTest</h3>
<nav class="nav nav-masthead justify-content-center">
<a class="nav-link active" href="index.html">Home</a>
<a class="nav-link" href="page-1.html">Page 1</a>
<a class="nav-link" href="page-2.html">Page 2</a>
</nav>
</div>
</header>
<main role="main" class="inner cover">
<h1 class="cover-heading">InAppWebViewInitialFileTest</h1>
<img src="images/flutter-logo.svg" alt="flutter logo">
<p>
<img src="https://via.placeholder.com/100x50" alt="placeholder 100x50">
</p>
</main>
</div>
</body>
</html>
\ No newline at end of file
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>InAppWebViewJavaScriptHandlerTest</title>
</head>
<body>
<h1>InAppWebViewJavaScriptHandlerTest</h1>
<script>
window.addEventListener("flutterInAppBrowserPlatformReady", function(event) {
window.flutter_inappbrowser.callHandler('handlerFoo').then(function(result) {
window.flutter_inappbrowser.callHandler('handlerFooWithArgs', 1, true, ['bar', 5], {foo: 'baz'}, result).then(function(result) {
});
});
});
</script>
</body>
</html>
\ No newline at end of file
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>InAppWebViewOnLoadResourceTest</title>
<link rel="stylesheet" href="https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<link rel="shortcut icon" href="favicon.ico">
</head>
<body class="text-center">
<div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
<main role="main" class="inner cover">
<h1 class="cover-heading">InAppWebViewOnLoadResourceTest</h1>
<img src="images/flutter-logo.svg" alt="flutter logo">
<p>
<img src="https://via.placeholder.com/100x50" alt="placeholder 100x50">
</p>
</main>
</div>
</body>
</html>
\ No newline at end of file
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Flutter InAppBrowser</title>
<link rel="stylesheet" href="http://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<link rel="shortcut icon" href="favicon.ico">
</head>
<body class="text-center">
<div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
<header class="masthead mb-auto">
<div class="inner">
<h3 class="masthead-brand">Flutter InAppBrowser</h3>
<nav class="nav nav-masthead justify-content-center">
<a class="nav-link active" href="index.html">Home</a>
<a class="nav-link" href="page-1.html">Page 1</a>
<a class="nav-link" href="page-2.html">Page 2</a>
</nav>
</div>
</header>
<main role="main" class="inner cover">
<h1 class="cover-heading">Inline WebView</h1>
<img src="my-special-custom-scheme://images/flutter-logo.svg" alt="flutter logo">
<p class="lead">Cover is a one-page template for building simple and beautiful home pages. Download, edit the text, and add your own fullscreen background photo to make it your own.</p>
<select name="" id="">
<option value="1">option 1</option>
<option value="2">option 2</option>
</select>
<input type="file">
<input type="file" accept="image/*" capture>
<button onclick="testHistoryPush1()">History Push 1</button>
<button onclick="testHistoryPush2()">History Push 2</button>
<button onclick="testLocationHref()">Location Href</button>
<p>
<img src="https://via.placeholder.com/100x50" alt="placeholder 100x50">
</p>
</main>
<!--<form method="POST" action="http://192.168.1.20:8082/test-post">
<input type="text" name="name" placeholder="name" value="Lorenzo">
<input type="submit" value="SEND">
</form>-->
<footer class="mastfoot mt-auto">
<div class="inner">
<p>Cover template for <a target="_blank" href="https://getbootstrap.com/">Bootstrap</a>, by <a href="https://twitter.com/mdo">@mdo</a>.</p>
<p>Phone link example <a href="tel:1-408-555-5555">1-408-555-5555</a></p>
<p>Email link example <a href="mailto:example@gmail.com">example@gmail.com</a></p>
</div>
</footer>
</div>
<script>
var state = { 'page_id': 1, 'user_id': 5 };
function testHistoryPush1() {
var randomNumber = 100 * Math.random();
var title = 'Hello World ' + randomNumber;
var url = 'hello-foo-' + randomNumber + '.html';
history.pushState(state, title, url);
}
function testHistoryPush2() {
var randomNumber = 100 * Math.random();
var title = 'Hello World ' + randomNumber;
var url = 'hello-bar-' + randomNumber + '.html';
history.replaceState(state, title, url);
}
function testLocationHref() {
var randomNumber = 100 * Math.random();
window.location = "#foo-" + randomNumber;
}
window.addEventListener("flutterInAppBrowserPlatformReady", function(event) {
window.flutter_inappbrowser.callHandler('handlerFoo').then(function(result) {
window.flutter_inappbrowser.callHandler('handlerFooWithArgs', 1, true, ['bar', 5], {foo: 'baz'}, result).then(function(result) {
});
});
});
$(document).ready(function() {
console.log("jQuery ready");
var xhttp = new XMLHttpRequest();
xhttp.addEventListener("load", function() {
console.log(this.response);
});
xhttp.open("POST", "http://192.168.1.20:8082/test-ajax-post");
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send("name=Lorenzo");
var xhttp2 = new XMLHttpRequest();
xhttp2.open("GET", "http://192.168.1.20:8082/test-download-file");
xhttp2.send();
fetch(new Request("http://192.168.1.20:8082/test-download-file")).then(function(response) {
console.log(response);
}).catch(function(error) {
console.error("ERROR: " + error);
});
fetch("http://192.168.1.20:8082/test-ajax-post", {
method: 'POST',
body: JSON.stringify({
name: 'Lorenzo Fetch API'
}),
headers: {
'Content-Type': 'application/json'
}
}).then(function(response) {
console.log(response);
}).catch(function(error) {
console.error("ERROR: " + error);
});
/*
alert("Alert Popup");
console.log(confirm("Press a button!"));
console.log(prompt("Please enter your name", "Lorenzo"));
*/
/*
if ("geolocation" in navigator) {
console.log("Geolocation API enabled");
navigator.geolocation.getCurrentPosition(function(position) {
console.log(position.coords.latitude, position.coords.longitude);
});
} else {
console.log("No geolocation API");
}
*/
});
</script>
</body>
</html>
\ No newline at end of file
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Flutter InAppBrowser</title>
<link rel="stylesheet" href="https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>
<body class="text-center">
<div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
<header class="masthead mb-auto">
<div class="inner">
<h3 class="masthead-brand">Flutter InAppBrowser</h3>
<nav class="nav nav-masthead justify-content-center">
<a class="nav-link" href="index.html">Home</a>
<a class="nav-link active" href="page-1.html">Page 1</a>
<a class="nav-link" href="page-2.html">Page 2</a>
</nav>
</div>
</header>
<main role="main" class="inner cover">
<h1 class="cover-heading">Page 1</h1>
<p class="lead">Cover is a one-page template for building simple and beautiful home pages. Download, edit the text, and add your own fullscreen background photo to make it your own.</p>
<p class="lead">
<a href="#" class="btn btn-lg btn-secondary">Learn more</a>
</p>
</main>
<footer class="mastfoot mt-auto">
<div class="inner">
<p>Cover template for <a href="https://getbootstrap.com/">Bootstrap</a>, by <a href="https://twitter.com/mdo">@mdo</a>.</p>
</div>
</footer>
</div>
</body>
</html>
\ No newline at end of file
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Flutter InAppBrowser</title>
<link rel="stylesheet" href="https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>
<body class="text-center">
<div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
<header class="masthead mb-auto">
<div class="inner">
<h3 class="masthead-brand">Flutter InAppBrowser</h3>
<nav class="nav nav-masthead justify-content-center">
<a class="nav-link" href="index.html">Home</a>
<a class="nav-link" href="page-1.html">Page 1</a>
<a class="nav-link active" href="page-2.html">Page 2</a>
</nav>
</div>
</header>
<main role="main" class="inner cover">
<h1 class="cover-heading">Page 2</h1>
<p class="lead">Cover is a one-page template for building simple and beautiful home pages. Download, edit the text, and add your own fullscreen background photo to make it your own.</p>
<p class="lead">
<a href="#" class="btn btn-lg btn-secondary">Learn more</a>
</p>
</main>
<footer class="mastfoot mt-auto">
<div class="inner">
<p>Cover template for <a href="https://getbootstrap.com/">Bootstrap</a>, by <a href="https://twitter.com/mdo">@mdo</a>.</p>
</div>
</footer>
</div>
</body>
</html>
\ No newline at end of file
import 'package:flutter_driver/driver_extension.dart';
import 'app_test.dart';
import 'main_test.dart' as app;
void main() {
// This line enables the extension.
enableFlutterDriverExtension();
// Call the `main()` function of the app, or call `runApp` with
// any widget you are interested in testing.
app.main();
}
\ No newline at end of file
// Imports the Flutter Driver API.
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart';
void main() {
group('Flutter InAppBrowser', () {
FlutterDriver driver;
// Connect to the Flutter driver before running any tests.
setUpAll(() async {
driver = await FlutterDriver.connect();
});
// Close the connection to the driver after the tests have completed.
tearDownAll(() async {
if (driver != null) {
driver.close();
}
});
myTest({@required String name, @required Function callback, Timeout timeout}) {
timeout = (timeout == null) ? new Timeout(new Duration(minutes: 5)) : timeout;
test(name, () async {
await Future.delayed(const Duration(milliseconds: 2000));
callback();
}, timeout: timeout);
}
//
// IMPORTANT NOTE!!!
// These tests need to follow the same order of "var routes" in "buildRoutes()" function
// defined in main_test.dart
//
myTest(name: 'InAppWebViewInitialUrlTest', callback: () async {
final appBarTitle = find.byValueKey('AppBarTitle');
while((await driver.getText(appBarTitle)) == "InAppWebViewInitialUrlTest") {
await Future.delayed(const Duration(milliseconds: 1000));
}
String url = await driver.getText(appBarTitle);
expect(url, "https://flutter.dev/");
});
myTest(name: 'InAppWebViewInitialFileTest', callback: () async {
final appBarTitle = find.byValueKey('AppBarTitle');
while((await driver.getText(appBarTitle)) == "InAppWebViewInitialFileTest") {
await Future.delayed(const Duration(milliseconds: 1000));
}
String title = await driver.getText(appBarTitle);
expect(title, "true");
});
myTest(name: 'InAppWebViewOnLoadResourceTest', callback: () async {
List<String> resourceList = [
"https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css",
"https://code.jquery.com/jquery-3.3.1.min.js",
"https://via.placeholder.com/100x50"
];
final appBarTitle = find.byValueKey('AppBarTitle');
while((await driver.getText(appBarTitle)) == "InAppWebViewOnLoadResourceTest") {
await Future.delayed(const Duration(milliseconds: 1000));
}
String title = await driver.getText(appBarTitle);
print(title);
for (String resource in resourceList) {
expect(true, title.contains(resource));
}
});
myTest(name: 'InAppWebViewJavaScriptHandlerTest', callback: () async {
final appBarTitle = find.byValueKey('AppBarTitle');
while((await driver.getText(appBarTitle)) == "InAppWebViewJavaScriptHandlerTest") {
await Future.delayed(const Duration(milliseconds: 1000));
}
String title = await driver.getText(appBarTitle);
expect(true, !title.contains("false"));
});
myTest(name: 'InAppWebViewAjaxTest', callback: () async {
final appBarTitle = find.byValueKey('AppBarTitle');
while((await driver.getText(appBarTitle)) == "InAppWebViewAjaxTest") {
await Future.delayed(const Duration(milliseconds: 1000));
}
String title = await driver.getText(appBarTitle);
expect(title, "Lorenzo Pichilli Lorenzo Pichilli");
});
});
}
\ No newline at end of file
import 'package:flutter/widgets.dart';
import 'package:flutter_inappbrowser/flutter_inappbrowser.dart';
class WidgetTest extends StatefulWidget {
final WidgetTestState state = WidgetTestState();
WidgetTest({Key key}): super(key: key);
@override
WidgetTestState createState() {
return state;
}
}
class WidgetTestState extends State<WidgetTest> {
InAppWebViewController webView;
String appBarTitle;
@override
Widget build(BuildContext context) {
return null;
}
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'package:flutter_inappbrowser/flutter_inappbrowser.dart';
import 'main_test.dart';
import 'util_test.dart';
import 'custom_widget_test.dart';
class InAppWebViewAjaxTest extends WidgetTest {
final InAppWebViewAjaxTestState state = InAppWebViewAjaxTestState();
@override
InAppWebViewAjaxTestState createState() => state;
}
class InAppWebViewAjaxTestState extends WidgetTestState {
String appBarTitle = "InAppWebViewAjaxTest";
int totTests = 2;
int testsDone = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: myAppBar(state: this, title: appBarTitle),
body: Container(
child: Column(children: <Widget>[
Expanded(
child: Container(
child: InAppWebView(
initialFile: "test_assets/in_app_webview_ajax_test.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true,
useShouldInterceptAjaxRequest: true,
)
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
},
onLoadStart: (InAppWebViewController controller, String url) {
},
onLoadStop: (InAppWebViewController controller, String url) {
},
shouldInterceptAjaxRequest: (InAppWebViewController controller, AjaxRequest ajaxRequest) async {
if (ajaxRequest.url.endsWith("/test-ajax-post")) {
ajaxRequest.responseType = 'json';
ajaxRequest.data = "firstname=Lorenzo&lastname=Pichilli";
}
return ajaxRequest;
},
onAjaxReadyStateChange: (InAppWebViewController controller, AjaxRequest ajaxRequest) async {
if (ajaxRequest.readyState == AjaxRequestReadyState.DONE && ajaxRequest.status == 200 && ajaxRequest.url.endsWith("/test-ajax-post")) {
Map<String, Object> res = ajaxRequest.response;
appBarTitle = (appBarTitle == "InAppWebViewAjaxTest") ? res['fullname'] : appBarTitle + " " + res['fullname'];
updateCountTest(context: context);
}
return AjaxRequestAction.PROCEED;
},
onAjaxProgress: (InAppWebViewController controller, AjaxRequest ajaxRequest) async {
if (ajaxRequest.event.type == AjaxRequestEventType.LOAD && ajaxRequest.url.endsWith("/test-ajax-post")) {
Map<String, Object> res = ajaxRequest.response;
appBarTitle = (appBarTitle == "InAppWebViewAjaxTest") ? res['fullname'] : appBarTitle + " " + res['fullname'];
updateCountTest(context: context);
}
return AjaxRequestAction.PROCEED;
},
),
),
),
])
)
);
}
void updateCountTest({@required BuildContext context}) {
testsDone++;
if (testsDone == totTests) {
setState(() { });
nextTest(context: context, state: this);
}
}
}
...@@ -2,34 +2,37 @@ import 'package:flutter/material.dart'; ...@@ -2,34 +2,37 @@ import 'package:flutter/material.dart';
import 'package:flutter_inappbrowser/flutter_inappbrowser.dart'; import 'package:flutter_inappbrowser/flutter_inappbrowser.dart';
import 'main_test.dart';
import 'util_test.dart'; import 'util_test.dart';
import 'custom_widget_test.dart'; import 'custom_widget_test.dart';
class InAppWebViewInitialFileTest extends WidgetTest { class InAppWebViewInitialFileTest extends WidgetTest {
InAppWebViewInitialFileTest(): super(name: "InAppWebViewInitialFileTest"); final InAppWebViewInitialFileTestState state = InAppWebViewInitialFileTestState();
@override @override
_InAppWebViewInitialFileTestState createState() => new _InAppWebViewInitialFileTestState(); InAppWebViewInitialFileTestState createState() => state;
} }
class _InAppWebViewInitialFileTestState extends State<InAppWebViewInitialFileTest> { class InAppWebViewInitialFileTestState extends WidgetTestState {
InAppWebViewController webView; String appBarTitle = "InAppWebViewInitialFileTest";
String initialUrl = "https://flutter.dev/";
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: myAppBar(state: this, title: appBarTitle),
title: Text('InAppWebViewInitialFileTest'),
),
body: Container( body: Container(
child: Column(children: <Widget>[ child: Column(children: <Widget>[
Expanded( Expanded(
child: Container( child: Container(
child: InAppWebView( child: InAppWebView(
initialFile: "assets/index.html", initialFile: "test_assets/in_app_webview_initial_file_test.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(), initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
)
),
onWebViewCreated: (InAppWebViewController controller) { onWebViewCreated: (InAppWebViewController controller) {
webView = controller; webView = controller;
}, },
...@@ -37,8 +40,10 @@ class _InAppWebViewInitialFileTestState extends State<InAppWebViewInitialFileTes ...@@ -37,8 +40,10 @@ class _InAppWebViewInitialFileTestState extends State<InAppWebViewInitialFileTes
}, },
onLoadStop: (InAppWebViewController controller, String url) { onLoadStop: (InAppWebViewController controller, String url) {
customAssert(widget: widget, name: "initialFile", value: true); setState(() {
nextTest(context: context); appBarTitle = "true";
});
nextTest(context: context, state: this);
}, },
), ),
), ),
......
...@@ -2,26 +2,25 @@ import 'package:flutter/material.dart'; ...@@ -2,26 +2,25 @@ import 'package:flutter/material.dart';
import 'package:flutter_inappbrowser/flutter_inappbrowser.dart'; import 'package:flutter_inappbrowser/flutter_inappbrowser.dart';
import 'util_test.dart';
import 'custom_widget_test.dart'; import 'custom_widget_test.dart';
import 'main_test.dart';
import 'util_test.dart';
class InAppWebViewInitialUrlTest extends WidgetTest { class InAppWebViewInitialUrlTest extends WidgetTest {
InAppWebViewInitialUrlTest(): super(name: "InAppWebViewInitialUrlTest"); final InAppWebViewInitialUrlTestState state = InAppWebViewInitialUrlTestState();
@override @override
_InAppWebViewInitialUrlTestState createState() => new _InAppWebViewInitialUrlTestState(); InAppWebViewInitialUrlTestState createState() => state;
} }
class _InAppWebViewInitialUrlTestState extends State<InAppWebViewInitialUrlTest> { class InAppWebViewInitialUrlTestState extends WidgetTestState {
InAppWebViewController webView;
String initialUrl = "https://flutter.dev/"; String initialUrl = "https://flutter.dev/";
String appBarTitle = "InAppWebViewInitialUrlTest";
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: myAppBar(state: this, title: appBarTitle),
title: Text('InAppWebViewInitialUrlTest'),
),
body: Container( body: Container(
child: Column(children: <Widget>[ child: Column(children: <Widget>[
Expanded( Expanded(
...@@ -29,7 +28,12 @@ class _InAppWebViewInitialUrlTestState extends State<InAppWebViewInitialUrlTest> ...@@ -29,7 +28,12 @@ class _InAppWebViewInitialUrlTestState extends State<InAppWebViewInitialUrlTest>
child: InAppWebView( child: InAppWebView(
initialUrl: initialUrl, initialUrl: initialUrl,
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(), initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
)
),
onWebViewCreated: (InAppWebViewController controller) { onWebViewCreated: (InAppWebViewController controller) {
webView = controller; webView = controller;
}, },
...@@ -37,8 +41,10 @@ class _InAppWebViewInitialUrlTestState extends State<InAppWebViewInitialUrlTest> ...@@ -37,8 +41,10 @@ class _InAppWebViewInitialUrlTestState extends State<InAppWebViewInitialUrlTest>
}, },
onLoadStop: (InAppWebViewController controller, String url) { onLoadStop: (InAppWebViewController controller, String url) {
customAssert(widget: widget, name: "initialUrl", value: url == initialUrl); setState(() {
nextTest(context: context); appBarTitle = url;
});
nextTest(context: context, state: this);
}, },
), ),
), ),
......
import 'package:flutter/material.dart';
import 'package:flutter_inappbrowser/flutter_inappbrowser.dart';
import 'main_test.dart';
import 'util_test.dart';
import 'custom_widget_test.dart';
class Foo {
String bar;
String baz;
Foo({this.bar, this.baz});
Map<String, dynamic> toJson() {
return {
'bar': this.bar,
'baz': this.baz
};
}
}
class InAppWebViewJavaScriptHandlerTest extends WidgetTest {
final InAppWebViewJavaScriptHandlerTestState state = InAppWebViewJavaScriptHandlerTestState();
@override
InAppWebViewJavaScriptHandlerTestState createState() => state;
}
class InAppWebViewJavaScriptHandlerTestState extends WidgetTestState {
String appBarTitle = "InAppWebViewJavaScriptHandlerTest";
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: myAppBar(state: this, title: appBarTitle),
body: Container(
child: Column(children: <Widget>[
Expanded(
child: Container(
child: InAppWebView(
initialFile: "test_assets/in_app_webview_javascript_handler_test.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true
)
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
controller.addJavaScriptHandler(handlerName:'handlerFoo', callback: (args) {
appBarTitle = (args.length == 0).toString();
return new Foo(bar: 'bar_value', baz: 'baz_value');
});
controller.addJavaScriptHandler(handlerName: 'handlerFooWithArgs', callback: (args) {
appBarTitle += " " + (args[0] is int).toString();
appBarTitle += " " + (args[1] is bool).toString();
appBarTitle += " " + (args[2] is List).toString();
appBarTitle += " " + (args[2] is List).toString();
appBarTitle += " " + (args[3] is Map).toString();
appBarTitle += " " + (args[4] is Map).toString();
setState(() { });
nextTest(context: context, state: this);
});
},
onLoadStart: (InAppWebViewController controller, String url) {
},
onLoadStop: (InAppWebViewController controller, String url) {
},
),
),
),
])
)
);
}
}
...@@ -2,41 +2,41 @@ import 'package:flutter/material.dart'; ...@@ -2,41 +2,41 @@ import 'package:flutter/material.dart';
import 'package:flutter_inappbrowser/flutter_inappbrowser.dart'; import 'package:flutter_inappbrowser/flutter_inappbrowser.dart';
import 'main_test.dart';
import 'util_test.dart'; import 'util_test.dart';
import 'custom_widget_test.dart'; import 'custom_widget_test.dart';
class InAppWebViewOnLoadResourceTest extends WidgetTest { class InAppWebViewOnLoadResourceTest extends WidgetTest {
InAppWebViewOnLoadResourceTest(): super(name: "InAppWebViewOnLoadResourceTest"); final InAppWebViewOnLoadResourceTestState state = InAppWebViewOnLoadResourceTestState();
@override @override
_InAppWebViewOnLoadResourceTestState createState() => new _InAppWebViewOnLoadResourceTestState(); InAppWebViewOnLoadResourceTestState createState() => state;
} }
class _InAppWebViewOnLoadResourceTestState extends State<InAppWebViewOnLoadResourceTest> { class InAppWebViewOnLoadResourceTestState extends WidgetTestState {
InAppWebViewController webView;
List<String> resourceList = [ List<String> resourceList = [
"http://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css", "https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css",
"https://code.jquery.com/jquery-3.3.1.min.js", "https://code.jquery.com/jquery-3.3.1.min.js",
"https://via.placeholder.com/100x50" "https://via.placeholder.com/100x50"
]; ];
int countResources = 0; int countResources = 0;
String appBarTitle = "InAppWebViewOnLoadResourceTest";
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: myAppBar(state: this, title: appBarTitle),
title: Text('InAppWebViewOnLoadResourceTest'),
),
body: Container( body: Container(
child: Column(children: <Widget>[ child: Column(children: <Widget>[
Expanded( Expanded(
child: Container( child: Container(
child: InAppWebView( child: InAppWebView(
initialFile: "assets/index.html", initialFile: "test_assets/in_app_webview_on_load_resource_test.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions( initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions( inAppWebViewOptions: InAppWebViewOptions(
clearCache: true, clearCache: true,
debuggingEnabled: true,
useOnLoadResource: true useOnLoadResource: true
) )
), ),
...@@ -50,10 +50,11 @@ class _InAppWebViewOnLoadResourceTestState extends State<InAppWebViewOnLoadResou ...@@ -50,10 +50,11 @@ class _InAppWebViewOnLoadResourceTestState extends State<InAppWebViewOnLoadResou
}, },
onLoadResource: (InAppWebViewController controller, LoadedResource response) { onLoadResource: (InAppWebViewController controller, LoadedResource response) {
customAssert(widget: widget, name: "onLoadResource", value: resourceList.contains(response.url)); appBarTitle = (appBarTitle == "InAppWebViewOnLoadResourceTest") ? response.url : appBarTitle + " " + response.url;
countResources++; countResources++;
if (countResources == resourceList.length) { if (countResources == resourceList.length) {
nextTest(context: context); setState(() { });
nextTest(context: context, state: this);
} }
} }
), ),
......
...@@ -2,10 +2,43 @@ import 'dart:async'; ...@@ -2,10 +2,43 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'custom_widget_test.dart';
import 'in_app_webview_ajax_test.dart';
import 'in_app_webview_initial_file_test.dart'; import 'in_app_webview_initial_file_test.dart';
import 'in_app_webview_initial_url_test.dart'; import 'in_app_webview_initial_url_test.dart';
import 'in_app_webview_javascript_handler_test.dart';
import 'in_app_webview_on_load_resource_test.dart'; import 'in_app_webview_on_load_resource_test.dart';
List<String> testRoutes = [];
Map<String, WidgetBuilder> buildRoutes({@required BuildContext context}) {
var routes = {
'/': (context) => InAppWebViewInitialUrlTest(),
'/InAppWebViewInitialFileTest': (context) => InAppWebViewInitialFileTest(),
'/InAppWebViewOnLoadResourceTest': (context) => InAppWebViewOnLoadResourceTest(),
'/InAppWebViewJavaScriptHandlerTest': (context) => InAppWebViewJavaScriptHandlerTest(),
'/InAppWebViewAjaxTest': (context) => InAppWebViewAjaxTest(),
};
routes.forEach((k, v) => testRoutes.add(k));
return routes;
}
AppBar myAppBar({@required WidgetTestState state, @required String title}) {
return AppBar(
title: Text(
title,
key: Key("AppBarTitle")
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
if (state.webView != null)
state.webView.reload();
},
),
],
);
}
Future main() async { Future main() async {
runApp(new MyApp()); runApp(new MyApp());
...@@ -33,11 +66,7 @@ class _MyAppState extends State<MyApp> { ...@@ -33,11 +66,7 @@ class _MyAppState extends State<MyApp> {
return MaterialApp( return MaterialApp(
title: 'flutter_inappbrowser tests', title: 'flutter_inappbrowser tests',
initialRoute: '/', initialRoute: '/',
routes: { routes: buildRoutes(context: context)
'/': (context) => InAppWebViewInitialUrlTest(),
'/InAppWebViewInitialFileTest': (context) => InAppWebViewInitialFileTest(),
'/InAppWebViewOnLoadResourceTest': (context) => InAppWebViewOnLoadResourceTest()
}
); );
} }
} }
\ No newline at end of file
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'custom_widget_test.dart';
import 'main_test.dart';
int currentTest = 0;
void nextTest({@required BuildContext context, @required WidgetTestState state}) {
if (currentTest + 1 < testRoutes.length) {
currentTest++;
String nextRoute = testRoutes[currentTest];
Future.delayed(const Duration(milliseconds: 2000)).then((value) {
Navigator.pushReplacementNamed(context, nextRoute);
});
}
}
\ No newline at end of file
...@@ -21,6 +21,15 @@ ...@@ -21,6 +21,15 @@
<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/Flutter/App.framework/flutter_assets/packages" /> <excludeFolder url="file://$MODULE_DIR$/example/ios/Flutter/App.framework/flutter_assets/packages" />
<excludeFolder url="file://$MODULE_DIR$/flutter_inappbrowser_tests/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/flutter_inappbrowser_tests/.pub" />
<excludeFolder url="file://$MODULE_DIR$/flutter_inappbrowser_tests/build" />
<excludeFolder url="file://$MODULE_DIR$/test/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/test/.pub" />
<excludeFolder url="file://$MODULE_DIR$/test1/build" />
<excludeFolder url="file://$MODULE_DIR$/tests/flutter_in_app_browser_test/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/tests/flutter_in_app_browser_test/.pub" />
<excludeFolder url="file://$MODULE_DIR$/tests/flutter_in_app_browser_test/build" />
</content> </content>
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" /> <orderEntry type="library" name="Dart SDK" level="project" />
......
...@@ -11,7 +11,10 @@ import WebKit ...@@ -11,7 +11,10 @@ import WebKit
@available(iOS 11.0, *) @available(iOS 11.0, *)
class CustomeSchemeHandler : NSObject, WKURLSchemeHandler { class CustomeSchemeHandler : NSObject, WKURLSchemeHandler {
var schemeHandlers: [Int:WKURLSchemeTask] = [:]
func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) { func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
schemeHandlers[urlSchemeTask.hash] = urlSchemeTask
let inAppWebView = webView as! InAppWebView let inAppWebView = webView as! InAppWebView
if let url = urlSchemeTask.request.url, let scheme = url.scheme { if let url = urlSchemeTask.request.url, let scheme = url.scheme {
inAppWebView.onLoadResourceCustomScheme(scheme: scheme, url: url.absoluteString, result: {(result) -> Void in inAppWebView.onLoadResourceCustomScheme(scheme: scheme, url: url.absoluteString, result: {(result) -> Void in
...@@ -25,9 +28,12 @@ class CustomeSchemeHandler : NSObject, WKURLSchemeHandler { ...@@ -25,9 +28,12 @@ class CustomeSchemeHandler : NSObject, WKURLSchemeHandler {
json = r as! [String: Any] json = r as! [String: Any]
let urlResponse = URLResponse(url: url, mimeType: json["content-type"] as! String, expectedContentLength: -1, textEncodingName: json["content-encoding"] as! String) let urlResponse = URLResponse(url: url, mimeType: json["content-type"] as! String, expectedContentLength: -1, textEncodingName: json["content-encoding"] as! String)
let data = json["data"] as! FlutterStandardTypedData let data = json["data"] as! FlutterStandardTypedData
if (self.schemeHandlers[urlSchemeTask.hash] != nil) {
urlSchemeTask.didReceive(urlResponse) urlSchemeTask.didReceive(urlResponse)
urlSchemeTask.didReceive(data.data) urlSchemeTask.didReceive(data.data)
urlSchemeTask.didFinish() urlSchemeTask.didFinish()
self.schemeHandlers.removeValue(forKey: urlSchemeTask.hash)
}
} }
} }
}) })
...@@ -35,6 +41,6 @@ class CustomeSchemeHandler : NSObject, WKURLSchemeHandler { ...@@ -35,6 +41,6 @@ class CustomeSchemeHandler : NSObject, WKURLSchemeHandler {
} }
func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) { func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
schemeHandlers.removeValue(forKey: urlSchemeTask.hash)
} }
} }
...@@ -82,6 +82,8 @@ window.\(JAVASCRIPT_BRIDGE_NAME).callHandler = function() { ...@@ -82,6 +82,8 @@ window.\(JAVASCRIPT_BRIDGE_NAME).callHandler = function() {
} }
""" """
let platformReadyJS = "window.dispatchEvent(new Event('flutterInAppBrowserPlatformReady'));";
let findTextHighlightJS = """ let findTextHighlightJS = """
var wkwebview_SearchResultCount = 0; var wkwebview_SearchResultCount = 0;
var wkwebview_CurrentHighlight = 0; var wkwebview_CurrentHighlight = 0;
...@@ -298,7 +300,6 @@ let interceptAjaxRequestsJS = """ ...@@ -298,7 +300,6 @@ let interceptAjaxRequestsJS = """
}; };
ajax.prototype.setRequestHeader = function(header, value) { ajax.prototype.setRequestHeader = function(header, value) {
this._flutter_inappbrowser_request_headers[header] = value; this._flutter_inappbrowser_request_headers[header] = value;
setRequestHeader.call(this, header, value);
}; };
function handleEvent(e) { function handleEvent(e) {
var self = this; var self = this;
...@@ -439,7 +440,11 @@ let interceptAjaxRequestsJS = """ ...@@ -439,7 +440,11 @@ let interceptAjaxRequestsJS = """
}; };
for (var header in result.headers) { for (var header in result.headers) {
var value = result.headers[header]; var value = result.headers[header];
self.setRequestHeader(header, value); self._flutter_inappbrowser_request_headers[header] = value;
};
for (var header in self._flutter_inappbrowser_request_headers) {
var value = self._flutter_inappbrowser_request_headers[header];
setRequestHeader.call(self, header, value);
}; };
if ((self._flutter_inappbrowser_method != result.method && result.method != null) || (self._flutter_inappbrowser_url != result.url && result.url != null)) { if ((self._flutter_inappbrowser_method != result.method && result.method != null) || (self._flutter_inappbrowser_url != result.url && result.url != null)) {
self.abort(); self.abort();
...@@ -1342,6 +1347,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -1342,6 +1347,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
currentURL = url currentURL = url
InAppWebView.credentialsProposed = [] InAppWebView.credentialsProposed = []
evaluateJavaScript(platformReadyJS, completionHandler: nil)
onLoadStop(url: (currentURL?.absoluteString)!) onLoadStop(url: (currentURL?.absoluteString)!)
if IABController != nil { if IABController != nil {
......
...@@ -53,6 +53,11 @@ class ContentBlockerTriggerResourceType { ...@@ -53,6 +53,11 @@ class ContentBlockerTriggerResourceType {
static const SVG_DOCUMENT = const ContentBlockerTriggerResourceType._internal('svg-document'); static const SVG_DOCUMENT = const ContentBlockerTriggerResourceType._internal('svg-document');
///Any untyped load ///Any untyped load
static const RAW = const ContentBlockerTriggerResourceType._internal('raw'); static const RAW = const ContentBlockerTriggerResourceType._internal('raw');
bool operator ==(value) => value == _value;
@override
int get hashCode => _value.hashCode;
} }
///ContentBlockerTriggerLoadType class represents the possible load type for a [ContentBlockerTrigger]. ///ContentBlockerTriggerLoadType class represents the possible load type for a [ContentBlockerTrigger].
...@@ -68,6 +73,11 @@ class ContentBlockerTriggerLoadType { ...@@ -68,6 +73,11 @@ class ContentBlockerTriggerLoadType {
static const FIRST_PARTY = const ContentBlockerTriggerLoadType._internal('first-party'); static const FIRST_PARTY = const ContentBlockerTriggerLoadType._internal('first-party');
///THIRD_PARTY is triggered if the resource is not from the same domain as the main page resource. ///THIRD_PARTY is triggered if the resource is not from the same domain as the main page resource.
static const THIRD_PARTY = const ContentBlockerTriggerLoadType._internal('third-party'); static const THIRD_PARTY = const ContentBlockerTriggerLoadType._internal('third-party');
bool operator ==(value) => value == _value;
@override
int get hashCode => _value.hashCode;
} }
///Trigger of the content blocker. The trigger tells to the WebView when to perform the corresponding action. ///Trigger of the content blocker. The trigger tells to the WebView when to perform the corresponding action.
...@@ -187,6 +197,11 @@ class ContentBlockerActionType { ...@@ -187,6 +197,11 @@ class ContentBlockerActionType {
static const CSS_DISPLAY_NONE = const ContentBlockerActionType._internal('css-display-none'); static const CSS_DISPLAY_NONE = const ContentBlockerActionType._internal('css-display-none');
///Changes a URL from http to https. URLs with a specified (nondefault) port and links using other protocols are unaffected. ///Changes a URL from http to https. URLs with a specified (nondefault) port and links using other protocols are unaffected.
static const MAKE_HTTPS = const ContentBlockerActionType._internal('make-https'); static const MAKE_HTTPS = const ContentBlockerActionType._internal('make-https');
bool operator ==(value) => value == _value;
@override
int get hashCode => _value.hashCode;
} }
///Action associated to the trigger. The action tells to the WebView what to do when the trigger is matched. ///Action associated to the trigger. The action tells to the WebView what to do when the trigger is matched.
......
...@@ -97,7 +97,7 @@ class InAppBrowser { ...@@ -97,7 +97,7 @@ class InAppBrowser {
/// uses-material-design: true /// uses-material-design: true
/// ///
/// assets: /// assets:
/// - assets/t-rex.html /// - assets/index.html
/// - assets/css/ /// - assets/css/
/// - assets/images/ /// - assets/images/
/// ///
...@@ -106,7 +106,7 @@ class InAppBrowser { ...@@ -106,7 +106,7 @@ class InAppBrowser {
///Example of a `main.dart` file: ///Example of a `main.dart` file:
///```dart ///```dart
///... ///...
///inAppBrowser.openFile("assets/t-rex.html"); ///inAppBrowser.openFile("assets/index.html");
///... ///...
///``` ///```
/// ///
......
...@@ -153,6 +153,10 @@ class InAppWebView extends StatefulWidget { ...@@ -153,6 +153,10 @@ class InAppWebView extends StatefulWidget {
///[ajaxRequest] represents the `XMLHttpRequest`. ///[ajaxRequest] represents the `XMLHttpRequest`.
/// ///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptAjaxRequest] option to `true`. ///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptAjaxRequest] option to `true`.
///Also, unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that
///can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code
///used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS but just after some milliseconds (< ~100ms).
///Inside the `window.addEventListener("flutterInAppBrowserPlatformReady")` event, the fetch requests will be intercept for sure.
final Future<AjaxRequest> Function(InAppWebViewController controller, AjaxRequest ajaxRequest) shouldInterceptAjaxRequest; final Future<AjaxRequest> Function(InAppWebViewController controller, AjaxRequest ajaxRequest) shouldInterceptAjaxRequest;
///Event fired whenever the `readyState` attribute of an `XMLHttpRequest` changes. ///Event fired whenever the `readyState` attribute of an `XMLHttpRequest` changes.
...@@ -161,6 +165,10 @@ class InAppWebView extends StatefulWidget { ...@@ -161,6 +165,10 @@ class InAppWebView extends StatefulWidget {
///[ajaxRequest] represents the [XMLHttpRequest]. ///[ajaxRequest] represents the [XMLHttpRequest].
/// ///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptAjaxRequest] option to `true`. ///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptAjaxRequest] option to `true`.
///Also, unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that
///can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code
///used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS but just after some milliseconds (< ~100ms).
///Inside the `window.addEventListener("flutterInAppBrowserPlatformReady")` event, the fetch requests will be intercept for sure.
final Future<AjaxRequestAction> Function(InAppWebViewController controller, AjaxRequest ajaxRequest) onAjaxReadyStateChange; final Future<AjaxRequestAction> Function(InAppWebViewController controller, AjaxRequest ajaxRequest) onAjaxReadyStateChange;
///Event fired as an `XMLHttpRequest` progress. ///Event fired as an `XMLHttpRequest` progress.
...@@ -169,6 +177,10 @@ class InAppWebView extends StatefulWidget { ...@@ -169,6 +177,10 @@ class InAppWebView extends StatefulWidget {
///[ajaxRequest] represents the [XMLHttpRequest]. ///[ajaxRequest] represents the [XMLHttpRequest].
/// ///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptAjaxRequest] option to `true`. ///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptAjaxRequest] option to `true`.
///Also, unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that
///can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code
///used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS but just after some milliseconds (< ~100ms).
///Inside the `window.addEventListener("flutterInAppBrowserPlatformReady")` event, the fetch requests will be intercept for sure.
final Future<AjaxRequestAction> Function(InAppWebViewController controller, AjaxRequest ajaxRequest) onAjaxProgress; final Future<AjaxRequestAction> Function(InAppWebViewController controller, AjaxRequest ajaxRequest) onAjaxProgress;
///Event fired when an request is sent to a server through [Fetch API](https://developer.mozilla.org/it/docs/Web/API/Fetch_API). ///Event fired when an request is sent to a server through [Fetch API](https://developer.mozilla.org/it/docs/Web/API/Fetch_API).
...@@ -177,6 +189,10 @@ class InAppWebView extends StatefulWidget { ...@@ -177,6 +189,10 @@ class InAppWebView extends StatefulWidget {
///[fetchRequest] represents a resource request. ///[fetchRequest] represents a resource request.
/// ///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptFetchRequest] option to `true`. ///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptFetchRequest] option to `true`.
///Also, unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that
///can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code
///used to intercept fetch requests is loaded as soon as possible so it won't be instantaneous as iOS but just after some milliseconds (< ~100ms).
///Inside the `window.addEventListener("flutterInAppBrowserPlatformReady")` event, the fetch requests will be intercept for sure.
final Future<FetchRequest> Function(InAppWebViewController controller, FetchRequest fetchRequest) shouldInterceptFetchRequest; final Future<FetchRequest> Function(InAppWebViewController controller, FetchRequest fetchRequest) shouldInterceptFetchRequest;
///Event fired when the navigation state of the [InAppWebView] changes throught the usage of ///Event fired when the navigation state of the [InAppWebView] changes throught the usage of
...@@ -922,7 +938,7 @@ class InAppWebViewController { ...@@ -922,7 +938,7 @@ class InAppWebViewController {
/// uses-material-design: true /// uses-material-design: true
/// ///
/// assets: /// assets:
/// - assets/t-rex.html /// - assets/index.html
/// - assets/css/ /// - assets/css/
/// - assets/images/ /// - assets/images/
/// ///
...@@ -931,7 +947,7 @@ class InAppWebViewController { ...@@ -931,7 +947,7 @@ class InAppWebViewController {
///Example of a `main.dart` file: ///Example of a `main.dart` file:
///```dart ///```dart
///... ///...
///inAppBrowser.loadFile("assets/t-rex.html"); ///inAppBrowser.loadFile("assets/index.html");
///... ///...
///``` ///```
Future<void> loadFile({@required String assetFilePath, Map<String, String> headers = const {}}) async { Future<void> loadFile({@required String assetFilePath, Map<String, String> headers = const {}}) async {
...@@ -1111,6 +1127,14 @@ class InAppWebViewController { ...@@ -1111,6 +1127,14 @@ class InAppWebViewController {
///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.
/// ///
///In order to call `window.flutter_inappbrowser.callHandler(handlerName <String>, ...args)` properly, you need to wait and listen the JavaScript event `flutterInAppBrowserPlatformReady`.
///This event will be dispatch as soon as the platform (Android or iOS) is ready to handle the `callHandler` method.
///```javascript
/// window.addEventListener("flutterInAppBrowserPlatformReady", function(event) {
/// console.log("ready");
/// });
///```
///
///`window.flutter_inappbrowser.callHandler` returns a JavaScript [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) ///`window.flutter_inappbrowser.callHandler` returns a JavaScript [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
///that can be used to get the json result returned by [JavaScriptHandlerCallback]. ///that can be used to get the json result returned by [JavaScriptHandlerCallback].
///In this case, simply return data that you want to send and it will be automatically json encoded using [jsonEncode] from the `dart:convert` library. ///In this case, simply return data that you want to send and it will be automatically json encoded using [jsonEncode] from the `dart:convert` library.
...@@ -1118,6 +1142,7 @@ class InAppWebViewController { ...@@ -1118,6 +1142,7 @@ class InAppWebViewController {
///So, on the JavaScript side, to get data coming from the Dart side, you will use: ///So, on the JavaScript side, to get data coming from the Dart side, you will use:
///```html ///```html
///<script> ///<script>
/// window.addEventListener("flutterInAppBrowserPlatformReady", function(event) {
/// window.flutter_inappbrowser.callHandler('handlerFoo').then(function(result) { /// window.flutter_inappbrowser.callHandler('handlerFoo').then(function(result) {
/// console.log(result, typeof result); /// console.log(result, typeof result);
/// console.log(JSON.stringify(result)); /// console.log(JSON.stringify(result));
...@@ -1127,8 +1152,19 @@ class InAppWebViewController { ...@@ -1127,8 +1152,19 @@ class InAppWebViewController {
/// console.log(result, typeof result); /// console.log(result, typeof result);
/// console.log(JSON.stringify(result)); /// console.log(JSON.stringify(result));
/// }); /// });
/// });
///</script> ///</script>
///``` ///```
///
///Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
///```dart
/// // Inject JavaScript that will receive data back from Flutter
/// inAppWebViewController.evaluateJavascript(source: """
/// window.flutter_inappbrowser.callHandler('test', 'Text from Javascript').then(function(result) {
/// console.log(result);
/// });
/// """);
///```
void addJavaScriptHandler({@required String handlerName, @required JavaScriptHandlerCallback callback}) { void addJavaScriptHandler({@required String handlerName, @required JavaScriptHandlerCallback callback}) {
assert(!javaScriptHandlerForbiddenNames.contains(handlerName)); assert(!javaScriptHandlerForbiddenNames.contains(handlerName));
this.javaScriptHandlersMap[handlerName] = (callback); this.javaScriptHandlersMap[handlerName] = (callback);
......
This diff is collapsed.
...@@ -113,6 +113,7 @@ app.get("/", (req, res) => { ...@@ -113,6 +113,7 @@ app.get("/", (req, res) => {
app.post("/test-post", (req, res) => { app.post("/test-post", (req, res) => {
console.log(JSON.stringify(req.headers)) console.log(JSON.stringify(req.headers))
console.log(JSON.stringify(req.body))
res.send(` res.send(`
<html> <html>
<head> <head>
...@@ -127,10 +128,12 @@ app.post("/test-post", (req, res) => { ...@@ -127,10 +128,12 @@ app.post("/test-post", (req, res) => {
app.post("/test-ajax-post", (req, res) => { app.post("/test-ajax-post", (req, res) => {
console.log(JSON.stringify(req.headers)) console.log(JSON.stringify(req.headers))
console.log(JSON.stringify(req.body))
res.set("Content-Type", "application/json") res.set("Content-Type", "application/json")
res.send(JSON.stringify({ res.send(JSON.stringify({
"name": req.body.name, "firstname": req.body.firstname,
"key2": "value2" "lastname": req.body.lastname,
"fullname": req.body.firstname + " " + req.body.lastname,
})) }))
res.end() res.end()
}) })
......
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