Creating a chat application that uses node.js server in iOS

I am trying to create an iPhone (native) chat application that uses node.js on socket.io.

What is the best way to create a chat application on iOS

Is there a way to create a chat application with node.js server in iOS

Can anyone give me a suggestion?

Thanks for the offer

+5
source share
3 answers

You can create a chat application using Socket.io with iOS / Android and HTML!

There are two ways to do this!

i) Implement your own socket connection with Socket.io (this is difficult because you need to write most of the network implementation yourself!)

Socket.io will interact as the stream you need to connect from your iOS!

You can refer to the iOS dev manual on how to implement a thread!

https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/UsingSocketsandSocketStreams.html

There is an active thread that also discusses this!

iPhone Objective-C Socket Connection with Socket.IO

ii) Use the existing library or wrapper that people make for iOS, you can find the link below!

This library mainly performed the network part, and you just need to implement your application logic!

Ios

https://github.com/pkyeck/socket.IO-objc

Android

https://github.com/nkzawa/socket.io-client.java

It would be nice to start with the library first and then try to make your own implementation! :))

+6
source

I suggest the following:

  • Develop an HTML5 application with node.js and a NOSQL database (CouchDb in my example) on the server
  • Do not use socket.io for your first playground, because its complex. You must first understand websockets very well.

Do not burden in advance prepared frameworks and tons of code. To make the necessary changes, you will need a simple, simple code. You need complete control and understanding of the code that you have.

I attached a working sample (thanks to Ales Smodis). For the sample to work, you need to install 2 node.js packages:

npm install websocket npm install nano 

And you need to create a database and insert at least 1 user into the CouchDb database:

 curl -X PUT http://localhost:5984/chatroom curl -X PUT -H 'Content-Type: application/json' --data '{"username":"john","password":"john"}' http://localhost:5984/chatroom/john 

 $(document).ready(function () { var connection, username = 'Tester', password = 'Tester', historyCounter = 0, members = {}, // displays jqLogin = $('#login'), jqChatroom = $('#chatroom'), // login display components jqWaiting = $('#waiting'), jqNickname = $('#nickname'), jqPassword = $('#password'), // chat display components jqHistory = $('#history'), jqMembers = $('#members'), jqLine = $('#line'); function addLine(nick, line) { var jq = $('<p><span class="nick"></span><span class="line"></span></p>'), jqNick = jq.find('.nick'), jqLine = jq.find('.line'), i, lines; jqNick.text(nick ? nick + ': ' : '*** '); jqLine.text(line); jqHistory.append(jq); historyCounter++; for (lines = jqHistory.children(), i = 0; historyCounter > 100; i++, historyCounter--) { $(lines[i]).remove(); } } function addMsg(msgObj) { var msgHandler = states[activeState].messageHandlers[msgObj.type] || function () { addLine(null, 'Neveljaven paket tipa ' + msgObj.type); }; msgHandler(msgObj); } function clearMembers() { var nickname; for (nickname in members) { members[nickname].remove(); delete members[nickname]; } jqMembers.empty(); // just in case } function addMember(nickname) { var jq = $('<li></li>'); jq.text(nickname); jqMembers.append(jq); members[nickname] = jq; } function removeMember(nickname) { if (nickname in members) { members[nickname].remove(); delete members[nickname]; } } function connect () { connection = new WebSocket('ws://127.0.0.1:8080'); connection.onopen = function () { states[activeState].onopen(); }; connection.onmessage = function (message) { try { addMsg(JSON.parse(message.data)); } catch (e) { addLine(null, 'Exception while handling a server message: ' + e.toString()); } }; connection.onclose = function () { states[activeState].onclose(); }; } function loginKeypress(event) { if (13 !== event.keyCode) return; username = jqNickname.val(); password = jqPassword.val(); if (!username) jqNickname[0].focus(); else if (!password) jqPassword[0].focus(); else { jqWaiting.css('display', ''); jqNickname.unbind('keydown', loginKeypress); jqPassword.unbind('keydown', loginKeypress); connect(); } } function inputKeypress(event) { var line; if (13 === event.keyCode) { line = jqLine.val(); if (line.length === 0) return; jqLine.val(''); connection.send(JSON.stringify({ 'type': 'line', 'line': line })); } } var states = { 'login': { 'start': function () { jqChatroom.css('display', 'none'); jqWaiting.css('display', 'none'); jqLogin.css('display', ''); jqNickname.val(''); jqPassword.val(''); jqNickname[0].focus(); activeState = 'login'; jqNickname.bind('keydown', loginKeypress); jqPassword.bind('keydown', loginKeypress); }, 'onopen': function () { connection.send(JSON.stringify({ 'type': 'login', 'username': username, 'password': password })); }, 'messageHandlers': { 'state': function (msgObj) { var i, history, users; states.chat.start(); history = msgObj.history; jqHistory.empty(); historyCounter = 0; for (i = 0; i < history.length; i++) addMsg(history[i]); users = msgObj.users; clearMembers(); for (i = 0; i < users.length; i++) addMember(users[i]); } }, 'unhandledMessage': function (msgObj) { connection.close(4000, 'Unhandled message type'); }, 'onclose': function () { states.login.start(); } }, 'chat': { 'start': function () { jqLogin.css('display', 'none'); jqWaiting.css('display', 'none'); jqChatroom.css('display', ''); jqHistory.empty(); historyCounter = 0; activeState = 'chat'; jqLine.bind('keydown', inputKeypress); }, 'onopen': function () { connection.close(4001, 'Connection opened while chatting'); }, 'messageHandlers': { 'line': function (msgObj) { addLine(msgObj.nick, msgObj.line); }, 'join': function (msgObj) { addLine(null, 'Priklopil: ' + msgObj.nick); addMember(msgObj.nick); }, 'leave': function (msgObj) { addLine(null, 'Odklopil: ' + msgObj.nick); removeMember(msgObj.nick); } }, 'unhandledMessage': function (msgObj) { connection.close(4000, 'Unhandled message type'); }, 'onclose': function () { addLine(null, 'Connection closed'); jqLine.unbind('keydown', inputKeypress); } } }, activeState = 'login'; states.login.start(); }); 
 // node.js code var http = require('http'), url = require('url'), path = require('path'), fs = require('fs'), nano = require('nano')('http://localhost:5984'), chatroomDb = nano.use('chatroom'), websocket = require('websocket'), chatHistory = [], activeUsers = {}; var filesDir = path.join(process.cwd(), 'web'); var mimeTypes = { '.html': 'text/html', '.css': 'text/css', '.js': 'text/javascript' }; var getContentType = function (extension) { var mimeType = mimeTypes[extension]; return mimeType ? mimeType : 'application/octet-stream'; }; var server = http.createServer(function (request, response) { var relativePath = url.parse(request.url).pathname, absolutePath = path.join(filesDir, relativePath); var handler = function (err, stats) { if (stats) { if (stats.isDirectory()) { absolutePath = path.join(absolutePath, 'index.html'); fs.stat(absolutePath, handler); return; } if (stats.isFile()) { response.writeHead(200, getContentType(path.extname(absolutePath))); var stream = fs.createReadStream(absolutePath); stream.pipe(response); return; } } response.writeHead(404, {'Content-Type': 'text/plain'}); response.write('Not found\r\n'); response.end(); }; console.log('HTTP request for ' + relativePath); fs.stat(absolutePath, handler); }); server.listen(8080, function () {}); wsServer = new websocket.server({ 'httpServer': server }); function addLine (type, nick, line) { var msg = { 'type': type, 'nick': nick, 'line': line }, jsonMsg = JSON.stringify(msg), username; chatHistory.push(msg); while (chatHistory.length > 100) chatHistory.shift(); for (username in activeUsers) { activeUsers[username].sendMessage(jsonMsg); } } wsServer.on('request', function (request) { console.log('New websocket connection from ' + request.origin); // TODO: verify that request.origin is our web site var connection = request.accept(null, request.origin); var username = null; connection.on('message', function (message) { if (message.type !== 'utf8') { console.log('Refusing a non-utf8 message'); return; } console.log('Processing message: ' + message.utf8Data); try { var m = JSON.parse(message.utf8Data); switch (m.type) { case 'login': chatroomDb.get(m.username, function (err, body) { if (err || (body.password !== m.password)) { connection.close(); return; } username = m.username; addLine('join', username, null); activeUsers[username] = { 'sendMessage': function (jsonMsg) { connection.sendUTF(jsonMsg); } }; var users = [], u; for (u in activeUsers) users.push(u); connection.sendUTF(JSON.stringify({ 'type': 'state', 'history': chatHistory, 'users': users })); }); break; case 'line': if (!username) { connection.close(); break; } addLine('line', username, m.line); break; } } catch (e) { console.log(e); } }); connection.on('close', function (connection) { console.log('Connection closed'); if (username) { delete activeUsers[username]; addLine('leave', username, null); } }); }); console.log('Server running'); 
 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Chatroom</title> <style> html, body { width: 100%; height: 100%; padding: 0; border: none; margin: 0; } #heading { position: absolute; top: 0; left: 0; right: 0; height: 30px; margin: 0; padding: 0; line-height: 30px; text-align: center; font-size: 20px; background-color: green; } #outer { position: absolute; top: 30px; bottom: 0; left: 0; right: 0; margin: 20px; min-height: 400px; min-width: 400px; background-color: lime; } #inner { height: 100%; background-color: #ffc0cb; } #chat { position: absolute; top: 0; left: 0; right: 200px; bottom: 0; background-color: #ffd700; } #members { position: absolute; top: 0; right: 10px; width: 180px; bottom: 0; background-color: #ff00ff; list-style-type: none; padding: 10px; padding: 0; border: none; } #history { position: absolute; top: 0; left: 0; bottom: 2em; right: 0; background-color: #00ffff; padding: 10px; } #input { position: absolute; height: 2em; left: 0; right: 0; bottom: 0; background-color: #90ee90; line-height: 2em; } #line { width: 100%; margin: 0; border: none; padding: 0; } #history > p { margin: 2px; } .nick { white-space: pre; display: table-cell; } .line { display: table-cell; } #login { height: 100%; display: table; margin: 0 auto; } #login > .svg { vertical-align: middle; display: table-cell; } #login-wrapper1 { display: table; height: 100%; width: 100%; } #login-wrapper2 { display: table-cell; vertical-align: middle; } #login-table { margin: 0 auto; } #login-table .label { text-align: right; } #waiting { position: fixed; top: 0; bottom: 0; left: 0; right: 0; opacity: 0.3; } </style> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> <script src="client.js"></script> </head> <body> <div id="login"> <div class="svg"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 400" width="400" height="400"> <defs> <path id="curved-text" d="M0,0 c 50 -50 150 -50 200 0" /> </defs> <g> <text transform="translate(-100,40)" font-weight="bold" font-variant="small-caps" font-family="Arial sans-serif" font-size="30" fill="none" stroke="orange" text-anchor="middle"> <textPath xlink:href="#curved-text" startOffset="50%">Chatroom</textPath> </text> <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="360" dur="5s" fill="remove" additive="sum" repeatCount="indefinite" /> <animateMotion dur="10s" repeatCount="indefinite" path="M100,200 a100,100 0 1 1 200,0 a100,100 0 1 1 -200,0" /> </g> <foreignObject x="0" y="0" width="400" height="400" style="height:400px;"> <div xmlns="http://www.w3.org/1999/xhtml" id="login-wrapper1"> <div id="login-wrapper2"> <table id="login-table"> <tbody> <tr> <td class="label">Vzdevek:</td><td><input type="text" id="nickname" /></td> </tr> <tr> <td class="label">Geslo:</td><td><input type="password" id="password" /></td> </tr> </tbody> </table> </div> </div> </foreignObject> </svg> </div> </div> <div id="chatroom" style="display:none;"> <h1 id="heading">Chatroom</h1> <div id="outer"> <div id="inner"> <div id="chat"> <div id="history"> <p><span class="nick">Matej: </span><span class="line">Hi</span></p> <p><span class="nick">Borut: </span><span class="line">How are you?</span></p> <p><span class="nick">Martina: </span><span class="line">Ok, thanks!</span></p> </div> <div id="input"><input id="line" type="text"></div> </div> <ul id="members"> <li>Matej</li> <li>Borut</li> <li>Martina</li> </ul> </div> </div> </div> <div id="waiting" style="display:none;"></div> </body> </html> 
+3
source

If you are evaluating the parameters, check out IP Messaging from Twilio:

https://www.twilio.com/docs/tutorials/walkthrough/ip-chat/ios/swift#0

The tutorial above in Swift for iOS (also available for Objective-C) allows you to work with the native SDK when the server-side application ( yours in Node.js ) generates user access tokens for connecting to the API.

The code uses a connection to a channel, creating a channel, and sending messages.

Note. I work for Twilio. This quick sample app should at least help you determine which functionality will work best for you.

0
source

All Articles