diff --git a/.idea/markdown-navigator.xml b/.idea/markdown-navigator.xml
new file mode 100644
index 00000000..3e62462d
--- /dev/null
+++ b/.idea/markdown-navigator.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/markdown-navigator/profiles_settings.xml b/.idea/markdown-navigator/profiles_settings.xml
new file mode 100644
index 00000000..57927c5a
--- /dev/null
+++ b/.idea/markdown-navigator/profiles_settings.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index cc95c879..6e99f7c7 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -15,21 +15,19 @@
-
-
-
-
+
-
-
+
+
+
+
-
@@ -45,39 +43,65 @@
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
+
+
+
+
+
+
-
+
-
-
+
+
@@ -157,21 +181,21 @@
-
-
-
+
+
+
-
-
+
+
-
+
@@ -179,6 +203,8 @@
+
+
@@ -191,6 +217,11 @@
+
+
+
+
+
@@ -201,8 +232,6 @@
-
-
@@ -369,33 +398,33 @@
-
+
-
-
+
-
+
-
-
+
+
+
@@ -410,6 +439,7 @@
+
@@ -421,22 +451,21 @@
-
+
-
+
-
+
-
@@ -450,13 +479,6 @@
-
-
-
-
-
-
-
@@ -512,11 +534,6 @@
-
-
-
-
-
@@ -591,26 +608,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -634,18 +637,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
@@ -679,35 +670,91 @@
-
+
-
+
-
-
-
-
-
-
-
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
index fdf12b70..94b1e01b 100644
--- a/README.md
+++ b/README.md
@@ -187,7 +187,6 @@ Opens an `url` in a new `InAppBrowser` instance or the system browser.
- __presentationStyle__: Set the custom modal presentation style when presenting the WebView. The default value is `0 //fullscreen`. See [UIModalPresentationStyle](https://developer.apple.com/documentation/uikit/uimodalpresentationstyle) for all the available styles.
- __transitionStyle__: Set to the custom transition style when presenting the WebView. The default value is `0 //crossDissolve`. See [UIModalTransitionStyle](https://developer.apple.com/documentation/uikit/uimodaltransitionStyle) for all the available styles.
- __enableViewportScale__: Set to `true` to allow a viewport meta tag to either disable or restrict the range of user scaling. The default value is `false`.
- - __keyboardDisplayRequiresUserAction__: Set to `true` if you want the user must explicitly tap the elements in the WebView to display the keyboard (or other relevant input view) for that element. When set to `false`, a focus event on an element causes the input view to be displayed and associated with that element automatically. The default value is `true`.
- __suppressesIncrementalRendering__: Set to `true` if you want the WebView suppresses content rendering until it is fully loaded into memory.. The default value is `false`.
- __allowsAirPlayForMediaPlayback__: Set to `true` to allow AirPlay. The default value is `true`.
- __allowsBackForwardNavigationGestures__: Set to `true` to allow the horizontal swipe gestures trigger back-forward list navigations. The default value is `true`.
diff --git a/android/build.gradle b/android/build.gradle
index 28a1e933..29bac20f 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -38,4 +38,5 @@ android {
dependencies {
implementation 'com.android.support:customtabs:27.1.1'
implementation 'com.android.support:appcompat-v7:27.1.1'
+ implementation 'com.squareup.okhttp3:mockwebserver:3.11.0'
}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebViewClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebViewClient.java
index 68988eee..b09e5b91 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebViewClient.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebViewClient.java
@@ -1,29 +1,97 @@
package com.pichillilorenzo.flutter_inappbrowser;
+import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Build;
+import android.os.Handler;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
+import android.text.TextUtils;
import android.util.Log;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.HttpAuthHandler;
+import android.webkit.MimeTypeMap;
import android.webkit.SslErrorHandler;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
+import java.io.IOException;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
+
+import okhttp3.Headers;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
public class InAppBrowserWebViewClient extends WebViewClient {
protected static final String LOG_TAG = "IABWebViewClient";
private WebViewActivity activity;
+ Map statusCodeMapping = new HashMap();
public InAppBrowserWebViewClient(WebViewActivity activity) {
super();
this.activity = activity;
+ statusCodeMapping.put(100, "Continue");
+ statusCodeMapping.put(101, "Switching Protocols");
+ statusCodeMapping.put(200, "OK");
+ statusCodeMapping.put(201, "Created");
+ statusCodeMapping.put(202, "Accepted");
+ statusCodeMapping.put(203, "Non-Authoritative Information");
+ statusCodeMapping.put(204, "No Content");
+ statusCodeMapping.put(205, "Reset Content");
+ statusCodeMapping.put(206, "Partial Content");
+ statusCodeMapping.put(300, "Multiple Choices");
+ statusCodeMapping.put(301, "Moved Permanently");
+ statusCodeMapping.put(302, "Found");
+ statusCodeMapping.put(303, "See Other");
+ statusCodeMapping.put(304, "Not Modified");
+ statusCodeMapping.put(307, "Temporary Redirect");
+ statusCodeMapping.put(308, "Permanent Redirect");
+ statusCodeMapping.put(400, "Bad Request");
+ statusCodeMapping.put(401, "Unauthorized");
+ statusCodeMapping.put(403, "Forbidden");
+ statusCodeMapping.put(404, "Not Found");
+ statusCodeMapping.put(405, "Method Not Allowed");
+ statusCodeMapping.put(406, "Not Acceptable");
+ statusCodeMapping.put(407, "Proxy Authentication Required");
+ statusCodeMapping.put(408, "Request Timeout");
+ statusCodeMapping.put(409, "Conflict");
+ statusCodeMapping.put(410, "Gone");
+ statusCodeMapping.put(411, "Length Required");
+ statusCodeMapping.put(412, "Precondition Failed");
+ statusCodeMapping.put(413, "Payload Too Large");
+ statusCodeMapping.put(414, "URI Too Long");
+ statusCodeMapping.put(415, "Unsupported Media Type");
+ statusCodeMapping.put(416, "Range Not Satisfiable");
+ statusCodeMapping.put(417, "Expectation Failed");
+ statusCodeMapping.put(418, "I'm a teapot");
+ statusCodeMapping.put(422, "Unprocessable Entity");
+ statusCodeMapping.put(425, "Too Early");
+ statusCodeMapping.put(426, "Upgrade Required");
+ statusCodeMapping.put(428, "Precondition Required");
+ statusCodeMapping.put(429, "Too Many Requests");
+ statusCodeMapping.put(431, "Request Header Fields Too Large");
+ statusCodeMapping.put(451, "Unavailable For Legal Reasons");
+ statusCodeMapping.put(500, "Internal Server Error");
+ statusCodeMapping.put(501, "Not Implemented");
+ statusCodeMapping.put(502, "Bad Gateway");
+ statusCodeMapping.put(503, "Service Unavailable");
+ statusCodeMapping.put(504, "Gateway Timeout");
+ statusCodeMapping.put(505, "HTTP Version Not Supported");
+ statusCodeMapping.put(511, "Network Authentication Required");
}
@Override
@@ -202,4 +270,53 @@ public class InAppBrowserWebViewClient extends WebViewClient {
super.onReceivedHttpAuthRequest(view, handler, host, realm);
}
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ @Override
+ public WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request){
+ final String url = request.getUrl().toString();
+
+ Request mRequest = new Request.Builder().url(url).build();
+
+ try {
+ Response response = activity.httpClient.newCall(mRequest).execute();
+ String reasonPhrase = response.message();
+ if (reasonPhrase.equals("")) {
+ reasonPhrase = statusCodeMapping.get(response.code());
+ Log.d(LOG_TAG, reasonPhrase);
+ }
+ reasonPhrase = (reasonPhrase.equals("") || reasonPhrase == null) ? "OK" : reasonPhrase;
+
+ Map headers = new HashMap();
+ for (Map.Entry> entry : response.headers().toMultimap().entrySet()) {
+ String value = "";
+ for (String val: entry.getValue()) {
+ value += (value == "") ? val : "; " + val;
+ }
+ headers.put(entry.getKey().toLowerCase(), value);
+ }
+
+ Map obj = new HashMap<>();
+ obj.put("uuid", activity.uuid);
+ obj.put("url", url);
+ obj.put("statusCode", response.code());
+ obj.put("headers", headers);
+
+ InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadResource", obj);
+
+ return new WebResourceResponse(
+ response.header("content-type", "text/plain").split(";")[0].trim(),
+ response.header("content-encoding"),
+ response.code(),
+ reasonPhrase,
+ headers,
+ response.body().byteStream()
+ );
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.d(LOG_TAG, e.getMessage());
+ }
+ return null;
+ }
+
+
}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java
index 47fc9b66..cafbaabd 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java
@@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
+import okhttp3.OkHttpClient;
public class WebViewActivity extends AppCompatActivity {
@@ -37,6 +38,7 @@ public class WebViewActivity extends AppCompatActivity {
ProgressBar progressBar;
public boolean isLoading = false;
public boolean isHidden = false;
+ OkHttpClient httpClient;
static final String jsConsoleLogScript = "(function() {\n"+
" var oldLogs = {\n"+
@@ -87,6 +89,8 @@ public class WebViewActivity extends AppCompatActivity {
prepareWebView();
+ httpClient = new OkHttpClient();
+
webView.loadUrl(url, headers);
}
diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj
index 6da50500..517e7413 100644
--- a/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/example/ios/Runner.xcodeproj/project.pbxproj
@@ -16,7 +16,6 @@
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
- 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
@@ -176,7 +175,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0910;
+ LastUpgradeCheck = 1000;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
@@ -211,7 +210,6 @@
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
- 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
ED5EF13121506A3E0065FD45 /* WebView.storyboard in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
@@ -336,12 +334,14 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@@ -390,12 +390,14 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index f5a8db1a..ba1a9822 100644
--- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,6 +1,6 @@
-
+
-
-
-
-
+
+
@@ -15,6 +13,10 @@
+
+
+
+
@@ -22,14 +24,10 @@
-
-
-
-
-
-
-
-
+
+
+
+
@@ -43,7 +41,7 @@
-
+
@@ -68,29 +66,28 @@
-
+
-
-
-
+
+
+
-
-
+
+
-
@@ -102,7 +99,7 @@
-
+
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 7c1709e5..317f294f 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -71,6 +71,13 @@ class MyInAppBrowser extends InAppBrowser {
this.loadUrl(url);
}
+ @override
+ void onLoadResource(String url, int statusCode, Map headers) {
+ print("\n\n resource: $url\n\n");
+ print(statusCode);
+ print(headers);
+ }
+
@override
void onConsoleMessage(ConsoleMessage consoleMessage) {
print("""
diff --git a/ios/Classes/InAppBrowserOptions.swift b/ios/Classes/InAppBrowserOptions.swift
index b7f38b5b..252e7376 100644
--- a/ios/Classes/InAppBrowserOptions.swift
+++ b/ios/Classes/InAppBrowserOptions.swift
@@ -30,7 +30,7 @@ public class InAppBrowserOptions: Options {
var presentationStyle = 0 //fullscreen
var transitionStyle = 0 //crossDissolve
var enableViewportScale = false
- var keyboardDisplayRequiresUserAction = true
+ //var keyboardDisplayRequiresUserAction = true
var suppressesIncrementalRendering = false
var allowsAirPlayForMediaPlayback = true
var allowsBackForwardNavigationGestures = true
diff --git a/ios/Classes/InAppBrowserWebViewController.swift b/ios/Classes/InAppBrowserWebViewController.swift
index 80e0ded6..0463b4a3 100644
--- a/ios/Classes/InAppBrowserWebViewController.swift
+++ b/ios/Classes/InAppBrowserWebViewController.swift
@@ -92,8 +92,16 @@ extension WKWebView{
}
-class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigationDelegate, UITextFieldDelegate, WKScriptMessageHandler {
- @IBOutlet var webView: WKWebView!
+class WKWebView_IBWrapper: WKWebView {
+ required convenience init?(coder: NSCoder) {
+ let config = WKWebViewConfiguration()
+ self.init(frame: .zero, configuration: config)
+ self.translatesAutoresizingMaskIntoConstraints = false
+ }
+}
+
+class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigationDelegate, UITextFieldDelegate, WKScriptMessageHandler, MyURLProtocolDelegate {
+ @IBOutlet var webView: WKWebView_IBWrapper!
@IBOutlet var closeButton: UIButton!
@IBOutlet var reloadButton: UIBarButtonItem!
@IBOutlet var backButton: UIBarButtonItem!
@@ -122,6 +130,15 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
}
override func viewDidLoad() {
+ super.viewDidLoad()
+
+ URLProtocol.wk_registerScheme("http")
+ URLProtocol.wk_registerScheme("https")
+
+ MyURLProtocol.URLProtocolDelegate = self
+
+ URLProtocol.registerClass(MyURLProtocol.self)
+
webView.uiDelegate = self
webView.navigationDelegate = self
@@ -237,7 +254,7 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
let jscriptWebkitTouchCallout = WKUserScript(source: "document.body.style.webkitTouchCallout='none';", injectionTime: .atDocumentEnd, forMainFrameOnly: true)
self.webView.configuration.userContentController.addUserScript(jscriptWebkitTouchCallout)
- let jsConsoleLogScript = WKUserScript(source: jsConsoleLog, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
+ let jsConsoleLogScript = WKUserScript(source: jsConsoleLog, injectionTime: .atDocumentStart, forMainFrameOnly: false)
self.webView.configuration.userContentController.addUserScript(jsConsoleLogScript)
self.webView.configuration.userContentController.add(self, name: "consoleLog")
self.webView.configuration.userContentController.add(self, name: "consoleDebug")
@@ -259,7 +276,9 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
self.webView.configuration.allowsInlineMediaPlayback = (browserOptions?.allowsInlineMediaPlayback)!
- self.webView.keyboardDisplayRequiresUserAction = browserOptions?.keyboardDisplayRequiresUserAction
+
+ //self.webView.keyboardDisplayRequiresUserAction = browserOptions?.keyboardDisplayRequiresUserAction
+
self.webView.configuration.suppressesIncrementalRendering = (browserOptions?.suppressesIncrementalRendering)!
self.webView.allowsBackForwardNavigationGestures = (browserOptions?.allowsBackForwardNavigationGestures)!
if #available(iOS 9.0, *) {
@@ -469,6 +488,16 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
decisionHandler(.allow)
}
+ func webView(_ webView: WKWebView,
+ decidePolicyFor navigationResponse: WKNavigationResponse,
+ decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
+
+ //dump((navigationResponse.response as! HTTPURLResponse))
+ //print(navigationResponse.response.mimeType)
+ //print(navigationResponse.response.url)
+ decisionHandler(.allow)
+ }
+
// func webView(_ webView: WKWebView,
// decidePolicyFor navigationResponse: WKNavigationResponse,
// decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
@@ -518,9 +547,6 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
// update url, stop spinner, update back/forward
- // evaluate the console log script
- webView.evaluateJavaScript(jsConsoleLog)
-
currentURL = webView.url
updateUrlTextField(url: (currentURL?.absoluteString)!)
backButton.isEnabled = webView.canGoBack
@@ -529,15 +555,11 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
navigationDelegate?.onLoadStop(uuid: self.uuid, webView: webView)
}
-// func webView(_ webView: WKWebView,
-// didFailProvisionalNavigation navigation: WKNavigation!,
-// withError error: Error) {
-// print("webView:didFailProvisionalNavigationWithError - \(Int(error._code)): \(error.localizedDescription)")
-// backButton.isEnabled = webView.canGoBack
-// forwardButton.isEnabled = webView.canGoForward
-// spinner.stopAnimating()
-// navigationDelegate?.webView(uuid: self.uuid, webView: webView, didFailLoadWithError: error)
-// }
+ func webView(_ view: WKWebView,
+ didFailProvisionalNavigation navigation: WKNavigation!,
+ withError error: Error) {
+ webView(view, didFail: navigation, withError: error)
+ }
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print("webView:didFailNavigationWithError - \(Int(error._code)): \(error.localizedDescription)")
@@ -547,8 +569,11 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
navigationDelegate?.onLoadError(uuid: self.uuid, webView: webView, error: error)
}
+ func didReceiveResponse(_ response: URLResponse, from request: URLRequest?) {
+ navigationDelegate?.onLoadResource(uuid: self.uuid, webView: webView, response: response)
+ }
+
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
- print(message.name)
if message.name.starts(with: "console") {
var messageLevel = "LOG"
switch (message.name) {
diff --git a/ios/Classes/MyURLProtocol.swift b/ios/Classes/MyURLProtocol.swift
new file mode 100644
index 00000000..f38095c1
--- /dev/null
+++ b/ios/Classes/MyURLProtocol.swift
@@ -0,0 +1,102 @@
+//
+// MyURLProtocol.swift
+// Pods
+//
+// Created by Lorenzo on 12/10/18.
+//
+
+import Foundation
+
+class MyURLProtocol: URLProtocol {
+
+ struct Constants {
+ static let RequestHandledKey = "URLProtocolRequestHandled"
+ }
+
+ var session: URLSession?
+ var sessionTask: URLSessionDataTask?
+ static var URLProtocolDelegate: MyURLProtocolDelegate?
+
+ override init(request: URLRequest, cachedResponse: CachedURLResponse?, client: URLProtocolClient?) {
+ super.init(request: request, cachedResponse: cachedResponse, client: client)
+
+ if session == nil {
+ session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
+ }
+ }
+
+ override class func canInit(with request: URLRequest) -> Bool {
+ if MyURLProtocol.property(forKey: Constants.RequestHandledKey, in: request) != nil {
+ return false
+ }
+ return true
+ }
+
+ override class func canonicalRequest(for request: URLRequest) -> URLRequest {
+ return request
+ }
+
+ override func startLoading() {
+ let newRequest = ((request as NSURLRequest).mutableCopy() as? NSMutableURLRequest)!
+ MyURLProtocol.setProperty(true, forKey: Constants.RequestHandledKey, in: newRequest)
+ sessionTask = session?.dataTask(with: newRequest as URLRequest)
+ sessionTask?.resume()
+ }
+
+ override func stopLoading() {
+ sessionTask?.cancel()
+ }
+}
+
+extension MyURLProtocol: URLSessionDataDelegate {
+ func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
+ client?.urlProtocol(self, didLoad: data)
+ }
+
+ func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
+ let policy = URLCache.StoragePolicy(rawValue: request.cachePolicy.rawValue) ?? .notAllowed
+ client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: policy)
+ MyURLProtocol.URLProtocolDelegate?.didReceiveResponse(response, from: dataTask.currentRequest)
+ completionHandler(.allow)
+ }
+
+ func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
+ if let error = error {
+ client?.urlProtocol(self, didFailWithError: error)
+ } else {
+ client?.urlProtocolDidFinishLoading(self)
+ }
+ }
+
+ func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
+ client?.urlProtocol(self, wasRedirectedTo: request, redirectResponse: response)
+ completionHandler(request)
+ }
+
+ func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
+ guard let error = error else { return }
+ client?.urlProtocol(self, didFailWithError: error)
+ }
+
+ func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
+ let protectionSpace = challenge.protectionSpace
+ let sender = challenge.sender
+
+ if protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
+ if let serverTrust = protectionSpace.serverTrust {
+ let credential = URLCredential(trust: serverTrust)
+ sender?.use(credential, for: challenge)
+ completionHandler(.useCredential, credential)
+ return
+ }
+ }
+ }
+
+ func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
+ client?.urlProtocolDidFinishLoading(self)
+ }
+}
+
+protocol MyURLProtocolDelegate {
+ func didReceiveResponse(_ response: URLResponse, from request: URLRequest?)
+}
diff --git a/ios/Classes/NSURLProtocol+WKWebVIew.h b/ios/Classes/NSURLProtocol+WKWebVIew.h
new file mode 100644
index 00000000..d0dd71f3
--- /dev/null
+++ b/ios/Classes/NSURLProtocol+WKWebVIew.h
@@ -0,0 +1,23 @@
+//
+// NSURLProtocol+WKWebVIew.h
+// Pods
+//
+// Created by Lorenzo on 11/10/18.
+//
+
+#ifndef NSURLProtocol_WKWebVIew_h
+#define NSURLProtocol_WKWebVIew_h
+
+
+#endif /* NSURLProtocol_WKWebVIew_h */
+
+#import
+
+@interface NSURLProtocol (WKWebVIew)
+
++ (void)wk_registerScheme:(NSString*)scheme;
+
++ (void)wk_unregisterScheme:(NSString*)scheme;
+
+
+@end
diff --git a/ios/Classes/NSURLProtocol+WKWebVIew.m b/ios/Classes/NSURLProtocol+WKWebVIew.m
new file mode 100644
index 00000000..176ded26
--- /dev/null
+++ b/ios/Classes/NSURLProtocol+WKWebVIew.m
@@ -0,0 +1,54 @@
+//
+// NSURLProtocol+WKWebVIew.m
+// Pods
+//
+// Created by Lorenzo on 11/10/18.
+//
+
+#import
+#import "NSURLProtocol+WKWebVIew.h"
+#import
+//FOUNDATION_STATIC_INLINE 属于属于runtime范畴,你的.m文件需要频繁调用一个函数,可以用static inline来声明。从SDWebImage从get到的。
+FOUNDATION_STATIC_INLINE Class ContextControllerClass() {
+ static Class cls;
+ if (!cls) {
+ cls = [[[WKWebView new] valueForKey:@"browsingContextController"] class];
+ }
+ return cls;
+}
+
+FOUNDATION_STATIC_INLINE SEL RegisterSchemeSelector() {
+ return NSSelectorFromString(@"registerSchemeForCustomProtocol:");
+}
+
+FOUNDATION_STATIC_INLINE SEL UnregisterSchemeSelector() {
+ return NSSelectorFromString(@"unregisterSchemeForCustomProtocol:");
+}
+
+@implementation NSURLProtocol (WebKitSupport)
+
++ (void)wk_registerScheme:(NSString *)scheme {
+ Class cls = ContextControllerClass();
+ SEL sel = RegisterSchemeSelector();
+ if ([(id)cls respondsToSelector:sel]) {
+ // 放弃编辑器警告
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+ [(id)cls performSelector:sel withObject:scheme];
+#pragma clang diagnostic pop
+ }
+}
+
++ (void)wk_unregisterScheme:(NSString *)scheme {
+ Class cls = ContextControllerClass();
+ SEL sel = UnregisterSchemeSelector();
+ if ([(id)cls respondsToSelector:sel]) {
+ // 放弃编辑器警告
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+ [(id)cls performSelector:sel withObject:scheme];
+#pragma clang diagnostic pop
+ }
+}
+
+@end
diff --git a/ios/Classes/SwiftFlutterPlugin.swift b/ios/Classes/SwiftFlutterPlugin.swift
index 9f8e3fd4..5917082a 100644
--- a/ios/Classes/SwiftFlutterPlugin.swift
+++ b/ios/Classes/SwiftFlutterPlugin.swift
@@ -25,6 +25,14 @@ import SafariServices
let WEBVIEW_STORYBOARD = "WebView"
let WEBVIEW_STORYBOARD_CONTROLLER_ID = "viewController"
+extension Dictionary where Key: ExpressibleByStringLiteral {
+ public mutating func lowercaseKeys() {
+ for key in self.keys {
+ self[String(describing: key).lowercased() as! Key] = self.removeValue(forKey: key)
+ }
+ }
+}
+
public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
var webViewControllers: [String: InAppBrowserWebViewController?] = [:]
var safariViewControllers: [String: Any?] = [:]
@@ -481,6 +489,21 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
}
}
+ func onLoadResource(uuid: String, webView: WKWebView, response: URLResponse) {
+ if self.webViewControllers[uuid] != nil {
+ var headers = (response as! HTTPURLResponse).allHeaderFields as! [String: String]
+ headers.lowercaseKeys()
+
+ let arguments: [String : Any] = [
+ "uuid": uuid,
+ "url": response.url?.absoluteString ?? "",
+ "statusCode": (response as! HTTPURLResponse).statusCode,
+ "headers": headers
+ ]
+ channel.invokeMethod("onLoadResource", arguments: arguments)
+ }
+ }
+
func onExit(uuid: String) {
channel.invokeMethod("onExit", arguments: ["uuid": uuid])
}
diff --git a/lib/flutter_inappbrowser.dart b/lib/flutter_inappbrowser.dart
index 832dee6a..5348cffc 100644
--- a/lib/flutter_inappbrowser.dart
+++ b/lib/flutter_inappbrowser.dart
@@ -106,6 +106,12 @@ class InAppBrowser {
String url = call.arguments["url"];
shouldOverrideUrlLoading(url);
break;
+ case "onLoadResource":
+ String url = call.arguments["url"];
+ int statusCode = call.arguments["statusCode"];
+ Map headers = call.arguments["headers"];
+ onLoadResource(url, statusCode, headers.cast());
+ break;
case "onConsoleMessage":
String sourceURL = call.arguments["sourceURL"];
int lineNumber = call.arguments["lineNumber"];
@@ -173,7 +179,6 @@ class InAppBrowser {
/// - __presentationStyle__: Set the custom modal presentation style when presenting the WebView. The default value is `0 //fullscreen`. See [UIModalPresentationStyle](https://developer.apple.com/documentation/uikit/uimodalpresentationstyle) for all the available styles.
/// - __transitionStyle__: Set to the custom transition style when presenting the WebView. The default value is `0 //crossDissolve`. See [UIModalTransitionStyle](https://developer.apple.com/documentation/uikit/uimodaltransitionStyle) for all the available styles.
/// - __enableViewportScale__: Set to `true` to allow a viewport meta tag to either disable or restrict the range of user scaling. The default value is `false`.
- /// - __keyboardDisplayRequiresUserAction__: Set to `true` if you want the user must explicitly tap the elements in the WebView to display the keyboard (or other relevant input view) for that element. When set to `false`, a focus event on an element causes the input view to be displayed and associated with that element automatically. The default value is `true`.
/// - __suppressesIncrementalRendering__: Set to `true` if you want the WebView suppresses content rendering until it is fully loaded into memory.. The default value is `false`.
/// - __allowsAirPlayForMediaPlayback__: Set to `true` to allow AirPlay. The default value is `true`.
/// - __allowsBackForwardNavigationGestures__: Set to `true` to allow the horizontal swipe gestures trigger back-forward list navigations. The default value is `true`.
@@ -323,6 +328,11 @@ class InAppBrowser {
}
+ ///Event fires when the [InAppBrowser] webview will load the resource specified by the given [url].
+ void onLoadResource(String url, int statusCode, Map headers) {
+
+ }
+
///Event fires when the [InAppBrowser] webview receives a [ConsoleMessage].
void onConsoleMessage(ConsoleMessage consoleMessage) {
@@ -392,7 +402,6 @@ class ChromeSafariBrowser {
Future open(String url, {Map options = const {}, Map headersFallback = const {}, Map optionsFallback = const {}}) async {
Map args = {};
args.putIfAbsent('uuid', () => uuid);
- print(browserFallback.uuid);
args.putIfAbsent('uuidFallback', () => (browserFallback != null) ? browserFallback.uuid : '');
args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => headersFallback);