Is Facebook Caching FBAppEvents - ios

I'm trying to integrate FBAppEvents. I've already created my app and all I need to do now is call FBAppEvents logEvent:
However, I want to know if I need to cache my Events just in case logging wasn't successful due to sudden connection loss or something. If I'm caching them, my app could resend the events.
If FB is caching events and handling failed events on their own, then that would be awesome.
If not, then I would need to create my own event caching. Sadly, I couldn't find callback methods to inform me that events were successfully logged or not. Is there a way I could do to achieve what I want?

From the FBAppEvents documentation page: https://developers.facebook.com/docs/reference/ios/current/class/FBAppEvents
Events are not sent immediately when logged. They're cached and
flushed out to the Facebook servers in a number of situations:
when an event count threshold is passed (currently 100 logged events). when a
time threshold is passed (currently 15 seconds). when an app has gone
to background and is then brought back to the foreground.
Events will be accumulated when the app is in a disconnected state,
and sent when the connection is restored and one of the above 'flush'
conditions are met.

Related

Why Apple Health app is an inactive data source?

I'm developing app based on Health Kit and after some time it stopped receiving completion blocks from HealthKit. In Health app it figures as inactive data source and is not listed in apps allowed to read data, despite permission to read it is switched on.
Is there a way to fix that?
Is it because of query limit, some app blacklisting?
I couldn't find any documentation about this state.
If you were using HKObserverQuery, it will try three times (at increasing time intervals) before giving up and no longer sending notifications of new data. You may need to execute the completionHandler passed with the notification earlier; there is some dispute as to how much time can pass before the block is executed for a successful response to the notification.
I don't know how to clear the inactive application state; presumably, deleting the application from Health and then asking for permission again should do it.

Track Google Analytics Event in applicationWillTerminate

I want to track when the user closes the app. For this I send an event to google analytics in applicationWillTerminate. However this event never reaches the server. However the documentation states:
If a user loses network access or quits your app while there are still hits waiting to be dispatched, those hits are persisted in local storage. They will be dispatched the next time your app is running and dispatch is called.
Hence I would assume, that even if it does not manage to dispatch the tracked event in applicationWillTerminate it would do so on restart, after some time. Unfortunately it does not.
Next I tried to call GAI.sharedInstance().dispatch() to force Google Analytics to dispatch the event, but it also did not.
Do I miss something, or is it simply not possible to track events in applicationWillTerminate?
If your application terminates, there is simply no time to make a network connection. applicationWillTerminate is for frontend uses for most occurrences.
You might store a variable in UserDefaults when the application terminates and send the request with the data stored there after the next app launch.

Flurry: how to call -logEvent:withParameters:timed: when session ends?

I'm working with the Flurry API for iOS and I've come across a use case that doesn't seem to be supported:
I'm starting a timed event with -logEvent:timed: to track how long a user spends on a view. While the user is on that view a few parameters are being tracked that I plan to pass along to -endTimedEvent:withParameters: when the user navigates away from the view).
Here is the tricky part, if the user backgrounds the app while on the view, Flurry will automatically end the timed event after 10s without setting any parameters. One solution of course is to observe UIApplicationWillResignActiveNotification and call -endTimedEvent:withParameters: myself. However, I'd like to respect Flurry's setSessionContinueSeconds property and not end the event until the session is over. This way if the user returns to the app within 10s they are still under the same event that is tracking their time on the view.
Is there a way to do this?
For instance, is there a delegate method called when the session willEnd/didEnd where I could manually call -endTimedEvent:withParameters: before Flurry does? or alternatively is there a way to append parameters to a timed event while it is active (without ending it). That way when Flurry ends the session, the event already has the parameters set.
1) Flurry has a feature (only on iOS) to allow sessions to continue into the background that you can try for this use case.
[Flurry setBackgroundSessionEnabled:Yes]
You can find more details about these and other methods in the Analytics readme document that is included with our SDK.
[Flurry setBackgroundSessionEnabled:(BOOL)backgroundSessionEnabled];
This option is disabled by default. When enabled, Flurry will not finish the session if the app is paused for longer than the session expiration timeout. The session report will not be sent when the application is paused and will only be
sent when the application is terminated. This allows for applications that run in the background to keep collecting events data. The time application spends in the background contributes to the length of the application session reported when the application terminates.
[Flurry pauseBackgroundSession];
This method is useful if setBackgroundSessionEnabled: is set to YES. It can be called when application finishes all background tasks (such as playing music) to pause the session. A session report is sent if setSessionReportsOnPauseEnabled is set to YES. If the app is resumed before the session expiration timeout, the session will continue, otherwise a new session will begin.
2) You can keep the data in an array and place the parameters into a separate event that triggers after the timed event instead.

Schedule UILocalNotification based on changes to Core Data

I'm making a simple app with a Today Widget extension that logs events.
The user can tap a button in the app or the related Today Widget to log an event. These events are saved with Core Data any time the button is pressed either place.
Whenever a new event is logged in the app, I run a function called updateLocalNotificationsFromCoreData(). It handles the setup of UILocalNotifications based on the most recent event in Core Data after clearing the appropriate existing notifications.
However, when a new event is logged from the Today Widget, I can't use this function because I need to register the Local Notification with UIApplication.sharedApplication().scheduleLocalNotification(), and UIApplication is not available in the Today Widget extension.
I realize I'll probably need do something unconventional or hacky to get this working, so I'm trying to evaluate possible approaches and come up with a relatively robust solution.
Basically, I want to find a way I can call my
updateLocalNotificationsFromCoreData() function right away any time a new event is logged.
If I can't do it every time an event is logged, an alternative would be to trigger the updateLocalNotificationsFromCoreData() function periodically (somewhat frequently) another way. Here are some solutions I was thinking about using, but I don't like any of them:
Do it in AppDelegate when the app is launched (or another state change)
One approach I'm thinking about is running my updateLocalNotificationsFromCoreData()function in AppDelegate somewhere, like didFinishLaunchingWithOptions.
The downside is that it would require the user to open the app periodically. If the user didn't open it much the notification behavior would be inconsistent. I'd prefer a solution where a user could interact with only the Today Widget and reliably get Local Notifications without ever opening the app.
Sync the events to a server and use Push Notifications
I've thought about syncing the data in Core Data to a server, then setting up Push Notifications to the user's phone based on that.
I don't like this, because I want the user to still be able to get notifications without an Internet connection. It also introduces a lot of extra overhead of syncing the data with a server.
Ping a server, and send a content-available Push Notification
When someone logs an event with the widget, I could ping a server. That server could send back a silent content-available push notification to trigger the app to run updateLocalNotificationsFromCoreData() in the background.
I found a similar question (Scheduling local notification from within a Today extension) where one answer proposes a similar solution. Unlike the previous solution, an Internet connection is not needed to receive the notifications, but an Internet connection would be required to make sure the notifications are up to date when a new event is logged.
Background fetch
I thought about using Background Fetch to fetch something arbitrary from a server, then run the updateLocalNotificationsFromCoreData(). This would be a way to trigger the update in the background, although it seems silly to fetch data if that data isn't being used, and seems like something for which an app could be rejected. There also seems to be a risk of the system not calling the background update regularly if the user doesn't open the app much and mostly uses the Today Widget.
Use background location updates
This seems like the dumbest approach, but I thought I would mention it anyway since I thought about it. I could use one of the low accuracy background location update modes to trigger updateLocalNotificationsFromCoreData().
It would require the user to allow location in the background, which would be hard to explain. And, it would require the user to at least move around a few blocks to trigger the function, which could provide an inconsistent user experience. Also, it would increase power consumption of the app for a silly reason.
I'd really appreciate fresh ideas about how I might be able to reliably schedule local notifications when Core Data changes on a device that doesn't have an Internet connection!
Or, if that doesn't seem possible, I'd appreciated feedback on which approach seems to make the most sense.
EDIT: I came up with a new solution. It's not ideal, but I think it's better than these other approaches I was considering. When someone taps the button to log the event, I launch the full app. It's annoying because I have all the data I need at that point to give the user feedback and log the event within the Today Widget without launching the app, but by launching the app I have the opportunity to check and schedule local notifications.
Also, in iOS 9 the annoyance on the user is slightly minimized because the system-wide "back" button will appear and let the user go back to the previous app easily once my app has launched from the Today Widget.
In the future I may try a solution where one of the server-based approaches above is used when an Internet connection is available, and I would then fall back to this system of opening the app only when the network connection is not available and I need to schedule the local notifications within the app.

why are my new flurry parameters not showing up?

I have been tracking flurry events in my iOS app and they show up in the dashboard. I tried to add a new parameter to an existing event, and then activated the event on my phone a bunch of times yesterday, but I still don't see any occurrences of the new parameters on that event in the dashboard.
Does flurry not allow you to add new parameters to an existing event?
We noticed this too a little bit ago, and emailed support#flurry.com about it. Here's what they said:
Typically, Flurry sessions never completely report back to Flurry until the next time the app is launched. So, be sure to launch the app one more time after you complete a testing session. Furthermore you should make sure you launch the same build of the app. If you make a new build between sessions you may be removing incomplete sessions before they get reported. If you are running tests via an emulator, please ensure that the home button is pressed before closing the app. Then you should relaunch the app one more time with the same build to ensure all session data is reported.
If the app pauses or moves to the background for more than 10 seconds, the NEXT time the app runs, Flurry agent will automatically create a new session and end the previous session. Otherwise, Flurry agent will continue the same session. This can be updated via the setSessionContinueSeconds method. If the app is terminated, a new session will be created when the app runs again.
When we receive the complete session data (after the app is relaunched) the event logs should update first within 10 minutes or so. Please allow about 6 hours for this to populate to the dashboard, parameters pie chart etc.
Basically, what we were doing is just booting up the app, doing the thing that would send an analytic event, then quitting the app or whatever. Which wasn't giving the flurry agent enough time to actually send the event. (turns out that, contrary to the log events, flurry wasn't sending the log event right then :/)
Hope that helps!
The Flurry SDK only communicates with our servers twice per session. The first time is when the session is started and sets the timestamp for the session, counts a new user or updates an existing user as active. The second time is when the session ends and all event data is sent in one batch.
In cases where we do not receive the second report we refer to this as an "incomplete session". This arises in a few scenarios but mainly
-No network connection when the session ends
-The app is sent to the background for >10 seconds and the session continues running
In these cases the event data is stored on the device's disk and sent the next time the app is launched.

Resources