Browse Source

Example of how to communicate between the web view and the host game logic

Shaddock Heath 8 years ago
parent
commit
215420d0e1

+ 58 - 7
AtomicWebView/JavaScript/Resources/Components/WebView.js

@@ -8,12 +8,13 @@ var HEIGHT = Atomic.graphics.height - 100;
 var home = "http://www.atomicgameengine.com";
 
 var bookmarks = {
-    "Atomic" : "http://www.atomicgameengine.com",
-    "Google" : "http://www.google.com",
-    "YouTube" : "https://www.youtube.com",
-    "Steam" : "https://store.steampowered.com",
-    "Reddit" : "https://www.reddit.com/r/gamedev",
-    "Penny Arcade" : "https://www.penny-arcade.com/"
+  "Atomic": "http://www.atomicgameengine.com",
+  "Google": "http://www.google.com",
+  "YouTube": "https://www.youtube.com",
+  "Steam": "https://store.steampowered.com",
+  "Reddit": "https://www.reddit.com/r/gamedev",
+  "Penny Arcade": "https://www.penny-arcade.com/",
+  "Local Example": "atomic://Resources/WebClient/LocalPage.html"
 };
 
 // Create the UI view
@@ -235,8 +236,58 @@ function createBrowserTab(tabContainer, url) {
       if (!url.length)
         return;
 
-      webClient.loadURL(url);
+    webClient.loadURL(url);
 
   }));
 
+  /////////////////////////////////////////////////////
+  // HANDLE CUSTOM MESSAGES COMING IN FROM LOCAL PAGE  
+  var messageHandler = new WebView.WebMessageHandler();
+  webClient.addMessageHandler(messageHandler);
+
+  webView.subscribeToEvent(messageHandler, WebView.WebMessageEvent(function (webMessage) {
+    var messageType;
+    var messageObject;
+
+    try {
+      messageObject = JSON.parse(webMessage.request);
+      messageType = messageObject.message;
+    } catch (e) {
+      // not JSON, we are just getting a notification message of some sort
+      messageType = webMessage.request;
+    }
+
+
+    switch (messageType) {
+      // notification sent up from the web view client
+      case "CUSTOM_NOTIFICATION":
+        new Atomic.UIMessageWindow(view, "modal_error").show("Message from WebView", "Click Count: " + messageObject.clickCount, Atomic.UI_MESSAGEWINDOW_SETTINGS.UI_MESSAGEWINDOW_SETTINGS_OK, true, 480, 240);
+        webMessage.handler.success();
+        break;
+
+      // web view client is asking for something
+      case "GET_FROM_HOST":
+        // Got a prefix from the client, let's respond
+        webMessage.handler.success(JSON.stringify({
+          displayMessage: messageObject.prefix + "-ro-dah"
+        }));
+        break;
+
+      // web view client wants us to do some processing and call back to a specific function
+      case "CALLBACK_FUNCTION":
+        // mimic some kind of event loop and process on the next update event inside a closure
+        var msgloop = new Atomic.ScriptObject();
+
+        // cache the web client that called us since it will get GC'd
+        var webClient = webMessage.handler.webClient;
+        msgloop.subscribeToEvent(Atomic.UpdateEvent(function () {
+          msgloop.unsubscribeFromAllEvents();
+          webClient.executeJavaScript(messageObject.callbackFunction + "('Called from host');");
+        }));
+
+        webMessage.handler.success();
+        break;
+    }
+
+  }));
 }

+ 59 - 0
AtomicWebView/JavaScript/Resources/WebClient/LocalPage.html

@@ -0,0 +1,59 @@
+<!--
+    This is a custom local page hosted by the Atomic Game Engine.  Communication with the 
+    host can be done in 3 ways
+    - notify the host of an event via atomicHostEvent
+    - request data from the host (synchronously) via atomicHostRequest
+    - request the host to call back to a function whenever it is ready to (asynchronous)
+-->
+<html>
+
+<head>
+    Embedded Web Page in Atomic
+</head>
+<h1>
+    Embedded Web Page in Atomic.
+</h1>
+<p>
+    Click some links to demonstrate communication between the web view and the running game logic
+</p>
+
+<button onclick="sendToHost()">Send Message to Host Process</button>
+<button onclick="requestFromHost()">Request From Host</button>
+<button onclick="notifyCallbackFunction()">Host calls callback function</button>
+
+<script src="./atomicQuery.js"></script>
+<script>
+                 let clicks = 0;
+
+                 // Send a notification to the host
+                 function sendToHost() {
+                     clicks++;
+                     atomicHostEvent("CUSTOM_NOTIFICATION", {
+                         clickCount: clicks
+                     });
+                 }
+
+                 // request some information from the host
+                 function requestFromHost() {
+                     atomicHostRequest("GET_FROM_HOST", {
+                         prefix: "fus"
+                     }).then(function (response) {
+                         alert("Host Said: " + response.displayMessage);
+                     });
+                 }
+
+                 // Ask the host to call a function at some point in the future
+                 function notifyCallbackFunction() {
+                     atomicHostEvent("CALLBACK_FUNCTION", {
+                         callbackFunction: "HOST_callme"
+                     });
+                 }
+
+                 // The function the host should call
+                 function HOST_callme(message) {
+                     alert("Host called me with: " + message);
+                 }
+
+</script>
+
+</html>

+ 4 - 0
AtomicWebView/JavaScript/Resources/WebClient/LocalPage.html.asset

@@ -0,0 +1,4 @@
+{
+	"version": 1,
+	"guid": "6f9de6ce4f1770fe90bf2dc1f22d4058"
+}

+ 69 - 0
AtomicWebView/JavaScript/Resources/WebClient/atomicQuery.js

@@ -0,0 +1,69 @@
+/**
+* Used to send a notification message to the host
+* @param {string} messageType
+* @param {object} data
+* @return {Promise} will resolve when the host has handled the message
+*/
+function atomicHostEvent(messageType, data) {
+    let queryMessage;
+
+    // if we have a data element, then we need to structure the message so that the host understands it
+    // by adding the message to the object and then stringify-ing the whole thing
+    if (data) {
+        // stringify and reparse since we need to modify the data, but don't want to modify the passed in object
+        queryMessage = JSON.parse(JSON.stringify(data));
+        queryMessage.message = messageType;
+    } else {
+        queryMessage = {
+            message
+        };
+    }
+
+    return new Promise((resolve, reject) => {
+        window.atomicQuery({
+            request: JSON.stringify(queryMessage),
+            persistent: true,
+            onSuccess: (result) => resolve(),
+            onFailure: (error_code, error_message) => {
+                console.log(error_code);
+                console.log(error_message);
+                reject({ error_code, error_message });
+            }
+        });
+    });
+}
+
+/**
+ * Used to send a request to the server.  The server will send back the results in the promise
+ * @param  {string} messageType
+ * @param  {object} data
+ * @return {Promise}
+ */
+function atomicHostRequest(messageType, data) {
+    let queryMessage;
+
+    // if we have a data element, then we need to structure the message so that the host understands it
+    // by adding the message to the object and then stringify-ing the whole thing
+    if (data) {
+        // stringify and reparse since we need to modify the data, but don't want to modify the passed in object
+        queryMessage = JSON.parse(JSON.stringify(data));
+        queryMessage.message = messageType;
+    } else {
+        queryMessage = {
+            message
+        };
+    }
+
+    return new Promise((resolve, reject) => {
+        window.atomicQuery({
+            request: JSON.stringify(queryMessage),
+            persistent: false,
+            onSuccess: (s) => {
+                // unwrap the message that was returned
+                let o = JSON.parse(s);
+                resolve(o);
+            },
+            onFailure: (error_code, error_message) => reject({ error_code, error_message })
+        });
+    });
+}

+ 7 - 0
AtomicWebView/JavaScript/Resources/WebClient/atomicQuery.js.asset

@@ -0,0 +1,7 @@
+{
+	"version": 1,
+	"guid": "5fd9595ae4df50dcea737c20eb6fb193",
+	"JavascriptImporter": {
+		"IsComponentFile": false
+	}
+}