假设我有一款SwiftUI应用程序,它可以从列表中 Select 的URL开始播放音频:

struct ContentView: View {
    
    @ObservedObject var viewModel: ContentViewModel
    
    var body: some View {
        List(PlayerLinks.links, id: \.self) { link in
            Button(link) {
                viewModel.play(from: link)
            }
        }
    }
}

class ContentViewModel: ObservableObject {
    
    let player = Player()
    
    init() {
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(notificationAction),
            name: .newLinkChosen,
            object: nil
        )
    }
    
    func play(from url: String) {
        player.play(from: url)
    }
    
    @objc func notificationAction(_ notification: Notification) {
        if let userInfo = notification.userInfo,
           let newURL = userInfo["newLink"] as? String {
            self.play(from: newURL)
        }
    }
}

class Player {
    
    var player: AVPlayer?
    
    init() {
        do {
            try AVAudioSession.sharedInstance()
                .setCategory(
                    AVAudioSession.Category.playback,
                    mode: AVAudioSession.Mode.default,
                    options: []
                )
        } catch let error as NSError {
            print(error.localizedDescription)
        }
    }
    
    func play(from url: String) {
        let playerItem = AVPlayerItem(url: URL(string: url)!)
        player = AVPlayer(playerItem: playerItem)
        player?.play()
    }
}

这款应用程序有WatchOS配套应用程序,也有电台列表:

struct ContentWatchView: View {
    
    @ObservedObject var viewModel: ContentWatchViewModel
    
    var body: some View {
        List(PlayerLinks.links, id: \.self) { link in
            Button(link) {
                viewModel.onRowSelected(url: link)
            }
        }
    }
}

class ContentWatchViewModel: ObservableObject {
    
    var connectivityManager: WatchConnectivityManager
    
    init(connectivityManager: WatchConnectivityManager) {
        self.connectivityManager = connectivityManager
    }
    
    func onRowSelected(url: String) {
        connectivityManager.sendPlayerLinkToIOS(url)
    }
}

通过点击WatchOS应用程序中的ROW,我需要在iOS设备上启动AVPlayer播放.

为此,我实现了WatchConnectivityManager个来处理WatchOS和iOS应用程序之间的通信:

class WatchConnectivityManager: NSObject, ObservableObject, WCSessionDelegate {
    
    private let session: WCSession = WCSession.default
    var isReachable = false
    
    static var shared = WatchConnectivityManager()

    override init() {
        super.init()
        if WCSession.isSupported() {
            session.delegate = self
            session.activate()
        }
    }
    
    func session(
        _ session: WCSession,
        activationDidCompleteWith activationState: WCSessionActivationState,
        error: Error?
    ) {
        #if os(iOS)
        print("ACTIVATED ON IOS")
        #elseif os(watchOS)
        print("ACTIVATED ON WATCHOS")
        #endif
        DispatchQueue.main.async {
            self.isReachable = session.isReachable
        }
    }
    
    func sessionReachabilityDidChange(_ session: WCSession) {
        DispatchQueue.main.async {
            self.isReachable = session.isReachable
        }
    }
    
    #if os(iOS)
    func sessionDidDeactivate(_ session: WCSession) {
        session.activate()
    }

    func sessionDidBecomeInactive(_ session: WCSession) {
        print("Session did become inactive: \(session.activationState.rawValue)")
    }

    func sessionWatchStateDidChange(_ session: WCSession) {
        print("Session watch state did change: \(session.activationState.rawValue)")
    }
    #endif
    
    // MARK: MESSAGE RECEIVER
    func session(
        _ session: WCSession,
        didReceiveMessage message: [String : Any],
        replyHandler: @escaping ([String : Any]) -> Void
    ) {
        #if os(iOS)
        if let action = message["action"] as? String,
           action == "newPlayerLinkChosen",
           let link = message["link"] as? String {
            DispatchQueue.main.async {
                NotificationCenter.default.post(
                    name: .newLinkChosen,
                    object: nil,
                    userInfo: ["newLink": link]
                )
                replyHandler(["success": true])
            }
        } else {
            replyHandler(["success": false])
        }
        #endif
    }
    
    // MARK: MESSAGE SENDERS
    
    #if os(watchOS)
    func sendPlayerLinkToIOS(_ link: String) {
        let message = [
            "action": "newPlayerLinkChosen",
            "link": link
        ]

        session.sendMessage(message) { replyHandler in
            print(replyHandler)
        } errorHandler: { error in
            print(error.localizedDescription)
        }
    }
    #endif
}

extension Notification.Name {
    
    static let newLinkChosen = Notification.Name("NewLinkChosen")
}

sendPlayerLinkToIOSFFC发送具有选定链接的消息,该消息由MESSAGE RECEIVER方法接收,然后它将具有选定链接的通知发布到NotificationCenter.default.IOS ContentViewModel接收到该通知,然后播放器启动.

当iOS应用程序在前台时,一切都运行良好,however it's not working when we go to the Home Screen and choose some url from watch app again (the iOS app is not terminated).

以下是日志(log),如果它们对某人有帮助的话:

ACTIVATED ON IOS

2023-08-18 16:23:38.651377+0300 RemotePlayer[20479:6162721] [plugin] AddInstanceForFactory: No factory registered for id <CFUUID 0x6000022fce00> F8BB1C28-BAE8-11D6-9C31-00039315CD46

2023-08-18 16:23:52.046769+0300 RemotePlayer[20479:6163115] [AMCP]   4611          HALC_ProxyIOContext.cpp:783   HALC_ProxyIOContext::_StartIO(): Client running as an adaptive unboosted daemon

2023-08-18 16:23:52.047123+0300 RemotePlayer[20479:6163115]             HALPlugIn.cpp:519    HALPlugIn::StartIOProc: got an error from the plug-in routine, Error: 1852797029 (nope)

2023-08-18 16:23:52.048409+0300 RemotePlayer[20479:6163115] [aqme]                AQMEIO.cpp:211   error 1852797029

2023-08-18 16:23:52.049634+0300 RemotePlayer[20479:6163115] [aqme]  MEDeviceStreamClient.cpp:431   AQME Default-InputOutput: client stopping after failed start: <CA_UISoundClientBase@0x149514830>; running count now 0

2023-08-18 16:23:52.050233+0300 RemotePlayer[20479:6163115]      CA_UISoundClient.cpp:285   CA_UISoundClientBase::StartPlaying: AddRunningClient failed (status = 1852797029).
2023-08-18 16:23:53.738535+0300 RemotePlayer[20479:6163570] [AMCP]  59139          HALC_ProxyIOContext.cpp:783   HALC_ProxyIOContext::_StartIO(): Client running as an adaptive unboosted daemon

2023-08-18 16:23:53.741183+0300 RemotePlayer[20479:6163570]             HALPlugIn.cpp:519    HALPlugIn::StartIOProc: got an error from the plug-in routine, Error: 1852797029 (nope)

2023-08-18 16:23:53.744653+0300 RemotePlayer[20479:6163570] [aqme]                AQMEIO.cpp:211   error 1852797029

2023-08-18 16:23:53.745684+0300 RemotePlayer[20479:6163570] [aqme]  MEDeviceStreamClient.cpp:431   AQME Default-InputOutput: client stopping after failed start: <AudioQueueObject@0x14a809000; Unknown figplayer; [20479]; play>; running count now 0

推荐答案

我刚给自己买了Apple Watch,然后又测试了一下.当应用程序在后台和根本没有打开应用程序时,播放器工作正常.出于某种原因,这在仿真器上不起作用.因此,如果你在模拟器上遇到类似的问题,在真实的设备上try 一下,可能根本不是问题.

Ios相关问答推荐

构建iOS项目失败.我们运行了";xcodeBuild";命令,但它退出并返回错误代码65-expo reaction ative

SWIFT根据地球坐标修改 node 旋转

如何在本地iOS没有插件的情况下处理平台线程?

如何将 Info.plist 文件添加到 Xcode for admob,错误 添加后会产生多个命令

如何在 SwiftUI 中对表格行使用 Transferable

如何为 XCTest、SwiftUI 预览等初始化带有 @MainActor 注释的 Swift 类

iOS按钮和navigationLink在List中相邻

在标签中显示多个计数器但在同一屏幕(Swift,IOS)

SwiftUI 我自己的渲染函数的返回类型是什么?

如何在不支持并发的自动关闭中修复'async'调用?

分析应用程序版本时出错 - Apple 提交到store

如何在 Swift 中从另一个视图控制器将元素附加到数组中

如何快速设置条形按钮的图像?

缺少推送通知权利

滑动列表项以获取更多选项(Flutter)

SwiftUI 视图 - viewDidLoad()?

每个版本的 iOS 都附带什么版本的移动 Safari?

如何在ios中生成UUID

我的应用程序因使用广告支持框架而被拒绝.哪个图书馆负责?

AFNetworking 发布请求