iOS 7: MPMusicPlayerController的音量已经被弃用。现在如何改变设备音量?

42

MPMusicPlayerController的setVolume方法自iOS 7起已被弃用

还有其他方式可以改变系统音乐音量吗?最好不需要用户交互。 其中一个重要功能:自动增加AppStore中任何闹钟的音量。


8
我的用户希望能够设置并保存我的应用程序打开时的音量,因此我也依赖这个功能。将这种控制权从开发者手中删除似乎是一件奇怪的事情。 - amergin
有一个AVAudioPlayer:https://dev59.com/questions/tG435IYBdhLWcg3wxDH_。对我来说问题是它是否可以播放iPod库中的歌曲。 - Richard Lovejoy
同意,苹果公司废除这些方法而没有提供适当的替代方案确实很奇怪。 - Ric Santos
我注意到在iOS 8.3中,我的应用程序中的MPMusicPlayerController音量滑块根本没有显示出来。它在早期的iOS版本中得到了显示。应用没有做任何更改。是否有其他人在他们的应用程序中遇到这个问题? - kzia
@kzia 请为此问题创建一个单独的问题。 - Maxim Kholyavkin
8个回答

51
回答你的问题: 是的,有其他方法可以在没有用户交互的情况下更改系统音量。
直到最近,我一直认为使用MPVolumeView编程方式更改音量只能使用私有API实现。但我刚刚验证了,更改volumeSlider的值并伪造滑块的touchUP事件就可以实现:
MPVolumeView* volumeView = [[MPVolumeView alloc] init];

//find the volumeSlider
UISlider* volumeViewSlider = nil;
for (UIView *view in [volumeView subviews]){
    if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
        volumeViewSlider = (UISlider*)view;
        break;
    }
}

[volumeViewSlider setValue:1.0f animated:YES];
[volumeViewSlider sendActionsForControlEvents:UIControlEventTouchUpInside];

当滑块接收到 touchUP 事件时,它会在自身上调用 _commitVolumeChange 方法,该方法将更改系统音量。


1
抱歉如果我很蠢。我正在尝试将您的代码粘贴到我的JS函数中。Dreamweaver会显示红色语法箭头。这是JS代码还是其他什么? - Garavani
1
@Garavani 这是一段Objective-C代码。将其与js集成并不那么简单。请在诸如此类的教程中在线查找更多信息 - http://www.bignerdranch.com/blog/javascriptcore-example/ - ambientlight
1
此代码如写,将会引发一个问题: 可能存在一个存储在 'volumeView' 中的对象泄漏。 - Ashton Honnecke
1
只要您不使用私有API调用,它就不会出现问题。 - ambientlight
2
@ambientlight 我知道它没有直接使用私有API,但是通过模拟用户交互来触发私有API“_commitVolumeChange”似乎有点冒险。不过还是谢谢你的建议! :) - Alex
显示剩余13条评论

13

在苹果决定取消此项功能之前,我已经发现有两种解决方法:

  • 继续使用volume属性,在iOS 7.0.2下仍然有效。
  • 使用AVAudioSession.outputVolume读取音量并在应用唤醒时弹出一个包含MPVolumeView的提示框,如果音量低于(或高于)用户指定的值。至少你的用户知道他们的闹钟(或其他内容)将以安静的方式播放,并有机会调整音量。或者,您也可以清楚地显示音量级别,这样他们就不会有任何惊喜了。

只有第二个选项应该在 iOS 7.0 或以上版本中使用。谢谢! :) - Alex
1
从iOS 10开始,您仍然可以使用音量属性! - Confused Vorlon

9

只需要这样做:

let masterVolumeSlider: MPVolumeView = MPVolumeView()

if let view = masterVolumeSlider.subviews.first as? UISlider{

    view.value = 1.0

}

还需要一个“import MediaPlayer”。 - Mike
masterVolumeSlider.alpha = 0.01; self.view.addSubview(masterVolumeSlider) 这样做使我能够降低音量而不显示操作系统的音量计。 - Rich Fox
我最喜欢这个答案,因为它简洁优雅,不需要使用内部类名。它似乎最有可能在未来不会出现问题。 - Chris Garrett

4

@Hurden,我写了一个Swift代码来实现MPVolumeSlider:

for view in mpVolumeView.subviews {
  let uiview: UIView = view as UIView
  //println("\(uiview.description)")
  if uiview.description.rangesOfString("MPVolumeSlider").first != nil {
    mpVolumeSilder = (uiview as UISlider)
    currentDeviceVolume = mpVolumeSilder!.value
    return
  }
}

在编程方面,可以在此处找到 func rangeOfString 扩展 String Swift:返回 String 实例范围的纯 Swift 方法(Xcode 6 Beta 5)

并使用此代码使手势和 mpvolumeslider 协同工作。

@IBAction func handlePan(recognizer: UIPanGestureRecognizer) {
  let translation = recognizer.translationInView(self.view)
  let dx = (translation.x-lastTranslationX)
  let volumeChanged = Float(dx / mpVolumeView.frame.width)
  currentDeviceVolume = currentDeviceVolume + Float(volumeChanged)

  if currentDeviceVolume > 1 {
    currentDeviceVolume = 1
  } else if currentDeviceVolume < 0 {
    currentDeviceVolume = 0
  }

  mpVolumeSilder!.value = currentDeviceVolume

  if recognizer.state == .Changed {
    lastTranslationX = translation.x
  }
  if recognizer.state == .Ended || recognizer.state == .Began {
    lastTranslationX = 0
  }
}

2

显然有一种方法可以在系统不显示任何内容的情况下更改系统音量。

最重要的是,它适用于iOS 11

以下是我实现它的步骤:

1)在所需的ViewController中创建两个变量

let volumeView = MPVolumeView()
var slider: UISlider?

2) 将以下代码添加到您的viewDidLoad中

volumeView.alpha = 0.01
self.view.addSubview(volumeView)

if let view = volumeView.subviews.first as? UISlider {
    slider = view
}

3) 随时更改音量

slider?.value = 0.4

1

Swift版本:

// Outlet added in Storyboard (Add UIView then set class to MPVolumeView)
@IBOutlet weak var mpVolumeView: MPVolumeView!

    // Get volume slider within MPVolumeView
    for subview in self.mpVolumeView.subviews {
        if (subview as UIView).description.rangeOfString("MPVolumeSlider") != nil {
            // Set volume
            let volumeSlider = subview as UISlider
            volumeSlider.value = 1

            // Works with or without the following line:
            // volumeSlider.sendActionsForControlEvents(UIControlEvents.TouchUpInside)
            break
        }
    }

0
let masterVolumeSlider  : MPVolumeView = MPVolumeView()

        if let view             = masterVolumeSlider.subviews.first as? UISlider{

        view.value              = fVolume!

        view.sendActionsForControlEvents(UIControlEvents.TouchUpInside)

        }

0

这个解决方案让我有点紧张,我认为官方API不存在有点奇怪,但这是我基于ambientlight的帖子构建的Swift解决方案

var _volumeView = MPVolumeView()
var _volumeSlider : UISlider? = nil



self.view.addSubview(_volumeView)
_volumeView.hidden = true

var i = 0
while i < _volumeView.subviews.count {
   if let _r = _volumeView.subviews[i] as? UISlider {
      _volumeSlider = _r
      break
   }
   ++i
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接