SPTSessionManager不初始化或失败

时间:2019-11-09 23:43:53

标签: ios swift xcode spotify

当我尝试呼叫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.

每次将应用发送到后台时(即,当应用重定向到Spotify进行身份验证时),都会触发

。但是,即使XCode中的应用程序为空,也存在此问题,并且不会停止执行。

2 个答案:

答案 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."

的部分