AVAudioSession setCategory Swift 4.2 iOS 12 - 在静音模式下播放声音

58

我曾经使用下面的方法来在静音模式下播放声音。但现在它不起作用了。

// Works on Swift 3  
do {
    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
} catch {
    print(error)
}

如何在4.2 / iOS 12上使其运作?

在更新的版本中,我们需要设置模式和选项。

try AVAudioSession.sharedInstance().setCategory(
    <#T##category:AVAudioSession.Category##AVAudioSession.Category#>,
    mode: <#T##AVAudioSession.Mode#>, 
    options: <#T##AVAudioSession.CategoryOptions#>)`

5
根据文档,我认为它应该是这样工作的:AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: []) - Herr der Töne
有关于像 mixWithOthers 这样的选项,请参考 https://dev59.com/mV0b5IYBdhLWcg3wLOnP#39084300,已更新至 Swift 4.2。 - Graham Perks
1
该方法已经在Xcode 10.2中重新添加。 - Gabriel Gava
9个回答

74

Her der Töne的评论向您展示了新的语法,但是在setCategory之后,您还需要激活音频会话:

do {
    try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
    try AVAudioSession.sharedInstance().setActive(true)
} catch {
    print(error)
}

2
以上解决方案强制放弃了与iOS 9设备的应用兼容性。有没有办法恢复iOS 9的兼容性? - aaberga
1
你确定吗?setCategory()自iOS 6起可用,而setActive()/sharedInstance()自iOS 3起可用。 - Rhythmic Fistman
2
@RhythmicFistman,是的,你可以在这里查看,它只适用于iOS 10+。 - manman
哈 - 如果您使用Objective-C调用代码,它是否有效?哦,等等,我看到问题了 - 有一个setCategory:withOptions(您的模式默认为任何方式) - 尽管我不确定在Swift中它被称为什么。 - Rhythmic Fistman
哎呀,那太糟糕了。用Objective-C来做吧 - AVAudioSession本来就是一个非常低级的单例,用Swift配置也不会有多大改进(在这种情况下相反)。 - Rhythmic Fistman
显示剩余3条评论

42

作为一种解决方法,您可以使用Objective-C的AVAudioSession.setCategory:方法,并使用NSObject.performSelector:进行调用:

if #available(iOS 10.0, *) {
    try! AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback)
}
else {
    // Workaround until https://forums.swift.org/t/using-methods-marked-unavailable-in-swift-4-2/14949 isn't fixed
    AVAudioSession.sharedInstance().perform(NSSelectorFromString("setCategory:error:"), with: AVAudioSession.Category.playback)
}

如果您想为iOS 9及更早版本设置类别和选项,请使用以下方法:

AVAudioSession.sharedInstance().perform(NSSelectorFromString("setCategory:withOptions:error:"), with: AVAudioSession.Category.playback, with:  [AVAudioSession.CategoryOptions.duckOthers])

更新:

Xcode 10.2已修复此问题。


好的,那么'options'参数怎么办?如何替换AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.duckOthers])? - Fallstreak
3
尝试设置类别和选项,例如 AVAudioSession.sharedInstance().perform(NSSelectorFromString("setCategory:withOptions:error:"), with: AVAudioSession.Category.playback, with: [AVAudioSession.CategoryOptions.duckOthers])。是否有效? - ricardopereira
执行 NSSelectorFromString("") 是有风险的。我不会在生产应用程序中这样做。 - Mallox
2
@Mallox 当然你会这样做:这里没有更安全的选择,不是吗? - Cœur
@Galvin 即使你在团队中工作,如果有人可以在你不知情的情况下修改你的源文件,那么你就会面临更大的问题。 - highboi
显示剩余6条评论

20

对于 iOS 12 中的 Swift 4.2,简单来说就是:

try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [])

15

Xcode 10.2更新:

Apple finally fix this issue in Xcode 10.2. 
So no need to add these workaround code anymore if you use Xcode 10.2 or newer version.

But you also could refer this code for any problem like this.

你可以使用一个objective-c分类来帮助解决这个问题。

创建一个 AVAudioSession+Swift.h 文件:

@import AVFoundation;

NS_ASSUME_NONNULL_BEGIN

@interface AVAudioSession (Swift)

- (BOOL)swift_setCategory:(AVAudioSessionCategory)category error:(NSError **)outError NS_SWIFT_NAME(setCategory(_:));
- (BOOL)swift_setCategory:(AVAudioSessionCategory)category withOptions:(AVAudioSessionCategoryOptions)options error:(NSError **)outError NS_SWIFT_NAME(setCategory(_:options:));

@end

NS_ASSUME_NONNULL_END

使用 AVAudioSession+Swift.m

#import "AVAudioSession+Swift.h"

@implementation AVAudioSession (Swift)

- (BOOL)swift_setCategory:(AVAudioSessionCategory)category error:(NSError **)outError {
    return [self setCategory:category error:outError];
}
- (BOOL)swift_setCategory:(AVAudioSessionCategory)category withOptions:(AVAudioSessionCategoryOptions)options error:(NSError **)outError {
    return [self setCategory:category withOptions:options error:outError];
}

@end

然后在您的<#target_name#>-Bridging-Header.h中导入“AVAudioSession+Swift.h”

#import "AVAudioSession+Swift.h"

结果是你可以像以前一样在Swift中调用该方法。

do {
    try AVAudioSession.sharedInstance().setCategory(.playback)
    try AVAudioSession.sharedInstance().setCategory(.playback, options: [.mixWithOthers])
    try AVAudioSession.sharedInstance().setActive(true)
} catch {
    print(error)
}

这是我使用过的最佳解决方案,以前它可以正常工作。现在苹果决定在Xcode 10.2上修复此问题,因此不再需要它了。实际上,这使得调用现在变得模糊不清,所以我不得不将其删除。感谢苹果让我的git历史记录无法在最新的Xcode上编译 :) - Gabriel Gava
Xcode 10.2 中已修复:不再需要那个解决方法。 - Cœur
我正在使用10.2.1版本,仍然无法获取该方法。即使添加了objC文件也不行。 - Krutika Sonawala

7
如果您的应用程序与iOS 9或以下版本不兼容,则上面的答案(由Rhythmic Fistman提供)是正确的。如果您的应用程序与iOS 9兼容,则会看到下一个错误:“'setCategory'在Swift中不可用”。在这种情况下,Swift 4.2存在一个错误,这是Xcode 10 SDK中AVFoundation的问题,您可以编写一个Objective-C函数来调用旧API,因为它们仍然在Objective-C中可用。您可以在下面的链接中阅读更多详细信息:https://forums.swift.org/t/using-methods-marked-unavailable-in-swift-4-2/14949

一个比编写 Objective-C 代码更容易的解决方法是使用 perform,如 ricardopereira 的回答所述。 - Cœur

5
将以下内容粘贴到您的viewDidLoad()中。
do {
    try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: AVAudioSession.Mode.default, options: [])
    try AVAudioSession.sharedInstance().setActive(true)
}
catch {
    print(error)
}

你也可以将以下代码添加到AppDelegate.swift文件中。下面是方法: func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { } - Maulik Patel

3
//Swift 4.2
if #available(iOS 10.0, *) {
    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, 
    mode: AVAudioSessionModeDefault)
} else {
 //Fallback on earlier versions
}

4
你好,欢迎来到 Stack Overflow。请 [编辑] 你的答案以解释你的代码。提前致谢。 - grooveplex

3

Swift 5

let audioSession = AVAudioSession.sharedInstance()
_ = try? audioSession.setCategory(.playback, options: .defaultToSpeaker)
_ = try? audioSession.setActive(true)

无法工作!.playback 导致错误 Error Domain=NSOSStatusErrorDomain Code=-50 "(null)"。但将其更改为 .playAndRecord 可以解决问题。 - iKK

1

Swift 4的代码:

do {
        try AKSettings.setSession(category: .playback, with: [])
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, mode: AVAudioSessionModeDefault, options: [])
        try AVAudioSession.sharedInstance().setActive(true)


    } catch {
        print(error)
    }

希望有所帮助。

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