40

我正在编写一个基本的音乐播放器应用程序,但在处理应用程序状态转换时遇到了一些问题。

我正在使用 Swift 3 和 MPMusicPlayerController.systemMusicPlayer()

目标是这样的:

1)当用户点击主页按钮并且应用程序进入bg时保持音乐播放(有效)

2)如果用户退出应用程序,则停止播放器( myMP.stop() )(有时有效,其他时候抛出错误)

我根据可能的操作使用打印语句跟踪流程并得到以下信息:

在此处输入图像描述

流程 2 是我所期望的,但流程 1 在应用程序关闭时会引发错误 - 我希望在这里“将终止”。

编辑:主要问题是当使用 Flow 1 退出应用程序时,永远不会调用“将终止” - 因此永远不会调用“myMP.stop()”,并且播放器在应用程序退出后继续播放。

如果您在应用程序处于活动状态时单击主页一次(流程 1)或两次(流程 2),行为会有明显差异。

为什么我会从应该是相同的操作中得到两个不同的响应?

编辑:最重要的是,如果 Flow 1 的 MediaPlayer 永远不会“将终止”,我该如何停止它?

编辑:

这是一些复制问题的示例代码:

AppDelegate.swift

//
//  AppDelegate.swift
//  Jumbo Player
//

import UIKit
//import MediaPlayer

//doesn't matter where this is declared - here or in ViewController - same results
//let myMP:MPMusicPlayerController = MPMusicPlayerController.systemMusicPlayer()

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

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
        print("applicationWillResignActive")
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        print("applicationDidEnterBackground")
    }

    func applicationDidReceiveMemoryWarning(_ application: UIApplication) {
        print("applicationDidReceiveMemoryWarning")
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        print("applicationWillEnterForeground")
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        print("applicationDidBecomeActive")
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        print("applicationWillTerminate")
        myMP.stop();
    }
}

ViewController.swift

//
//  ViewController.swift
//  junkplayer
//

import UIKit
import MediaPlayer

let myMP:MPMusicPlayerController = MPMusicPlayerController.systemMusicPlayer()

class ViewController: UIViewController {

    @IBOutlet weak var xxx: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let qrySongs = MPMediaQuery.songs()
        myMP.setQueue(with: qrySongs)

    }

    @IBAction func playbut(_ sender: UIButton) {
        myMP.play()
    }
}

在此处下载项目:www.NextCoInc.com/public/junkplayer.zip

4

3 回答 3

50

“因信号 9 而终止”消息仅表示您的应用程序已被 SIGKILL 信号终止。每当您的应用程序非自愿终止时,操作系统都会发送该信号,无论是由于内存压力(或与此讨论无关的其他几个原因),还是用户通过双击主页按钮并将其滑开来明确终止您的应用程序。

在您的情况下,用户明确地杀死了您的应用程序,因此完全可以预期“由于信号 9 而终止”消息。如果您的应用程序是当前前台应用程序,您的applicationWillTerminate方法将被调用,如上面的逻辑流程大纲所示(流程 2)。如果您的应用程序不是当前前台应用程序(流程 1),applicationWillTerminate如果您的应用程序处于挂起状态,您的方法将不会被调用。这是预期的行为。还要注意“背景状态”和“暂停状态”之间的区别。 他们不是一回事

因此,如果我对您的理解正确,那么听起来问题是在您的应用程序被用户终止后音频继续播放(流程 1)。这意味着您在处理 时做错了MPMusicPlayerController,因为它应该自动处理该状态转换。

确保为您的应用设置了正确的UIBackgroundMode。设置错误的后台模式可能会导致您的应用程序行为异常,因为操作系统仅允许在后台执行某些操作,具体取决于您设置的后台模式。设置错误的模式(或尝试在您设置的模式中明确禁止的事情)将导致您的应用程序被暂停或终止。

确保您已正确设置音频会话。

确保您正确响应音乐播放器的通知- 特别是,确保您正在适当地拨打电话,beginGeneratingPlaybackNotifications并且endGeneratingPlaybackNotifications您正在正确处理这些通知。检查您的通知处理程序以确保您没有在其中做任何愚蠢的事情。在调用endGeneratingPlaybackNotifications.

如果您已正确完成其他所有操作,则MPMusicPlayerController几乎可以自行管理,因此当您的应用程序进入后台时,您不必做任何特别的事情来使其工作(UIBackgroundMode当然,除了设置正确的 )。作为最后的手段,开始注释代码,直到您的应用程序只是一个准系统的“打开音频文件并播放它”应用程序,然后查看它是否正确退出。如果是这样,您可以开始逐段取消注释代码,直到它失败 - 然后您知道您的应用程序的哪个部分导致了问题,您可以从那里缩小范围。

于 2017-05-01T19:47:49.813 回答
7

Settings应用程序权限Camera或使用情况的更改Photo可能会导致此信号崩溃(硬刷新)。

您可以在以下链接中找到相关行为:

于 2019-12-13T11:33:32.390 回答
3

我正在为该应用程序执行三个后台任务。

<key>UIBackgroundModes</key>
<array>
    <string>bluetooth-central</string>
    <string>location</string>
    <string>remote-notification</string>
</array> 

Message from debugger: Terminated due to signal 9 当应用程序在后台运行时会出现此消息,并且它消耗的内存超出了 iPhone 操作系统为后台运行的应用程序分配的内存。

就我而言,我不断更新用户的位置并将用户的位置 api 执行到服务器。它消耗了大量的内存。由于这个原因,操作系统杀死了该应用程序。

由于操作系统的内存压力,我们收到此消息并在后台终止了该应用程序。

我优化了代码,每当我们需要更新用户的位置时,我们只需将位置 api 发送到服务器。我也是enable \ disable国旗allowsBackgroundLocationUpdates

if #available(iOS 9.0, *) {
   coreLocationManager.allowsBackgroundLocationUpdates = false
}

根据我们的需要。它工作得很好。

于 2017-08-10T12:39:46.630 回答