Torch Strobe not working in light (ambient light) environments on iOS 18.1

As of iOS 18.1 being released we are having issues with our users experiencing issues with our app that relies on strobing the device torch.

We have narrowed this down to being caused on devices with adaptive true-tone flash and have submitted a radar: FB15787160.

The issue seems to be caused by ambient light levels. If run in a dark room, the torch strobes exactly as effectively as in previous iOS versions, if run in a light room, or outdoors, or near a window, the strobe will run for ~1s and then the torch will get stuck on for half a second or so (less frequently it gets stuck off) and then it will strobe again for ~1s and this behaviour repeats indefinitely.

If we go to a darker environment, and background and then foreground the app (this is required) the issue is resolved, until moving to an area with higher ambient light levels again. We have done a lot of debugging, and also discovered that turning off "Auto-Brightness" from Settings -> Accessibility -> Display & Text Size resolves the issue.

We have also viewed logs from Console.app at the time of the issue occurring and it seems to be that there are quite sporadic ambient light level readings at the time at which the issue occurs. The light readings transition from ~100 Lux to ~8000 Lux at the point that the issue starts occurring (seemingly caused by the rear sensor being affected by the torch). With "Auto-Brightness" turned off, it seems these readings stay at lower levels.

This is rendering the primary use case of our app essentially useless, would be great to get to the bottom of it! We can't even really detect it in-app as I believe using SensorKit is restricted to research applications and requires a review process with Apple before accessing?

Edit: It's worth noting this is also affecting other apps with strobe functionality in the exact same way

Just an update on this, another way to fix it is to setup an AVCaptureDeviceInput and AVCaptureVideoDataOutput, attach them to an AVCaptureSession and call startRunning on the session.

Presumably this limits the changes to the torch so it can be used as a camera flash more effectively.

A less than ideal solution, as it will involve hand-holding of users to explain why we require camera permission, and will potentially also be picked up on by the review team too!

A further update after getting some analytics around this into our app:

  • It isn't related to the adaptive true-tone flash, rather it occurs on any device with dual ambient light sensors.
  • We still believe it's only an iOS 18 issue, but may also be present on iOS 18.0.1
  • The issue is not yet resolved on iOS 18.2 beta

Hey @simonmitchell. We are currently dealing with the same issue. did you receive any feedback from Apple yet? I can't seem to open the link to your radar, but I'm not sure if I just don't have access to it.

I have written the following code to gather some data on this issue. It simply flashes the torch at 10 Hz and measures the current time before every torchMode change and usleep call. You can also see that it generates a list of "ideal" timings, which assumes that the torchMode changes are instant and the usleep calls are perfectly accurate. This is obviously not possible, but allows us to calculate the deviation between our hypothetical ideal scenario and the real world.

let device = AVCaptureDevice.default(for: .video)!
try device.lockForConfiguration()

var measurements: [CFTimeInterval] = []

let repeats = 300
let durationMs = 50
let durationUs = UInt32(durationMs * 1000)

var ideal: [CFTimeInterval] = []

for _ in 0..<repeats {
    ideal.append(0.0)
    ideal.append(CFTimeInterval(durationMs))
    ideal.append(0.0)
    ideal.append(CFTimeInterval(durationMs))
}

for i in 0..<repeats {
    measurements.append(CACurrentMediaTime())
    device.torchMode = .on
    measurements.append(CACurrentMediaTime())
    usleep(durationUs)
    measurements.append(CACurrentMediaTime())
    device.torchMode = .off
    measurements.append(CACurrentMediaTime())
    usleep(durationUs)
}

measurements.append(CACurrentMediaTime())

device.unlockForConfiguration()

var diffs: [CFTimeInterval] = []

for (i, timestamp) in measurements[1...].enumerated() {
    let previous = measurements[i]

    diffs.append((timestamp - previous) * 1000 - ideal[i])
}

let str = diffs.map({ String($0) }).joined(separator: "\n")
print(str)

I ran this demo in a dark room on an iPhone 15 Pro Max and iPhone 13 Mini. The measured results can be seen in the graph below. The marked area in red roughly shows the time that the room lights were turned on.

You can clearly see that after turning the ambient light on the iPhone 15 Pro Max regularly takes up to almost 500ms to update the torchMode. The iPhone 13 Mini experiences no such problems. Even after the light is turned off again the iPhone 15 Pro Max continues to miss the desired timings.

I took a video of the demo that you can see here: https://drive.google.com/file/d/1CBWEBWPvq_QF_TLud1-8m1G5guFn_0Qq/view - I sadly cannot make this a proper link, because the Forum seems to block the domain. Uploading the video file itself is also not possible. Here's a screenshot of the setup for good measure:

I was able to reliably and consistently reproduce this issue on an iPhone 15 Pro and iPhone 15 Pro Max. I couldn't get my hands on any iPhone 16 myself yet, but after asking friends to take a slow motion video of a generic strobe app in a bright room it looks like they are not affected.

Torch Strobe not working in light (ambient light) environments on iOS 18.1
 
 
Q