Posts

Post marked as solved
7 Replies
Yes, TCP and Websocket, here is the send message: let info = // some String info guard let data = try? NSKeyedArchiver.archivedData(withRootObject: info, requiringSecureCoding: true) else { return } let message = NWProtocolWebSocket.Metadata(opcode: .text) let context = NWConnection.ContentContext(identifier: "send", metadata: [message]) connection.send(content: data, contentContext: context, isComplete: true, completion: .contentProcessed({ (error) in if let error = error { print("\(error.localizedDescription)"); return } print("Success") })) The NWListener, NWBrowser, and NWConnection all are initialized with let tcpOptions = NWProtocolTCP.Options() inside their NWParameters.
Post not yet marked as solved
8 Replies
Yes, they both have the same exact code. Btw neither device receives the echo but they both receive that first message. Here is startOutgoingConnection, actually here is PeerConnection because it is 1 class that has 2 initializers, one for outgoing and one for incoming. I put break points everywhere but nada on that 2nd incoming message. protocol PeerConnectionDelegate: class {     func sendOutgoing(_ connection: NWConnection)     func receivedIncoming(_ connection: NWConnection) } class PeerConnection: Hashable {     static func == (lhs: PeerConnection, rhs: PeerConnection) - Bool {         return lhs.connection?.endpoint.debugDescription == rhs.connection?.endpoint.debugDescription     }     func hash(into hasher: inout Hasher) {         guard let connection = connection else { return }         hasher.combine(connection.endpoint.debugDescription)     }     weak var delegate: PeerConnectionDelegate?     public var connection: NWConnection? // Outgoing     init(endPoint: NWEndpoint, delegate: PeerConnectionDelegate) {         self.delegate = delegate         let tcpOptions = NWProtocolTCP.Options()         tcpOptions.enableKeepalive = true         tcpOptions.keepaliveIdle = 2         let parameters = NWParameters(tls: nil, tcp: tcpOptions)         parameters.includePeerToPeer = true         parameters.allowLocalEndpointReuse = true         connection = NWConnection(to: endPoint, using: parameters)         startOutgoingConnection()     } // Incoming     init(connection: NWConnection, delegate: PeerConnectionDelegate) {         self.delegate = delegate         self.connection = connection         startIncomingConnection()     }     func startIncomingConnection() {         guard let connection = connection else { return }         connection.stateUpdateHandler = { [weak self](nwConnectionState) in             switch nwConnectionState {             case .preparing: print("preparing")             case .setup: print("setting up")             case .waiting(let error): print("\(error.localizedDescription)")             case .ready:                 self?.delegate?.receivedIncoming(connection)             case .cancelled:                 connection.cancel() // remove incoming connection from an array that holds it/them and remove corresponding cell             case .failed(let error):                 connection.cancel()                 // remove incoming connection from an array that holds it/them and remove corresponding cell             default:break             }         }         connection.start(queue: .main)     }     func startOutgoingConnection() {         guard let connection = connection else { return }         connection.stateUpdateHandler = { [weak self](nwConnectionState) in             switch nwConnectionState {             case .preparing: print("preparing")             case .setup: print("setting up")             case .waiting(let error): print(error.localizedDescription)             case .ready:                 self?.delegate?.sendOutgoing(connection)             case .cancelled:                 connection.cancel() // remove outgoing connection from an array that holds it/them             case .failed(let error):                 connection.cancel() // remove outgoing connection from an array that holds it/them             default:break             }         }         connection.start(queue: .main)     } } The connection isn't failing on either end/device because once it is cancelled I remove data from both devices which never happens after they both send and receive messages from each other. For example Device_A sends its info to Device_B and vice versa. I have a cell that shows the connection info String data like connection.endpoint.debugDescription and the uid from the opposite device. Once either device goes to the background and the connection is cancelled then both devices remove the corresponding cell. If the connection was cancelled after the initial send/receive then both cells (the cell on each device) would immediately disappear.
Post not yet marked as solved
8 Replies
@eskimo Thanks for the reply. Here are the successful print statements: The Initial Send does not send a color, it just sends some data like a String message : print("Sent") // successful After the Initial Send sends the message and it is first received, I didn't add a print statement for a successful reception but the code inside Receive data and send Echo response is successful, specifically if let data = data, !data.isEmpty { // successful only once } Inside there, the data that is decoded, only has the String message from above, the color isn't sent yet so the colorData decoding is skipped. However once the String message is received, I send an echo with the colorData connection.send(content: colorData, ... { } Inside the completionHandler of the echo, this print statement always runs: print("Color data sent") // successful At that point the other device, the Receive Data receives nothing, there isn't a response whatsoever. Nothing prints, it's as if the connection got cut off after the first reception. I put breakpoints everywhere but none of them get hit.
Post marked as solved
7 Replies
@eskimo ok thanks for the answer. I'll start a new thread about the issue that you just identified. As far as this one, how do I know who is talking to who by using self inside the receive(_:) method? Once a sender sends a message, I used these for the receiver to identify the sender: let endPointDescription = connection.currentPath?.localEndpoint?.debugDescription ... encode then send let remoteEndPoint = connection.currentPath?.remoteEndpoint?.debugDescription ... encode then send // they both get sent together This works fine when detecting when either end is cut off, for example if Device_A is connected to Device_B, if Device_B goes to the background the connection is cut and Device_A immediately knows about it. I haven't had any problems even when using 3 devices and 2 simulators. They all will know that Device_B has left the building and respond accordingly.
Post not yet marked as solved
8 Replies
I forgot to add the listener code let tcpOptions = NWProtocolTCP.Options() tcpOptions.enableKeepalive = true tcpOptions.keepaliveIdle = 2 let parameters = NWParameters(tls: nil, tcp: tcpOptions) parameters.includePeerToPeer = true parameters.allowLocalEndpointReuse = true
Post marked as solved
2 Replies
Thanks for the answer! Exactly what I was looking for :)
Post marked as solved
1 Replies
I got the answer from here: - https://github.com/fitomad/NearbyInteraction-Guide/blob/master/NearbyInteraction-Framework-Guide.md The distance is a Float type whose value is measured in meters: func session(_ session: NISession, didUpdate nearbyObjects: [NINearbyObject]) {		 		guard let object = nearbyObjects.first else { return }          		 		guard let distance = object.distance else { return }  		let meters = String(format: "%.2f m", distance) 		print("meters: ", meters) }
Post not yet marked as solved
1 Replies
I couldn't add these because the Edit button disappeared. 1- For clarity sendDataWhenNewDeviceIsDiscovered() {...} will run every time a new device is discovered but there will only be 20 sessions at a time. This won't stop it from running but the incomingData will never be added if the sessions are at 20. 2- In place of: var sessions = [MyAppUserID: NISession]() I used: var sessions = [String: NISession]() The problem is because the current user's userId is always the key, it will only have one key the will write always over its value self.sessions[currentUserId] = session I wasn't sure what was supposed to happen here. Did you mean: var sessions = [NISession: MyAppUserID]() or var sessions = [NISession: String]()
Post not yet marked as solved
1 Replies
It turns out this seems to be an issue with the simulator. I've been playing around and searching the internet for 12 hrs and nothing. I finally tried it out on my real device and 2 simulators. I sent the real device to the background and the connection.stateUpdateHandler's .failed and .cancelled worked fine on the simulators. On the reverse when I sent either of the simulators to the background the real device's connection.stateUpdateHandler didn't get hit. I don't have another real device on hand to try to see what happens with 2 real devices. This is a strange issue. Any ideas out there?
Post not yet marked as solved
5 Replies
Here is the reason for the the multiple call problem, which isn't a problem, as explained by @eskimo here: - https://developer.apple.com/forums/thread/654953 Apple’s connect-by-name API uses a fancy algorithm to run multiple connections in parallel to see which one connects first (see RFC 8305 for - https://tools.ietf.org/html/rfc8305 some background on this)
Post marked as solved
5 Replies
Here is the reason for the the multiple call problem, which isn't a problem, as explained by @eskimo here: - https://developer.apple.com/forums/thread/654953 Apple’s connect-by-name API uses a fancy algorithm to run multiple connections in parallel to see which one connects first (see RFC 8305 for - https://tools.ietf.org/html/rfc8305 some background on this)
Post marked as solved
5 Replies
I found the answer to my problem here - https://www.example.com/ @eskimo said: . TCP is not a message-oriented protocol, and thus  receiveMessage(…) doesn’t make any sense [1]. What you want is  receive(minimumIncompleteLength:maximumLength:completion:) And he is 100% correct, as soon as I changed signatures, the callback was entered: connection.receive(minimumIncompleteLength: 1, maximumLength: 8192) { [weak self](data, context, isComplete, error) in     print("\n*** call back entered *** ")     if let err = error {         print("Recieve error: \(err.localizedDescription)")         return     }     print("databytes", data?.count as Any)     if let data = data, !data.isEmpty {         print("Receive is complete")         self?.received(data, from: connection)     } } The multiple calls is still happening be that's another question that I'll ask in a different post. PS I don't know why I have 3 different usernames under the same account lsamaria - https://developer.apple.com/forums/profile/lsamaria is the same person as ohmannnnnn - https://developer.apple.com/forums/profile/ohmannnnnn who is the same person as lance145 - https://developer.apple.com/forums/profile/lance145
Post marked as solved
3 Replies
@theepicapple hi, was you able to get around this issue? I'm currently in the same situation
Post not yet marked as solved
6 Replies
I don't know how to edit my question but I forgot to add that I also have this set: playerItem?.preferredForwardBufferDuration = TimeInterval(1.0)
Post not yet marked as solved
8 Replies
I followed this answerhttps://stackoverflow.com/a/52666724/4833705Settings > Your Name (Apple ID, iCloud & App Store) > iTunes & App StoreThere you will find a section called "SANDBOX ACCOUNT" where you can sign out of the sandbox account you've been using.