当我尝试呼叫sessionManager.initialize()
时,func sessionManager(manager: SPTSessionManager, didFailWith error: Error)
和func sessionManager(manager: SPTSessionManager, didInitiate session: SPTSession)
都不会被呼叫。
我有一个运行在AWS上的nodeJS服务器,用于令牌访问和刷新,并且我还尝试过运行本地Ruby服务器来获取令牌。无论如何,调用initialize()
都无济于事。它确实失败还是成功,并且没有任何输出到控制台。我尝试过运行XCode调试器,好像程序只是跳过initialize
。这是我完整的ViewController.swift文件,其中删除了不相关/私有的部分:
import UIKit
import Firebase
class LobbyAdminViewController: UIViewController, SPTSessionManagerDelegate, SPTAppRemoteDelegate, SPTAppRemotePlayerStateDelegate {
fileprivate let SpotifyClientID = "client_id"
fileprivate let SpotifyRedirectURI = URL(string: "redirect_url")!
fileprivate var lastPlayerState: SPTAppRemotePlayerState?
var refreshAPI = "token_server/refresh_token"
var tokenAPI = "token_server/token"
lazy var configuration: SPTConfiguration = {
let configuration = SPTConfiguration(clientID: SpotifyClientID, redirectURL: SpotifyRedirectURI)
configuration.playURI = ""
configuration.tokenSwapURL = URL(string: tokenAPI)
configuration.tokenRefreshURL = URL(string: refreshAPI)
return configuration
}()
lazy var sessionManager: SPTSessionManager = {
let manager = SPTSessionManager(configuration: configuration, delegate: self)
return manager
}()
lazy var appRemote: SPTAppRemote = {
let appRemote = SPTAppRemote(configuration: configuration, logLevel: .debug)
appRemote.delegate = self
return appRemote
}()
override func viewDidLoad() {
super.viewDidLoad()
let random = Int(arc4random_uniform(900000) + 100000)
lobbyCode = String(random)
lobbyCodeLabel.text = lobbyCode
var ref: DatabaseReference!
ref = Database.database().reference()
ref.child(lobbyCode).child("null").setValue("null")
let scope: SPTScope = [.appRemoteControl]
if #available(iOS 11, *) {
print("ios 11+")
sessionManager.initiateSession(with: scope, options: .clientOnly)
} else {
print("ios 11-")
sessionManager.initiateSession(with: scope, options: .clientOnly, presenting: self)
}
}
func update(playerState: SPTAppRemotePlayerState) {
print("Updating")
lastPlayerState = playerState
currentSongLabel.text = playerState.track.name
currentArtistLabel.text = playerState.track.artist.name
if playerState.isPaused {
pausePlayButton.setBackgroundImage(UIImage(named: "play"), for: .normal)
} else {
pausePlayButton.setBackgroundImage(UIImage(named: "pause"), for: .normal)
}
}
func fetchPlayerState() {
print("Getting player state")
appRemote.playerAPI?.getPlayerState({ [weak self] (playerState, error) in
if let error = error {
print("Error getting player state:" + error.localizedDescription)
} else if let playerState = playerState as? SPTAppRemotePlayerState {
self?.update(playerState: playerState)
}
})
}
@IBAction func onTap_pausePlayButton(_ sender: UIButton) {
print("tapped")
if let lastPlayerState = lastPlayerState, lastPlayerState.isPaused {
appRemote.playerAPI?.resume(nil)
print("Resuming")
} else {
appRemote.playerAPI?.pause(nil)
print("Pausing")
}
}
func sessionManager(manager: SPTSessionManager, didFailWith error: Error) {
print("Bad init")
print(error.localizedDescription)
}
func sessionManager(manager: SPTSessionManager, didRenew session: SPTSession) {
print("Renewed")
}
func sessionManager(manager: SPTSessionManager, didInitiate session: SPTSession) {
print("Trying to connect")
appRemote.connectionParameters.accessToken = session.accessToken
print(session.accessToken)
appRemote.connect()
}
// MARK: - SPTAppRemoteDelegate
func appRemoteDidEstablishConnection(_ appRemote: SPTAppRemote) {
print("App Remote Connected")
appRemote.playerAPI?.delegate = self
appRemote.playerAPI?.subscribe(toPlayerState: { (success, error) in
if let error = error {
print("Error subscribing to player state:" + error.localizedDescription)
}
})
fetchPlayerState()
}
func appRemote(_ appRemote: SPTAppRemote, didDisconnectWithError error: Error?) {
lastPlayerState = nil
print("Error connecting to app remote")
}
func appRemote(_ appRemote: SPTAppRemote, didFailConnectionAttemptWithError error: Error?) {
lastPlayerState = nil
print("Another error connectiong to app remote")
}
// MARK: - SPTAppRemotePlayerAPIDelegate
func playerStateDidChange(_ playerState: SPTAppRemotePlayerState) {
print("Player state changed")
update(playerState: playerState)
}
// MARK: - Private Helpers
fileprivate func presentAlertController(title: String, message: String, buttonTitle: String) {
let controller = UIAlertController(title: title, message: message, preferredStyle: .alert)
let action = UIAlertAction(title: buttonTitle, style: .default, handler: nil)
controller.addAction(action)
present(controller, animated: true)
}
}
唯一触发的print()
语句是viewDidLoad()
中的“ ios 11”
我已经搜索了互联网上有同样问题的任何人,但空了。
我唯一能想到的可能是导致此问题的原因是iOS 13的已知运行时问题。此错误:
Can't end BackgroundTask: no background task exists with identifier 8 (0x8), or it may have already been ended. Break in UIApplicationEndBackgroundTaskError() to debug.
。但是,即使XCode中的应用程序为空,也存在此问题,并且不会停止执行。
答案 0 :(得分:1)
我现在才知道。在场景委托类中,您必须实现
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
}
方法,您必须访问LobbyAdminViewController中具有的sessionManager并创建它的实例,并将这些代码行添加到方法中
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
print("Opened url")
guard let url = URLContexts.first?.url else {
return
}
lobbyAdminVC.sessionManager.application(UIApplication.shared, open: url, options: [:])
}
完成此操作后,应用程序遥控器已连接,并且所有打印语句已打印,并且所述应用程序遥控器已连接。
答案 1 :(得分:0)
我遇到了同样的问题,一直遇到完全相同的Can't end BackgroundTask
错误,并且卡住了一段时间。直到我弄清楚问题(就我而言)。它与您的AppDelegate.swift
文件有关。该错误代码实际上与我不认为的问题无关,这只是会话初始化突然停止之前记录到控制台的最后一件事。
随着scene delegates的推出,最近几个月以来,默认的App Delegate文件已更改。您需要做的是确保您没有使用与场景委托一起使用的更新的App Delegate,而是需要将App Delegate转换为过去的样子。
对我来说,从我的应用程序中完全删除场景委托涉及两个步骤:
1。还原您的AppDelegate.swift文件
我的看起来像这样:
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var application: UIApplication!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return true
}
func applicationWillResignActive(_ application: UIApplication) {
//SpotifyManager.shared.appRemote is of type SPTAppRemote
if SpotifyManager.shared.appRemote.isConnected {
SpotifyManager.shared.appRemote.disconnect()
}
}
func applicationDidBecomeActive(_ application: UIApplication) {
//SpotifyManager.shared.appRemote is of type SPTAppRemote
if let _ = SpotifyManager.shared.appRemote.connectionParameters.accessToken {
SpotifyManager.shared.appRemote.connect()
}
}
}
2。从您的info.plist
中删除Application Scene Manifest
在info.plist文件中,有一个属性告诉您的应用程序您正在使用场景委托。我们需要从plist中删除它。它应该看起来像这样:
<key>UIApplicationSceneManifest</key>
<dict>
<key>New item</key>
<string></string>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
如果您更新应用程序委托并将其从plist中删除,则该属性应该对您有用(或者至少对我有用)。
PS (如果要使用场景委托并使用Spotify SDK,I believe you have to do it in the way outlined in this resource)。值得注意的是,请查找授权指南中提到"If you are using UIScene then you need to use appropriate method in your scene delegate."