66

I'd like to add flashlight functionality to my app in Swift. How can I go about doing that?

Aidan Gomez
  • 8,167
  • 5
  • 28
  • 51
Lachtan
  • 4,803
  • 6
  • 28
  • 34

15 Answers15

122

Update #1: (torchActive isn't returning the expected value; perhaps because it's been modified)

Update #2: For Swift 2.0

To toggle the flash from on to off (not just "on" as in mad pig's answer), you can use the following method:

func toggleFlash() {
    let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
    if (device.hasTorch) {
        do {
            try device.lockForConfiguration()
            if (device.torchMode == AVCaptureTorchMode.On) {
                device.torchMode = AVCaptureTorchMode.Off
            } else {
                do {
                    try device.setTorchModeOnWithLevel(1.0)
                } catch {
                    print(error)
                }
            }
            device.unlockForConfiguration()
        } catch {
            print(error)
        }
    }
}

I used nested do-catch blocks to implement Awesomeness's suggestion from the comments. This way, even if try device.setTorchModeOnWithLevel(1.0) fails, the device is properly unlocked for configuration.

Update #3: For Swift 4:

(I edited the code a bit to my personal taste)

func toggleFlash() {
    guard let device = AVCaptureDevice.default(for: AVMediaType.video) else { return }
    guard device.hasTorch else { return }

    do {
        try device.lockForConfiguration()

        if (device.torchMode == AVCaptureDevice.TorchMode.on) {
            device.torchMode = AVCaptureDevice.TorchMode.off
        } else {
            do {
                try device.setTorchModeOn(level: 1.0)
            } catch {
                print(error)
            }
        }

        device.unlockForConfiguration()
    } catch {
        print(error)
    }
}

Original answer:

To toggle the flash from on to off (not just "on" as in mad pig's answer), you can use the following method:

func toggleFlash() {
    let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
    if (device.hasTorch) {
        device.lockForConfiguration(nil)
        let torchOn = !device.torchActive
        device.setTorchModeOnWithLevel(1.0, error: nil)
        device.torchMode = torchOn ? AVCaptureTorchMode.On : AVCaptureTorchMode.Off
        device.unlockForConfiguration()
    }
}
caffeinum
  • 401
  • 5
  • 13
Lyndsey Scott
  • 37,080
  • 10
  • 92
  • 128
  • 2
    I think the `setTourchModeOnWithLevel` call needs to be in its own try block, so that it can unlock the device for configuration in the event that something goes wrong. ` do { try device.setTorchModeOnWithLevel(1.0) } catch { device.unlockForConfiguration() } ` – Awesomeness Dec 02 '15 at 14:52
  • 1
    @Awesomeness I implemented your suggestion, but used a nested do-catch block instead since it's one less line of code... No need to call device.unlockForConfiguration() both within and outside of the setTorchModeOnWithLevel(1.0) catch block. – Lyndsey Scott Dec 02 '15 at 16:26
  • when you quickly press the flashlight button, this solution is not the fastest, and it works with a slight delay – Leon Jakonda Apr 13 '21 at 10:03
  • I suggest using AVCaptureDevice.maxAvailableTorchLevel instead of 1.0. – henrique Sep 08 '21 at 19:29
35

Updated Swift 4 Answer:

func toggleTorch(on: Bool) {
    guard 
        let device = AVCaptureDevice.default(for: AVMediaType.video),
        device.hasTorch
    else { return }

    do {
        try device.lockForConfiguration()
        device.torchMode = on ? .on : .off                    
        device.unlockForConfiguration()
    } catch {
        print("Torch could not be used")
    }
}

Then to actually turn it on or off, call the function and pass in a true or false boolean.

toggleTorch(on: true) of toggleTorch(on: false)

I got this answer from Hacking with Swift, however their example had an error in it.

They used AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) but this produces an error saying defaultDevice doesn't exist. So I changed it to AVCaptureDevice.default(for: AVMediaType.video)

Todd
  • 317
  • 1
  • 11
Joshua Dance
  • 8,847
  • 4
  • 67
  • 72
  • 1
    I like how this code was written. Worked perfectly in my app. Just remember to import AVFoundation to use the torch. – Josh Dec 29 '18 at 18:22
26

I've updated @Lyndsey Scott's great answer for Swift 2.0

let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
    if (device.hasTorch) {
        do {
            try device.lockForConfiguration()
            if (device.torchMode == AVCaptureTorchMode.On) {
                device.torchMode = AVCaptureTorchMode.Off
            } else {
                try device.setTorchModeOnWithLevel(1.0)
            }
            device.unlockForConfiguration()
        } catch {
            print(error)
        }
    }
gpichler
  • 2,181
  • 2
  • 27
  • 52
  • 4
    For the newbies (like me), I'd like to add that you need to include 'import AVFoundation' in the top of the view controller swift file. – dmcknight Jan 02 '16 at 16:45
  • 1
    FYI I updated my answer for Swift 2.0 as well (the answer this one was based on) a few months ago and unlike this answer, my answer also handles the case where try device.setTorchModeOnWithLevel(1.0) fails. – Lyndsey Scott Mar 07 '16 at 17:31
11

Swift 5

The solution was already written by many, but I want to propose also the more concise one I came up in my project:

func toggleTorch(on: Bool) {
    guard let device = AVCaptureDevice.default(for: AVMediaType.video) else { return }
    guard device.hasTorch else { print("Torch isn't available"); return }

    do {
        try device.lockForConfiguration()
        device.torchMode = on ? .on : .off
        // Optional thing you may want when the torch it's on, is to manipulate the level of the torch
        if on { try device.setTorchModeOn(level: AVCaptureDevice.maxAvailableTorchLevel.significand) }
        device.unlockForConfiguration()
    } catch {
        print("Torch can't be used")
    }
}

As mentioned in the comment, you can also change the torch level when it's on, which I find quite handy.

Also import AVFoundation to use torch.

Ahmadreza
  • 6,950
  • 5
  • 50
  • 69
Alessandro Francucci
  • 1,528
  • 17
  • 25
7

For swift 3

func toggleFlash() {
    if let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo), device.hasTorch {
        do {
            try device.lockForConfiguration()
            let torchOn = !device.isTorchActive
            try device.setTorchModeOnWithLevel(1.0)
            device.torchMode = torchOn ? .on : .off
            device.unlockForConfiguration()
        } catch {
            print("error")
        }
    }
}
Chuy47
  • 2,391
  • 1
  • 30
  • 29
6

Like so:

 func turnTorchOn(){

    let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
    if device.hasTorch {
        device.lockForConfiguration(nil)
        device.setTorchModeOnWithLevel(1.0, error: nil)
        device.unlockForConfiguration()
    }


}
mad pig
  • 788
  • 6
  • 10
6

For xcode 9.1, swift 4 (updated to not crash if no torch):

   func toggleFlash() {
    let device = AVCaptureDevice.default(for: AVMediaType.video)

    if (device != nil) {
        if (device!.hasTorch) {
            do {
                try device!.lockForConfiguration()
                    if (device!.torchMode == AVCaptureDevice.TorchMode.on) {
                        device!.torchMode = AVCaptureDevice.TorchMode.off
                    } else {
                        do {
                            try device!.setTorchModeOn(level: 1.0)
                            } catch {
                                print(error)
                            }
                    }

                    device!.unlockForConfiguration()
            } catch {
                print(error)
            }
        }
    }
}
Lance
  • 61
  • 1
  • 2
4

If you want to use only one button to on or off flashlight this is code;

func toggleTorch() {
        guard
            let device = AVCaptureDevice.default(for: AVMediaType.video),
            device.hasTorch
        else { return }

        do {
            try device.lockForConfiguration()
            if device.torchMode == AVCaptureDevice.TorchMode.on
            {
                device.torchMode = .off
                
            } else {
                device.torchMode = .on
                
            }
            device.unlockForConfiguration()
        } catch {
            print("Torch could not be used")
        }
    }

you can call toggleTorch() in button click function to on and off flashlight.

uyarc
  • 579
  • 4
  • 17
3

Solution For Swift 4 With Condition torch is available or not

 func flashlight() {
            guard let device = AVCaptureDevice.default(for: AVMediaType.video) else{
                return
            }
            if (device.hasTorch) {
                    do {
                        try device.lockForConfiguration()
                        if (device.torchMode == .on) {
                            device.torchMode = .off
                        } else {
                            device.torchMode = .on

                        }
                        device.unlockForConfiguration()
                    } catch {

                        print("Torch could not be used")
                        print(error)
                    }
                }
            else{
                print("Torch is not available")
            }
        }

The Solution is Combination of @Joshua Dance And @Lance

Anup Gupta
  • 1,993
  • 2
  • 25
  • 40
2

SwiftUI

// TorchState.swift

import SwiftUI
import AVFoundation

class TorchState: ObservableObject {
    
    @Published var isOn: Bool = false {
        didSet {
            toggleTorch(isOn)
        }
    }
    
    private func toggleTorch(_ isOn: Bool) {
        guard let device = AVCaptureDevice.default(for: .video), device.hasTorch else { return }
        
        do {
            try device.lockForConfiguration()
            
            device.torchMode = isOn ? .on : .off
            
            if isOn {
                try device.setTorchModeOn(level: AVCaptureDevice.maxAvailableTorchLevel)
            }
            
            device.unlockForConfiguration()
        } catch {
            print("Error: \(error)")
        }
    }
}

Example (iOS 14.0):

//ContentView.swift

import SwiftUI

struct ContentView: View {
    @StateObject var torchState = TorchState()
    
    var body: some View {
          Toggle(isOn: $torchState.isOn) {
                Text("Torch")
          }
    }
}
        
Peter Kreinz
  • 7,979
  • 1
  • 64
  • 49
1

Swift 4.2

if let device = AVCaptureDevice.default(for: AVMediaType.video) {

    if (device.hasTorch) {
        do {
            try device.lockForConfiguration()
            let torchOn = !device.isTorchActive
            try device.setTorchModeOn(level: 1.0)
            device.torchMode = torchOn ? AVCaptureDevice.TorchMode.on : AVCaptureDevice.TorchMode.off
            device.unlockForConfiguration()
        } catch {
            print(error.localizedDescription)
        }
    }
}
1

Swift version 5.2.4

    func toggleFlash(on: Bool ) {
        guard let device = AVCaptureDevice.default(for: .video), device.hasTorch else { return }
        
        do {
            try device.lockForConfiguration()
            
            device.torchMode = on ? .on : .off
            if on {
                try device.setTorchModeOn(level: AVCaptureDevice.maxAvailableTorchLevel)
            }
            
            device.unlockForConfiguration()
        } catch {
            print("Error: \(error)")
        }
    }
hectorsvill
  • 681
  • 8
  • 7
1

Refactored. Swift 5.4

import AVFoundation


extension UIDevice {
    
    static func toggleFlashLight() {
        guard let device = AVCaptureDevice.default(for: AVMediaType.video),
              device.hasTorch else { return }
        do {
            try device.lockForConfiguration()
            try device.setTorchModeOn(level: 1.0)
            device.torchMode = device.isTorchActive ? .off : .on
            device.unlockForConfiguration()
        } catch {
            assert(false, "error: device flash light, \(error)")
        }
    }

}
Denis Rybkin
  • 471
  • 6
  • 7
0

Decided to add a solution here using defer:

struct TorchError: Error {
  var description: String
}

func toggleTorch() throws {
  guard let device = AVCaptureDevice.default(for: .video) else {
    throw TorchError(description: "Failed to acquire default capture device")
  }

  if device.hasTorch {
    try device.lockForConfiguration()
    defer {
      device.unlockForConfiguration()
    }
            
    let isTorchOn = device.torchMode == .on
    device.torchMode = isTorchOn ? .off : .on
  } else {
    throw TorchError(description: "Capture device is missing torch functionality")
  }
}
Austino
  • 21
  • 3
  • 5
-1
Swift 4.1

@objc func Flash() {
        let device = AVCaptureDevice.default(for: AVMediaType.video)
        if (device?.hasTorch)! {
            do {
                try device?.lockForConfiguration()
                if (device?.torchMode == AVCaptureDevice.TorchMode.on) {
                    device?.torchMode = AVCaptureDevice.TorchMode.off
                } else {
                    do {
                        try device?.setTorchModeOn(level: 1.0)
                    } catch {
                        print(error)
                    }
                }
                device?.unlockForConfiguration()
            } catch {
                print(error)
            }
        }
    }