Add dual communication into ConfiguringAWiFiAccessoryToJoinTheUsersNetwork Apple Example Codes Issue

Add above codes to Matt's [https://developer.apple.com/documentation/networkextension/configuring_a_wi-fi_accessory_to_join_the_user_s_network] sample to verify certified local network, Why not correct send to server ? Thanks any reply.

``**Button Action**`` SetupRemoveHotspotViewController
   @IBAction func sendDataBTN() {
   
     // This part get url info and create a valid WebSocket connection。
    
     if websocketConnection == nil,let connectionTuple = DeviceNetworkManager.shared.accessoryNetwork?.accessoryConnectionInfo {
   // (scheme: String, host: String, port: String, psk: String, pskIdentity: String)
   
    var urlComponents = URLComponents()
    urlComponents.scheme = connectionTuple.scheme
    urlComponents.host = connectionTuple.host
    urlComponents.port = Int(connectionTuple.port)

    guard let wsURL = urlComponents.url else {
        print("Failed to build a proper URL out of URLComponents")
        return
    }
        
    // Create the new NWConnection object.
    let tlsParams = NWParameters(psk: connectionTuple.psk, pskIdentity: connectionTuple.pskIdentity)

    let urlConnectionEndpoint = NWEndpoint.url(wsURL)
    let connection = NWConnection(to: urlConnectionEndpoint, using: tlsParams)

    let websocket = WebSocketConnection(newConnection: connection)
    websocketConnection = websocket
    websocket.delegate = self
    websocket.startConnection()
    
}

}

``**Delegation sendData **``SetupRemoveHotspotViewController
  extension SetupRemoveHotspotViewController: WebSocketConnectionDelegate {

/// @function didEstablishConnection
/// @discussion Automatically sends the network information when the app establishes a valid WebSocket connection.
func didEstablishConnection(connection: WebSocketConnection, with error: Error?) {

    let message = WebSocketMessage(ssid: DeviceNetworkManager.shared.getOriginalAssociatedSSID(),
                                   passphrase: "123456789", status: "", sendData: "TEST12345")

    connection.sendDataOnConnection(websocketMessage: message)
}


/// @function didReceivedData
/// @discussion Validates the response and instructs the user to remove the configuration (if it's still present from joinOnce).
func didReceivedData(connection: WebSocketConnection, with messageResponse: WebSocketMessage) {

    var instructionMessage = "\(messageResponse.ssid):\(messageResponse.passphrase)"
    if messageResponse.status == "ACK" {
        // Cancel the connection.
        connection.cancel()
        didPassNetworkDataSuccessfully = true
    }
}

}

Why not correct send to server ? Thanks any reply.

Thanks for bringing this up. I see that you made reference to SetupRemoveHotspotViewController, which on the iOS side and is the last ViewController in this workflow. Now, the important part about this is that once the original websocket connection goes through over on SetupSendDataViewController, the macOS NWListener will accept this connection, and then reject all other incoming connections on that listener. The reason for this is so that extra connections do not come in and interfere with the logic that is being run to while the accessory is setting itself up on the same Wi-Fi network the iOS device is on.

If you want to refactor this, take a look on the macOS side at the WebSocketListenerDelegate in BrandXAccessoryConfigureViewController:

// If a new connection comes in while an existing connection is ready, return.
guard websocketConnection == nil else {
	return
}
Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

Hi Matt, Thanks your replay. As you said, MacOS NWListener will ignore extra websocket connection without interfering with the running logic. But I added the button event in the last ViewController and copied the original websocket connection info and sent it to the server. Before sending, the state of NWConnection was 0x3d (waiting) .Normal it is 0x02 (ready). This may have caused me not to be able to send successfully main reason. Of course I am also trying to refactor the WebSocketListenerDelegate code on the macOS side.

func startConnection() {

        

        // Receive state updates for the connection and perform actions upon the ready and failed state.

        connection.stateUpdateHandler = { newState in

            switch newState {

            case .ready:

                print("Connection established")

                self.delegate?.didEstablishConnection(connection: self, with: nil)

                

            case .preparing:

                print("Connection preparing")

            case .setup:

                print("Connection setup")

            case .waiting(let error):

                // Attempt to account for a disallowed local network privacy prompt.

                if let currentPathDescription = self.connection.currentPath?.debugDescription {

                    print("Check local network privacy permissions: \(currentPathDescription)")

                    self.delegate?.didEstablishConnection(connection: self, with: error)

                } else {

                    print("Connection waiting: \(error.localizedDescription)")

                }

            case .failed(let error):

                print("Connection failed: \(error.localizedDescription)")

                

                // Cancel the connection upon a failure.

                self.connection.cancel()

                

                // Notify your delegate with an error message when the connection fails.

                self.delegate?.didEstablishConnection(connection: self, with: error)

            default:

                break

            }

        }

Thank you for the update. Were you able to get this issue resolved?

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

Yes ,thanks for your open source codes in Apple developer community. Maybe I haven't fully understood your code yet. I would like to ask for some help about the error code of NWConnection state. I comb out my thoughts and added two steps (13, 14)according to your steps. as below:

  1. Build and run the BrandXAccessory app.

  2. Build and run the BrandXAccessorySetup app on an iOS device, and associate the device with the user's network.

  3. In the BrandXAccessory app, click Next to embed the accessory network information in a QR code. A QR code appears with the following encoded network information:

    • SSID of the accessory network: AccessoryWiFi
    • Passphrase of the accessory network: embedded1
    • Service URL for NWConnection
    • TLS PSK
    • TLS PSK identity
  4. In the iOS app, tap Capture Accessory Network Info to bring up a QR code capture session.

  5. Point the iOS device's camera at the QR code in the BrandXAccessory app to capture, decode, and save the QR data. Tap Next.

  6. In the iOS app, tap Get Network Info to capture the user's network SSID. Tap Next.

  7. In the iOS app, tap Associate to Accessory Network. NEHotspotConfiguration creates a Wi-Fi configuration with the accessory's network data from the QR code, applies it to the device, and updates the device's screen when the association finishes. Tap Next.

  8. In the iOS app, tap Confirm Network to confirm the device's association with the accessory network. Tap Next.

  9. In the BrandXAccessory app, click Start Listener so the NWListener begins listening for incoming connections from the iOS app.

  10. In the iOS app, tap Enter Network Passphrase and enter the passphrase for the user's network. Tap Set Passphrase.

  11. In the iOS app, tap Send Network Data. The sample sends the passphrase to the BrandXAccessory app, along with the user's network SSID.

  12. In the BrandXAccessory app, the view displays the SSID and passphrase of the user's network.

  13. In the iOS app, tap Next, and Entry RemoveNetworkConfigurationViewController , add one SendData button, tap SendData button, after collection original websocket info send new data. (This time send data interface ocurrent error code 0x3d NWConnection state is waiting)

  14. In the BrandXAccessory app, get the new data info and refresh new data to label.

  15. final in the iOS app, tap Remove Network Configuration to disassociate from the accessory network and rejoin the user's network.

It looks like you are referring to the Run the Sample Code Project steps here. In these steps, they only go up to 13. Here is step 13 from the documentation:

  1. In the iOS app, tap Next, and then tap Remove Network Configuration to disassociate from the accessory network and rejoin the user’s network.

If you are asking about the .waiting state, then this is the state in which the local network privacy prompt can be displayed for the connection. When this happens, the connection will go into state .waiting.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Add dual communication into ConfiguringAWiFiAccessoryToJoinTheUsersNetwork Apple Example Codes Issue
 
 
Q