I want to implement a volume shutter in my camera app. When the user presses the volume button, I should get an event to take a photo.
I'm looking for an implementation that meets the following requirements:
Other questions and answers exist on this topic, but for older versions of iOS, so I wanted to find one that works on iOS 11.
Camera apps like ProCamera, ProCam and Camera+ have the volume shutter that satisfies all these conditions, so it's clearly possible.
You can adjust the sound of the shutter in Camera , or mute it using the Ring/Silent switch on the side of your iPhone.
Adjust the volumePress the Volume buttons on the left side of the device to adjust media or call volume. You can also adjust the volume from the Sounds & Haptics screen. Select and drag the Volume slider as desired. To enable or disable changing the volume with buttons, select the Change with Buttons switch.
So here is the code that will meet all your requirements – I'm not sure whether or not Apple will approve this though.
I've pulled all this code from questions/answers here on StackOverflow.
Tested with iOS 10.2 in Xcode 8.3.1
You need to use the AVFoundation
and MediaPlayer
frameworks for this to work.
import UIKit
import AVFoundation
import MediaPlayer
class ViewController: UIViewController {
//keeps track of the initial volume the user had set when entering the app
//used to reset the volume when he exits the app
var volume: Float = 0
override func viewDidLoad() {
super.viewDidLoad()
let audioSession = AVAudioSession.sharedInstance()
volume = audioSession.outputVolume-0.1 //if the user is at 1 (full volume)
try! audioSession.setActive(true)
audioSession.addObserver(self, forKeyPath: "outputVolume", options: NSKeyValueObservingOptions.new, context: nil)
//prevents the volume hud from showing up
let volView = MPVolumeView(frame: .zero)
view.addSubview(volView)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
//when the user changes the volume,
//prevent the output volume from changing by setting it to the default volume we specified,
//so that we can continue pressing the buttons for ever
(MPVolumeView().subviews.filter{NSStringFromClass($0.classForCoder) == "MPVolumeSlider"}.first as? UISlider)?.setValue(volume, animated: false)
//implement your photo-capturing function here
print("volume changed")
}
}
If you want to make sure your code is still working after the user exits the app, use the AppDelegate to install the observer when the app becomes active, like this:
AppDelegate
import UIKit
import AVFoundation
import MediaPlayer
var volume: Float = 0.5
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let audioSession = AVAudioSession.sharedInstance()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
return true
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
(MPVolumeView().subviews.filter{NSStringFromClass($0.classForCoder) == "MPVolumeSlider"}.first as? UISlider)?.setValue(volume, animated: false)
NotificationCenter.default.removeObserver(self)
NotificationCenter.default.post(Notification(name: Notification.Name(rawValue: "volumeChanged")))
}
func applicationDidBecomeActive(_ application: UIApplication) {
volume = audioSession.outputVolume
if volume == 0 { volume += 0.1 } else if volume == 1 { volume -= 0.1 }
try! audioSession.setActive(true)
audioSession.addObserver(self, forKeyPath: "outputVolume", options: NSKeyValueObservingOptions.new, context: nil)
}
func applicationWillResignActive(_ application: UIApplication) {
audioSession.removeObserver(self, forKeyPath: "outputVolume")
}
}
ViewController
import UIKit
import AVFoundation
import MediaPlayer
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.volumeChanged), name: Notification.Name(rawValue: "volumeChanged"), object: nil)
//prevents the volume hud from showing up
let volView = MPVolumeView(frame: .zero)
view.addSubview(volView)
}
func volumeChanged() {
print("volume changed")
}
}
As per Apple's App Store Review Guidelines, this would be explicit grounds for rejection.
2.5.9 Apps that alter the functions of standard switches, such as the Volume Up/Down and Ring/Silent switches, or other native user interface elements or behaviors will be rejected.
Source: Is it possible to disable volume buttons in iOS apps?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With