Skip to content

Commit

Permalink
Fix webview's resource loading detection
Browse files Browse the repository at this point in the history
fix #56
  • Loading branch information
fjcaetano committed Dec 6, 2018
1 parent dc4010c commit 050ce19
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 96 deletions.
2 changes: 1 addition & 1 deletion Example/ReCaptcha_Tests/RxSwift/ReCaptcha+Rx__Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class ReCaptcha_Rx__Tests: XCTestCase {
let exp = expectation(description: "stop loading")

// Stop
let recaptcha = ReCaptcha(manager: ReCaptchaWebViewManager(messageBody: "{action: \"showReCaptcha\"}"))
let recaptcha = ReCaptcha(manager: ReCaptchaWebViewManager(messageBody: "{log: \"foo\"}"))
recaptcha.configureWebView { _ in
XCTFail("should not ask to configure the webview")
}
Expand Down
4 changes: 0 additions & 4 deletions Example/ReCaptcha_Tests/mock.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@
}
};

window.onload = function() {
post({action: "didLoad"});
};

var reset = function() {
shouldFail = false;
post({action: "didLoad"});
Expand Down
109 changes: 18 additions & 91 deletions ReCaptcha/Classes/ReCaptchaWebViewManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,88 +13,6 @@ import WebKit
/** Handles comunications with the webview containing the ReCaptcha challenge.
*/
internal class ReCaptchaWebViewManager {
/** The `webView` delegate object that performs execution uppon script loading
*/
fileprivate class WebViewDelegate: NSObject, WKNavigationDelegate {
struct Constants {
/// The host that loaded requests should have
static let apiURLHost = "www.google.com"
}

/// The parent manager
private weak var manager: ReCaptchaWebViewManager?

/// The active requests' urls
private var activeRequests = Set<String>(minimumCapacity: 0)

/// - parameter manager: The parent manager
init(manager: ReCaptchaWebViewManager) {
self.manager = manager
}

/**
- parameters:
- webView: The web view invoking the delegate method.
- navigationAction: Descriptive information about the action triggering the navigation request.
- decisionHandler: The decision handler to call to allow or cancel the navigation. The argument is one of
the constants of the enumerated type WKNavigationActionPolicy.
Decides whether to allow or cancel a navigation.
*/
func webView(
_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy
) -> Void) {
defer { decisionHandler(.allow) }

if let url = navigationAction.request.url, url.host == Constants.apiURLHost {
activeRequests.insert(url.absoluteString)
}
}

/**
- parameters:
- webView: The web view invoking the delegate method.
- navigationResponse: Descriptive information about the navigation response.
- decisionHandler: A block to be called when your app has decided whether to allow or cancel the navigation
Decides whether to allow or cancel a navigation after its response is known.
*/
func webView(
_ webView: WKWebView,
decidePolicyFor navigationResponse: WKNavigationResponse,
decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void
) {
defer { decisionHandler(.allow) }
guard let url = navigationResponse.response.url?.absoluteString,
activeRequests.remove(url) != nil, activeRequests.isEmpty else {
return
}

execute()
}

/// Flag the requests as finished and call ReCaptcha execution if necessary
func execute() {
guard manager?.didFinishLoading != true else { return }

DispatchQueue.main.throttle(deadline: .now() + 1, context: self) { [weak self] in
// Did finish loading the ReCaptcha JS source
self?.manager?.didFinishLoading = true

if self?.manager?.completion != nil {
// User has requested for validation
self?.manager?.execute()
}
}
}

/// Flags all requests as finished
func reset() {
activeRequests.removeAll()
}
}

fileprivate struct Constants {
static let ExecuteJSCommand = "execute();"
Expand Down Expand Up @@ -135,29 +53,39 @@ internal class ReCaptchaWebViewManager {
fileprivate var decoder: ReCaptchaDecoder!

/// Indicates if the script has already been loaded by the `webView`
fileprivate var didFinishLoading = false // webView.isLoading does not work in this case
fileprivate var didFinishLoading = false { // webView.isLoading does not work for WKWebview.loadHTMLString
didSet {
if didFinishLoading && completion != nil {
// User has requested for validation
// A small delay is necessary to allow JS to wrap its operations and avoid errors.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) { [weak self] in
self?.execute()
}
}
}
}

/// The observer for `.UIWindowDidBecomeVisible`
fileprivate var observer: NSObjectProtocol?

/// The observer for `\WKWebView.estimatedProgress`
fileprivate var loadingObservation: NSKeyValueObservation?

/// The endpoint url being used
fileprivate var endpoint: String

/// The `webView` delegate implementation
fileprivate lazy var webviewDelegate: WebViewDelegate = {
WebViewDelegate(manager: self)
}()

/// The webview that executes JS code
lazy var webView: WKWebView = {
let webview = WKWebView(
frame: CGRect(x: 0, y: 0, width: 1, height: 1),
configuration: self.buildConfiguration()
)
webview.navigationDelegate = self.webviewDelegate
webview.accessibilityIdentifier = "webview"
webview.accessibilityTraits = UIAccessibilityTraits.link
webview.isHidden = true
self.loadingObservation = webview.observe(\.estimatedProgress, options: [.new]) { [weak self] _, change in
self?.didFinishLoading = change.newValue == 1
}

return webview
}()
Expand Down Expand Up @@ -224,7 +152,6 @@ internal class ReCaptchaWebViewManager {
func reset() {
didFinishLoading = false
configureWebViewDispatchToken = UUID()
webviewDelegate.reset()

webView.evaluateJavaScript(Constants.ResetCommand) { [weak self] _, error in
if let error = error {
Expand Down Expand Up @@ -297,7 +224,7 @@ fileprivate extension ReCaptchaWebViewManager {

case .didLoad:
// For testing purposes
webviewDelegate.execute()
didFinishLoading = true

case .log(let message):
#if DEBUG
Expand Down

0 comments on commit 050ce19

Please sign in to comment.