Javascript call to Swift from UIWebView
You must a custom URL Scheme
such as myawesomeapp
and intercept requests to it using:
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool
Fire a call to native code using window.location=myawesomeapp://hello=world
, and get the query params you pass from request.URL.query
in the native code.
For more information, see my question about UIWebView
s here: JavaScript synchronous native communication to WKWebView
Call swift function with javascript using UIWebview
Implement listenInSwift
like this:
function listenInSwift() {
window.location = 'yoururlscheme://somehost?greeting=hello'
}
Then listen for this URL with this code in your UIWebViewDelegate
class:
func webView(_ webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType navigationType: UIWebViewNavigationType) -> Bool {
if request.URL.scheme == 'yoururlscheme' {
print('Hello JavaScript...')
}
}
Don't forget to register your URL Scheme (in this case 'yoururlscheme') in Xcode.
To load a local file in the web view, try this:
let baseURL = NSURL.fileURLWithPath(NSBundle.mainBundle().bundlePath);
let relativePath = "www/\(file)"
let fileURL = NSURL(string: relativePath, relativeToURL: baseURL);
let URLRequest = NSURLRequest(URL: fileURL!);
webView.loadRequest(URLRequest)
UIWebView and JavaScriptInterface in Swift
For WKWebView: source here
JavaScript
function callNativeApp () {
try {
webkit.messageHandlers.callbackHandler.postMessage("Hello from JavaScript");
} catch(err) {
console.log('The native context does not exist yet');
}
}
Swift
import WebKit
class ViewController: UIViewController, WKScriptMessageHandler {
@IBOutlet var containerView: UIView? = nil
var webView: WKWebView?
override func loadView() {
super.loadView()
let contentController = WKUserContentController()
contentController.addScriptMessageHandler(self, name: "callbackHandler")
let config = WKWebViewConfiguration()
config.userContentController = contentController
self.webView = WKWebView( frame: self.containerView!.bounds, configuration: config)
self.view = self.webView
}
override func viewDidLoad() {
super.viewDidLoad()
//I use the file html in local
let path = NSBundle.mainBundle().pathForResource("index", ofType: "html")
let url = NSURL(fileURLWithPath: path!)
let req = NSURLRequest(URL: url)
self.webView!.loadRequest(req)
}
func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {// edit: changed fun to func
if (message.name == "callbackHandler"){
print("\(message.body)")
}
}
}
For UIWebView: source here
JavaScript in HTML
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
(function(){
$(window).load(function(){
$('.clickMe').on('click', function(){
window.location = "foobar://fizz?Hello_from_javaScript";
});
});
})(jQuery);
</script>
Swift
import UIKit
class ViewController: UIViewController, UIWebViewDelegate {
@IBOutlet weak var Web: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
let path = NSBundle.mainBundle().pathForResource("index", ofType: "html")
let url = NSURL(fileURLWithPath: path!)
let req = NSURLRequest(URL: url)
Web.delegate = self
Web.loadRequest(req)
}
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
if request.URL?.query != nil {
print("\(request.URL!.query!)")
}
return true
}
}
Inject Javascript into Webview - Swift
Just do:
let js = "var myelement = document.getElementById(\"test\");myelement.innerHTML= \"New Text\";"
webView.evaluateJavaScript(js, completionHandler: nil)
If you are using UIWebView
instead of WKWebView
, do this:
let js = "var myelement = document.getElementById(\"test\");myelement.innerHTML= \"New Text\";"
_ = webView.stringByEvaluatingJavaScript(from: js)
Javascript console log in UIWebView in Swift
Here's a basic implementation for the UIWebView
:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Create the web view.
let webView = UIWebView()
webView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(webView)
webView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
webView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
webView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
webView.delegate = self
webView.loadRequest(URLRequest(url: URL(string: "https://www.google.com.py")!))
}
}
extension ViewController: UIWebViewDelegate {
func webViewDidFinishLoad(_ webView: UIWebView) {
let js = "console.log = function() {window.location = 'logger://webview?' + JSON.stringify(Array.prototype.slice.call(arguments))}"
webView.stringByEvaluatingJavaScript(from: js)
}
func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
if request.url?.scheme == "logger" {
guard let data = request.url?.query?.removingPercentEncoding?.data(using: .utf8) else { return true }
guard let obj = try? JSONSerialization.jsonObject(with: data, options: []) else { return true }
guard let jsonData = try? JSONSerialization.data(withJSONObject: obj, options: .prettyPrinted) else { return true }
guard let json = String(data: jsonData, encoding: .utf8) else { return true }
print(json)
}
return true
}
}
Example
console.log(4, 3.53, 'Hello', {d: {f: 4}}, function() {}, undefined, null, true)
Prints the following in Xcode log:
[
4,
3.5299999999999998,
"Hello",
{
"d" : {
"f" : 4
}
},
null,
null,
null,
true
]
Caveats
- This only prints logs executed after the page has loaded.
- Since we're using JSON.stringify, we can't print the following types:
function
,undefined
- Since we're using JSON.stringify,
true
andfalse
are
printed as1
and0
, respectively
Controlling website within Xcode/ Swift UIWebView
Check this question and responses:
Calling Javascript using UIWebView
- Create a js method to receive your barcode.
When the page is already loaded, you can call it by using stringByEvaluatingJavaScriptFromString.
let codebar = "34244342342424234"
webView.stringByEvaluatingJavaScriptFromString("methodName("\(codebar)");")
Update
I used this method some time ago: evaluateJavaScript in WKWebView, this example loads a jQuery and then change the background:
var navigator : WKWebView!
func runJS(js:String) {
navigator.evaluateJavaScript(js) {
res, error in
print(res ?? "no res", error ?? "no error")
}
}
@IBAction func changeBackground(_ sender: Any) {
navigator.evaluateJavaScript("jQuery('body').css('background', 'magenta!important')") {res, error in print(error ?? "no error buton 1")}
}
@IBAction func loadJQuery(_ sender: Any) {
//Load jQuery library using plain JavaScript
runJS(js: "(function(){ " +
"var newscript = document.createElement('script'); " +
"newscript.type = 'text/javascript'; " +
"newscript.async = true; " +
"newscript.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js'; " +
"(document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(newscript); " +
"})();")
}
Related Topics
Pdf.Js: Rendering a PDF File Using a Base64 File Source Instead of Url
Draggable Line Chart in R/Shiny
How to Prevent Closing Browser Window
The .Replace() Method Does Change the String in Place
Google Maps Places API V3 Autocomplete - Select First Option on Enter
Using Enter Key with Action Button in R Shiny
What's the Difference Between Returning Value or Promise.Resolve from Then()
How to Extract Text from a PDF in JavaScript
How to Remove a Character from a String Using JavaScript
Can Nokogiri Interpret JavaScript? - Web Scraping
Best Way to Display Flash Notices in Rails
Access Elements of Parent Window from Iframe
Differencebetween Regexp's Exec() Function and String's Match() Function