probablyCorey
probablyCorey

Reputation: 2498

WebSockets on iOS

I've read that WebSockets work on iOS 4.2 and above. And I can verify that there is indeed a WebSocket object. But I can't find a single working WebSocket example that works on the phone.

For example http://yaws.hyber.org/websockets_example.yaws will crash the Mobile Safari app. Has anyone got WebSockets working successfully on the phone?

Upvotes: 22

Views: 59114

Answers (6)

Justin Bullard
Justin Bullard

Reputation: 33

I was debugging a similar issue and found that if you have used https to get the web page iOS will trap if you use the pass a the "ws:" protocol into WebSocket. If you use "wss:" everything will work and there will be no traps.

Upvotes: 1

moka
moka

Reputation: 23047

It is supported, but bear in mind regarding the standard that iOS Safari browser implements, it is not RFC 6455, but HyBi-00/Hixie-76.

You can test as well using this browser: http://websocketstest.com/

As well check this great post that have most of info regarding versions: https://stackoverflow.com/a/2700609/1312722


OBS!, this is an old answer. I have checked through the webpage mentioned in this post combined with browserstack.com:

  • iPhone4S
  • iPhone5
  • iPhone5S
  • iPhone6
  • iPhone6 Plus
  • iPhone6S
  • iPhone6S Plus

All using RFC 6455

Upvotes: 7

Durai Amuthan.H
Durai Amuthan.H

Reputation: 32270

Here is a working sample

Web socket client

<!DOCTYPE html>
<meta charset="utf-8" />
<head>
<title>WebSocket Test</title>
<script language="javascript" type="text/javascript">

    var websocket;

function OpenWebSocket()
{

   try {
       websocket = new WebSocket(document.getElementById("wsURL").value);
       websocket.onopen = function(evt) { onOpen(evt) };
       websocket.onclose = function(evt) { onClose(evt) };
       websocket.onmessage = function(evt) { onMessage(evt) };
       websocket.onerror = function(evt) { onError(evt) };
   }
   catch(err) {
       writeToScreen(err.message);
   }
}

function CloseWebSocket()
{
     websocket.close();
}

function FindWebSocketStatus()
{
     try {
         if (websocket.readyState == 1){
          writeToScreen("Websocket connection is in open state")
         }
         else if (websocket.readyState == 0){
             writeToScreen("Websocket connection is in connecting state")
         }
         else{
          writeToScreen("Websocket connection is in close state")
         }
     }
     catch(err) {
         writeToScreen(err.message);
     }
}

function FindWebSocketBufferedAmount(){
    try {
            writeToScreen(websocket.bufferedAmount)
    }
    catch(err) {
        writeToScreen(err.message);
    }
}

function SendMessageThroughSocket(){
    doSend(document.getElementById("wsMessage").value);
}

function onOpen(evt)
{
    writeToScreen("Socket Connection Opened");
}

function onClose(evt)
{
    writeToScreen("Socket Connection Closed");
}

function onMessage(evt)
{
    writeToScreen('<span style="color: blue;">SERVER RESPONSE: ' + evt.data+'</span>');
}

function onError(evt)
{
    writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
}

function doSend(message)
{
    try{
    writeToScreen("CLIENT SENT: " + message);
    websocket.send(message);
    }
    catch(err) {
        writeToScreen(err.message);
    }
}

function writeToScreen(message)
{
    var output = document.getElementById("output");
    var pre = document.createElement("p");
    pre.style.wordWrap = "break-word";
    pre.innerHTML = message;
    output.appendChild(pre);
}
</script>
</title>
</head>
<body>
    <table>
        <tr>
            <td>
                WebSocket URL
            </td>
            <td>
                <input type="text" id="wsURL" value="ws://echo.websocket.org/"/>
            </td>
        </tr>
        <tr>
            <td>
                WebSocket Message
            </td>
            <td>
                <input type="text" id="wsMessage" value="Hi"/>
            </td>
        </tr>
        <tr>
            <td colspan="2" style="text-align:left;">
                <input type="button" value="Open Socket Connection" onclick="OpenWebSocket();"/>
            </td>
        </tr>
        <tr>
            <td colspan="2" style="text-align:left;">
                 <input type="button" value="Send Message" onclick="SendMessageThroughSocket();"/>
            </td>
        </tr>
        <tr>
          <td colspan="2" style="text-align:left;">
              <input type="button" value="Close Socket Connection" onclick="CloseWebSocket();"/>
          </td>
         </tr>
        <tr>
            <td colspan="2" style="text-align:left;">
                <input type="button" value="Find Socket Status" onclick="FindWebSocketStatus();"/>
            </td>
        </tr>
        <tr>
            <td colspan="2" style="text-align:left;">
                <input type="button" value="Find Socket Buffered Amount" onclick="FindWebSocketBufferedAmount();"/>
            </td>
        </tr>
    </table>

<div id="output"></div>
</body>
</html>

Web Socket server

Creating your own socket server is also simple Just install the Node.js and socket.io then proceed to install web socket via npm

#!/usr/bin/env node
var WebSocketServer = require('websocket').server;
var http = require('http');

var server = http.createServer(function(request, response) {
                               console.log((new Date()) + ' Received request for ' + request.url);
                               response.writeHead(404);
                               response.end();
                               });
server.listen(8888, function() {
              console.log((new Date()) + ' Server is listening on port 8888');
              });

wsServer = new WebSocketServer({
                               httpServer: server,
                               // You should not use autoAcceptConnections for production
                               // applications, as it defeats all standard cross-origin protection
                               // facilities built into the protocol and the browser.  You should
                               // *always* verify the connection's origin and decide whether or not
                               // to accept it.
                               autoAcceptConnections: false
                               });

function originIsAllowed(origin) {
    // put logic here to detect whether the specified origin is allowed.
    return true;
}

wsServer.on('request', function(request) {
            if (!originIsAllowed(request.origin)) {
            // Make sure we only accept requests from an allowed origin
            request.reject();
            console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
            return;
            }

            var connection = request.accept();
            console.log((new Date()) + ' Connection accepted.');
            connection.on('message', function(message) {
                          if (message.type === 'utf8') {
                          console.log('Received Message: ' + message.utf8Data);
                          connection.sendUTF('Message received at server:'+message.utf8Data);
                          }
                          else if (message.type === 'binary') {
                          console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');
                          connection.sendBytes(message.binaryData);
                          }
                          });
            connection.on('close', function(reasonCode, description) {
                          console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
                          });
            });

NodeJS folder in finder

save the above file as .js and run it like node filename.js from terminal or command prompt

NodeJS

The above file is like we have first created a http server using node then we're passing the created http server instance to Websocketserver then subsequently to Socket.iO instance

Upvotes: 1

I got them working on Chrome and Safari, iPhone and iPad (and other mobile devices too, but I guess you don't mind about them). Here is the Javascript code I am using :

<script language="javascript" type="text/javascript">

    var wsUri = document.URL.replace("http", "ws");
    var output;
    var websocket;


    function init()
    {
        output = document.getElementById("output");
        wsConnect();
    }

    function wsConnect()
    {
        console.log("Trying connection to " + wsUri);
        try
        {
            output = document.getElementById("output");
            websocket = new WebSocket(wsUri);
            websocket.onopen = function(evt)
            {
                    onOpen(evt)
            };
            websocket.onclose = function(evt)
            {
                    onClose(evt)
            };
            websocket.onmessage = function(evt)
            {
                    onMessage(evt)
            };
            websocket.onerror = function(evt)
            {
                    onError(evt)
            };
        }
        catch (e)
        {
            console.log("Exception " + e.toString());
        }
    }


    function onOpen(evt)
    {
        alert("Connected to " + wsUri);
    }

    function onClose(evt)
    {
        alert("Disconnected");
    }

    function onMessage(evt)
    {
        alert('Received message : ' + evt.data);
    }

    function onError(evt)
    {
        alert("Error : " + evt.toString());
    }

    function doSend(message)
    {
        websocket.send(message);
    }

    window.addEventListener("load", init, false);

Sending data from client to server is done calling doSend() function. Receiving data from server also works, I've tested it from a custom C++ server.

Upvotes: 2

Matt
Matt

Reputation: 1445

I had a similar problem and even looked to this post to find a fix for it. For me, it had nothing to do with being on a wifi connection. It appears to be a bug in the iOS implementation of websockets (even up to the current version 5.1). Turning on a bunch of XCode's debugging I found that it has something to do with memory management because I would get something along the lines of "message sent to a deallocated instance." Most likely there was an object that didn't have the correct reference count and was cleaned up way too early.

This blog has a lot of great information about the symptoms of the problem and how to debug it, but doesn't have a workaround: http://dalelane.co.uk/blog/?p=1652

Eventually though, I found this workaround, and my app has almost entirely stopped crashing now.

me = this // strange javascript convention
this.socket = new WebSocket(url);
// put onmessage function in setTimeout to get around ios websocket crash
this.socket.onmessage = function(evt) { setTimeout(function() {me.onMessageHandler(evt);}, 0); };

Upvotes: 4

probablyCorey
probablyCorey

Reputation: 2498

I may have found the solution. Mobile Safari only crashes with websockets when you have setup a proxy over wifi.

Upvotes: 12

Related Questions