Calling native code from Javascript in iOS likes JavascriptInterface in Android.
- Xcode 11.4+
- Swift 5.2+
- iOS8+
(based on WKJavaScriptController 2.1.0+)
Add the following to your Package.swift
:
dependencies: [
// ...
.package(url: "https://github.com/ridi/WKJavaScriptController.git"),
]
import WKJavaScriptController
// Create protocol.
// '@objc' keyword is required. because method call is based on ObjC.
@objc protocol JavaScriptInterface {
func onSubmit(_ dictonary: [String: AnyObject])
func onSubmit(_ email: String, firstName: String, lastName: String, address1: String, address2: String, zipCode: JSInt, phoneNumber: String)
func onCancel()
var isSubmitted: JSBool { get }
@objc optional func getErrorMessages(codes: [JSInt]) -> [String]
}
// Implement protocol.
extension ViewController: JavaScriptInterface {
func onSubmit(_ dictonary: [String: AnyObject]) {
NSLog("onSubmit \(dictonary)")
}
func onSubmit(_ email: String, firstName: String, lastName: String, address1: String, address2: String, zipCode: JSInt, phoneNumber: String) {
NSLog("onSubmit \(email), \(firstName), \(lastName), \(address1), \(address2), \(zipCode.value), \(phoneNumber)")
}
func onCancel() {
NSLog("onCancel")
}
var isSubmitted: JSBool {
return JSBool(true)
}
func getErrorMessages(codes: [JSInt]) -> [String] {
return codes.map { "message\($0)" }
}
}
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Create javaScriptController.
let javaScriptController = WKJavaScriptController(name: "native", target: self, bridgeProtocol: JavaScriptInterface.self)
// [Optional] Add your javascript.
let configuration = WKWebViewConfiguration()
let jsCode = ...
let userScript = WKUserScript(source: jsCode, injectionTime: .AtDocumentEnd, forMainFrameOnly: true)
userContentController.addUserScript(userScript)
configuration.userContentController = userContentController
// Create WKWebView instance.
webView = WKWebView(frame: view.frame, configuration: configuration)
// Assign javaScriptController.
webView.javaScriptController = javaScriptController
// Call prepareForJavaScriptController before initializing WKWebView or loading page.
webView.prepareForJavaScriptController()
webView.loadRequest(...)
}
...
}
// In javascript.
native.onSubmit({
'first_name': 'Davin',
'last_name': 'Ahn',
'mail': '[email protected]',
});
Can receive native return in JavaScript as Promise:
// In javascript.
const isSubmitted = await native.isSubmitted;
// or native.isSubmitted.then(isSubmitted => ...);
const messages = await native.getErrorMessages([200, 400, 500]);
// or native.getErrorMessages([200, 400, 500]).then(messages => ...);
- Can not receive native return in JavaScript as sync. can only async return.
- Method argument length is up to 10.
- Allowed argument types are String, Date, Array, Dictionary, JSBool, JSInt, JSFloat, NSNumber and NSNull(when
undefined
ornull
passed from JavaScript). - If Swift value types(Bool, Int32, Int, Float, Double, ...) used in argument, it must be replaced with JSBool, JSInt or JSFloat. (Because Swift value type is replaced by NSNumber in ObjC.)
- Class methods in protocol are not supported.