简体   繁体   English

如何在iOS 11中实现音量快门?

[英]How do I implement a volume shutter in iOS 11?

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. 应该没有屏幕上的UI显示卷已更改。
  • There should be no known cases of Apple rejecting an app that used this technique. 应该没有已知的Apple拒绝使用此技术的应用程序的情况。

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. 关于这个主题存在其他问题和答案,但对于旧版本的iOS,我想找到一个适用于iOS 11的版本。

Camera apps like ProCamera, ProCam and Camera+ have the volume shutter that satisfies all these conditions, so it's clearly possible. ProCamera,ProCam和Camera +等相机应用程序具有满足所有这些条件的音量快门,因此显然可行。

So here is the code that will meet all your requirements. 所以这里的代码将满足您的所有要求。
I've pulled all this code from questions/answers here on StackOverflow. 我在StackOverflow上从问题/答案中提取了所有这些代码。

Apple will reject any apps that are submitted using this code. Apple将拒绝使用此代码提交的所有应用。

Tested with iOS 10.2 in Xcode 8.3.1 在Xcode 8.3.1中使用iOS 10.2进行测试

You need to use the AVFoundation and MediaPlayer frameworks for this to work. 您需要使用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")
    }
}

Update 更新

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安装观察者,如下所示:

AppDelegate 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. 根据Apple的App Store评论指南 ,这将是拒绝的明确理由。

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. 2.5.9将拒绝更改标准交换机功能的应用程序,例如音量调高/降低和振铃/静音开关,或其他本机用户界面元素或行为。

Source: Is it possible to disable volume buttons in iOS apps? 来源: 是否可以禁用iOS应用中的音量按钮?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM