【问题标题】:SPTSessionManager does not initialize or failSPTSessionManager 未初始化或失败
【发布时间】:2020-03-06 03:33:43
【问题描述】:

当我尝试调用 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 中的空白应用程序也存在此问题,并且不会停止执行。

【问题讨论】:

标签: ios swift xcode spotify


【解决方案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: [:])
}

完成此操作后,应用程序远程连接,打印所有打印语句并表示应用程序远程已连接。

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,一直收到完全相同的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 中删除此属性,它应该对您有用(或者,至少对我有用)。

    P.S.,如果您想使用场景委托并使用 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."的部分

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-25
      • 2012-11-17
      • 2017-12-10
      • 2018-09-17
      • 1970-01-01
      • 2018-10-13
      • 2014-03-13
      • 1970-01-01
      相关资源
      最近更新 更多