swift firebase onDisconnectRemoveValue not firing when turning off wifi - ios

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.

Related

iOS 14 StoreKit - SKCloudServiceController's requestusertoken not being called properly

I am trying to play songs on iOS 14 using Apple Music API.
I have the developer's token, and I have asked for the permission for accessing the user's apple music.
However, when I call requestusertoken api, its closure never gets called, so obviously I don't receive anything from the request - not even an error. It's driving me crazy.
Here is my code. What am I doing wrong?
func getUserToken() -> String {
var userToken = String()
let lock = DispatchSemaphore(value: 0)
SKCloudServiceController().requestUserToken(forDeveloperToken: developerToken) { (receivedToken, error) in
guard error == nil else { return }
if let token = receivedToken {
userToken = token
lock.signal()
}
}
lock.wait()
return userToken }
I've tried the code and there were two major problems.
First, DispatchSemaphore makes the return line execute too early. Second, original developer token doesn't work due to latest iOS 14.3 issue.
So, I first erased DispatchSemaphore.
func getUserToken() {
var userToken = String()
SKCloudServiceController().requestUserToken(forDeveloperToken: developerToken) { (receivedToken, error) in
guard error == nil else { return }
if let token = receivedToken {
userToken = token
print(userToken)
}
}
}
Then tweaked developer token following this repository.
Now, it's printing user token properly. I hope this helped.
I think we've all got stuck on the same tutorial. To fix, I put it on a different thread as the lock was holding up the main thread hence preventing the completion handler.
DispatchQueue.global(qos: .background).async {
print(AppleMusicAPI().fetchStorefrontID())
}
If it's the same tutorial, this will put the fetchStorefrontID() and the getUserToken() methods (which is called by the former) on a background thread and allow the completion handlers and the lock.signal() to occur.
If it's not, then this shall suffice for an answer:
DispatchQueue.global(qos: .background).async {
getUserToken()
}
Did you remove Bearer from your developerToken?
Okay so I know what's going on -- the DispatchSemaphore is being locked right after it's being created -- so it's never executing that code. Once I made the Semaphore value 1 instead of 0 it started to execute -- but then I had issues with the rest of the code because of the sequencing of events.
It looks like perhaps you're working with the same tutorial I was working through on Apple Music SDK integration -- if that's the case, I basically tweaked the code to :
download the user token to a local variable, and then the other methods begin to reference it in their requests.
Remove the Semaphore lock in the getuserToken() method only
The rest started working again, without having to change any other DispatchSemaphore values.
By no means am I an expert in how DispatchSemaphore works and best practices with apple music user tokens, but wanted to at least let you know why you were running into the same wall as me -- with no code being executed at all.

How can I check if the socket is connecting or not using Starscream?

I use Starscream. How can I check the socket is connecting or not?
isConnecting is a private property.
You should use socket.isConnected:
if socket.isConnected {
//socket is connected
}
In case if you want to check your socket is still alive (In case if you feel that it might be dead for example you are not receiving a packets stream you are suppose to get) then you can send ping, it will result in triggering websocketDidDisconnect method in case socket is gone. and Yes, You are right isConnected says that it was connected in the past so you can not rely on it.
func sendPing() {
guard let socket = socket, socket.isConnected
else { return }
socket.write(ping: "PING")
}

How to use observeSingleEvent in Firebase with callback when not connected?

I am building iOS App using Firebase, I found that the method observeSingleEvent(with or without cancel block) in Firebase would not even fire if the app is not connected to the network and there is no cached value for the location.
I need to show messages to users when the App lose connection to internet but no need to do it if there is cached value for the location when use keepSynced to it.
How can I do if the API without an error that can detect connect or not in return? Since the document says the cancelBlock will be called if you don't have permission to access this data, but it even not callback when the App without connection.
if and else statetment check your problem ? If it is connected, you will be call the observeSingleEvent function
let connectedRef = Database.database().reference(withPath: ".info/connected")
connectedRef.observe(.value, with: { snapshot in
if snapshot.value as? Bool ?? false {
print("Connected")
} else {
print("Not connected")
}
})
More detail : Detecting Connection State

OBEXFileTransferServices doesn't connect

I'm trying to write a macOS app that would connect to already paired the bluetooth phone and retrieves the list of address book entries and call records. This information should be available via standard OBEX interface. I'm relatively new to macOS development (although have enough experience with iOS development) and I have a feeling that I'm doing something wrong on a very basic level.
Here are snippets of my code:
First I'm finding particular paired Bluetooth device by its address
let paired = IOBluetoothDevice.pairedDevices()
let device = paired?.first(where: { (device) -> Bool in
return (device as? IOBluetoothDevice)?.addressString == "some_address"
}) as? IOBluetoothDevice
This actually works fine and I'm getting back valid object. Next, I'm picking up address book service and creating BluetoothOBEXSession for it
let service = device!.getServiceRecord(for: IOBluetoothSDPUUID(uuid32:kBluetoothSDPUUID16ServiceClassPhonebookAccess.rawValue))
let obexSession = IOBluetoothOBEXSession(sdpServiceRecord: service!)
This also works fine, I'm getting proper service object and session is created.
Next step (I would assume) is to create an OBEXFileTransfer session and do something (like checking current directory or retrieving the content of telecom/cch which supposed to have the list of combined outgoing and incoming calls:
let ftp = OBEXFileTransferServices(obexSession: obexSession!)
ftp!.delegate = self
if ftp!.connectToFTPService() == 0 {
NSLog("\(ftp!.currentPath())") // -- empty
ftp!.changeCurrentFolderForward(toPath: "telecom/cch")
NSLog("\(ftp!.currentPath())") // -- empty
ftp!.retrieveFolderListing()
}
I have added the following delegate's method to my view controller (to receive callbacks from OBEX FTS but they never get called:
override func fileTransferServicesRetrieveFolderListingComplete(_ inServices: OBEXFileTransferServices!, error inError: OBEXError, listing inListing: [Any]!) {
NSLog("Listing complete...")
}
override func fileTransferServicesConnectionComplete(_ inServices: OBEXFileTransferServices!, error inError: OBEXError) {
NSLog("Connection complete...")
}
override func fileTransferServicesDisconnectionComplete(_ inServices: OBEXFileTransferServices!, error inError: OBEXError) {
NSLog("Disconnect complete...")
}
override func fileTransferServicesAbortComplete(_ inServices: OBEXFileTransferServices!, error inError: OBEXError) {
NSLog("Abort complete...")
}
What am I doing wrong here?
I also could not find any good Bluetooth examples for macOS either, if somebody has good links, please do share.

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