ReactiveCocoa / ReactiveSwift

Streams of values over time

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Signal triggered by phone call when device is closed

zbencz3 opened this issue · comments

I run into an issue that puzzles me, so I am trying to see if others experience the problem, and if this is the expected behaviour.

I have the following SignalProducer:

    func clockSignal(_ interval: DispatchTimeInterval, leeway: DispatchTimeInterval) -> SignalProducer<NSDate, Never> {
        let timerSignal = SignalProducer.timer(interval: interval, on: clockScheduler, leeway: leeway)
            .startValue(Date())

        return timerSignal
            .map { $0 as NSDate }
            .skipRepeats() // this is necessary if a long-running sync has blocked a few cycles
            .observe(on: taskScheduler)
    }

If I close the device (not the app), and wait for 4-5 seconds or so, and place a call to the device the app is installed on from another device, the signal is triggered, and does the work. In case the pipeline uses a setup with NSFileProtectionComplete, this would cause the app to crash since we would try to access the files/DB while encrypted. (isProtectedDataAvailable: false)

Please see the sample project attached and a video (with sound) explaining what happens.
Sample project
Phone.zip
video recording:
PhoneCall.mov.zip

Please let me know if this is expected and I should find a workaround. This not used to be the case in the past I believe, I think it's not related to a recent change in the ReactiveSwift codebase, but maybe a behaviour change in the OS. I will try to gather supportive evidence for this claim.

Current pod versions:

  - ReactiveCocoa (12.0.0):
    - ReactiveSwift (~> 7.0)
  - ReactiveObjC (3.1.1)
  - ReactiveSwift (7.1.1)

Same happens on

  - ReactiveCocoa (11.2.2):
    - ReactiveSwift (~> 6.6)
  - ReactiveObjC (3.1.1)
  - ReactiveObjCBridge (6.0.0):
    - ReactiveObjC (~> 3.1)
    - ReactiveSwift (~> 6.1)
  - ReactiveSwift (6.7.0)
  - RXCollections (1.0)

UPDATE: just to clarity, the app is in the foreground when I lock the device.

Is the app in the background when the device is locked before the phone call is received, or did you lock the device whilst the app is in the foreground?

@datwelk thanks for following up with this issue. The app was in the foreground when I locked the device. The issue happens consistently, easy to reproduce.

To me this sounds a lot like an iOS bug. I know in iOS 15 they changed quite a bit with app warming, but since the app was already in the foreground, it's unlikely that it was killed and launched again in the short timespan. Perhaps worth filing a Feedback item with Apple using Feedback Assistant.

Regarding the file protection crash, a possible fix is to write a canary item to the keychain with value kSecAttrAccessibleWhenUnlocked. Then you immediately attempt to read the item after writing, and if the read doesn't result in the same value that was written, the database can't be used / opened.

Then you retry this previous step after receiving UIApplicationProtectedDataDidBecomeAvailable.

The above approach works well for the app warming launch sequence. In your particular case however it may suffice to just listen to UIApplicationProtectedDataWillBecomeUnavailable and UIApplicationProtectedDataDidBecomeAvailable.