Swift - didReceiveRemoteNotification - PromiseKit - ios

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!

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()
})
}

VOIP outgoing call from native call UI

Whenever I receive incoming call in my VOIP application I can see the logs on my native iPhone call UI.
I wanted to make outgoing call from native iPhone callog of UI by clicking last incoming call. Like it works for WhatsApp , Skype , hangout etc.
How is it possible for outgoing call ?
Below are the methods I wrote for incoming call :
-(void)reportIncomingCall:(NSUUID*)UDID handle:(NSString*)handle;
-(CXCallController*)startCall:(NSUUID*)UDID handle:(NSString*)handle
-(void)connectCallWithCallController:(CXCallController*)controller
I know there is one more method for outgoing call.But I don't know when to call this:
- (NSUUID *)reportOutgoingCallContactIdentifier:(NSString *)identifier destination:(NSString *)name telNumber:(NSString *)telnum
When tapping on an item in the native iOS Call log, the application delegate's continueUserActivity function is called. My implementation looks something like this in Swift:
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
self.startCallHandle = userActivity.startCallHandle
// Cache call handle here, and make call using cached call handle
// when applicationDidBecomeActive is called
return true
}
startCallHandle is defined in file NSUserActivity+StartCallConvertible.swift, as seen in the SpeakerBox sample project.
In your app's Info.plist, you must have INStartAudioCallIntent and/or INStartVideoCallIntent. Once again, see the SpeakerBox example app for details.

iOS: Why is fetch background function never fully executed?

My code in appdelegate for background fetch is never fully run. I have the background fetch option turned on and the plist updated.
I trigger the code by pressing Debug > Simulate Background Fetch
This is the code
func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
User.getNotifications(User.getUserDetails()["id"].string!, callback: {(notifications) in
//update notification badge count
notificationBadgeCount = X
})
}
'User.getNotifications' looks like this
getNotifications(id: String, callback...){
alamofire.request(.GET....){ jsonResponse in
//GETS HERE
callback(jsonResponse)
}
}
When triggering the simulated background fetch, the alamofire GET request is sent and data is returned (I've checked the server and the call is sent), however, the app seems to suspend at (//GETS HERE) in the getNotifications call, so the rest the code in the background fetch (//update notification badge count) is never run.
The code seems to time out. I'm supposed to get 30s however it seems to time out in 5s or something.
Any idea why that section of code isn't executed?
NOTE: If I re-open the app manually, then the rest of the code executes.
performFetch has an incoming function called completionHandler. You must call that function to complete the fetch and stop the countdown clock. You are not doing that and you thus are timing out and the app is suspended.

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

How to trigger communication with backend from Apple Watch?

I want to click on a push notification on my Apple Watch trigger communication with backend and show the results in a table on my Apple Watch.
I know how to show the result in a table on my Apple Watch. I also know the openParentApplication:reply: method.
But if I want to trigger my backend communication in application:handleWatchKitExtensionRequest:reply: I get a error that reply() is never called. It seems that iOS kill this method if it takes to much time.
If I test application:handleWatchKitExtensionRequest:reply: with a hard coded dictionary with only one entry, all works fine.
That is the recommended way to do this?
In my opinion I should do something in NotificationController.swift in didReceiveRemoteNotification method and app group but how can I trigger the backend communication on my iPhone?
UPDATE:
Part of my code in AppDelefate.swift:
func application(application: UIApplication!, handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]!, reply: (([NSObject : AnyObject]!) -> Void)!) {
var workaround: UIBackgroundTaskIdentifier?
workaround = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({
UIApplication.sharedApplication().endBackgroundTask(workaround!)
})
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), {
UIApplication.sharedApplication().endBackgroundTask(workaround!)
})
var realBackgroundTaks: UIBackgroundTaskIdentifier?
realBackgroundTaks = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({
reply(nil)
UIApplication.sharedApplication().endBackgroundTask(realBackgroundTaks!)
})
let testDict = ["Hello" : "World"]
reply(testDict)
UIApplication.sharedApplication().endBackgroundTask(realBackgroundTaks!)
}
This code works fine.
But if I change testDict to the backend communication code this method will killed.
Today I found the solution for my problem. You can not pass custom objects in the reply dictionary, you have to use primitive types.
The splution is described on the following page from Kristina Thai.
http://realm.io/news/watchkit-mistakes/
You'll need to start a background task on the iPhone to ensure your app isn't killed in the background before your API request can complete. I've shared some resources in a similar answer here: https://stackoverflow.com/a/29848521/3704092

Resources