Siri INPlayMediaIntent не воспроизводит подкаст-шоу - PullRequest
0 голосов
/ 12 июля 2020

Я пытался следовать примеру Apple пример кода , но адаптирован для подкастов , и Siri не может воспроизводить шоу даже после написания кода для рекомендованного INPlayMediaIntent то есть только Resolve и Handle (как для расширения, так и для приложения в фоновом режиме).

Я также следил за документами для включения Siri, запросив авторизацию в приложении сначала с помощью трех шагов , и не происходит сбоев во время выполнения.

У меня есть следующий код для моего расширения IntentHandler:

import Intents
import IntentsUI
import MediaPlayer

class IntentHandler: INExtension, INPlayMediaIntentHandling {

  func resolveLocalPodcastFromSearch(_ mediaSearch: INMediaSearch, completion: ([INMediaItem]?) -> Void) {
    // Look up podcast in the local library.
    guard let podcastName = mediaSearch.mediaName,
          let podcast = MediaPlayerUtilities.searchForPodcastInLocalLibrary(byName: podcastName) else {
      completion(nil)
      return
    }
    
    // Construct the media item with an identifier indicating this is a local identifier.
    let persistentID = "\(MediaPlayerUtilities.LocalLibraryIdentifierPrefix)\(podcast.persistentID)"
    let mediaItem = INMediaItem(identifier: persistentID, title: podcast.podcastTitle, type: .podcastShow, artwork: nil)
    
    completion([mediaItem])
  }
  
  func  resolveMediaItems(for optionalMediaSearch: INMediaSearch?, completion: @escaping ([INMediaItem]?) -> Void) {
      guard let mediaSearch = optionalMediaSearch else {
        completion(nil)
        return
      }
      
      switch mediaSearch.mediaType {
        case .podcastShow:
          self.resolveLocalPodcastFromSearch(mediaSearch, completion: completion)
        default:
          completion(nil)
      }
  }

Я не уверен, как разработать свой собственный пользовательский logi c для высоконадежного поиска по транскрипции Siri, поскольку я не могу использовать точки останова. Я не знаю, как надежно искать подкаст по заголовку показа, поскольку текст из заголовка показа подкаста не имеет знаков препинания, дефисов или нечетного альтернативного текста, и я скопировал его точно во фразе вызова в Edit Scheme.

Вот подкаст в приложении для подкастов:

Podcast description

App Intent Vocabulary

My app intent vocabulary plist similar to the sample code (my display name is "Siri Podcasts"), also seems to not miss out essential keys given the project compiles. The only things I've changed are the INPlayMediaIntent.showTitle and removing the INAddMediaIntent. I am not fully 100% sure on the variable name, as mediaShowTitle is a property of INVocabularyStringType , however presumed it'd work as the same format worked for mediaPlaylistTitle also from INVocabularyStringType in the sample code.

(Followed all steps as recommended by Apple in the WWDC 19: Introducing SiriKit Media Intents). I have tried to resolve the podcast from my local library as follows in the AppDelegate handler, using the library:// prefix as I have downloaded the latest 2 podcast shows to my device:

class MediaPlayerUtilities {
    public static let LocalLibraryIdentifierPrefix = "library://"

    private class func searchForPodcastInLocalLibrary(withPredicate predicate: MPMediaPropertyPredicate) -> MPMediaItem? {
        let mediaQuery = MPMediaQuery.podcasts()
        mediaQuery.addFilterPredicate(predicate)

      return mediaQuery.items?.first
    }

    class func searchForPodcastInLocalLibrary(byName podcastName: String) -> MPMediaItem? {
        let predicate = MPMediaPropertyPredicate(value: podcastName, forProperty: MPMediaItemPropertyPodcastTitle)
        return searchForPodcastInLocalLibrary(withPredicate: predicate)
    }

    class func searchForPodcastInLocalLibrary(byPersistentID persistentID: UInt64) -> MPMediaItem? {
        let predicate = MPMediaPropertyPredicate(value: persistentID, forProperty: MPMediaItemPropertyPersistentID)
        return searchForPodcastInLocalLibrary(withPredicate: predicate)
    }
}

The relevant App Delegate code is here:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
  
  var window: UIWindow?
  var player: AVPlayer?

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
    // Set our podcast title in AppIntentVocabulary.plist so we get the proper Siri intent.
    // In your app, you'll want to make this dynamically tuned to a user's podcast titles.
    let vocabulary = INVocabulary.shared()
    let podcastNames = NSOrderedSet(objects: "The Talk Show with John Gruber")
    vocabulary.setVocabularyStrings(podcastNames, of: .mediaShowTitle)
    
    INPreferences.requestSiriAuthorization { (status) in
      print(status)
    }
    
    return true
  }

  func handlePlayMediaIntent(_ intent: INPlayMediaIntent, completion: @escaping (INPlayMediaIntentResponse) -> Void) {
    // Extract the first media item from the intent's media items (these will have been resolved in the extension).
    guard let mediaItem = intent.mediaItems?.first, let identifier = mediaItem.identifier else {
      return
    }
    
    // Check if this media item is a podcast and if it's identifier has the local library prefix.
    if mediaItem.type == .podcastShow, let range = identifier.range(of: MediaPlayerUtilities.LocalLibraryIdentifierPrefix) {
      // Extract the persistentID for the local podcast and look it up in the library.
      guard let persistentID = UInt64(identifier[range.upperBound...]),
            let podcast = MediaPlayerUtilities.searchForPodcastInLocalLibrary(byPersistentID: persistentID) else {
        return
      }
      
      guard let podcastURL = podcast.assetURL else {
        return
      }
      
      // Set the player queue to the local show.
      player = AVPlayer(url: podcastURL)
      
      DispatchQueue.main.async {
        self.player?.play()
      }
    } else {
      print("ERROR with finding in library.")
    }
    
    
    completion(INPlayMediaIntentResponse(code: .success, userActivity: nil))
  }

  // This method is called when the application is background launched in response to the extension returning .handleInApp.
  func application(_ application: UIApplication, handle intent: INIntent, completionHandler: @escaping (INIntentResponse) -> Void) {
    guard let playMediaIntent = intent as? INPlayMediaIntent else {
      completionHandler(INPlayMediaIntentResponse(code: .failure, userActivity: nil))
      return
    }
    handlePlayMediaIntent(playMediaIntent, completion: completionHandler)
  }
}

I've also tried to see if anything was printed in the console but there's nothing. The Podcasts app is not blocked due to Screen Time too, but Siri responds with "Just a sec", and then "Uh oh, something went wrong".

Sorry for the amount of code, but given I am unable to set breakpoints or debug in any way I felt it was the only way. The repository is live здесь на случай, если вы хотите что-то быстро собрать и протестировать (я использовал Xcode 12 beta для создания этого проекта).

Есть идеи?

...