health kit observer query always called when the app becomes active - ios

The resultHandler of HKObserverQuery is always called when the app becomes active (background -> foreground)
But, I wrote the code of the query in didFinishLaunchingWithOptions method in AppDelegate.swift. I know the method is called when the app is launched not the app become active.
func application(application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
healthStore.authorizeHealthKit {
...
}
}
// other AppDelegate methods are empty
How do I make the handler of the query called only when my app is launched?

Why do you want to prevent the updateHandler from firing?
You can't control when the updateHandler of an HKObserverQuery fires while the query is running. You can prevent it from being called at all by stopping the query. It is designed to be called whenever there might be new HealthKit data matching your predicate. You should design your updateHandler such that it doesn't matter when it is called.
If you really wanted the observer query to not fire when your app returns to the foreground, you would need to stop the query completely with -[HKHealthStore stopQuery:] when your app enters the background, before it suspends.

Related

How to track the time a user listens an specific podcast

I have an iOS app that is about podcasts and I want to track how long a user listens every podcast. I have tried the basic - when a user plays I save the timestamp and when stops it sends an event with the timestamp difference but it obviously doens't work because there's many edge cases.
I have issues to know when a user has the app in background and stops listening at some point through the the system controls. Also when the user or the system kills the app without tapping on "pause" or "stop". I think these 2 cases are my main non-tracked cases so far.
Any idea how can I build a working solution? I don't want/can't pay an external service - I am merely relying on Firebase.
Thanks!
You can override applicationWillTerminate method in your app, and save a current user progress to UserDefaults.
As docs say, you have few seconds to do it:
This method lets your app know that it is about to be terminated and
purged from memory entirely. You should use this method to perform any
final clean-up tasks for your app, such as freeing shared resources,
saving user data, and invalidating timers. Your implementation of this
method has approximately five seconds to perform any tasks and return.
Your code can look like this:
var player: AVPlayer!
func applicationWillTerminate(_ application: UIApplication) {
UserDefaults.standard.setValue(player.currentTime().seconds, forKey: "curPlayerTime")
}
Then, on application launch, you can restore it:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if let lastPlayerTime = UserDefaults.standard.value(forKey: "curPlayerTime") as? Double {
// update your player
}
return true
}

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 - Call method when any app starts

I want to call an action which will get called every time any app start.
Example:
Showing a modal with app name saying Welcome to Twitter.
you can add that action in this method of app delegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
perfornAction()
return true
}
There are 2 methods in which you can write your code.
applicationWillEnterForeground: Gets called when you app comes into picture after INACTIVE or TERMINATED state
didFinishLaunchingWithOptions: Gets called when app gets called for first time. Also this method will get called when app is in terminated state and you open the app.
So if you want to perform it every time when app opens, prefer applicationWillEnterForeground. And for first time user call same method in didFinishLaunchingWithOptions with some flag value(Set it to true when your code runs successfully) so that your method will not get called twice.

iOS run async method on background task?

Stack Overflow. Here is what I´m dealing with.
I´m developing an iOS 8 app that starts monitoring significant location changes when app is terminated using startMonitoringSignificantLocationChanges(). Until here everything works fine. The app relaunches when it get a location change with the application:didFinishLaunchingWithOptions:. I configure a CLLocationManager object and get the CLLocation like it says in Apple reference:
If you start this service and your app is subsequently terminated, the
system automatically relaunches the app into the background if a new
event arrives. In such a case, the options dictionary passed to the
application:willFinishLaunchingWithOptions: and
application:didFinishLaunchingWithOptions: methods of your app
delegate contains the key UIApplicationLaunchOptionsLocationKey to
indicate that your app was launched because of a location event. Upon
relaunch, you must still configure a location manager object and call
this method to continue receiving location events. When you restart
location services, the current event is delivered to your delegate
immediately. In addition, the location property of your location
manager object is populated with the most recent location object even
before you start location services.
Like I said, this works pretty well. My problem is when I try to fetch data from a web service (like Twitter API with TwitterKit) with a asynchronous method; I just not get onto the completion handler. I was researching a lot about this subject and I read that apparently the method I use is running in its own thread.
Here is how I listen to the location change launch and create the background task:
var locationManager: CLLocationManager!
var bgTaskId: UIBackgroundTaskIdentifier!
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// API keys configuration
if let options = launchOptions {
if options[UIApplicationLaunchOptionsLocationKey] != nil {
self.bgTaskId = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({ () -> Void in
UIApplication.sharedApplication().endBackgroundTask(self.bgTaskId)
self.bgTaskId = UIBackgroundTaskInvalid
})
// Location manager configuration
// Async func
theAsyncRequest(){ (response) -> Void in
//
// NEVER GETS HERE
//
UIApplication.sharedApplication().endBackgroundTask(self.bgTaskId)
self.bgTaskId = UIBackgroundTaskInvalid
}
}
return true
}
// Some code when app launches the normal way
return true
}
I tried the same with a synchronous method like in Parse Framework eg. let objects = someQuery.findObjects() and it worked. But it doesn´t with an asynchronous method.
What do I´m missing in here? Is it possible what I´m trying to accomplish? I know this would be an easy task if I´d use a synchronous method.
Thanks in advance.

SourceKitService Crashed in Xcode 6.1.1

I started having an issue with Xcode 6.0.1 where the error "SourceKitService Crashed Crashlog generated in ~/Library/Logs/DiagnosticReports" started popping up and all syntax highlighting was gone in Swift. Then Apple released a new update Xcode 6.1.1 where mentioned this issue was resolved. So I updated my Xcode to 6.1.1 but this problem still exists. I my case the issue is just staying there and never disappearing.
I tried few solutions found in StackOverflow like deleting the content of: DerivedData/ModuleCache, cleaning up the project etc but the issue still exists.
I am not able to make a build and whenever I try to get these 2 errors.
/Users/MY_PROJECT/AppDelegate.swift:11:1: 'UIApplicationMain' class must conform to the 'UIApplicationDelegate'
protocol at UIApplicationMain in my AppDelegate.h file and this Command failed due to signal: Segmentation fault: 11
Here is the code of my AppDelegate.swift
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
return true
}
func applicationWillResignActive(application: UIApplication!) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application: UIApplication!) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(application: UIApplication!) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication!) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(application: UIApplication!) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
I'am not sure about the cause of this error, i was getting this sourcekit crash for various reasons. For you if you look into UIApplicationDelegate methods, they are slightly changed in the signature. For eg UIApplication parameter is not optional now.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
return true
}
So if you compare your delegate methods with new UIApplicationDelegate methods(if you command+click you can check the method signature)and make changes you may get rid off this error. Give a try.

Resources