iOS - Call method when any app starts - ios

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.

Related

App crashing [FIRApp appWasConfiguredTwice:usingOptions:]

iOS Extension - Fatal Exception: com.firebase.core Default app has already been configured.
enter image description here
From the message it is clear that FIRApp's configure function is called twice by your app. It is supposed to call once. The best place to call it, is in the func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool in your AppDelegate.
In order to identify from where it is being called you can use 2 approaches.
Press CMD + Shift + F and search for configure keyword and identify from the results.
Add a symbolic break point and app will pause when configure function get called. See the screenshots below:

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
}

Change initial View Controller from AppDelegate after async request

I want to change the initial view controller when the user starts the app, but only after I get the information on which one to present, from the server.
It goes like this somewhat like this:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseManager.getUserProfile() { user in
if user?.sports.count == 0 {
// present View Controller 1
} else {
// present View Controller 2
}
}
return true
}
After the call is made, I decide which VC to be shown, but, the problem is that return true is triggered synchronously at the start.
This results in an unpleasant user experience because it shows the initial storyboard (Login.storyboard, as configured in the info.plist) and only after the request has finished (after several seconds), it changes to the correct view controller. I want it to change directly to the view controller, without showing anything else before (even if it will required more waiting from the user).
How can I avoid this? What is the best practice when dealing with such a situation?
I would suggest using Firebase remote config parameters. It stores your data locally. And you can remotely manage it.
Or store value in UserDefaults of FirebaseManager.getUserProfile() beforehand.

Xcode showing multiple warnings in AppDelegate after updating to version 8?

I had updated my Xcode 7.3 to Xcode 8.
It is showing multiple warnings in AppDelegate. The warning is as follows.
Extraneous '_' in parameter: 'application' has no keyword argument name
My AppDelagate.swift file is this:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
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 invalidate graphics rendering callbacks. 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 active 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:.
}
}
when I followed the Xcode suggestion to remove _ in the functions that shows warning.
I got rid of the above warning. But now I get a new warning for
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
The warning is:
Non-#objc method 'application(_:didFinishLaunchingWithOptions:)' cannot satisfy optional requirement of #objc protocol 'UIApplicationDelegate'
I followed the solutions online. But had no luck in getting rid of this warning.
Any help would be appreciated.
Thanks.
Your code is correct for Swift 3. But the environment you are in clearly thinks it is supposed to be Swift 2, and that is the reason for the error messages.
It sounds as if you have accidentally opened the file in Xcode 7. That would explain it. Your code is now Swift 3. Xcode 7 is Swift 2; it does not know about Swift 3 and doesn't understand your code.
Now that you have converted to Swift 3, you can never use Xcode 7 with this project ever again.
Or maybe this is Xcode 8 but the legacy build setting is still on, so it thinks this is supposed to be Swift 2. But it isn't. It is Swift 3.

health kit observer query always called when the app becomes active

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.

Resources