web-dev-qa-db-fra.com

AVAudioSession setCategory disponible dans Swift 4.2

Après avoir migré vers Swift 4.2, je reçois plusieurs erreurs, dont l’une est étrange. Cela ressemble à un bogue dans Xcode 1, mais existe-t-il une solution de contournement?

do {
    try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playAndRecord, with: options)
} catch {
    NSLog("Could not set audio session category")
}

**** 'setCategory (_: with :)' n'est pas disponible dans Swift

16
Deepak Sharma

iOS 10+

Si vous ciblez iOS 10 + , passez simplement à la nouvelle API et utilisez:

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

Anciennes versions iOS

Lorsque vous essayez ceci pour une application ciblant une ancienne version iOS (par exemple iOS 9) , vous obtenez une setCategory(_:mode:options:)' is only available on iOS 10.0 or newer Erreur.

Cela a été signalé comme erreur dans l'API d'Apple et corrigé dans Xcode 10.2. Pour les anciennes versions de Xcode (par exemple, Xcode 10.1) , il existe une solution de contournement que j'ai trouvée. Lorsque vous créez un assistant Objective-C comme décrit, vous pouvez toujours accéder à l'ancienne API car elle est toujours exposée pour Objective-C.

Solution de contournement 1: méthode .perform ()

Si vous souhaitez un correctif en ligne rapide sans traitement d'erreur, vous pouvez appeler l'API Obj.-C avec la méthode .perform():

if #available(iOS 10.0, *) {
  try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])
} else { 
  // Set category with options (iOS 9+) setCategory(_:options:)       
  AVAudioSession.sharedInstance().perform(NSSelectorFromString("setCategory:withOptions:error:"), with: AVAudioSession.Category.playback, with:  [])

  // Set category without options (<= iOS 9) setCategory(_:)
  AVAudioSession.sharedInstance().perform(NSSelectorFromString("setCategory:error:"), with: AVAudioSession.Category.playback)
}

Solution 2: méthode de la classe d'assistance

Voici les étapes à suivre pour le faire maintenant si vous voulez plus de contrôle sur les erreurs

  1. Créer un nouveau fichier Objective-C Dans mon cas AudioSessionHelper.m. Lorsque le système vous demande si un fichier d'en-tête de pontage doit être créé, cliquez sur Oui (si vous n'en avez pas déjà dans votre projet)
  2. Créer un nouveau fichier HeaderAudioSessionHelper.h
  3. Insérer le code
#ifndef AudioSessionHelper_h
#define AudioSessionHelper_h
#import <AVFoundation/AVFoundation.h>

@interface AudioSessionHelper: NSObject
+ (BOOL) setAudioSessionWithError:(NSError **) error;
@end

#endif /* AudioSessionHelper_h */
#import "AudioSessionHelper.h"
#import <Foundation/Foundation.h>

@implementation AudioSessionHelper: NSObject

+ (BOOL) setAudioSessionWithError:(NSError **) error {
    BOOL success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:error];
    if (!success && error) {
        return false;
    } else {
        return true;
    }
}
@end
  1. Insérez votre classe d'assistance dans le fichier d'en-tête de pontage
#import "AudioSessionHelper.h"
  1. Utilisez-le dans votre projet Swift
if #available(iOS 10.0, *) {
    try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])
} else {
    try AudioSessionHelper.setAudioSession()
}

Ce n'est pas beau et ajoute beaucoup de code et de fichiers inutiles à votre projet, donc utilisez-le si vous voulez ou devez utiliser de toute urgence Swift 4.2 sur Xcode 10.1 pour le moment. Dans tous les autres cas, vous devriez être mieux en utilisant Xcode 10.2.

31
Benno

Il s'agit d'un problème lié à AVFoundation dans les SDK de Xcode 10. Vous pouvez contourner ce problème en écrivant une fonction Objective-C qui fait appel à l'ancienne API, car elles sont toujours disponibles dans Objective-C. Mais si vous ne ciblez que iOS 10 ou une version ultérieure, vous pouvez écrire dans Swift.

do{
    if #available(iOS 10.0, *) {
        try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: options)
    } else {
        //the following line is now "unavailable", hence there is no way to support iOS <10
        //try AVAudioSession.sharedInstance().setCategory(.playAndRecord, with: options)
    }
} catch let error {
    print("Could not set audio session category: \(error.localizedDescription)")
}

Source: Forum rapide

1
Mehedi Hasan

Ce que je fais est d'appeler setCategory(_:mode:options:). Le paramètre options: Peut être omis et si vous n'avez pas de mode, vous pouvez utiliser un mode de .default.

1
matt

Le problème a été résolu dans Xcode 10.2.


Pour Xcode 10.1 avec iOS 9 (et versions antérieures), la seule autre solution proposée est celle de Benno. Elle repose sur Objective-C ou sur perform(NSSelectorFromString("setCategory:error:")). Malheureusement, le code fourni ne vous permet pas de gérer correctement les erreurs. Je souhaiterais donc présenter une solution reposant simplement sur le retour à Swift 4.1 dans un cadre séparé lors de l'utilisation de Xcode 10.1 (et cela fonctionnera même si votre projet utilise Swift 4.2).

L'astuce consiste simplement à créer un framework séparé (ou lib) pour encapsuler l'appel à setCategory(_:) en utilisant une version antérieure de Swift (comme 4.1). Dans ce framework, seulement besoin d'avoir:

import AVFoundation

extension AVAudioSession {
    @available (iOS 3.0, tvOS 9.0, watchOS 2.0, *)
    @objc open func setCategorySwift(_ category: String) throws {
        try setCategory(category)
    }
}

(également disponible via pod 'AVAudioSessionSetCategorySwift' )

Puis, revenons à votre Swift 4.2 (et éventuellement à un pod install)), Vous pouvez l’utiliser aussi simplement que setCategorySwift(AVAudioSession.Category.playback.rawValue). Un exemple plus long, avec try -catch, peut être:

import AVAudioSessionSetCategorySwift

let session = AVAudioSession.sharedInstance()
do {
    if #available(iOS 10.0, *) {
        try session.setCategory(AVAudioSession.Category.playback, mode: .default, options: [])
    } else {
        // Swift 4.2 workaround: https://github.com/coeur/AVAudioSessionSetCategorySwift
        try session.setCategorySwift(AVAudioSession.Category.playback.rawValue)
    }
    try session.setActive(true)
} catch {
    print("AVAudioSession.setCategory error: \(error)")
}
0
Cœur