2017-05-26 51 views
3

我有一個應用程序,由於它播放音樂往往保持清醒的背景;然而,由於連接問題或用戶將音樂靜音,如果由於連接問題導致歌曲之間的音樂停留時間超過預期(可能時間相對較短),則極少數情況下,應用程序將被暫停。我知道UIApplicationExitOnSuspend,但不同於它的描述,這實際上是在進入背景時退出。我已經做了相當數量的研究,我知道沒有進入暫停狀態的系統通知。UIApplicationExitOnSuspend掛起不是背景

是否有無法識別離開暫停狀態該應用程序被暫停?另外還有什麼辦法可以做類似UIApplicationExitOnSuspend的事情,除非應用程序實際上被暫停而不僅僅是當它進入後臺?

+0

你似乎已經在這裏想到的東西,很可能將是不可能的,因爲沒有委託方法通知您從後臺到暫停的狀態轉換。文檔明確表示您應該「準備暫停」。與其試圖專注於此,我會尋找一種方法來防止由於連接問題或延遲而離開後臺狀態,並相應地調整問題。 :)如果這是一個不夠快的下載任務,請嘗試調整它,讓這裏的人知道你做了什麼以及如何停止(導致操作系統認爲你完成並暫停你)。 – Gero

回答

2

您可以嘗試在UIApplication上使用backgroundtimeremaining屬性,並在某個時間間隔內用定時器輪詢它,並且該值是否足夠接近零 - 設置標誌,甚至可以檢查userDefaults中的值在回到前景之後未被設置?

The documentation reads:

此屬性包含應用必須在後臺運行之前,它可能會被系統強行殺死了的時間量。當應用程序在前臺運行時,此屬性中的值保持適當的大。如果應用程序使用beginBackgroundTask(expirationHandler :)方法啓動一個或多個長時間運行的任務,然後轉換到後臺,則會調整此屬性的值以反映應用程序運行的時間量。

+1

感謝您的建議,我最終做出了一個小班,每隔一段時間遞增一次。每當應用程序從後臺返回時,它會檢查距離實際時間有多遠,這似乎確定應用程序是否被暫停。 –

0

我結束了創建一個小班,以確定當應用程序已經進入暫停狀態:

class SuspendedMonitor { 
    static let shared = SuspendedMonitor() 

    var delegate: SuspendedMonitorDelegate? 

    private let Interval = 10.0 

    private let MaxDelta = 2.0 

    private var _timestamp: Double 

    private var _timer: Timer? 

    private init() { 
    _timestamp = timeInMs() 
    } 

    public func start() { 
    _timestamp = timeInMs() 

    NotificationCenter.default.addObserver(
     self, 
     selector: #selector(enterForeground), 
     name: NSNotification.Name.UIApplicationWillEnterForeground, 
     object: nil 
    ) 

    NotificationCenter.default.addObserver(
     self, 
     selector: #selector(enterBackground), 
     name: NSNotification.Name.UIApplicationDidEnterBackground, 
     object: nil 
    ) 
    } 

    @objc func enterForeground() { 
    checkSync() 
    _timer?.invalidate() 
    } 

    @objc func enterBackground() { 
    _timestamp = timeInMs() 
    setupTimer() 
    } 

    @objc func incrementTime() { 
    _timestamp = _timestamp + (Interval * 1000) 
    } 

    private func setupTimer() { 
    _timer = Timer.scheduledTimer(
     timeInterval: Interval, 
     target: self, 
     selector: #selector(incrementTime), 
     userInfo: nil, 
     repeats: true 
    ) 
    } 

    private func checkSync() { 
    if timeInMs() - _timestamp > ((Interval + MaxDelta) * 1000) { appSuspended() } 
    } 

    private func appSuspended() { 
    delegate?.appDidSuspend(self) 
    } 

} 

protocol SuspendedMonitorDelegate: class { 
    func appDidSuspend(_ monitor: SuspendedMonitor) 
}