6

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:

  • It should work even if the volume is currently at the maximum, and the user presses the volume up button.
  • There should be no on-screen UI showing that the volume changed.
  • There should be no known cases of Apple rejecting an app that used this technique.

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.

4

2 回答 2

8

所以这里的代码可以满足你的所有要求——不过我不确定苹果是否会批准这个。
我已经从 StackOverflow 上的问题/答案中提取了所有这些代码。

在 Xcode 8.3.1 中使用 iOS 10.2 测试

您需要使用AVFoundationMediaPlayer框架才能使其工作。

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")
    }
}

更新

如果您想确保您的代码在用户退出应用程序后仍然有效,请在应用程序激活时使用 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")
    }
}

视图控制器

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")
    }
}
于 2017-04-11T12:47:25.787 回答
1

根据 Apple 的App Store Review Guidelines,这将是拒绝的明确理由。

2.5.9改变标准开关功能的应用程序,例如音量增大/减小和响铃/静音开关,或其他原生用户界面元素或行为将被拒绝。

资料来源: 是否可以禁用 iOS 应用程序中的音量按钮?

于 2017-04-11T12:27:30.113 回答