Canvas+ secure WebSocket support


#1

I’m developing a game using Canvas+. I just added websocket stuff to the game and tried to setup websockets over SSL. I ran the app inside of the Cocoon Developer App and in the console I saw this:

WebSocket Exception: wss / secure connections are not supported at this time

This is extremely important for us so I was wondering what the status on getting this into Canvas+ is?


#2

I had this same problem, though have not attempted to remedy it yet so it’s possible the recent updates have resolved it. I was told ws are currently supported in Canvas+. Just out of curiosity, are you using socket.io?


#3

I’m not using socket.io. I am just using vanilla websockets.

var ws = new WebSocket('wss://ws.example.com');

#4

Hi,

Sorry but we are no planning to add support for WS over SSL in the near future.


#5

What would you suggest to send encrypted data to the client then?


#6

You could use the webview to manage your WSS. Android can use WSS from 4.4 and iOS support it as well.

http://cocoonio.github.io/cocoon-canvasplus/dist/doc/js/Cocoon.App.html#toc6

And if you need to support older Android device, you can try this plugin : https://github.com/knowledgecode/WebSocket-for-Android

Let me know if it works because we need this feature too for our next project.

@imanolm1 : this will probably become a frequent request. The release of Clash Royale from Supercell showed a successfull path to a “realtime” (kinda) multiplayer games.


#7

Oh so the problem is it being wss and not just ws? My server is currently set up to use only wss and ssl :((


#8

Thanks for the idea. I will see if I can implement this tonight and let you know.


#9

I couldn’t get the WebView to work. Whenever I tried to create a new WebSocket there, it would fail.

var ws = Cocoon.App.forward("new WebSocket('wss://echo.websocket.org')");
console.log(ws);

That would log SyntaxError: Unexpected token u and then undefined.

In contrast, if I did this:

var test = Cocoon.App.forward("3");
console.log(test);

The console would show 3.

I tried these snippets both with Cocoon.App.loadInTheWebView and without.
https://cocoonio.github.io/cocoon-canvasplus/dist/doc/js/Cocoon.App.html#toc9


#10

You should see the webview as an iframe (because it is), it means that you can create a new file to load into the webview, with your socket code in it, and then some bridge functions to communicate with Canvas+ like an API.

When you are doing a “forwardAsync” (don’t forget the “async” or you will freeze your app at every call), what the code does is an “eval”. So you want to do the most simple thing possible with it, like calling an API.


#11

I kept at it last night, and I ended up getting it working. I haven’t tested it fully, but with my initial tests it seems to be working. I did what you described, where I put the socket logic inside the webview and passed the strings back to Canvas+.

I will share my code so you can see.

index.html

document.addEventListener('deviceready', ready);
        
function ready() {
    Cocoon.App.WebView.on('load', {
        success: init,
        error: function() {
            console.log('Could not load webview.html');
            console.log(JSON.stringify(arguments));
        }
    });
    Cocoon.App.loadInTheWebView('/webview.html');
}

function init() {
    ws.on('test', function() {
        console.log('test called');
    });
    ws.emit('test');
}

webview.html (Required JS files: cocoon.js & cocoon_canvasplus.js)

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>WebView</title>
        <script src="cordova.js"></script>
        <script src="/js/webview/cocoon.js"></script>
        <script src="/js/webview/cocoon_canvasplus.js"></script>
    </head>
    <body>
        <script>
            ws = new WebSocket('wss://echo.websocket.org');
        
            ws.emit = function(obj) {
                // TODO: need to make sure its connected before sending stuff
                ws.send(JSON.stringify(obj));
            };
        
            ws.onopen = function() {
                Cocoon.App.forwardAsync('ws.onopen()');
            };
        
            ws.onerror = function(err) {
                Cocoon.App.forwardAsync('ws.onerror(' + JSON.stringify(err) + ')');
            };
        
            ws.onclose = function() {
                Cocoon.App.forwardAsync('ws.onclose()');
            };
        
            ws.onmessage = function(event) {
                // don't need to JSON.stringify event.data because it's already stringified
                Cocoon.App.forwardAsync('ws.onmessage(' + event.data + ')');
            };
        </script>
    </body>
</html>

websocket.js (included in index.html)

ws = (function() {
    var listeners = {},

    emit = function(method, payload) {
        payload = payload || {};

        var data = {
            method: method,
            payload: payload
        };

        Cocoon.App.forwardAsync('ws.emit(' + JSON.stringify(data) + ')');
    },

    on: function(method, cb) {
        if (!listeners[method]) {
            listeners[method] = [];
        }

        listeners[method].push(cb);
    };

    return {
        emit: emit,
        on: on,
        onopen: function() {},
        onerror: function(err) {},
        onclose: function() {},
        onmessage: function(data) {
            for (var i = 0, l = listeners[data.method].length; i < l; i++) {
                listeners[data.method][i](data.payload || {});
            }
        }
    };
})();

That’s the gist of it. This link helped me out as well:


#12

Amazing ! Thanks for sharing :wink:


#13

Indeed thank you I’m sure this will help me in the very near future!


#14

Thanks all for sharing! I haven’t even though of doing it using the webview forwarder, great idea.


#15

Thank you very much for your contribution :slight_smile:


#16

Hi guys,

We faced the same problem at my company - wss not supported in Canvas+.
A little online search lead me to the current thread and I jumped on implementing the nice workaround idea you came up with.

The problem appeared when started to play around on Android.
Turning off the WiFi / LTE / 3G network while the socket connection is still open causes the app to crash.

This is my implementation:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
    <title>Web Sockets</title>
    <!--Libs-->
    <script src="cordova.js"></script>
    <script>
        document.addEventListener("deviceready", onDeviceReady, false);
        function onDeviceReady() {
            // Remove listener.
            document.removeEventListener("deviceready", onDeviceReady);
            // Initialize. Give it couple of seconds.
            setTimeout(loadWSWebView, 2000);
        };
        /**
         * Load WSView
         */
        function loadWSWebView() {
            // Load the wsWebView.
            Cocoon.App.WebView.on("load", {success: wsviewLoaded, error: wsviewFailed});
            Cocoon.App.loadInTheWebView("wswebview.html");
        }
        /**
         * Called on successful load.
         */
        function wsviewLoaded() { 
            // Create socket connection.
            var url = "wss://echo.websocket.org/";
            Cocoon.App.forwardAsync("wsCreate('" + url + "');");
        }
        /**
         * Called on load error.
         */
        function wsviewFailed() {

        }
    </script>
</head>
<body>
</body>
</html>

wswebview.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
    <title>Web Socket WebView</title>
    <!--Libs-->
    <script src="cordova.js"></script>
    <script src="libs/cocoon.js"></script>
    <script src="libs/cocoon_canvasplus.js"></script>
    <script>
        var _websocket;
        function wsCreate(url) {
            // Create new socket.
            _websocket = new WebSocket(url);
            // Add callbacks.
            _websocket.onopen = onOpen;
            _websocket.onclose = onClose;
            _websocket.onmessage = onMessage;
            _websocket.onerror = onError;
        }
        function onOpen(evt) {
            _websocket.send("HELLO");
        }
        function onClose(evt) {
            //alert("CLOSE");
        }
        function onError(evt) {

        }
        function onMessage(evt) {
            alert("Message received");
        }
    </script>
</head>
<body>
</body>
</html>

Here are the repo steps:

  1. Open up Cocoon Dev app.
  2. Type the project .zip file URL and load it.
  3. Open socket connection.
  4. Send/Recieve simple message.
  5. Pull down “Quick Access” menu on Android and turn of your WiFi / LTE / 3G network.
  6. App will crash in couple of seconds.

Loading index.html project file (not .zipped version) in Coccon Dev app seems to work and doesn’t crash.
Unfortunately building an .apk out of that project crashes as well.
//
Tested on Galaxy Tab A 9.8" and Asus Nexus 4 phone both running Android 5.x
//
There is no problem when testing on iOS - iPhone5/6 and iPad4


#17

Can you show us a log from the Android Monitor Logcat please ?


#18

This topic was automatically closed after 30 days. New replies are no longer allowed.