Hello everyone,
I’m developing an iOS application that uses WebSocket Secure (wss) to connect to a backend server, which is working correctly. The server is hosted on Render.com and accepts connections over https and wss.
Context:
• I can connect to the backend without issues using HTTPS from both the app and a web browser.
• Using Node.js and the Socket.IO client, the WebSocket connection to the server works correctly over wss://.
• The server is configured with a valid SSL certificate (the HTTPS connection is verified and works in a browser).
• The problem occurs when I try to connect from the iOS client (using Socket.IO in Swift) to the server through wss://social-gamer-backend.onrender.com. The connection consistently fails on iOS.
The Issue:
Even though the URL is correctly configured, and I can connect via Node.js, when I attempt to connect from the iOS app, I get connection-related errors. The most common error is:
Error while connecting to the socket: Tried emitting when not connected
• The server URL is correct (wss://social-gamer-backend.onrender.com).
• The JWT token is being sent correctly in the headers.
• There are no visible SSL certificate issues since the HTTPS connection works fine.
• I’ve tried enabling and disabling App Transport Security (ATS) in the Info.plist.
• From Node.js, the same connection code works fine, indicating that the WebSocket server is active and operational.
Current iOS Configuration:
let manager = SocketManager(socketURL: url, config: [
.log(true),
.compress,
.reconnects(true),
.forceWebsockets(true),
.extraHeaders(["Authorization": "Bearer (token)"])
])
What I’ve tried so far:
1. I’ve tested the connection on different networks, including Wi-Fi and mobile data.
2. I’ve checked the iOS device restrictions and disabled potential network limitations.
3. I’ve enabled detailed logs in Crashlytics, but I can’t find any relevant information indicating why the connection is failing.
4. The same URL with wss:// works on Node.js, so it’s not an issue with the WebSocket server.
Question:
What could be preventing the iOS app from establishing a successful connection to the WebSocket server over wss://? Is there anything else I should configure in the app or server to allow iOS to handle secure WebSocket connections?
I would appreciate any help or suggestions to resolve this issue.
Thank you in advance.
Networking
RSS for tagExplore the networking protocols and technologies used by the device to connect to Wi-Fi networks, Bluetooth devices, and cellular data services.
Post
Replies
Boosts
Views
Activity
There is a problem with the Apple local network setting api, iOS18 system, you turn off the local network permissions of the APP, uninstall the APP, and then re-install, the local network permissions even if opened, there is no effect, only restart the phone is useful
Hi,
Goal:
I want to change VPN configuration when app is closed and user joins unsecure wifi. (a wifi without a password).
Possible solution.
With help of an Hotspot helper I can listen the wifi changes when app is closed and if above criteria matches, execute code. (Start a new VPN Tunnel / change VPN configuration).
Questions.
Is this allowed.
Can we get hotspot helper entitlement for this kind of usage.
Is there other way to do this?
I have two applications (MinimServer and MinimWatch) that run on macOS. Both use the local network.
On Sequoia, starting MinimWatch for the very first time after installing Sequoia shows a prompt for permission to access the local network. If the user agrees, an enabled entry for MinimWatch appears in the Privacy & Security > Local Network section as expected.
If MinimServer is then started for the very first time, there is no prompt and the existing Local Network entry for MinimWatch now controls local network access for both MinimWatch and MinimServer.
If ths above order is reversed (start MinimServer first after installing Sequoia and then start MinimWatch), Local Network shows a single entry for MinimServer which controls network access for both MinimServer and MinimWatch.
It appears there is a false positive match when the second application is started. Sequoia finds the Local Network entry for the first application and incorrectly idenfies this as matching the second application.
Both applications are written in Java and have a similar internal structure. The app packages contain some identical files but the following files are different:
The bundle executable in the MacOS folder
Other executables in the MacOS folder launched by the bundle executable
The Info.plist keys CFBundleName, CFBundleIdentifier, CFBundleExecutable, CFBundleIconFile and JVMMainJarName
What might be the similarity between these app packages that is causing Sequoia to incorrectly identify one of these applications as being the other application?
According to the Apple documentation, if this value is NO, the Wi-Fi connection will be disconnected after the application is used for 30 minutes; but after actual testing, it doesn't happen. So what exactly is the specific function of UIRequiresPersistentWiFi? If the value of UIRequiresPersistentWiFi is NO, it will disconnect Wi-Fi. What conditions does the device need to meet or in which situations will it disconnect Wi-Fi?
We are developing an iOS app and are using Firebase's Auth module. During IPv6 network testing, we found that the app fails when calling Apple's login authorization in an IPv6 environment.
After investigation, we confirmed that the following two API calls:
https://gateway.icloud.com.cn:443/ckdatabase/api/client/record/save
https://gsa.apple.com/grandslam/GsService2
remain in a pending state.
We tested gateway.icloud.com.cn and gsa.apple.com and found that these two domains do not support IPv6 DNS.
What we would like to understand is whether these two domains truly do not support IPv6 DNS, and how we can implement Apple's login authorization in an IPv6 environment.
NETransparentProxyProvider having these two methods:
override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool
override func handleNewUDPFlow(
_ flow: NEAppProxyUDPFlow,
initialRemoteEndpoint remoteEndpoint: NWEndpoint
) -> Bool
During initial days when NETransparentProxyProvider was introduced,
We used handleNewFlow to handle NEAppProxyTCPFlow and handleNewUDPFlow to handle NEAppProxyUDPFlow .
Since handleNewUDPFlow is now deprecated, is it just okay to use handleNewFlow to handle both NEAppProxyTCPFlow & NEAppProxyUDPFlow?
will this works always or there are some scenario where keeping handleNewUDPFlow will be usefull?
I want to download some large files on watchOS and I found Apple Music app is able to download songs in background and pause downloading depending on battery life. Does there any way to do the same thing in my own app? After users choose to download, keep the downloading task in background and pause/resume on demand.
Hello 👋
I need to implement a logic for searching for devices with our own service type using Bonjour. Using the NWBrowser, I can receive a list of all devices and connect to them. I need to utilize a WebSocket connection. By the property endpoint of NWBrowser.Result objects I can create NWConnection. Below is my implementation which works fine on iOS 17:
let params = NWParameters.tcp
let webSocketOptions = NWProtocolWebSocket.Options()
params.defaultProtocolStack.applicationProtocols.insert(webSocketOptions, at: 0)
// The `endpoint` is from `browseResultsChangedHandler` of NWBrowser
let connection = NWConnection(to: endpoint, using: params)
However, it doesn't work on iOS 15 and 16 because of the crash:
2024-06-01 16:07:18.136068+0300 MyApp[591:16845549] [] nw_endpoint_get_url called with null endpoint
2024-06-01 16:07:18.136932+0300 MyApp[591:16845549] [] nw_endpoint_get_url called with null endpoint, dumping backtrace:
[arm64] libnetcore-3100.102.1
0 Network 0x000000018530e174 __nw_create_backtrace_string + 188
1 Network 0x000000018538ba20 nw_endpoint_get_url + 852
2 Network 0x0000000185310020 nw_ws_create_client_request + 84
3 Network 0x0000000184f4b3cc __nw_ws_create_state_block_invoke + 416
4 Network 0x000000018504bc68 nw_protocol_options_access_handle + 92
5 Network 0x0000000184f41e98 nw_ws_create_state + 204
6 Network 0x0000000184f41aec __nw_protocol_copy_ws_definition_block_invoke_2 + 176
7 Network 0x0000000184f69188 nw_framer_protocol_connected + 348
8 Network 0x00000001854a6638 _ZL29nw_socket_handle_socket_eventP9nw_socket + 1560
9 libdispatch.dylib 0x0000000126b89d50 _dispatch_client_callout + 16
10 libdispatch.dylib 0x0000000126b8d208 _dispatch_continuation_pop + 756
11 libdispatch.dylib 0x0000000126ba48d4 _dispatch_source_invoke + 1676
12 libdispatch.dylib 0x0000000126b94398 _dispatch_workloop_invoke + 2428
13 libdispatch.dylib 0x0000000126ba0b74 _dispatch_workloop_worker_thread + 1716
14 libsystem_pthread.dylib 0x000000012371f814 _pthread_wqthread + 284
15 libsystem_pthread.dylib 0x000000012371e5d4 start_wqthread + 8
Also, there is the stack trace of bt-command in the debug console:
* thread #20, queue = 'com.apple.network.connections', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
* frame #0: 0x0000000123078c24 libsystem_platform.dylib`_platform_strlen + 4
frame #1: 0x00000001803c538c CoreFoundation`CFStringCreateWithCString + 40
frame #2: 0x0000000185310030 Network`nw_ws_create_client_request + 100
frame #3: 0x0000000184f4b3cc Network`__nw_ws_create_state_block_invoke + 416
frame #4: 0x000000018504bc68 Network`nw_protocol_options_access_handle + 92
frame #5: 0x0000000184f41e98 Network`nw_ws_create_state + 204
frame #6: 0x0000000184f41aec Network`__nw_protocol_copy_ws_definition_block_invoke_2 + 176
frame #7: 0x0000000184f69188 Network`nw_framer_protocol_connected + 348
frame #8: 0x00000001854a6638 Network`nw_socket_handle_socket_event(nw_socket*) + 1560
frame #9: 0x0000000126b89d50 libdispatch.dylib`_dispatch_client_callout + 16
frame #10: 0x0000000126b8d208 libdispatch.dylib`_dispatch_continuation_pop + 756
frame #11: 0x0000000126ba48d4 libdispatch.dylib`_dispatch_source_invoke + 1676
frame #12: 0x0000000126b94398 libdispatch.dylib`_dispatch_workloop_invoke + 2428
frame #13: 0x0000000126ba0b74 libdispatch.dylib`_dispatch_workloop_worker_thread + 1716
frame #14: 0x000000012371f814 libsystem_pthread.dylib`_pthread_wqthread + 284
I have found out a couple things:
There are no crashes if I initialize the NWConnection object with using, for instance, the NWEndpoint.url(_:). initializer:
let urlHost = URL(string: "ws://10.20.30.40:5060")!
let endpoint = NWEndpoint.url(urlHost)
let params = NWParameters.tcp
let webSocketOptions = NWProtocolWebSocket.Options()
params.defaultProtocolStack.applicationProtocols.insert(webSocketOptions, at: 0)
let connection = NWConnection(to: endpoint, using: params)
self.connection = connection
But, in this case, I must extract IP-addresses 🙇♂️ Meanwhile, there is a topic such as Don’t Try to Get the Device’s IP Address..
I have tried to find anything that could help me move forward in this problem and run into some odd behaviour. There is a property skipHandshake of NWProtocolWebSocket.Options object. If I set the property value to true, there are no crashes as well as no connection to a device.
I'm trying to create a network extension packaged as a system extension on macOS,
let request = OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier: "com.example.Desktop.PacketTunnelDesktop",
queue: DispatchQueue.main)
request.delegate = delegate
// Submit the request to the system.
let extensionManager = OSSystemExtensionManager.shared
extensionManager.submitRequest(request)
The application is installed in /Applications, I have also turned off SIP and systemextensionsctl developer on
I'm not getting any breakpoint hits on my request delegate, but I am getting some logs in the console app:
making activation decision for extension with teamID teamID("XXXXXX"), identifier com.example.Desktop.PacketTunnelDesktop
no related kext found for sysex `com.example.Desktop.PacketTunnelDesktop`
extension XXXXXXX com.example.Desktop.PacketTunnelDesktop (1.0/1) advancing state from validating to validating_by_category
validate: category: com.apple.system_extension.network_extension, extension: com.example.Desktop.PacketTunnelDesktop
waiting for external validation of extension with identifier com.example.Desktop.PacketTunnelDesktop
It seems to stop here, and running systemsextensionsctl list shows:
[validating by category] as the status.
I'm trying to find some barebones example code for a network extension packaged as system extension but couldn't find any. Any ideas where to go from here?
I am developing an app designed for use in hospital environments where public internet access may not be available. The app consists of two parts: the main app and a Local Connectivity Extension. Both components rely on socket connections (TCP and UDP) to maintain communication with a server.
We have observed consistent disconnections occurring every 1-2 hours when app in the foreground (both extension and app), and would like to clarify Apple's guidelines regarding long-term socket connections. Specifically, is it permissible to keep a continuous socket connection (both TCP and UDP) active for an extended period? If so, are there any restrictions or best practices we should follow to ensure stable connectivity?
Thank you for your assistance.
Hi,
We are currently working on porting our PacketTunnelProvider app extension to run as a system extension. Things are mostly working great, but we're now testing upgrades from the existing app extension to a system extension.
We have an existing configuration that gets created and runs perfectly fine with the app extension. Then, when we go and upgrade to the system extension, and attempt to connect using the same existing configuration.
We see this error in the nesessionmanager logs:
10:00:57.717694-0700 nesessionmanager Signature check failed: code failed to satisfy specified code requirement(s) error
10:00:57.717914-0700 nesessionmanager Rejecting agent com.agentBundleID.bundleID because it does not satisfy the code signature requirements error
10:00:57.717937-0700 nesessionmanager Failed to launch com.agentBundleID.bundleID
If we create a new configuration profile in our upgraded app w/system extension it works fine. The problem only occurs with existing profiles.
Our app doesn't even get any notification about this error,
startVPNTunnelWithOptions:andReturnError: doesn't return any error that we can work with.
My gut tells me this has to do with the ProviderDesignatedRequirement not being correct, but I really have no way to confirm this at all. The NETunnelProviderProtocol has no way to specify that in its API. Our providerBundleIdentifier was unchanged between the two extensions.
Is there anything that we can do here? Or are we stuck re-creating the configuration profile after an upgrade?
In macOS 15 Sequoia (tested on 15.0 and 15.0.1), the icon of our network extension (and of other third party apps) is missing. See the attached screenshot, instead of the generic app icon there should be the icon of our app.
Is this a bug, or is there something we developers can/should do? I tried adding an asset catalog with the app icon, and specifying that using ASSETCATALOG_COMPILER_APPICON_NAME like we do in the main app. Even though the icon is added to the Resources folder of our .systemextension, and is referenced in the Info.plist using CFBundleIconFile and CFBundleIconName, the icon is still not showing in the System Settings.
I’m seeking clarification on why iOS prioritizes IPv6 when both IPv4 and IPv6 are available. Does iOS always default to using IPv6 in such scenarios? Is this happening by design as Apple developer docs never explicitly state the prioritization rules.
This might explain us why the issue doesn’t occur as frequently in IPv4-only environments
Hello Team,
I want to know if there's a way to uninstall System Extension without prompting the user for authorisation.
These are ways I found to uninstall System Extension
The deactivationRequest api prompts the user for uninstalling System extension.
If I use Apple script to drag and drop the application[which is embedded with System Extension] to trash also prompts the user.
The only workaround that doesn't prompt is by disabling SIP and using the systemextensionsctl uninstall command.
I want to know if there's any other solution that can uninstall System Extension without prompting the user for authorisation.
Thanks!
Hello everyone I'm new to swift and I can't quite figure it out yet:(
I am developing a simple online game for mac os that involves two players connected to the same WIFI. I need to constantly receive information from the server and I don't understand how to implement it. If I call the receive function indefinitely, then my program freezes. I realized that this should happen asynchronously, but that's just how my program understands when a package came from the server. I understand that I need a delegate or handler, but I don't understand how to do it. Please help me to add the receive function and everything that is necessary for it
import Foundation
import Network
enum CustomErrors: Error {
case DataError
case NetworkError
case DecoderError
case InvalidAddress
}
class TapperConnection: ObservableObject {
private var _serverAlive = false
private var connection: NWConnection!
private var serverPort: UInt16 = 20001
private var serverIp: String = "127.0.0.1"
private var _myDeviceName = Host.current().localizedName ?? ""
@Published var messageDc: [HostData] = []
@Published var messageLobby: [HostData] = []
@Published var messageState: GameData = GameData()
private var buffer = 2048
private var _inputData = ""
private var _outputData = ""
private var _myIp = ""
private var isServer = false
private var isClient = false
var myIp: String {
return _myIp
}
var myDeviceName: String {
return _myDeviceName
}
private func getMyIp() -> String? {
var address: String?
var ifaddr: UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else { return nil }
guard let firstAddr = ifaddr else { return nil }
for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let interface = ifptr.pointee
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
let name = String(cString: interface.ifa_name)
if name == "en0" || name == "en2" || name == "en3" || name == "en4" || name == "pdp_ip0" || name == "pdp_ip1" || name == "pdp_ip2" || name == "pdp_ip3" {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST)
address = String(cString: hostname)
}
}
}
freeifaddrs(ifaddr)
return address
}
private func isValidIP(_ ip: String) -> Bool {
let regex = try! NSRegularExpression(pattern: "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$")
return regex.firstMatch(in: ip, range: NSRange(location: 0, length: ip.utf16.count)) != nil
}
@Sendable
private func updateServerState(to state: NWConnection.State) {
switch state {
case .setup:
_serverAlive = true
case .waiting:
_serverAlive = true
case .ready:
_serverAlive = true
case .failed:
_serverAlive = false
case .cancelled:
_serverAlive = false
case .preparing:
_serverAlive = false
default:
_serverAlive = false
}
}
func createConnection() throws {
let ip = getMyIp()
if ip != nil {
serverIp = ip!
_myIp = ip!
} else {
throw CustomErrors.NetworkError
}
isServer = true
do {
try connectToServer()
} catch {
throw CustomErrors.NetworkError
}
}
func createConnection(ip: String) throws {
if isValidIP(ip) {
serverIp = ip
} else {
throw CustomErrors.InvalidAddress
}
let _ip = getMyIp()
if _ip != nil {
_myIp = _ip!
} else {
throw CustomErrors.NetworkError
}
isClient = true
do {
try connectToServer()
} catch {
throw CustomErrors.NetworkError
}
}
private func connectToServer() throws {
if isServer {
// ...............
// run server exec
// ...............
}
let _params = NWParameters(dtls: nil, udp: .init())
_params.requiredLocalEndpoint = NWEndpoint.hostPort(host: NWEndpoint.Host(_myIp), port: 20002)
connection = NWConnection(host: NWEndpoint.Host(serverIp), port: NWEndpoint.Port(rawValue: serverPort)!, using: _params)
connection.stateUpdateHandler = updateServerState(to:)
connection.start(queue: .global())
while !_serverAlive {}
do {
try send(message: "im:\(_myDeviceName)")
receive()
} catch {
print("Error sending disconnect message: \(error)")
}
}
func closeConnection() {
do {
try send(message: "dc:\(_myDeviceName)")
} catch {
print("Error sending disconnect message: \(error)")
}
_serverAlive = false
connection.cancel()
}
func send(message: String) throws {
var error = false
connection.send(content: message.data(using: String.Encoding.utf8), completion: NWConnection.SendCompletion.contentProcessed(({ NWError in
if NWError == nil {
print("Data was sent!")
} else {
error = true
}
})))
if error {
throw CustomErrors.NetworkError
}
}
func receive() {
self.connection.receive(minimumIncompleteLength: 1, maximumLength: 65535) { data, _, isComplete, _ in
if isComplete {
if data != nil {
let response: String = String(decoding: data!, as: UTF8.self)
var decodeData: Any
var messageType: MessageType
(decodeData, messageType) = try! Decoder.decodeMessage(response)
switch messageType {
case MessageType.lobby:
self.messageLobby = decodeData as! [HostData]
case MessageType.state:
self.messageState = decodeData as! GameData
case MessageType.dc:
self.messageDc = decodeData as! [HostData]
}
}
self.receive()
}
}
}
}
I am developing an application that allows you to interact with people on your local network.
I have a view called ProfileView() which has has identifiers inside of it such as that build up the profile for each person.
Essentially, what I want to do is discover people who are on this app on your local network, or who are nearby to you based on bluetooth. I do not want to use a server, as I would like this to be an application that does not require internet access to function. Also if possible, I would like a toggle to allow yourself to be discovered in the background, even if not using the app.
Any ideas how to do this? Also, is there any better way to do this instead of Bluetooth and Local Network?
Thank you
Possible code chunks needed:
Discover nearby bluetooth users
Discover nearby network users
Toggle for discovery
Toggle for background discovery (while not using app)
Share profile (mainly just text and a profile image)
Hi,
I upgraded my MacOs to 15.0. I work with maven in my environment. Normally, while running tests with maven in my environment in Sonomo 14.5, I was connecting to my test database environment with the postgresql library in the background.
But after the upgrade, I realized that maven could not do this.
After some research, I saw that this policy for applications was newly added at https://support.apple.com/en-us/121011.
So, starting from 15.0, we have to allow "Local Network" usage for each application.
But when I run the "mvn test" command from the terminal, it does not ask me if I allow Local Network usage and that's why my mvn test gets an error.
But in normal applications, the same transaction works differently; For example, if I use the terminal of VSCode.app, it pops up a popup asking if I allow it and I allow it.
Then, I see that this application has been added under Local Network.
I definitely think there is a bug here.
Even though I allowed the postgresql jdbc driver with the "socketfilterfw" command, it doesn't work. Even though I allowed maven, it doesn't come under "Local Network applications".
1- Here, there definitely needs to be an option to add an application to the "Local Network" screen.
2- We need to define the "Local Network" usage authorization for all my applications or the relevant user with a single permission.
The worst part here is for CI servers. There are too many application runtimes in CI. It is unnecessary to bother with authorizing all of them here.
Dear all,In macOS Catalina we have the new NetworkExtension framework that can filter network trafic on a computer.In my usecase I need the PID of the process that is the originator of the network flow. I'm aware that PID are not a reliable way to identify a process (since PIDs can be reused), but in my usecase only PID can identify what I need.In handleNewFlow(_ flow: NEFilterFlow) we can get the sourceAppAuditToken (flow.sourceAppAuditToken), where sourceAppAuditToken is a Data type. Is there a way to convert this sourceAppAuditToken to a PID value?I'm also aware of getting the signature of the process (eventually the Bundle ID) with SecCodeCopySigningInformation / kSecCSDynamicInformation, but again in my usecase it does not help.A way to do this is to call "netstat" and look for the local port in the output and get the PID from there, but sometimes this is not very reliable.Any ideas how to do this?Regards,Alex
Hi,
Is it possible to get NEDNSSettings to enable for only .wifi or only .cellular?
I tried using interfaceTypeMatch = .wifi standalone and I also tried it together with a NEEvaluateConnectionRule matching all domains but it skips using the EDNSSettings also on .cellular even if .interfaceTypeMatch is .wifi.
This is the more advanced example of the two and it seems to not care about the interfaceTypeMatch flag:
let evaluateRule = NEEvaluateConnectionRule(matchDomains: [], andAction: .neverConnect)
let evaluateConnectionRule = NEOnDemandRuleEvaluateConnection()
evaluateConnectionRule.connectionRules = [evaluateRule]
evaluateConnectionRule.interfaceTypeMatch = .wiFi
self.dnsManager.onDemandRules = [evaluateConnectionRule]
Should this be possible or does it only work with VPN?