Unable to send files between 2 device using Network Framework - ios

I'm having trouble using network framework to transfer a collection of 1 minute video files between a recording device and a repository master device. All devices are on the same wifi. But the problem is that the distance between devices somehow is player a role in the transfer. When I have strong wifi signal on both devices, but if the devices are further than 100 feet apart, the transfer won't happen. Conversely, if both devices have very weak wifi signal (e.g. 1 bar), but are next to each other, the transfer happens without a hitch. It's as if the devices are doing something more akin to wifi direct than transfer for a LAN, which is what I really want. I'm assuming someone familiar with the framework can advise how to entirely avoid using any peer to peer wifi direct type of transfer, and force the system to transfer over the WLAN. That way all I need to do is make sure all devices have a decent wifi signal (e.g. are on the network with a decent connection), and regardless of how far they are physically from each other, the files will transfer without a hitch. Hope someone can clear this up for me.
Thanks.
Sending files between 2 devices at close range
disabled Bluetooth
Made sure both devices are on the same local network.
#Paulw11 - Thank you for the response, I have provided more details that I should have provided initially, I do apologize for that. Thanks again for the help.
We are using the mDNS approach.
func startBrowsing() {
guard browser == nil else { return }
let params = NWParameters()
params.includePeerToPeer = true
params.requiredInterfaceType = .wifi
let browser = NWBrowser(for: .bonjour(type: bonjourService, domain: nil), using: params)
self.browser = browser
browser.browseResultsChangedHandler = {
[weak self] results, changes in
guard let self = self else { return }
self.delegate?.peerBrowser(self, didUpdateResults: Array(results))
}
browser.stateUpdateHandler = { [weak self] newState in
guard let self = self else { return }
os_log("[browser] %#", newState.debugDescription)
switch newState {
case .cancelled:
break
case .failed:
os_log("[browser] restarting")
self.browser?.cancel()
self.startBrowsing()
case .ready:
break
case .setup:
break
#unknown default:
break
}
}
browser.start(queue: .main)
}
There are no such errors. I can see the standard communication is still working and because of that the sender(iPhone) will continue to send the files to iPad (receiver) with out fail but the receiver couldn’t able to receive it.
3.No
The code used to send data from one peer to another.
func sendMessage(type: UInt32, content: Data) {
guard connection?.state == .ready else {
return
}
let framerMessage = NWProtocolFramer.Message(messageType: type)
let context = NWConnection.ContentContext(identifier: "Message", metadata: [framerMessage])
connection?.send(content: content, contentContext: context, isComplete: true, completion: .idempotent)
}

Related

WiFi Packets Delayed on Real iPhone but not Simulator

I'm working on an app that connects to a device on the same local WiFi network. The device takes measurements and streams the data to the iPhone. The iPhone plots it in real time.
The problem I've run into is the iPhone delays the packets by up to 200ms every half second or so. This causes noticeable stutter in the UI that I'd like to eliminate.
I started debugging the issue by placing signposts in the code when packet is received.
Looking at the profiler, you can easily see the gaps in data.
Zooming in on the space after a gap, you can see a burst of packets received.
I've checked and it isn't dropping any packets. It is simply delaying them from my app.
The weird thing is this isn't an issue on the simulator or with the Android version of the app so I know it isn't an issue with the device or the WiFi network.
Here is the same code running on the simulator showing a much more even distribution of packets.
Has anyone experienced anything like this? Is this just some kind of battery saving limitation of the iPhone hardware? Is there anyway to ensure a more timely delivery of the data to my application?
I tried rewriting the connection using SwiftNIO and ended up with the same results. I've also tried changing the serviceClass parameter of the connection to all the possibilities with no change.
Here is the relevant connection code.
private func udpReceive() {
if udpConnection?.state == .ready {
udpConnection?.receive(minimumIncompleteLength: 1, maximumLength: Int(Hangboard.shared.BufferSize), completion: { content, contentContext, isComplete, error in
os_signpost(
.begin,
log: log,
name: "udpReceive",
signpostID: signpostID
)
Task {
if let content = content {
let _ = await asyncResult(for: Hangboard.shared.udpDataReceivedNative(data: content.toKotlinByteArray(), offset: 0, length: Int32(content.count)))
}
os_signpost(
.end,
log: log,
name: "udpReceive",
signpostID: signpostID
)
self.udpReceive()
}
})
} else {
disconnect(hadError: true)
}
}
private func startUdpListener(port: NWEndpoint.Port) {
let params = NWParameters.udp
params.allowFastOpen = true
params.serviceClass = .responsiveData
let listener = try? NWListener(using: params, on: port)
self.udpListener = listener
listener?.newConnectionLimit = 1
listener?.newConnectionHandler = { connection in
connection.parameters.serviceClass = .responsiveData
self.startUdpConnection(connection: connection)
}
listener?.start(queue: .global(qos: .userInteractive))
}
private func startUdpConnection(connection: NWConnection) {
self.udpConnection = connection
connection.stateUpdateHandler = { state in
switch state {
case .ready:
self.udpReceive()
case .failed(let error):
print("Connection error! \(error.localizedDescription)")
self.disconnect(hadError: true)
default:
break
}
}
connection.start(queue: .global(qos: .userInteractive))
}
Turns out the reason for this was because I was still running a Bonjour search in the background.
Disabling the search when connecting and restarting it on disconnect removed the latency issues.
Apple's tech support mentioned this can be a problem when includePeerToPeer is enabled on a connection.

swift firebase onDisconnectRemoveValue not firing when turning off wifi

I want to be able to remove a connection value from my app's real-time firebase database when they lose connection unexpectedly. This does not seem to be possible from what I have tried already.
I have tried using the "goOffline" function to properly close the sockets because from what I've heard, it doesn't close properly when you turn off your wifi.
func connect() {
let connectionsRef = self.rootRef.child("connections")
AF.request("https://projectname.cloudfunctions.net/Connect").response { response in
if response.data != nil {
if self.visiblename != nil {
connectionsRef.observeSingleEvent(of: .value, with: { snapshot in
for value in JSON(snapshot.value!).arrayValue {
if value["Address"].string! == self.visiblename {
let connectionRef = connectionsRef.child(String(value["Index"].int!))
connectionRef.keepSynced(true)
connectionRef.onDisconnectRemoveValue()
}
}
})
}
}
}
}
self.reachability.whenUnreachable = { _ in
Database.database().goOffline()
}
self.reachability.whenReachable = { _ in
Database.database().goOnline()
}
do {
try self.reachability.startNotifier()
} catch {}
It does automatically remove the value after around 60 seconds but I need my app to be able to handle any internet interruptions and remove the connection value quickly.
Also, if there is no available way to remove the value from the client when the client turns off their wifi. Is there a way to detect the disconnection from the server on the server itself? I have tried comparing date.getTime() to another date.getTime() variable that when you invoke the Connect request it updates the variable. Then the server watches but it didn't seem to work because for some reason it stopped watching the variable as soon as the client disconnected and doesn't have time to realize it. I assume this is because the server is based on cloud functions and has no reason to run when no clients are invoking it.

Firebase Storage Upload Fails in Adverse Network Conditions iOS

Firebase Storage claims here in its iOS documentation that it
performs uploads and downloads regardless of network quality. Uploads and downloads are robust, meaning they restart where they stopped
so one would expect it to handle a loss of connection when uploading, but it doesn't seem to.
With the following Swift code in iOS, I am able to perform an upload just fine when there is a connection, but if the device doesn't have a connection or if it is ever disconnected from the network it goes to the failure condition.
let storage = FIRStorage.storage().referenceForURL("VALID_URL_REMOVED")
let imagesRef = storage.child("images/test.jpg")
let data = UIImageJPEGRepresentation(observationImage!, 0.7);
let uploadTask = imagesRef.putData(data!, metadata: nil)
uploadTask.observeStatus(.Progress) { snapshot in
// Upload reported progress
if let progress = snapshot.progress {
let percentComplete = 100.0 * Double(progress.completedUnitCount) / Double(progress.totalUnitCount)
print("percent \(percentComplete)")
}
}
uploadTask.observeStatus(.Success) { snapshot in
// Upload completed successfully
print("success")
}
uploadTask.observeStatus(.Failure) { snapshot in
print("error")
print(snapshot.error?.localizedDescription)
}
The debug output for this code is as follows.
/*
percent 0.0
percent 0.0044084949781492
2016-06-30 11:49:16.480 Removed[5020:] <FIRAnalytics/DEBUG> Network status has changed. Code, status: 1, Disconnected
percent 0.0044084949781492
error
Optional("An unknown error occurred, please check the server response.")
*/
Firebase's Real Time Database offline storage is also set up with the following code, but I'm unsure of whether this is related.
FIRDatabase.database().persistenceEnabled = true
I have also tried manually setting the timeout as mentioned in the answers to this question using the following lines, with no change.
let config = FIRStorage()
config.maxUploadRetryTime = 1000000
Is there a way to have it handle these disconnects without implementing the functionality from scratch? Am I missing something?
You are missing observers. Right now you only observe .success and .failure events. Try add observers for .resume, .pause, .progress to handle different events.
// Listen for state changes, errors, and completion of the upload.
uploadTask.observe(.resume) { snapshot in
// Upload resumed, also fires when the upload starts
}
uploadTask.observe(.pause) { snapshot in
// Upload paused
}
uploadTask.observe(.progress) { snapshot in
// Upload reported progress
let percentComplete = 100.0 * Double(snapshot.progress!.completedUnitCount)
/ Double(snapshot.progress!.totalUnitCount)
}
uploadTask.observe(.failure) { snapshot in
if let error = snapshot.error as? NSError {
switch (FIRStorageErrorCode(rawValue: error.code)!) {
case .objectNotFound:
// File doesn't exist
break
case .unauthorized:
// User doesn't have permission to access file
break
case .cancelled:
// User canceled the upload
break
/* ... */
case .unknown:
// Unknown error occurred, inspect the server response
break
default:
// A separate error occurred. This is a good place to retry the upload.
break
}
}
}

Check if device is connected to the internet in Swift2

I'm trying to find a way to check to see if my application has a connection to the internet for my application. I've tried using the various Reachability libraries you can find on GitHub which cause compiling errors for my project. (Makes other libraries not available, for some reason) and I've also tried the JustHTTP library for making a GET request to http://www.google.com but it fails every time.
I'm not exactly sure what the issue is here, but I'd like to know how some of you go about validating a connection to the internet before allowing users to use the application.
This question was marked as a duplicated and linked to a question which used the Reachability library provided by AshleyMills. Which I had stated I've attempted using these libraries already, but could not do to confliction errors in my project. The GET request code provided on this question is also out of date, and does not work on SWIFT2. This linked question also assumes that I do not need to support anything under iOS 9 which seems like a bad practice. My minimum support is iOS8
Swift 2.x (requires Reachability)
do {
let reachable = try Reachability.init(hostname: "https:\\www.google.com")
if(reachable.currentReachabilityStatus == Reachability.NetworkStatus.ReachableViaWWAN){
//Device is connected thru 3G/4G/LTE
}else if(reachable.currentReachabilityStatus == Reachability.NetworkStatus.ReachableViaWiFi){
//Device is connected thru WiFi
}else{
//Device is not connected to the internet
}
}catch{
//Device is not connected to the internet
}
You can get Reachability here
Add Reachability.swift to your project.
And try below code.
do
{
let connected: Bool = try Reachability.reachabilityForInternetConnection().isReachable()
if connected == true
{
print("Internet connection OK")
}
else
{
print("Internet connection FAILED")
let alert = UIAlertView(title: "No Internet Connection", message: "Make sure your device is connected to the internet.", delegate: nil, cancelButtonTitle: "OK")
alert.show()
}
}
catch
{
print("Handle Exception")
}
This code might help. You need the Reachability lib, this snippet can give you an example to check if your device reaches Internet via WiFi or via 4G/3G/LTE
func checkNetworkStatus() -> Bool {
let reachability: Reachability = Reachability.reachabilityForInternetConnection()
let networkStatus = reachability.currentReachabilityStatus().rawValue;
var isAvailable = false;
switch networkStatus {
case (NotReachable.rawValue):
isAvailable = false;
break;
case (ReachableViaWiFi.rawValue):
isAvailable = true;
break;
case (ReachableViaWWAN.rawValue):
isAvailable = true;
break;
default:
isAvailable = false;
break;
}
return isAvailable;
}
If your request fail all the time maybe it's because you are not doing them over https but over http. It has to do with ATS on iOS 9 - this blog explains very well how to disable (if you want - not recommended) ATS http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/

How to check when ios device just lost connection to internet

how to detect losing connection to network as fast as it can be
now im using reachabitity framework for swift and it takes abouut 3 sec to detect that there is no network so user can make the app crash
here how i check it :
func setupReachability() {
do {
self.reachability = try Reachability.reachabilityForInternetConnection()
} catch {
print("Cannot setup reachability monitoring")
return
}
self.reachability!.whenReachable = { reachability in
self.loginButton(true)
}
self.reachability!.whenUnreachable = { reachability in
self.loginButton(false)
}
do { try self.reachability!.startNotifier() } catch {
print("Cannot start reachability monitoring")
return
}
print("Started reachability")
}
You always, ALWAYS, must handle errors in your connections. You absolutely cannot rely on Reachability. You also cannot rely that your connection goes to the server that you want to connect to. It is possible and practically happens a lot that you get a reply from a totally different server in a totally different format than you expected, and you need to handle that. (Take your app to the nearest Starbucks and check whether it survives).

Resources