Game client
Game client
Show the game in your web site and in your iOS and Android apps. Listen for what happens in it.
Web The same game link works in every app. Only the way messages pass differs. Every message is a JSON text, for example {"type":"player.exit"}. None carries money, a player id or a balance.
Your web site Game → page Page → game
Game inside your page : an iframewindow.parent.postMessage(text, page address) iframe.contentWindow.postMessage(text, "https://play.nartifacts.com")
Full page : the browser tabNone. Exit opens exitUrl. None
Web · iframe Example Game → page: window.parent.postMessage(text, page address)
Page → game: iframe.contentWindow.postMessage(text, "https://play.nartifacts.com" )
{"type" :"player.exit" }
In an iframe, the game takes messages only from the environment’s page addresses, and only from its parent window (event.source).
Your page takes messages only from https://play.nartifacts.com, and only from its own game iframe (event.source is that iframe’s contentWindow).
Neither side ever sends to "*".
Both sides check that the message is the expected JSON shape, and ignore anything else.
iOS
Part How
Shows the game in WKWebView
Game → your app A message handler named nartifacts, added with WKUserContentController.add(_:name:)
Your app → game callAsyncJavaScript or evaluateJavaScript running nartifactsGame.receive(text)
To catch the exit by exitUrl, use decidePolicyFor.
If the web view’s process is killed (webViewWebContentProcessDidTerminate), do not reload the old link. Start a new session and open the new link.
Android
Part How
Shows the game in WebView
Game → your app WebViewCompat.addWebMessageListener named nartifacts, allowed only for https://play.nartifacts.com. The game calls nartifacts.postMessage(text).
Your app → game evaluateJavascript running nartifactsGame.receive(text)
First check WebViewFeature.isFeatureSupported(WEB_MESSAGE_LISTENER). If it is not supported: no client messages, and exit opens exitUrl, as in a full page.
Do not use addJavascriptInterface. Any frame in the page can call it, and your app can’t tell who called.
To catch the exit by exitUrl, use shouldOverrideUrlLoading.
If the web view’s process is gone (onRenderProcessGone), remove the old WebView and make a new one. Start a new session and open the new link.
Unity
Part How
Shows the game in Unity has no web view of its own. Application.OpenURL opens the browser.
Game → your app None. Exit opens exitUrl, the app’s own link back.
Your app → game None
React Native
Part How
Shows the game in react-native-webview
Game → your app onMessage. The game calls window.ReactNativeWebView.postMessage(text).
Your app → game injectJavaScript running nartifactsGame.receive(text)
To catch the exit by exitUrl, use onShouldStartLoadWithRequest.
Flutter
Part How
Shows the game in webview_flutter
Game → your app addJavaScriptChannel named nartifacts. The game calls nartifacts.postMessage(text).
Your app → game runJavaScript running nartifactsGame.receive(text)
To catch the exit by exitUrl, use onNavigationRequest.
Events These are the client messages between the game and your app.
Direction Message What it means
Game → appgame.loaded The game is on screen: either ready to play, or showing its own error with a retry button. Show your own loading screen until then.
Game → appgame.failed The game can’t be played. reason says why (below).
Game → appbalance.changed The balance changed. Fetch it again, and show the new one in your header.
Game → appplayer.exit The player pressed exit. Close the game. We already closed the session as exit.
App → gamebalance.refresh The player added money while the game stayed open. The game asks for the new balance.
game.failed reasons
reason Meaning What to do
link_usedThe link was already opened. Start a new session.
link_expiredThe link was opened after 2 minutes. Start a new session.
session_closedThe session was closed on purpose (logout, self-exclusion). Go back to the lobby. Do not start again by itself.
What your app must do
Case What your app does
player.exit Close the game. The session is already closed.
Neither game.loaded nor game.failed comes within 15 seconds Show your own error with “Try again”. “Try again” starts a new session.
The player leaves the game another way (back button, a lobby tab)Close the game. Your server calls session.close. Otherwise the session stays active until it closes as idle after 30 minutes.
The web view’s process is killed Do not reload the old link. Your server starts a new session, and the app opens the new link. An open Mines round moves to the new session.
game.failed with link_used or link_expiredYour server starts a new session, and the app opens the new link.
game.failed with session_closedGo back to the lobby.
The app goes to the background during a round Nothing. A spin ends on our server. A Mines round stays open and waits for the player.
The game finds the channel by itself. Your app does nothing extra to tell it which one. One way in for every native app: nartifactsGame.receive(text).