How can I distinguish internal from external updates in Firebase - ios

I'm using iOS/Swift with Firebase as my backend.
When the value of a reference change, I get notified, because I'm adding an observer.
What I need is to be able to know when this change was triggered from my local code or from the server.

You can simply add a child to your reference which stores the uid of the user that updated the reference and compare it with the current app user

Related

How to send a Firebase Notification when new data is available to user?

I have a coaching app that has a section where I can push realtime updates out to the players like: "No Practice - Do to inclement weather, practice will be pushed until Friday"
I have been trying to figure out how to send automatic notifications when I update this UpdatesTableView with a new post. Like "New Update Posted".
I post my updates to the Firebase Database. There must be a way to listen for changes and when there is to push a notification out to all the users?
I already have firebase notifications set up in my app but I have to utilize the Firebase console to push these notifications every time i push an update. Does anyone know how to automate this? Thanks!
You can easily do that by listening/Observing to any data change at a particular location in firebase. If new child is added to that path, associated block will be called.
In your case, you can observe UpdatesTableView. and whenever you post any update, call the block which will send notification to all users.
If you are using Swift:
func observe(_ eventType: FIRDataEventType, with block: #escaping (FIRDataSnapshot) -> Void) -> UInt
If you are using Objective C:
- (FIRDatabaseHandle)
observeEventType:(FIRDataEventType)eventType
withBlock:(nonnull void (^)(FIRDataSnapshot *_Nonnull))block;
According to official firebase documentation :
observeEventType:withBlock: is used to listen for data changes at a particular location. This is the primary way to read data from the
Firebase Database. Your block will be triggered for the initial data
and again whenever the data changes.
And, Whenever you would like to stop listening to data changes, you can Use removeObserverWithHandle
Use removeObserverWithHandle: to stop receiving updates. - parameter:
eventType The type of event to listen for. - parameter: block The
block that should be called with initial data and updates. It is
passed the data as a FIRDataSnapshot. - returns: A handle used to
unregister this block later using removeObserverWithHandle:
For more and detailed information, Read iOS firebase#Attaching Observers to read data Documentation.
Also, For sending Notifications to users effieciently, you can use Firebase Notification. Have a look at it. i dont know about your usecase properly, But i think this will help.
I also stucked with same problem where I wanted to show notification to users whenever data changes in Firebase irrespective of application in foreground or background.
I achieved it by binding ChildEventListener with a service which keeps running in background. At every childAdded event data is stored in sqlited db and a new notification object is created and shown to user.

Firebase push conversion event

We have a app with 3 different flavours. We set them up to use firebase notifications with one project per flavour. So 3 apps from the same codebase each one with there own firebase project.
We also added a custom event that we enabled for conversion.
For one of the apps, when sending pushes I can select the custom event to be used as a conversion event with the push, and that works and tracks fine. For the other two I can select the custom event fine but when I try to send the notification I get a error:
"Unable to reserve a user property for Notification conversion funnel analysis for"
Anyone know why this occurs and how to resolve it?
I fixed it by adding a user property to the user properties tab in the analytics section of firebase console. The user property had nothing to do with the actual conversion event but adding at least one user property seems to have initialised something that made the conversion event selectable.

Handle Push Notification infos before login

My question is about a best practice to use to handle a push notification in a defined scenario.
My app has 3 ViewControllers:
Login: User authenticates to start using the app
TableView: A simple table view with a contacts like appearance
DetailView: A simple viewController containing details from selected row of TableView
I receive a remote notification with some info in the payload (let's say a phone number for example). I need to use that info on DetailView but at receiving time I'm not logged in (app not running), so I press notification and it opens my app (Login) but I need to keep somewhere notification payload (or an object created from it) and pass it to DetailView.
So question is:
what is best practice to pass data from the notification to an inner ViewController, if the notification is received before user is logged in?
My only solution right now is: evaluate an object in didReceiveRemoteNotification, keep it in AppDelegate and access it everytime user's login to open DetailView if object is present (and clean it after using of course) but I don't think it is a good one.
Any suggestion?
What you said is mostly right because the only place you will receive a notification in is your app delegate.
but keeping a global object with the data is not the right thing to do, specially if you would like to respect design pattern and isolation between the classes.
as I understand from you the data you will get in the payload will be used in other screens in the app, so what I think the best is :
save it in User defaults or data base and access it when ever you need, and keep overriding it every time you a new notification.
if you would like to use the data base option I would like to recommend you to use Realm as it way much easier than core data and didn't take much time implementing it.
Hint: if this is the only kind of data you gonna save in the app then use User defaults.
hope this answer your question
try to save this data in User Defaults then, when you are logged in, get the data from User Defaults. Second option - set some variable and initialize it whit this data, and after that pass the data to new ViewController/

iCloud + Core Data: First import and user's feeling of loss of data

I've implemented an iPhone application that has around 50k users. Switching from iOS7 to iOS8 a lot of these users have experienced a terrible feeling when they thought that they data get lost.
I've implemented the first-import behaviour that I thought was the one suggested by Apple
1) Users launch the App
2) iCloud, automatically, starts synching data previously stored on iCloud
3) At some point user get notified that data from iCloud is ready thanks to NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted
The problem is with 3) At some point:
Users that have to sync a lot of data need minutes to get the synch completed and in the meanwhile they think that their data is lost.
I really don't know how to let my users know that they have to wait to see their data synched, because I don't know when this operation starts.
I'm thinking about a possible solution:
During the first launch of the App, asking to the user if he wants to use iCloud. If he chooses to use it, building the database with iCloud options, so I know exactly that the synch is starting here (I suppose...)
I'm really not sure about how to implement this behaviour since I've always seen Core Data settings into the AppDelegate but to achieve this behaviour I suppose I need to move all the CoreData settings in a Controller.
What do you think about this solution? how are you working around this problem in you Apps?
Your idea is right, at least it is that what we do. But leave it in the appDelegate.
Differentiate between with iCloud and without iCloud when doing the "addPersistentStoreWithType". If you do it with iCloud options, it will directly start to build the local store which is a kind of a placeholder ( I'm sure you know that, but just to make my thoughts clear). As soon as this is done, the sync starts from iCloud. So this is the starting point I understood you were looking for.
You can watch that process using the notifications by NSPersistentStoreCoordinatorStoresDidChangeNotification and inform you user accordingly triggered by that notification.
If you look at "Reacting to iCloud Events" in the docs https://developer.apple.com/library/ios/documentation/DataManagement/Conceptual/UsingCoreDataWithiCloudPG/UsingSQLiteStoragewithiCloud/UsingSQLiteStoragewithiCloud.html#//apple_ref/doc/uid/TP40013491-CH3-SW5 there is a detailed desc.
To summarize, the event you're describing is part of the account transitions process. An account transition occurs when one of the following four events is triggered:
Initial import
the iCloud account used did change
iCloud is disabled
your application's data is deleted
During this event, Core Data will post the NSPersistentStoreCoordinatorStoresWillChangeNotification and NSPersistentStoreCoordinatorStoresDidChangeNotification notifications to let you know that an account transition is happening. The transition type we're interested in is NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted.
For information, I've moved all Core Data related code to my own Manager for simplicity and use it with a singleton design pattern. While setting up the singleton, I register the Manager for all relevant notifications (NSPersistentStoreDidImportUbiquitousContentChangesNotification, NSPersistentStoreCoordinatorStoresWillChangeNotification, NSPersistentStoreCoordinatorStoresDidChangeNotification, NSPersistentStoreCoordinatorWillRemoveStoreNotification).
I store several informations in my settings (NSUserDefaults or anything) like the last iCloud state (enabled, disabled, unknown), if the initial import is done or not, etc.
What I end up doing was having a prompt (UIAlertController or anything) to get a confirmation if the user wants to use iCloud or not. I have a displayICloudDialogAndForce:completion: method to do that and only do that if my iCloud state setting is unknown or I use the force parameter.
Then, after the user input, I call a setupCoreDataWithICloud: method, the iCloud boolean parameter depending on the user choice. I would then setup my Core Data stack, on the cloud or not according to the iCloud parameter.
If I'm setting up using iCloud, I would check my settings for the value of an iCloud imported key (boolean). If the value is NO, then I'm presenting a new modal to warn the user about the incoming import that could take some time.
I've registered my manager for different notifications and specially NSPersistentStoreCoordinatorStoresDidChangeNotification. In my storeDidChange: callback, I'm checking the transition type and if it's NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted, I'm changing the content of my modal to show the user that the import was successful and removing it a few seconds later, saving in my settings that the initial import is done.
- (void)storeDidChange:(NSNotification *)notification
{
NSPersistentStoreUbiquitousTransitionType transitionType = [notification.userInfo[NSPersistentStoreUbiquitousTransitionTypeKey] integerValue];
if (transitionType == NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted) {
[settings setDefaults:#(YES) forKey:kSettingsICloudImportedKey];
[ICloudModal dismissWithSuccess];
// ...
}
// Do other relevant things...
}

Can a pass in passbook be updated by an application or only by an APN?

If I have an application that creates a pass and the user adds it to the passbook, then is it possible for an application to update the content of that pass at a later time.
i.e. when the app runs can it update the pass with a new time trigger and new content, then when the trigger fires the user would get notified.
Or can an existing pass only be updated by an APN and nothing else?
I am not sure why the answer is accepted above as it is incorrect.
An app can update a pass without a push notification, providing that it has permission for the passTypeIdentifier and knows the pass serialNumber.
Passes need to be created and signed on a server outside of your app, but once your app receives the new .pkpass bundle, it can update the pass using the replacePassWithPass method of the PKPassLibrary class.
From the document linked above.
Your app downloads the new pass from your server and uses the
replacePassWithPass: method of the PKPassLibrary class to install it.
only by an apn AFAIK -- it needs to be re-signed so the signature is valid for the new content
see: https://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/PassKit_PG/Chapters/Apps.html#//apple_ref/doc/uid/TP40012195-CH6-SW1
Edit: as the user PassKit says, of course no PUSH Notification is required to update the Pass BUT the APN (here: YOUR access point => YOUR server) has to create the new data of the pass.

Resources