I want to connect my app to the socket here is the code :-
import UIKit
import SocketIO
class SocketIOManager: NSObject {
static let manager = SocketManager(socketURL: URL(string: "myURL")!)
static let socket = manager.defaultSocket
class func connectSocket() {
let token = UserDefaults.standard.getAccessToken()
self.manager.config = SocketIOClientConfiguration(
arrayLiteral: .connectParams(["token": token]), .secure(true) // problem is here in passing token value
)
socket.connect()
}
class func receiveMsg() {
socket.on("new message here") { (dataArray, ack) in
print(dataArray.count)
}
}
}
I created a new class SocketIOManager.swift and I invoke my function in view controller
SocketIOManager.connectSocket()
and I am not using the localhost url but still my app is not connected to the socket I think I followed this How to connect with Socket.io? Swift 4 and I also add App Transport Security in info.plist. Any help? The problem is when I am passing the token value it gives me error otherwise it is working properly. Should I need to pass token when using socket?
You should make a shared property in your SocketIOManager class like this:
static let shared = SocketIOManager()
and then create init() like this:
var socket: SocketIOClient!
// defaultNamespaceSocket and swiftSocket both share a single connection to the server
let manager = SocketManager(socketURL: URL(string: "http://localhost:3000")!, config: [.log(true), .compress])
override init() {
super.init()
socket = manager.defaultSocket
}
and finally write your methods like this:
func connectSocket() {
let token = UserDefaults.standard.getAccessToken()
self.manager.config = SocketIOClientConfiguration(
arrayLiteral: .connectParams(["token": token]), .secure(true)
)
socket.connect()
}
func receiveMsg() {
socket.on("new message here") { (dataArray, ack) in
print(dataArray.count)
}
}
and call your method like this:
SocketIOManager.shared.connectSocket()
The point is that you should make a strong reference to manager property in your viewController and static let shared = SocketIOManager() you do this for you!
Is your URL secured under HTTPS?
If it is not, that could be the problem, due to App Transport Security restrictions.
See Info Plist Reference
See also this post here.
If that's not the problem. I'd suggest to check if your Socket version on both sides, server and client, are the same. Recently I had a problem because of that.
Hope it helps!
try this Example:
let manager = SocketManager(socketURL: URL(string:
"http://xxxxxxxxx.com")!, config: [.log(true), .compress])
var socket = manager.defaultSocket
socket.connect()
socket.on(clientEvent: .connect) {data, ack in
print("socket connected")
self.gotConnection()
}
}
func gotConnection(){
socket.on("new message here") { (dataArray, ack) in
print(dataArray.count)
}
}
Related
I am creating an iOS demo where I am implementing the functionality to control a Google/Android tv using the iOS app by referring to the following link.
https://github.com/Aymkdn/assistant-freebox-cloud/wiki/Google-TV-(aka-Android-TV)-Remote-Control-(v2)
Also the working demo for this in Node.
https://github.com/louis49/androidtv-remote
I am implementing this using the socket IO library for iOS swift.
During the connection, I am facing the SSL handshake failure.
Here is the code
import UIKit
import SocketIO
class ConnectViewController: UIViewController {
let manager = SocketManager(socketURL: URL(string: "wss://172.16.16.23:6467")!)
var socket:SocketIOClient!
override func viewDidLoad() {
super.viewDidLoad()
let ssl = SSLSecurity.init(usePublicKeys: true)
manager.setConfigs([.secure(true),.selfSigned(false),.security(ssl),.log(true),.sessionDelegate(self),.reconnects(false),.forceWebsockets(true),.forcePolling(true)])
self.socket = manager.defaultSocket
self.socket.on(clientEvent: .connect) {data, ack in
print("socket connected")
}
}
}
I am working on Chat engine using Socket io version 15.2.0,
When first time when I call socket.connect() it works properly, then if I call socket.disconnect() and then again try to call socket.connect() then socket fails to connect without any error or log. Then I have to kill the app and need to relaunch the app then socket connects without any issue.
following is my Shared class for Socket connect and disconnect
class SocketHelper {
static let shared = SocketHelper()
var socket: SocketIOClient!
let manager = SocketManager(socketURL: URL(string: ApiUrls.socketUrl)!, config: [.log(true), .compress, .connectParams(["token": Globals.shared.session.accessToken]), .secure(true), .forceNew(true)])
private init() {
socket = self.manager.defaultSocket
}
func getSocketWithLazyConnect() -> SocketIOClient {
if self.socket.status == .connected {
return self.socket
}
self.socket.connect()
return self.socket
}
func disconnect() {
self.socket.disconnect()
}
func isConnected() -> Bool {
return self.socket.status == .connected
}
}
Any help much appreciated...
Thank you guys but I figured out what I was doing wrong
I have one shared class named ChatEngine it handle all chat related socket events.
in that method while to disconnect from socket, I wrote a function switchOff
func switchOff() {
socket?.off(Constants.SocketEvent.connect)
SocketHelper.shared.disconnect()
}
as shown above I was calling off funtion for connect event and that's why after that when I called socket.connect, I didn't received any call back for that inside
self.socket?.on(clientEvent: .connect, callback: { (data, ack) in
})
I just removed off function call from my switchOff function and now it's working fine. Now my switchOff function is like this
func switchOff() {
SocketHelper.shared.disconnect()
}
I found following libraries to start a server locally.
https://github.com/httpswift/swifter
https://github.com/swisspol/GCDWebServer
For instance, I'm using swifter. It does compile for iOS.
I also added code to start a local server as follows.
class ViewController: UIViewController {
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let server = HttpServer()
server["/hello"] = { .ok(.htmlBody("You asked for \($0)")) }
let semaphore = DispatchSemaphore(value: 0)
do {
try server.start(9080, forceIPv4: true)
print("Server has started ( port = \(try server.port()) ). Try to connect now...")
let config = WKWebViewConfiguration()
webView = WKWebView(frame: self.view.bounds, configuration: config)
/////////////////////////////
// What should be url here to point to local server?
webView.load(URLRequest(url: URL(string: "http://192.168.31.70:9080/hello")!))
/////////////////////////////
view = webView
semaphore.wait()
} catch {
print("Server start error: \(error)")
semaphore.signal()
}
}
}
Also, If I submit it to apple, is there any possibility of rejection because of starting a local server?
Can you elaborate on what you are trying to achieve by starting an HTTP server in-process?
If you need control over the way that responses are made, I would recommend looking at registering a custom URL protocol handler with WKWebViewConfiguration.setURLSchemeHandler(_:forURLScheme:). Then, ask the WKWebView to load a resource from that custom URL scheme, and your handler (that conforms to WKURLSchemeHandler) will get called, and you can construct a URLResponse however you'd like.
I tried Telegraph
Step 1. Open Podfile & add a dependency - pod 'Telegraph'
Step 2. Open AppDelegate.swift & put code as follows.
// Serve the Server from Build folder
let demoBundleURL = Bundle.main.url(forResource: "webApp", withExtension: nil)!
// and handle those requests at Path
serverHTTP.serveDirectory(demoBundleURL, "/webApp")
// Setting Custom Router - OPTIONAL
serverHTTP.httpConfig.requestHandlers.insert(DRHTTPMiddleWare(), at: 0)
// Start Server
try? serverHTTP.start(port: 9000, interface: "localhost")
Step 3. In ViewController.swift, put code as follows.
func loadWebView() {
guard let url = URL(string: "http://localhost:9000/webApp") else { return }
webView = WKWebView(
frame: self.view.bounds,
configuration: WKWebViewConfiguration()
)
webView.load(URLRequest(url: url))
view = webView
}
I'm using https://github.com/auth0/socketio-jwt to connect the user to my node.js/socket.io server and I'm using one round trip
My problem right now is that whenever user logs in on the IOS part, the socket.connect() is not consistent, my theory is that the token is not yet ready even before the socket.connect() gets invoked.
I'm using Singleton design for my Socket.io class as many people pointed that out.
Here's the code on the SocketManager.swift part
import SocketIO
class SocketIOManager: NSObject {
static let sharedInstance = SocketIOManager()
var socket = SocketIOClient(socketURL: URL(string: mainURL)!, config: [.log(false), .compress, .connectParams(["token": getToken()])]) // getToken() I got it from other file which is Constant.Swift
func establishConnection() {
socket.connect()
}
func closeConnection() {
socket.disconnect()
}
}
I'm using KeychainAccess to store the token and Constant.Swift file store all the global variables and functions so that I could call it on any Swift files.
Constant.Swift
import Foundation
import KeychainAccess
let keychain = Keychain(server: "www.example.com", protocolType: .https)
func getToken() -> String {
if let token = keychain["token"] {
return token
}
return ""
}
LoginViewController.swift
#IBAction func facebookButtonClicked(_ sender: UIButton) {
Alamofire.request("/login", method: .post, parameters: parameters, encoding: JSONEncoding.default)
.responseJSON { response in
if let value = response.result.value {
let json = JSON(value)
self.keychain["token"] = String(describing: json["token"])
SocketIOManager.sharedInstance.establishConnection()
self.segueToAnotherVC() // Segue to another screen, to simplify things i put it in a function
}
}
}
So technically what is happening in this controller is, when the user logs in, I will store the token into KeychainAccess (it is equivalent to NSUserDefaults), then only I will make a socket connection because the socket connection needs a token beforehand.
What should I do to make the connection consistent all the time, whenever user logs in? Any methods that I could use?
I suggest you to use keychain like this:
let keychain = KeychainSwift()
keychain.set("string", forKey: "key")
keychain.get("key")
keychain.delete("key")
keychain Usage:
let saveBool: Bool = KeychainWrapper.setString("String", forKey: "key")
let retrievedString: String? = KeychainWrapper.stringForKey("key")
let removeBool: Bool = KeychainWrapper.removeObjectForKey("key")
And make sure that your token is set when calling establish connection, if not, don't try and connect.
References:
https://github.com/socketio/socket.io-client-swift/issues/788
https://github.com/marketplacer/keychain-swift
https://github.com/jrendel/SwiftKeychainWrapper
More info:
JSON Web Token is a JSON-based open standard for creating access tokens that assert some number of claims.
I'm new to sockets and i'm stuck with the following problem, i use this library to connect my app to my nodejs server.
I'd like to know why if i call socket.emit() in the following way doesn't work:
override func viewDidLoad() {
var socket: SocketIOClient = SocketIOClient(socketURL: NSURL(string: "myhosturl")!)
socket.emit("ping","some data");
socket.connect();
}
It doesn't work neither swiping socket.emit and socket.connect functions but if I trigger the socket.emit function by clicking a button it works:
override func viewDidLoad() {
var socket: SocketIOClient = SocketIOClient(socketURL: NSURL(string: "myhosturl")!)
socket.connect();
}
#IBAction func sendMessage(sender: AnyObject) {
socket.emit("ping","some data");
}
I think i'm missing something here, it would be great is someone could explain this to me
Sockets require a connection before emit is called. You should probably wait until there is a connection before u emit. Try this:
override func viewDidLoad() {
let socket = SocketIOClient(socketURL: NSURL(string: "myhosturl")!)
socket.on("connect") { _, _ in
print("socket connected")
socket.emit("ping", "data")
}
socket.on("ping") { _, _ in
print("ping received")
}
socket.connect()
}