-
-
Save jkereako/d111ff6f4594873d409d3194371d6732 to your computer and use it in GitHub Desktop.
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1" /> | |
<script src="https://www.google.com/recaptcha/api.js?onload=onLoad&render=explicit&hl=en" async defer></script> | |
<title></title> | |
<script type="text/javascript"> | |
const post = function(value) { | |
window.webkit.messageHandlers.recaptcha.postMessage(value); | |
}; | |
console.log = function(message) { | |
post(message); | |
}; | |
var onLoad = function() { | |
grecaptcha.render( | |
"recaptcha", | |
{ | |
sitekey: "${siteKey}", | |
callback: function(token) { | |
post(token); | |
}, | |
size: "normal" | |
} | |
); | |
}; | |
</script> | |
</head> | |
<body> | |
<div id="recaptcha"></div> | |
</body> | |
</html> |
import UIKit | |
import WebKit | |
final class ReCAPTCHAViewController: UIViewController { | |
private var webView: WKWebView! | |
private let viewModel: ReCAPTCHAViewModel | |
init(viewModel: ReCAPTCHAViewModel) { | |
self.viewModel = viewModel | |
super.init(nibName: nil, bundle: nil) | |
} | |
required init?(coder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
override func loadView() { | |
let webConfiguration = WKWebViewConfiguration() | |
let contentController = WKUserContentController() | |
contentController.add(viewModel, name: "recaptcha") | |
webConfiguration.userContentController = contentController | |
webView = WKWebView(frame: .zero, configuration: webConfiguration) | |
view = webView | |
} | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
navigationItem.leftBarButtonItem = UIBarButtonItem( | |
barButtonSystemItem: .close, | |
target: self, | |
action: #selector(didSelectCloseButton) | |
) | |
webView.loadHTMLString(viewModel.html, baseURL: viewModel.url) | |
} | |
} | |
// MARK: - Target-Actions | |
private extension ReCAPTCHAViewController { | |
@IBAction func didSelectCloseButton() { | |
dismiss(animated: true) | |
} | |
} |
import WebKit | |
protocol ReCAPTCHAViewModelDelegate: class { | |
func didSolveCAPTCHA(token: String) | |
} | |
final class ReCAPTCHAViewModel: NSObject { | |
weak var delegate: ReCAPTCHAViewModelDelegate? | |
var html: String { | |
guard let filePath = Bundle.main.path( | |
forResource: "recaptcha", ofType: "html" | |
) else { | |
assertionFailure("Unable to find the file.") | |
return "" | |
} | |
let contents = try! String( | |
contentsOfFile: filePath, encoding: .utf8 | |
) | |
return parse(contents, with: ["siteKey": siteKey]) | |
} | |
let siteKey: String | |
let url: URL | |
/// Creates a ReCAPTCHAViewModel | |
/// - Parameters: | |
/// - siteKey: ReCAPTCHA's site key | |
/// - url: The URL for registered with Google | |
init(siteKey: String, url: URL) { | |
self.siteKey = siteKey | |
self.url = url | |
super.init() | |
} | |
} | |
// MARK: - WKScriptMessageHandler | |
extension ReCAPTCHAViewModel: WKScriptMessageHandler { | |
func userContentController(_ userContentController: WKUserContentController, | |
didReceive message: WKScriptMessage) { | |
guard let message = message.body as? String else { | |
assertionFailure("Expected a string") | |
return | |
} | |
delegate?.didSolveCAPTCHA(token: message) | |
} | |
} | |
private extension ReCAPTCHAViewModel { | |
func parse(_ string: String, with valueMap: [String: String]) -> String { | |
var parsedString = string | |
valueMap.forEach { key, value in | |
parsedString = parsedString.replacingOccurrences( | |
of: "${\(key)}", with: value | |
) | |
} | |
return parsedString | |
} | |
} |
@dittma75 did you finish it up?
Unfortunately, work has gotten really busy for me, and I haven't been able to get back to it. I'm not hopeful that I will get back to it any time soon, so please don't wait for it to happen. Sorry to disappoint 😞.
In the meantime, @jkereako's gist works pretty well, and the modified HTML that I posted above helps to make it work for invisible reCAPTCHAs.
Do you have code for Objective C???
Hi, @safranashereen. I threw a Swift Package together that's essentially @jkereako's gist with some very minor tweaks to make it visible to Objective-C. I wasn't able to test it to make sure that it fully works, but I can verify that I'm able to load the Swift Package into an Objective-C project, and I am able to call the code to initialize and present a ReCAPTCHAViewController.
This is the repository: https://github.com/dittma75/ReCAPTCHA_Package. Give it a try and let me know if it helps.
For clarity, this isn't the improved package I was working on months ago. That one isn't ready. This is just a straight copy of @jkereako's code wrapped up in a package so that Swift Package Manager can be used to install it, and it should work for Objective-C as well. Hopefully that's at least a bit helpful to the people in this thread (and future visitors to this gist).
Hola estoy desarrollando un app y necesito dibujar un recaptcha que se encuentra en un sitio web. me ayudan por favor? Algun consejo
is it possible to hide the white window with visible or invisible captcha ( so that the code works in the background. to use version 3) ?
Hello anyone,
can you tell me why i am getting "Error for site owner, invalid key type."
I have used above sample code and trying to integrate recaptcha v3, my code working fine in recaptcha v2.
i did not do anything code on my server side.
I am integrating it in ios, swift.
please help me, i am stuck on it.
@Hokila nice work!
Thanks
thanks it work fine in my case,but it show retapcha code everytime while access via web did not completely invisibe. any suggestion why?
What is the reason to not use reCAPTCHA Enterprise ? there is the same limit as I can see 1,000,000 views per month?
I think need iOS Target 14.x for reCAPTCHA Enterprise
How can I Observe Expired Sessions?
https://www.google.com/recaptcha/api/siteverify?secret=your_secret&response=response_token
Use this GET api for timeout status validation. Replace your_secret
& response_token
Is this possible to generate a delegate method like didSolveCAPTCHA?
If yes, then how can I achieve that?
No problem. I'll post here if and when I finish 😄.