Detecting inactivity (no user interaction) in iOS

2019-07-23 08:12发布

问题:

How to detect inactivity or no user interaction in iOS App. For showing separate Screen like an Overlay or something like a screensaver. With the following link link that used to present screen overlay when the app became inactive I'm able to show the screen saver in the app. But with normal dismiss view controller code not being able to dismiss the presented view controller.

 we are presenting the custom overlay using

// The callback for when the timeout was fired.
    func applicationDidTimout(notification: NSNotification) {

       let storyboard = UIStoryboard(name: "MyStoryboard", bundle: nil)
              let vc = 
 storyboard.instantiateViewControllerWithIdentifier("myStoryboardIdentifier")
        UIApplication.shared.keyWindow?.rootViewController = vc       
    }

The problem that we are facing in this is. Once the View is presented we are not able to dismiss or remove the view controller.

回答1:

From @Prabhat Kesara's comment and @Vanessa Forney answer in the helper link. I come with the below solution and it is working fine. If someone comes with the requirement like this they can use this

import UIKit
import Foundation

extension NSNotification.Name {
    public static let TimeOutUserInteraction: NSNotification.Name = NSNotification.Name(rawValue: "TimeOutUserInteraction")
}

class UserInterractionSetup: UIApplication {

    static let ApplicationDidTimoutNotification = "AppTimout"

    // The timeout in seconds for when to fire the idle timer.

    let timeoutInSeconds: TimeInterval = 1 * 60 //5 * 60 //

    var idleTimer: Timer?

    // Listen for any touch. If the screen receives a touch, the timer is reset.

    override func sendEvent(_ event: UIEvent) {

        super.sendEvent(event)


        if idleTimer != nil {

            self.resetIdleTimer()

        }

        if let touches = event.allTouches {

            for touch in touches {

                if touch.phase == UITouch.Phase.began {

                    self.resetIdleTimer()

                }

            }

        }

    }


    // Resent the timer because there was user interaction.

    func resetIdleTimer() {

        if let idleTimer = idleTimer {

            // print("1")

            let root = UIApplication.shared.keyWindow?.rootViewController

            root?.dismiss(animated: true, completion: nil)

            idleTimer.invalidate()

        }


        idleTimer = Timer.scheduledTimer(timeInterval: timeoutInSeconds, target: self, selector: #selector(self.idleTimerExceeded), userInfo: nil, repeats: false)

    }

    // If the timer reaches the limit as defined in timeoutInSeconds, post this notification.

    @objc func idleTimerExceeded() {

        print("Time Out")
         NotificationCenter.default.post(name:Notification.Name.TimeOutUserInteraction, object: nil)

        let screenSaverVC = UIStoryboard(name:"ScreenSaver", bundle:nil).instantiateViewController(withIdentifier:"LandingPageViewController") as! LandingPageViewController

        if let presentVc = TopMostViewController.sharedInstance.topMostViewController(controller: screenSaverVC){


            let root: UINavigationController = UIApplication.shared.keyWindow!.rootViewController as! UINavigationController

            if let topView = root.viewControllers.last?.presentedViewController {

                topView.dismiss(animated: false) {

                    root.viewControllers.last?.navigationController?.present(presentVc, animated: true, completion: nil)

                }

            }else if let topViewNavigation = root.viewControllers.last {

                topViewNavigation.navigationController?.present(presentVc, animated: true, completion: nil)



            }

        }

    }

}

the difficulty I was faced was presenting overlay or screensaver above an already presented a view. That case, also we are handling in the above solution. Happy coding :)