I can get CKSubscription work using CKNotificationInfo() and CKNotificationInfo.alertBody. So I can send one piece of information. I'm trying to make CKSubscription send the user something like message, username, location, etc in a dictionary format. I've dabbled with CKNotificationInfo.alertLocaliztionKey and CKNotificationInfo.alertLocaliztionArgs but just can't seem to make it work. It feels like i'm missing something small because CKSubscription shouldn't be this troublesome to make it work.
Because that is not what is intended in the notification framework. What you do get back is information about WHAT has changed, and then you have to fetch this data and do what ever you want to do. I have made an app which both tells the user that something has changed and silently in the back refreshes the local data:
let cloudKitNotifiction = CKQueryNotification(fromRemoteNotificationDictionary: uif)
if cloudKitNotifiction.notificationType == CKNotificationType.Query{
if let recordId = cloudKitNotifiction.recordID{
let ccs = CloudCoreSynchronizer()
ccs.syncOneCustomerFromCloudToCore(recordId)
resetBadgeCounter()
}
}
To make this work you have to enable push notifications and background modes, if you want it to happen when the app is in the background.Hope this helps. PS: Just disregard the inapp purchase thing, it has nothing to do with this
Related
I wrote a custom Notification Content Extension for my Push Notifications like this:
The thing is, whenever the user is on a certain item in the carousel, I want the GO TO APP button to send a String to the app when it's opening, and from there, handle that string to move the user to the correct ViewController.
I already have the handling part inside the app, I just need to know how to pass that String from the Notification Content Extension to the container app.
Thanks! :)
Enable app groups in capabilities and use suite userDefaults to write the key and read it in the app
NSUserDefaults*defaults= [[NSUserDefaults alloc] initWithSuiteName:#"group.com.company.appName"];
// Write in extension
[defaults setObject:#"anyThing" forKey:#"sharedContent"];
// Read in app
[defaults objectForKey:#"sharedContent"];
If your app is configured for Universal Links or you have defined a Custom URL Scheme for your app, you can also open your app's URL (e.g. with data in query parameters) by calling
extensionContext?.open(url)
in your NotificationViewController.
iOS 13, Swift 5.
Based on the answer by Sh_Khan, here is some Swift Syntax. Obviously I have added App Group as a capability to the target of the main app + the target of the extension, naming the group as "group.ch.Blah" for this example.
Setting your app group, saving a string in our case, needed to set the type as Any cause strings not a type that is available in groups.
let localK = getPrivateKey64() as Any
let defaults = UserDefaults.init(suiteName: "group.ch.Blah")
defaults?.set(localK, forKey: "privateK")
Setting your app group, and reading the string back, needed to recast it back to string.
let defaults = UserDefaults.init(suiteName: "group.ch.Blah")
let localK = defaults?.object(forKey: "privateK") as? String
Worked perfectly with a notification service extension.
So, I have been coming across a problem where my Firebase app does not update user values when a user makes an update. To be more clear: Lets say user 1 has a photo of a dog and then changes it to a cat.
Once they change it to a cat, my node value in Firebase is successfully updated but the user themselves won't be able to see the change in other previously loaded areas in the app (other places with the dog picture) until they log out and then log back in.
For this reason I was wondering if there was any way to conduct a background app refresh that way all previous dog values in the app are changed to cat values without the user having to log out and then log back in. Please note that this same problem occurs not only with my user's profile picture but also any other user field I have setup.
Here is how I am updating a node value for my user in Firebase:
let storageRef = FIRStorage.storage().reference()
_ = FIRStorageMetadata()
let filePath = "\(FIRAuth.auth()?.currentUser?.uid)/\("userPhoto")"
let profileImageData = UIImageJPEGRepresentation(self.profilePicture.image!, 1.0)
if let data = profileImageData {
storageRef.child(filePath).put(data, metadata: nil){(metaData,error) in
if let error = error {
print(error.localizedDescription)
return
} else {
let downloadURL = metaData!.downloadURL()!.absoluteString
let userPhotoUpdateRef = FIRDatabase.database().reference().child("users").child(self.currentUser).child("userPhoto")
userPhotoUpdateRef.setValue(downloadURL)
}
}
}
If you have any questions please ask! Any help would be appreciated!
The Firebase SDK for Cloud Storage provides an easy way to read file from and write files to cloud storage. It does not provide a way to monitor those files.
The easiest way to provide a monitoring approach is to write the metadata of the files to the Firebase Realtime Database. See this short section in the Storage docs for a brief mention of that: https://firebase.google.com/docs/storage/ios/file-metadata#custom_metadata
When you write data to a location in the Firebase Database, all apps that are actively monitoring that location will be instantly updated. When they get that update, you can reload the image from Cloud Storage for Firebase.
I am developing a messaging app in iOS that could have an option for user to delay sending message for a specific amount of time ( ex. Send this text 5 hours latter) and I am using Firebase as my database. Anyone know how to achieve this functionality?
Specifically:
Every time sending a message I use Firebase.child(XXX).setValue(message)
to add a new message into firebase
Then use
Firebase.child(XXX).observeEventType(.ChildAdded,...
to get newly send message
Is there any way I could delay the setValue action for an amount of time and therefore achieve the functionality? Or there is better way to do it.
There is nothing like that in Firebase out of the box.
The easies solution for you here is to add filed like validFrom to your message and on client side to filter all messages by this field.
You can even add validTo field and make messages expire!
Its probably not a good idea to delay setting a value to your Firebase Database, You can with Timer but then you have to be sure that your app has to be still in running mode five hours after you have started the Timer. Which i think even you understand is a stupid idea.
But what you can do is set your value to your Database with a timestamp as a key.
While setting the value :-
let timeStamp = Int(NSDate().timeIntervalSince1970)
FIRDatabase.database().reference().child("your_path").setValue(["\(timeStamp)":"yourMessage"])
Where
timeStamp :- is your current timeStamp
yourMessage :- is your message
Whenever you wanna retrieve your message retrieve that message's timeStamp and check wether or not 5 hours have passed.
FIRDatabase.database().reference().child("your_path").observeSingleEventOfType(.Value, withBlock:{(snap) in
if let messageDict = snap.value as? [String:AnyObject]{
for each in messageDict{
let timeKey = Int(each.0) //your TimeStamp
let datePosted = NSDate(timeIntervalSince1970: TimeInterval(timeKey))
let elapsedTime_Hours = Int(NSDate().timeIntervalSince(datePosted as Date)/3600)
if elapsedTime_Hours >= 5 {
print("Five hours have passed and now the user can see the message")
}
}
}
})
I have a iPhone app using Swift 2 and Parse as a back-end. In my app people can like everybody else pictures (the same way you will do it in Instagram). The notification system works well and everytime someone like a picture, I'm sending a Parse notification to the picture owner like this :
let pushQuery:PFQuery = PFInstallation.query()
pushQuery.whereKey("user", equalTo: receiver)
let push:PFPush = PFPush()
let data = [
"alert" : message,
"badge" : "Increment",
"sound" : "default"
]
push.setData(data)
push.setQuery(pushQuery)
push.sendPushInBackground()
I'm facing a problem when I have a lot of users liking a picture in a short amount of time. The problem is that the receiver is flooded by Notifications and I don't want the receiver to have his phone vibrating (or ringing) 100 times in 5 minutes.
As I'm a new user using parse I have no idea if I have to modify some parameters in the server (Parse) of I have to do it programmatically (and I have no idea how to do this).
Anyone has an idea ? Thank you !
A possible solution. create an extra column in your parse table called lastPush. In this store the date and time of the last push. So when you send a push first check to see if there is a lastPush value, if not send one and store the time. If there is a date then check if it's in your range, you can decide if you want to send a push or not. If you do remember to save the new time.
I've spent two days no reading and testing as there is a lot of info about this topic.
Unfortunately I've found no solution yet. I can't implement my own authentication as this doesn't help with the issue I want to solve (see Backgrounding at the end of the question).
Here is my current best approach:
I'm generating a UUID thanks to https://stackoverflow.com/a/8677177/1443733 and storing it in the KeyChain as suggested with SwiftKeychainWrapper (https://github.com/jrendel/SwiftKeychainWrapper)
The short nice and sweet code for that is:
let stored = KeychainWrapper.stringForKey("UUID")
if stored != nil {
Helper.log(TAG, msg: "retrieved from keychain: \(stored!)")
} else {
let theUUID = CFUUIDCreate(nil)
let str = CFUUIDCreateString(nil, theUUID)
Helper.log(TAG, msg: "generated UUID: \(str)")
let ret = KeychainWrapper.setString(str, forKey: "UUID")
Helper.log(TAG, msg: "setkeychain: \(ret)")
}
But the UUID stored in the keychain seems to be per device and not per store ID as well.
When I store the UUID like above and login with a different Store ID on the device KeychainWrapper.stringForKey("UUID")still returns the value of the other user.
Isn't their a way to store a value in a store-id keychain?
It seems that I'm so close so I hope someone could point me in the right direction.
If that approach (with a keychain) can't succeed please let me know as well.
I reckon you can ask a different question as well: Is there some cryptic data I can read/generate or a store which changes with the Store Id currently used on a device?
Ohh... and Swift examples preffered ;)
Backgroundinfo:
I use IAPs in my app and want to save the Store-Id of the user once a refresh of the receipt is valid.
On each start of the app I check if the current Store-Id is the same as the saved one. If not I trigger immediately a refresh of the receipt. If it fails I fall back to the free version of the app.
iOS devices do not support multiple users.
If you want to differentiate between users you will have to do that in your app, perhaps with a user login. Then save a UUID per userID in the Keychain.
As NSUserdefaults temporarily stores the UUID.so,after unistalling the app and again installing,the UID changes. So, UUID must be stored in keychain