如何检查用户设备上是否安装了Apple Music?

10

我正在使用Swift制作一款音乐应用程序。该应用程序允许用户通过其Apple Music应用程序使用其Apple Music订阅播放音乐。我能够通过以下方式检查用户是否有Apple Music订阅:

SKCloudServiceController().requestCapabilities { (capability:SKCloudServiceCapability, err:Error?) in

    guard err == nil else {
        print("error in capability check is \(err!)")
        return
    }

    if capability.contains(SKCloudServiceCapability.musicCatalogPlayback) {
        print("user has Apple Music subscription")
    }

    if capability.contains(SKCloudServiceCapability.musicCatalogSubscriptionEligible) {
        print("user does not have subscription")
    }

}

然而:有一些情况,某些人会因为某种原因订阅了Apple Music,但没有在他们的设备上下载Apple Music应用程序。如果用户有订阅但没有设备,我希望将这种情况视为根本没有订阅,即我们无法通过Apple Music播放音乐。
因此,我开始寻找方法来检查用户设备上是否安装了Apple Music。我找到了这个答案:使用Swift检查应用是否已安装 结合 这个查找Apple Music的URL方案的资源,我得出结论,我可以通过以下方式检查用户是否同时拥有Apple Music订阅和安装在他们设备上的Apple Music应用程序:
SKCloudServiceController()requestCapabilities { (capability:SKCloudServiceCapability, err:Error?) in

    guard err == nil else {
        print("error in capability check is \(err!)")
        return
    }

    if capability.contains(SKCloudServiceCapability.musicCatalogPlayback) && UIApplication.shared.canOpenURL(URL(string: "music://")!) {
        print("user has Apple Music subscription and has the apple music app installed")
    }

    if capability.contains(SKCloudServiceCapability.musicCatalogSubscriptionEligible) || !UIApplication.shared.canOpenURL(URL(string: "music://")!) {
        print("user does not have subscription or doesn't have apple music installed")
    }

}

问题是,即使我从设备中删除了Apple Music,第一种情况仍会被调用,即打印“用户订阅了Apple Music并安装了Apple Music应用程序”。我相信我有正确的URL方案,因为当将“music://”更改为“musi://”时,第二种情况即打印“用户没有订阅或未安装Apple Music”被调用。
尝试通过“UIApplication.shared.open(URL(string:“music://”)!)”打开已删除Apple Music的“URL(string:“music://”)”,我遇到了以下警报:

enter image description here

所以,即使删除了Apple Music,设备为什么会显示我可以打开URL(string: "music://")URL是否能够被打开,但结果只是呈现上述警报?这是确认用户在设备上安装了Apple Music的正确方法吗?甚至有一种方法可以确认用户在设备上安装了Apple Music吗?如果Apple允许用户删除Apple Music应用程序,则还应该允许开发人员检查该应用程序是否已安装。

1
不幸的是,在我的info.plist中列入白名单并没有改变行为。我的问题是,即使删除了Apple Music应用程序,UIApplication.shared.canOpenURL(URL(string: "music://")!)始终返回true。我需要它在删除应用程序时返回false。列入url scheme白名单无法解决此问题(我已经尝试过了)。 - David Chopin
你找到更好的解决方案了吗? - Martin Mlostek
我提供了一个解决方法,但它要求您在MPMusicPlayerController.prepareToPlay的完成处理程序中进行检查,因此实际上直到用户尝试使用Apple Music(即播放歌曲)之前,您才能进行检查。@MartinMlostek - David Chopin
这个在你的iOS 12上工作吗?在我的测试中,第一次尝试没有调用准备回调函数。 - Martin Mlostek
MPMusicPlayerController.prepareToPlay 在iOS 10.1及以上版本中可用。https://developer.apple.com/documentation/mediaplayer/mpmusicplayercontroller/2582424-preparetoplay - David Chopin
显示剩余3条评论
7个回答

5

我最好的解决方案,虽然我认为还有更好的方法,就是使用MPMusicPlayer.prepareToPlay(completionHandler:)检查是否在尝试播放音轨时出现错误:

SKCloudServiceController().requestCapabilities { (capability:SKCloudServiceCapability, err:Error?) in

    guard err == nil else {
        print("error in capability check is \(err!)")
        return
    }

    if capability.contains(SKCloudServiceCapability.musicCatalogPlayback) {
        print("user has Apple Music subscription")
        MPMusicPlayerController.systemMusicPlayer.setQueue(with: ["1108845248"])
        systemMusicPlayer.prepareToPlay { (error) in
            if error != nil && error!.localizedDescription == "The operation couldn’t be completed. (MPCPlayerRequestErrorDomain error 1.)" {
                //It would appear that the user does not have the Apple Music App installed
            }
        }
    }

    if capability.contains(SKCloudServiceCapability.musicCatalogSubscriptionEligible) {
        print("user does not have subscription")
    }

}

我不确定这如何适用于在其应用程序中使用Apple Music进行除播放音轨以外的任何操作的任何人,但是当您要播放检查时,这似乎绝对有效。每当我遇到该错误时,我只需创建警报,告诉个人他们有一个Apple Music订阅,但没有安装该应用程序。

尽管如此,如果能够在没有完成处理程序的情况下进行检查将非常好,因为这将允许将布尔检查集成到条件语句中(通过if capability.contains(SKCloudServiceCapability.musicCatalogPlayback) && hasAppleMusicAppInstalled { //do something })。


这个解决方案通过检查错误来工作,但有点不太正规,并需要在完成处理程序中执行以下代码。最好有一种简单的方法来检查它是否是MusicKit框架的一部分,以及应用程序本身是否已安装。 - David Chopin
但是,是的,这个答案是一个解决方法,利用了准备播放曲目时出现的错误。开发人员可能需要知道是否安装了Apple Music,而不必播放曲目。 - David Chopin
1
你找到的这个解决方案还是最好的吗? - Martin Mlostek
不幸的是,是的。 - David Chopin

1

对于需要安装音乐应用程序以显示 MPMediaPickerController 的幸运用户,最简单的检查方法是查看视图是否已呈现。如果缺少音乐应用程序,则会静默失败。

let mediaPickerController = MPMediaPickerController(mediaTypes: MPMediaType.anyAudio)
mediaPickerController.delegate = self
mediaPickerController.prompt = "prompt"
presenter.present(mediaPickerController, animated: true, completion: nil)

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) { [weak self] () -> () in
    if self?.presenter.presentedViewController == nil {
        self?.callback(.failure(.failedToPresentMusicPickerError))
    }
}

等等,但这样还是会弹出一些东西,对吧? - Arnaldo Capo
如果有音乐应用程序,它将弹出MPMediaPickerController。如果应用程序不可用,则presentedViewController将为nil,您可以以适合您的应用程序的方式处理它。在上面的代码中,它将调用回调并传递错误代码。 - Raimundas Sakalauskas
在某些版本的iOS上,这会使您的视图控制器处于一种无法呈现任何内容的状态,直到不可能呈现的选择器被呈现为止 - 您需要调用dismissViewControllerAnimated来释放它。在其他版本中,MPMediaPickerController被呈现(presentedViewController!= nil),并且在它消失之前显示了一个错误,这将导致问题(没有双关语)如果您希望此操作静默运行。 - head in the codes
你能具体说明一下吗?你在哪些iOS版本上遇到了这个问题? - Raimundas Sakalauskas

1
幸运的是,苹果提供了一种方法,如果设备上没有安装任何应用程序来处理URL方案或者您没有在Info.plist文件中声明URL方案,则返回false;否则返回true。
func canOpenURL(_ url: URL) -> Bool

以下是我发布的URL方案。
Open = music://
Open = musics://
Open = audio-player-event://

将您将进一步使用的内容添加到info.plist文件中。

之后使用'canOpenURL'进行检查 有关更多信息,请查阅Apple文档

https://developer.apple.com/documentation/uikit/uiapplication/1622952-canopenurl


2
Apple Music的URL方案在通过canOpenUrl时总是返回true。这就是我想要解决的主要问题。 - David Chopin
你是否在LSApplicationQueriesSchemes中指定了“音乐应用程序”? - Zeeshan Ahmed
根据Karthick Ramesh的评论,我之前尝试过白名单URL方案,但行为没有改变。 - David Chopin
你不需要将 musicmusics 添加到 plist 中 - 它会自动工作。 - Yonathan Goriachnick

0
你可以使用这个属性来检测是否安装了Apple Music。
import MediaPlayer

var isAppleMusicInstalled: Bool {
    get async {
        await withCheckedContinuation { continuation in
            MPMusicPlayerController.systemMusicPlayer.setQueue(with: ["1108845248"])
            self.systemMusicPlayer.prepareToPlay { (error) in
                if error != nil && error!.localizedDescription.contains("error 6") {
                    print("Apple Music App not installed")
                    continuation.resume(returning: false)
                } else {
                    continuation.resume(returning: true)
                }
            }
        }
    }
}

请注意,这会触发一个权限对话框,并且您需要在您的 Info.plist 中添加 NSAppleMusicUsageDescription 键,值为“检查是否已安装 Apple Music”。

0
一个可能的解决方案是执行以下操作:通过Apple Music API设置开发者令牌(用于查询Apple Music REST端点)。向以下StoreKit函数提交请求(文档):
requestUserToken(forDeveloperToken:completionHandler:)

如果您的开发者令牌有效,且返回的用户令牌值仍为nil/null,则设备用户不是Apple Music服务的订阅者。HTTP状态代码生成的错误为401(未经授权)。这仍然需要您检查错误,但不需要尝试播放特定曲目(特别是如果您正在检查的内容曲目ID变得无效或更改)。

对于设备已登录帐户并具有订阅但未下载音乐应用程序的问题:在尝试播放特定内容时处理错误,并向用户提供信息或在出现错误时使用不需要Apple Music订阅的内容作为替代方案。


2
是的,我已经知道如何检查用户是否有订阅了。我上面提供的答案解决了实际的错误处理。我正在寻找的解决方案严格是关于如何判断用户是否在设备上安装了Apple Music应用程序,而不必尝试播放曲目。 - David Chopin

0

是的,我们可以通过以下步骤检查大多数应用程序:

  1. 使用特定应用程序的深度URLURL方案,将其添加到info.plist中以打开该应用程序
  2. 使用相同的URL并调用此方法
    func canOpenURL(_ url: URL) -> Bool

    let url = URL(string: "music://")

    UIApplication.shared.open(url!) { (result) in
       if result {
          // The URL was delivered successfully!
       }
    }

2
这不是问题,问题在于UIApplication.shared.canOpenUrl(URL(string: “music://”)!)无论应用程序是否安装,始终返回true - David Chopin
@DavidChopin 你找到解决方案了吗? - Krishna Kirana
很遗憾,@KrishnaKirana,我已经好几个月没有去看了。我给出的答案是可行的,但不是最理想的,它感觉有些“hacky”。 - David Chopin
这个问题已经在最新版本中修复了。@Kirshna Kirana - donkey

-1

直接进行:UIApplication.shared.canOpenUrl(URL(string: “music://”)!)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接