Pushes open tracking with Parse - ios

I have implemented the push open tracking like described here https://parse.com/docs/ios/guide#push-notifications-tracking-pushes-and-app-opens.
If i open the push on the device, in the parse dashboard, the push opens number is updated on the previous push sent.
For example, if i send the push "Hello" twice and open it twice on the device, the push opens will be 1 for the first push, 0 for the last one.
I can reproduce it if the app is in background or if it's closed.
I use the latest pod Parse (1.11.0) and the application is in Swift.
The source code :
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
if application.applicationState == .Inactive {
PFAnalytics.trackAppOpenedWithRemoteNotificationPayload(userInfo)
}
}
I tried with the following code to check if the BFTask is completed. Everything is fine and the task has the completed status.
PFAnalytics.trackAppOpenedWithRemoteNotificationPayload(userInfo).continueWithBlock({ (task) -> AnyObject! in
assert(task.completed, "task should have completed")
assert(!task.cancelled, "task should not have been cancelled")
assert(!task.faulted, "task should not complete due to error or exception")
return task
})
Did someone experience the same issue ?

Related

How to resolve these CloudKit Background Task Warnings

I have a functioning iOS app that is producing some troubling warning messages and I'd like to resolve them.
From the console:
Background Task 37 ("CoreData: CloudKit Import"), was created over 30 seconds ago. In applications running in the background, this creates a risk of termination. Remember to call UIApplication.endBackgroundTask(_:) for your task in a timely manner to avoid this.
This warning is repeated periodically, however, each time with a different Task Id. I presume that if I can capture the Task Id, I could figure where to call
UIApplication.endBackgroundTask(_:)
I do not know if it's possible to obtain the Task Id. I do have a notification observer set to check for data changes. I'd prefer not to remove that.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
OperationQueue.main.addOperation({ () -> Void in
self.fetchProjects()
})
}

Why async / long running operations in BackgroundTasks don't work?

Trying to use BackgroundTasks for iOS 13+. Long running operations don't seem to work:
// in AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
BGTaskScheduler.shared.register(forTaskWithIdentifier: "foo.bar.name", using: nil) { task in
print("start!")
task.expirationHandler = {
// Not executed
print("expired!")
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
// Not executed
print("finish!")
task.setTaskCompleted(success: true)
}
}
return true
}
func applicationDidEnterBackground(_ application: UIApplication) {
BGTaskScheduler.shared.cancelAllTaskRequests()
let request = BGProcessingTaskRequest(identifier: "foo.bar.name")
request.earliestBeginDate = nil // or Date(timeIntervalSinceNow: 0) or Date(timeIntervalSinceNow: 5)...
do {
try BGTaskScheduler.shared.submit(request)
} catch let e {
print("Couldn't submit task: \(e)")
}
}
I also tried using a queue with Operation (for which I modeled my flow synchronously). This also didn't work. As soon as there's something that takes a while to complete, it gets stuck.
It doesn't log anything else to the console, no errors, no expired task message. It shows the last message before the long running operation and that's it. I confirmed that it doesn't move forward by storing a preference and examining it when restarting. It's not stored.
I added "foo.bar.name" to the info.plist (in "Permitted background task scheduler identifiers") and enabled capabilities both for background fetch and background processing. I'm testing on an iPhone with iOS 13.3.1 and using Xcode 11.4.1.
Additional notes:
I've been starting the tasks immediately as described here: https://developer.apple.com/documentation/backgroundtasks/starting_and_terminating_tasks_during_development
I also tested with Apple's demo project. It shows the same problem: The database cleaning operation doesn't complete (I added a log at the beginning of cleanDatabaseOperation.completionBlock and it never shows).
A couple of observations:
You should check the result code of register. And you should make sure you didn’t see your “Couldn't submit task” log statement.
Per that discussion in that link you shared, did you set your breakpoint immediately after the submit call? This accomplishes two things:
First, it makes sure you hit that line (as opposed, for example, to the SceneDelegate methods).
Second, if you just pause the app manually, some random amount of time after the app has gone into background, that’s too late. It has to be in that breakpoint immediately after you call submit. Then do e command. Then resume execution.
Anyway, when I do that, running your code, the BGProcessingTaskRequest ran fine. I’m running iOS 13.4.1 (and like you, Xcode 11.4.1).

Swift - didReceiveRemoteNotification - PromiseKit

Can I use PromiseKit in AppDelegate - application:didReceiveRemoteNotification method?
I am using GCM to push notification from the server. Once the app receives the notification I would like to fetch some data from the server, parse it, massage it and then save it using Core Data.
Am using PromiseKit to chain the steps together and its working fine when you manually refresh the data with a swipe down on TableViewController. However, when I use the same logic to refresh data on push notification from the sever, the behaviour is unpredictable, sometimes the execution stops at firstly(), other times it executes couple of then blocks and then nothing.
Basically this is what I would do:
func application( application: UIApplication,
didReceiveRemoteNotification userInfo: [NSObject : AnyObject],
fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void) {
firstly() {
// fetch data (JSON) from server
}.then {
// Parse the JSON
}.then {
// Sync the db (using Core Data)
}.then {
// Raise local Notification
}.error {
}
}
Obviously, looks like the control exists the didReceiveRemoteNotification method before all the Promises are fulfilled.
PromiseKit gurus, any suggestions? The only thing I can think of is to rewrite the code without PromiseKit for sequential operation.
PromiseKit is an asynch library.
All your then blocks are executed asynchronously. The method didReceiveRemoteNotification will return before your then blocks are called.
If you want to make a synch call, you should not use promisekit!

Parse Push Notification Payload nil in didFinishLaunchingWithOptions

Parameters: iOS 9.1, iphone 5S, xcode 7.1, Swift 2, Parse SDK 1.9.0
I am trying to capture push notification messages sent via Parse for all states of the receiving device (i.e. foreground/background/not loaded/device turned off). For all cases, my device receives the push notifications but in some cases the payload/userInfo dictionary does not arrive.
For situations where:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void)
is called (e.g. app in foreground) in the AppDelegate, the userInfo dictionary is received correctly and I can save the message, issue a notification & display it in an appropriate ViewController.
However, where
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
is called in the AppDelegate (e.g. if device is turned off and the push notification banner is "swiped" to open the App), the payload obtained from the statement:
if let notificationPayload:NSDictionary = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary
is always nil and I cannot complete the same actions as above.
The statements that generate the push are:
push.setData(["alert" : message, "badge": "Increment", "content-available": NSNumber(integer: 1)])
push.sendPushInBackground()
where message is a String containing the message to be displayed.
I have read numerous posts on SO, etc. & tried various ways to solve this but cannot find a solution. Any ideas/assistance would be greatly appreciated. I can post more code if necessary but I am basically following the standard approach from Parse examples & other SO posts.
RB

WKInterfaceController.openParentApplication is delayed on real device?

I've been tracking this bug for days and finally realized the issue is that there is an actual delay with WKInterfaceController.openParentApplication. I am not referring to the callback in the Apple Watch, but the AppDelegate event in the iPhone.
Here's what I'm doing in the Apple Watch:
override func awakeWithContext(context: AnyObject?) {
var userInfo = [
"test": 123
]
WKInterfaceController.openParentApplication(userInfo, reply: nil)
}
Then in the iPhone, I'm doing this in AppDelegate:
func application(application: UIApplication, handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]?, reply: (([NSObject : AnyObject]!) -> Void)!) {
let test = userInfo["test"]
// Do something
}
The problem is when I call WKInterfaceController.openParentApplication, there is a 2 or 3 second delay before the handleWatchKitExtensionRequest event is triggered in the iPhone. This is problematic if the user performs an action on their watch really quickly and puts down their arm right after. I can't assume the user is going to hold up their arm for 3 seconds until the watch sends the command.
Here's the catch: if the user wakes up the watch, the command still doesn't get sent to the iPhone.. UNTIL the user opens up the original app that sent the WKInterfaceController.openParentApplication. I don't think any of this would be a problem without this catch, the command should be queued until the watch is awakened, not awakened AND reopen the app.
Any workaround that can be done for this? I plan on logging this as a bug, but wanted to see if anyone has any thoughts or experience with this?

Resources