Riddle on iOS and macOS
You can use Riddle in your iOS / macOS app. We have tested with SwiftUI, iOS 16.4, macOS 13.3, and Xcode 13.0, but it should also work with older versions and UIKit.
There are two ways to use Riddle in your app:
- Riddle Showcase in a WebView in your app
- Your own website in a WebView in your app
Riddle Showcase in a WebView in your app
In this example, the Riddle Showcase URL will open in a WebView in your app.
What you need for this:
- A WebView in your appdA WebView in your app
- The Riddle Showcase URL: https://www.riddle.com/embed/a/ + your Riddle ID
The Riddle Showcase URL
The Riddle Showcase URL is made up of two parts:
- https://www.riddle.com/embed/a/
- Your Riddle ID
To find your Riddle ID:
- In your Riddle, go to PUBLISH.
- Click on Embed / Showcase.
- Click on GET THE CODE.
In this code you will find the Riddle Showcase URL. - Copy the Riddle Showcase URL.
- Enter the Riddle Showcase URL in this line:
let url = URL(string: "https://www.riddle.com/embed/a/RIDDLEID")!
Riddle in your own web page in a WebView in your app
In this example, your own web page is opened in a WebView in your app. You can then embed Riddle in this webpage.
What you need for this:
- A WebView in your app
- Your own website with embedded Riddle
- Your domain must be activated for Riddle
Your own website with embedded Riddle
You can embed Riddle in your own website. It is important that you use the normal embed code.
Your domain must be activated for Riddle
For Riddle to work on your domain, it must be activated on Riddle. You can find out how this works here.
Enter your own URL in this line:
let url = URL(string: "https://www.example.com")!
JavaScript to communicate with your app
In order for your app to communicate with Riddle, you need to run JavaScript in your WebView. This JavaScript then sends data to your app.
Riddle sends JavaScript postMessages when the status of the Riddle changes. You can receive these postMessages in your app and then respond accordingly.
Running JavaScript in your WebView
In order to run JavaScript in your WebView, you need to add a WKUserScript in your WebView. This WKUserScript is then executed when the WebView is loaded.
let userScript = WKUserScript(source: javascript,
injectionTime: .atDocumentEnd,
forMainFrameOnly: false)
let webView = WKWebView()
webView.navigationDelegate = context.coordinator
webView.configuration.userContentController.add(context.coordinator, name: "postMessageHandler")
webView.configuration.userContentController.addUserScript(userScript)
webView.load(request)
The JavsScript is passed as a string. This string can be in your app or you can load it from a file. In this example, an event handler is added that responds to postMessages and sends them to your app as a JSON string. In addition, a postMessage is sent to Riddle so that a variable is stored in the Riddle data layer.
let javascript = """
// Hier dein JavaScript-Code
window.postMessage({
dataLayer: [{ key: 'username', value: 'Tom Riddle' }],
}, "*");
window.addEventListener("message", (event) => {
window.webkit.messageHandlers.postMessageHandler.postMessage(JSON.stringify(event.data));
});
"""
Alternatively, you can insert the JavaScript into your own web page. Then you don't have to include it in your app.
The handleEvent function is called when a postMessage is received. In this function you can react accordingly. For example, you can store whether the user has completed the Riddle or not and give a reward accordingly.
func handleEvent(jsonMsg: String) {
print("Received Post-Message: \(jsonMsg)")
}
Example Code in SwiftUI
import SwiftUI
import WebKit
func handleEvent(jsonMsg: String) {
print("Received Post-Message: \(jsonMsg)")
}
#if os(macOS)
struct WebView: NSViewRepresentable {
let request: URLRequest
let javascript: String
func makeNSView(context: Context) -> WKWebView {
let userScript = WKUserScript(source: javascript,
injectionTime: .atDocumentEnd,
forMainFrameOnly: false)
let webView = WKWebView()
webView.navigationDelegate = context.coordinator
webView.configuration.userContentController.add(context.coordinator, name: "postMessageHandler")
webView.configuration.userContentController.addUserScript(userScript)
webView.load(request)
return webView
}
func updateNSView(_ nsView: WKWebView, context: Context) {
nsView.evaluateJavaScript(javascript, completionHandler: nil)
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if let body = message.body as? String {
handleEvent(jsonMsg: body)
}
}
}
}
#else
struct WebView: UIViewRepresentable {
let request: URLRequest
let javascript: String
func makeUIView(context: Context) -> WKWebView {
// Create user script that inject the JavaScript after the HTML finishes loading
let userScript = WKUserScript(source: javascript,
injectionTime: .atDocumentEnd,
forMainFrameOnly: false)
let webView = WKWebView()
webView.navigationDelegate = context.coordinator
webView.configuration.userContentController.add(context.coordinator, name: "postMessageHandler")
webView.configuration.userContentController.addUserScript(userScript)
webView.load(request)
return webView
}
func updateUIView(_ webView: WKWebView, context: Context) {
webView.evaluateJavaScript(javascript, completionHandler: nil)
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if let body = message.body as? String {
handleEvent(jsonMsg: body)
}
}
}
}
#endif
struct ContentView: View {
let url = URL(string: "https://www.riddle.com/embed/a/RIDDLEID")!
let javascript = """
// Hier dein JavaScript-Code
window.postMessage({
dataLayer: [{ key: 'username', value: 'Tom Riddle' }],
}, "*");
window.addEventListener("message", (event) => {
window.webkit.messageHandlers.postMessageHandler.postMessage(JSON.stringify(event.data));
});
"""
var body: some View {
Text("Example App")
WebView(request: URLRequest(url: url), javascript: javascript)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}