程序访问iPhone音量按钮

时间:2009-04-21 14:24:06

标签: iphone objective-c

有没有办法订阅音量按钮按事件?

5 个答案:

答案 0 :(得分:21)

最近Apple拒绝后

不要使用它。 Apple现在使用一些补丁,如果它使用任何私有API,它会直接拒绝你的应用程序 - 虽然应该注意到App Store上的一些应用程序已经使用它并且仍在那里!

现在唯一的办法是让AVAudioPlayer准备播放但不播放([player prepareToPlay])。这似乎是根据摇杆按钮调整应用程序的音量。

目前还没有其他方法可以解决这个问题。

请阅读上面的说明

是,使用MPVolumeView

MPVolumeView *volume = [[[MPVolumeView alloc] initWithFrame:CGRectMake(18.0, 340.0, 284.0, 23.0)] autorelease];
  [[self view] addSubview:volume];

  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(volumeChanged:) 
                                        name:@"AVSystemController_SystemVolumeDidChangeNotification" 
                                        object:nil];    
  for (UIView *view in [volume subviews]){
    if ([[[view class] description] isEqualToString:@"MPVolumeSlider"]) {
      volumeViewSlider = view;  //volumeViewSlider is a UIView * object
    }
  }
  [volumeViewSlider _updateVolumeFromAVSystemController];

-(IBAction)volumeChanged:(id)sender{
  [volumeViewSlider _updateVolumeFromAVSystemController];
}

这将为您提供一个滑块(与ipod中使用的滑块相同),其值将根据手机的音量进行更改

您将收到一个编译时警告,该视图可能无法响应_updateVolumeFromAVSystemControl,但只是忽略它。

答案 1 :(得分:17)

如果您只是想收到通知,我认为是这样的:

如果我错了,请纠正我,但我不相信这会使用任何内部API。

[[NSNotificationCenter defaultCenter] addObserver:self
        selector:@selector(volumeChanged:) 
        name:@"AVSystemController_SystemVolumeDidChangeNotification" 
        object:nil];

此活动的详情如下:http://www.cocoadev.com/index.pl?AVSystemController

这里的其他回复似乎是基于这个黑客:http://blog.stormyprods.com/2008/09/proper-usage-of-mpvolumeview-class.html这是一个现在修复的bug的解决方法。

但是我很确定你想要做的只是 GET 通知,而不是 SET 系统卷,你可以像使用通知中心一样任何其他事件!!

请注意:由于Apple向相机添加了音量调节操作,因此当UIImagePickerController可见时,此通知

答案 2 :(得分:1)

如果您愿意使用私有API,我会a patch to Wolf3d添加您正在寻找的功能。它使用私有AVSystemController类和UIApplication

上的一些隐藏方法

答案 3 :(得分:1)

好,

所以我看到了你的解决方案,并且不确切地知道Apple是否会拒绝或接受使用AVSystemController_SystemVolumeDidChangeNotification。但我有一个解决方法。

使用UISlider MPVolumeView来注册iPhone硬件的音量变化

MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectZero];

for (UIView *view in [volumeView subviews]) {
    if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
        self.volume_slider = (UISlider*)view;
        break;
    }
}
[volumeView sizeToFit];
#THIS IS THE MAIN LINE. ADD YOUR CALLBACK TARGET HERE
[self.volume_slider addTarget:self action:@selector(volumeListener:) forControlEvents:UIControlEventValueChanged];
[self addSubview:volumeView];
[volumeView setAlpha:0.0f];

-(void)volumeListener:(NSNotification*)notification {
     #UPDATE YOUR UI ACCORDING OR DO WHATEVER YOU WANNA DO.
     #YOU CAN ALSO GET THE SOUND STEP VALUE HERE FROM NOTIFICATION.
}

如果这有助于任何人,请告诉我。

答案 4 :(得分:1)

我在研究上面提到的所有资源以及其他线程中找到的最简单,功能最完善的方法是:JPSVolumeButtonHandler(除了作为用户之外我不介入。但是非常感谢给责任人!)

编辑:版本1.0.2附带了一些重大更改/增强功能。我将首先留下1.0.1的答案。

我放置了一个样本包装类,您可以按原样部署它,或者用于学习JPSVolumeButtonHandler,希望在separate Github repository real quick here中正确使用。

这里是如何使用包装器的(我一到达就将它添加到存储库中):

  1. 单例类有两个标志:isInUseisOnisInUse旨在通常在某些常规应用设置和开关按钮支持中设置。 因此,无论类中是否有任何其他值,如果这是false,当用户按下音量按钮时,不会发生任何事情,并且实现确保尽可能保持干净并且不会不必要地影响系统音量。 (阅读README中提到的问题,了解第一次启用按钮支持时可能发生的情况。) isOn在需要按钮的持续时间内完全是true。您可以打开和关闭它,而不考虑isInUse

  2. 的当前值
  3. 在初始化按下音量按钮时应该发生的操作的任何视图中,设置操作如下:

    PhysicalButton.shared.action = {/ *做点什么* /}

  4. 该操作的类型为() -> Void。在你初始化动作之前,什么都不会破坏。什么都不会发生。这种防御功能对我来说很重要,因为只有在设置了按钮支持后才能创建使用音量按钮支持的视图。

    为了看到实际行动,你可以download the app我真正快速地免费使用它。设置操纵"物理按钮支持"一般来说。主秒表视图是在进入视图时实际切换按钮处理的视图,而在离开视图时关闭。如果您找到时间,您还可以在设置>中找到重要提示。用户指南>选项:物理按钮支持:

      

    在特殊情况下,应用可能无法正常使用   在秒表视图外部切换音量按钮处理...

    我将完整的注释添加到Github README.md。如果它与您的情况相关,请随意调整和重复使用。

    情况实际上并不是那么特别,而且我还没有完全弄明白什么是错的。当用户在打开音量按钮时杀死应用程序(或者您只是在Xcode中停止应用程序)时,可能无法从操作系统中正确删除物理按钮支持。因此,您最终可以得到两个内部处理程序实例,其中只有一个是您可以控制的。因此,每按一次按钮都会导致两次或更多次调用操作例程。我的包装器有一些监护代码,以防止按钮调用太快。但那只是部分解决方案。修复需要进入底层处理程序,遗憾的是我仍然对自己尝试解决问题的理解太少了。

    OLD,FOR 1.0.1:

    特别是,我的兴趣在于Swift解决方案。代码在Objective-C中。为了节省一些研究,这就是我使用Cocoapods(对我这样的假人)所做的一切:

    1. pod 'JPSVolumeButtonHandler'添加到podfile
    2. 在命令行上运行pod install
    3. #import <JPSVolumeButtonHandler.h>添加到桥接头文件
    4. 设置音量增大和减小按钮的回调,如下所示:

      let volumeButtonHandler = JPSVolumeButtonHandler(
          upBlock: {
              log.debug("Volume up button pressed...")
              // Do something when the volume up button is pressed...
          }, downBlock: {
              log.debug("Volume down button pressed...")
              // Do something else for volume down...
          })
      
    5. 那就是它。其余的是可选的。

      在我的情况下,我想启用覆盖虚拟屏幕按钮的物理按钮,仅用于选择视图,同时确保尽可能少地阻止正常的按钮功能(这样用户就可以在背景,并在应用程序的其余部分调整其音量就好了)。我最终选择了一个单独的单身课程如下:

      class OptionalButtonHandler {
      
        static var sharedInstance: OptionalButtonHandler?
      
        private var volumeButtonHandler: JPSVolumeButtonHandler? = nil
        private let action: () -> ()
      
        var enabled: Bool {
          set {
              if !enabled && newValue {
                  // Switching from disabled to enabled...
                  assert(volumeButtonHandler == nil, "No leftover volume button handlers")
                  volumeButtonHandler = JPSVolumeButtonHandler(upBlock: {
                      log.debug("Volume up button pressed...")
                      self.action()
                      }, downBlock: {
                          log.debug("Volume down button pressed...")
                          self.action()
                  })
              } else if enabled && !newValue {
                  log.debug("Disabling physical button...")
                  // The other way around: Switching from enabled to disabled...
                  volumeButtonHandler = nil
              }
          }
          get { return (volumeButtonHandler != nil) }
        }
      
        /// For one-time initialization of this otherwise singleton class.
        static func initSharedInstance(action: () -> ()) {
            sharedInstance = OptionalButtonHandler(action: action)
        }
      
        private init(action: () -> ()) {
            self.action = action
        }
      }
      

      此处上下音量按钮只有一个常用操作。 initSharedInstance()是必要的,因为我的操作包括对UI元素(视图)的引用,该元素仅在应用启动后在某个用户相关点设置。

      一次性设置如下:

      OptionalButtonHandler.initSharedInstance({
          // ...some UI action
      })
      

      有选择地启用/禁用如下:

      OptionalButtonHandler.sharedInstance!.enabled = true  // (false)
      

      (请注意,我的代码逻辑确保.enabled之前永远不会访问initSharedInstance()。)

      我在(required!)测试设备上运行Xcode 7.3和iOS 9.3.2。

      期待了解Apple如何重置超重的音量按钮。至少我的应用程序确保微创和按钮使用真的很有意义。它不是相机应用程序,但类似的应用程序之前使用过物理音量按钮(甚至不太好)。