1

I am building a workout timer in my app. Workflow is:

  1. User hits "start timer" button
  2. Timer counts down for 90 seconds
  3. Timer ends after 90 seconds and triggers PlayAlertSound to vibrate

This only works if the app is open, and I don't expect my user to be looking at my app when the timer reaches 0. I can send a notification, but then I'm sending dozens of notifications over the course of a single workout. Personally, I don't like having lots of notifications from a single app. It feels noisy.

Is there a way to have the app send a vibration while the app is closed without sending a notification?

I tried to ask for background resources so my timer runs after closing the app, but even if the timer continues to run, it won't fire the vibration until I open the app, i.e., the user needs to be looking at their phone.

Here is my code:

class TimerViewController: UIViewController {

@IBOutlet weak var startTimerButton: UIButton!
@IBOutlet weak var timerLabel: UILabel!
@IBOutlet weak var resetTimerButton: UIButton!

var timer = NSTimer() 
let timeInterval:NSTimeInterval = 0.05
let timerEnd:NSTimeInterval = 90
var timeCount:NSTimeInterval = 0.0

var backgroundTaskIdentifier: UIBackgroundTaskIdentifier?

override func viewDidLoad() {
    super.viewDidLoad()
}

@IBAction func startTimerButtonTapped(sender: UIButton) {
    backgroundTaskIdentifier = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({
        UIApplication.sharedApplication().endBackgroundTask(self.backgroundTaskIdentifier!)
    })

    if !timer.valid { 
        timerLabel.text = timeString(timeCount)
        timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval,
                                                       target: self,
                                                       selector: #selector(TimerViewController.timerDidEnd(_:)),
                                                       userInfo: "Time is up!!",
                                                       repeats: true) //repeating timer in the second iteration
    }

}

@IBAction func resetTimerButtonTapped(sender: UIButton) {
    timer.invalidate()
    resetTimeCount()
    timerLabel.text = timeString(timeCount)
}

func resetTimeCount(){
    timeCount = timerEnd
}

func timeString(time:NSTimeInterval) -> String {
    let minutes = Int(time) / 60
    //let seconds = Int(time) % 60
    let seconds = time - Double(minutes) * 60
    let secondsFraction = seconds - Double(Int(seconds))
    return String(format:"%02i:%02i.%02i",minutes,Int(seconds),Int(secondsFraction * 100.0))
}

func timerDidEnd(timer:NSTimer){
    //timerLabel.text = timer.userInfo as? String
    //timer that counts down
    timeCount = timeCount - timeInterval
    if timeCount <= 0 {  
        timerLabel.text = "Time is up!!"
        timer.invalidate()
        AudioServicesPlayAlertSound(kSystemSoundID_Vibrate)
        //pushNotification()
    } else { //update the time on the clock if not reached
        timerLabel.text = timeString(timeCount)
    }

}
//    
//    func pushNotification() {
//        let notification = UILocalNotification()
//        notification.alertAction = "Go back to App"
//        notification.alertBody = "This is a Notification!"
//        notification.fireDate = NSDate(timeIntervalSinceNow: 1)
//        UIApplication.sharedApplication().scheduleLocalNotification(notification)
//    }
//    

}
briancl
  • 171
  • 13

1 Answers1

0

Unfortunately it's not possible to wake up your app when a local notification is received - and that's a good thing, otherwise it would be abused a lot.

But you can play audio in background like this: How to Play Audio in Background Swift?

Try to play 90 seconds of silence, and then play your alarm sound.

Community
  • 1
  • 1