Reputation: 3219
I am building an app with web programming languages and want to start the camera when the user clicks on an HTML button. Since I want my camera view to be a custom one, I need to design it with Swift. So when the user clicks on this HTML button, I want to "catch" this click in Swift so I can start my native camera view.
I know it can be done with the WKWebview, but I don't really know how to do that.
For example, my Javascript (jQuery) code could look like that :
// User clicks to start the native camera with Swift
$(".camera_button").click(function() {
// Function to call the camera view from JS to Swift
});
Can you help me to do that?
Thanks.
Upvotes: 29
Views: 36890
Reputation: 51
First, set the html string:
var playerURL = """"
https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/\(trackId)%3Fsecret_token%3D\(secretToken)&auto_play=false&hide_related=true&show_comments=false&show_user=false&show_reposts=false&show_teaser=false&visual=false
"""
Second, create your WKWebView
and config it
private var webView: WKWebView?
override func awakeFromNib() {
super.awakeFromNib()
...(1)...
self.webView?.navigationDelegate = self
self.webView?.isUserInteractionEnabled = true
self.webView?.scrollView.isScrollEnabled = false
self.webView?.allowsLinkPreview = false
self.webView?.contentMode = .scaleAspectFit
self.webView?.loadHTMLString(self.playerUrl, baseURL: nil)
DispatchQueue.main.async {
self.webView = WKWebView(frame: self.viewSoundclound.bounds, configuration: config)
guard let webView = self.webView else { return }
self.viewSoundclound.addSubview(webView)
}
}
Third, set the configuration of your JavasScript
script that you are gonna add to your WKWebView
override func awakeFromNib() {
super.awakeFromNib()
let config = WKWebViewConfiguration()
let script = WKUserScript(source: self.eventListenerScript, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
config.userContentController.addUserScript(script)
config.userContentController.add(self, name: "soundCloundEvents")
...(2)...
}
After, create your script. IMPORTANT: the name in 'messageHandler.(name).postMessage' must be equals to name in this line:
'config.userContentController.add(self, name: "soundCloundEvents")'
private var eventListenerScript = """
var iframe = document.querySelector('iframe');
widget = SC.Widget(iframe);
widget.bind(SC.Widget.Events.PLAY, function() {
window.webkit.messageHandlers.soundCloundEvents.postMessage('PLAY');
});
widget.bind(SC.Widget.Events.FINISH, function() {
window.webkit.messageHandlers.soundCloundEvents.postMessage('FINISH');
});
"""
Finally, extends Controller or Cell (this case) to listen script
extension PodcastsListTableViewCell: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print(message)
}
}
Upvotes: 0
Reputation: 3219
Based on the answer from @Alex Pelletier, which really helped me, here is the solution the my question.
In my "loadView()" function, here is what I have :
let contentController = WKUserContentController();
contentController.addScriptMessageHandler(
self,
name: "callbackHandler"
)
let config = WKWebViewConfiguration()
config.userContentController = contentController
webView = WKWebView(frame: CGRectZero, configuration: config)
webView.navigationDelegate = self
view = webView
My function to handle the Javascript event which is sent to Swift :
func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage)
{
if(message.name == "callbackHandler") {
print("Launch my Native Camera")
}
}
... And finally, my Javascript (jQuery) code when a click happens on my camera button (in HTML) :
$(document).ready(function() {
function callNativeApp () {
try {
webkit.messageHandlers.callbackHandler.postMessage("camera");
} catch(err) {
console.log('The native context does not exist yet');
}
}
$(".menu-camera-icon").click(function() {
callNativeApp();
});
});
I hope it will help someone else :-) !
Upvotes: 42
Reputation: 5123
First lets create a js file. In the js, when an element has been you clicked you can send a message back like so:
varmessageToPost = {'ButtonId':'clickMeButton'};
window.webkit.messageHandlers.buttonClicked.postMessage(messageToPost);
After you have created the js file and the wkwebview you need to inject the script:
// Setup WKUserContentController instance for injecting user script
var userController:WKUserContentController= WKUserContentController()
// Get script that's to be injected into the document
let js:String= GetScriptFromResources()
// Specify when and where and what user script needs to be injected into the web document
var userScript:WKUserScript = WKUserScript(source: js,
injectionTime: WKUserScriptInjectionTime.AtDocumentEnd
forMainFrameOnly: false)
// Add the user script to the WKUserContentController instance
userController.addUserScript(userScript)
// Configure the WKWebViewConfiguration instance with the WKUserContentController
webCfg.userContentController= userController;
//set the message handler
userController.addScriptMessageHandler(self, name: "buttonClicked")
Finally you have to add listener function:
func userContentController(userContentController: WKUserContentController,
didReceiveScriptMessage message: WKScriptMessage) {
if let messageBody:NSDictionary= message.body as? NSDictionary{
// Do stuff with messageBody
}
}
Upvotes: 15