【问题标题】:How to check if Apple Music is installed on the user's device?如何检查用户设备上是否安装了 Apple Music?
【发布时间】:2020-03-05 10:27:46
【问题描述】:

我正在用 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 是否在用户的设备上。我找到了这个答案:Check whether an app is installed using Swift 结合 this resource for finding Apple Music's url scheme 并得出结论,我可以检查用户是否订阅了 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,第一个案例,即打印 user has Apple Music subscription and has the apple music app installed 的案例仍然被调用。我相信我有正确的 url 方案,因为当将"music://" 更改为"musi://" 时,第二种情况,即打印user does not have subscription or doesn't have apple music installed 的情况正在被调用。

当尝试打开 URL(string: "music://") 并通过 UIApplication.shared.open(URL(string: "music://")!) 删除 Apple Music 时,我收到以下警告:

那为什么设备说我可以打开URL(string: "music://"),即使Apple Music 被删除了? URL 是否可以打开,但结果只是上述警报的呈现?这是确认用户在其设备上安装了 Apple Music 的正确方法吗?有没有办法确认用户在他们的设备上安装了 Apple Music? 如果 Apple 允许用户选择删除 Apple Music 应用,他们还应该让开发者能够检查应用是否已安装。

【问题讨论】:

  • 我自己从未使用过 Apple Music,但我相信 Apple 以一种特殊的方式对待这个 url 方案,因为它是他们自己的产品,所以每当你点击那个 url 方案时,他们最好向用户提出建议下载应用程序,而不是返回 false。您是否尝试确定一个有效的 url 方案,该方案实际上会在 Apple Music 中打开一张真正的专辑或播放一首真正的歌曲?例如:URL(string: "music://trackID=3214534")。也许这个显式 url 方案会以通常的方式处理,但不会触发 app restore 警报。
  • 我尝试了一些使用有效 Apple Music 曲目和艺术家 ID 的 URL,这些 URL 似乎与 Apple Music 没有深度链接:URL(string: "music://trackId=1377813289")!,URL(string: "music://track=1377813289"),URL(string: "music://artist=562555")!,@987654340 @。我能够进行深度链接的唯一方法是通过URL(string: "https://music.apple.com/us/artist/562555")! 之类的方法,但这显然无济于事,因为这是 HTTP。
  • 您是否使用 LSApplicationQueriesSchemes 在 info.plist 中将“music://”列入白名单?如果不是,canOpenUrl 应该是行为不端。
  • 不幸的是,将我的 info.plist 中的方案列入白名单根本不会改变行为。我的问题是 UIApplication.shared.canOpenURL(URL(string: "music://")!) 一直在返回 true,即使 Apple Music 应用程序已被删除。当应用程序被删除时,我需要它返回false。将 url 方案列入白名单并不能解决这个问题(我试过了)。
  • 你找到更好的解决方案了吗?

标签: ios swift nsurl apple-music


【解决方案1】:

我得到的最佳解决方案是使用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 })。

【讨论】:

  • 嗯,这个解决方案通过检查错误来工作,但它有点hacky,需要在完成处理程序中执行以下代码。最好有办法简单检查,是否是 MusicKit 框架的一部分,是否安装了应用本身。
  • 但是是的,这个答案是一种在准备播放曲目时利用错误的解决方法。开发者可能需要知道 Apple Music 是否在未播放曲目的情况下安装。
  • 这仍然是您找到的最佳解决方案吗?
  • 很遗憾,是的
【解决方案2】:

对于需要安装音乐应用来显示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))
    }
}

【讨论】:

  • 等等,但是这还是会弹出一些东西不是吗?
  • 如果有音乐应用,它会弹出 MPMediaPickerController。如果应用程序不可用,presentedViewController 将为 nil,您可以以适合您应用程序的方式处理它。如果是上面的代码,它将调用回调并传递错误代码。
  • 在某些版本的 iOS 上,这会使您的视图控制器陷入困境,在出现不可能呈现的选择器之前,它无法呈现任何东西 - 您需要调用 dismissViewControllerAnimated再次释放它。在其他版本上,会显示MPMediaPickerController (presentedViewController != nil),并在它消失之前显示错误,如果您希望它静默运行,则会出现问题(不是双关语)
  • 你能说得更具体点吗?您在哪个 iOS 版本上体验过?
【解决方案3】:

幸运的是,Apple 为您提供了一个方法,如果设备上没有注册任何应用程序来处理 URL 的方案,或者如果您没有在 Info.plist 文件中声明 URL 的方案,则该方法返回 false;否则,为真。

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

【讨论】:

  • Apple Music 的 url 方案在通过 canOpenUrl 传递时总是返回 true。这是我想用这个问题解决的主要问题。
  • 您是否在 LSApplicationQueriesSchemes 中指定了“音乐应用”?
  • 根据 Karthick Ramesh 的评论,我之前尝试将 URL 方案列入白名单而不改变行为
  • 您无需在 plist 中添加 musicmusics - 无论如何都可以使用
【解决方案4】:

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

requestUserToken(forDeveloperToken:completionHandler:)

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

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

【讨论】:

  • 是的,所以我已经知道如何检查用户是否有订阅。我上面提供的答案解决了实际的错误处理。我正在寻找的解决方案是严格您是否可以判断用户是否在设备上安装了 Apple Music 应用 而不必尝试播放曲目。
【解决方案5】:

是的,我们可以按照以下步骤检查大部分应用程序:

  1. 为您要打开的特定应用程序使用 Deep URLURL Scheme,将其添加到 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!
       }
    }

【讨论】:

  • 这不是问题,问题概述了UIApplication.shared.canOpenUrl(URL(string: “music://”)!) 总是返回true,即使未安装应用程序。
  • @DavidChopin 你找到解决方案了吗?
  • 不幸的是@KrishnaKirana,我已经好几个月没有研究它了。我给出的答案有效,但感觉并不理想。感觉“hacky”。​​
  • 此问题已在最新版本中得到修复。 @Kirshna Kirana
【解决方案6】:

只需:UIApplication.shared.canOpenUrl(URL(string: “music://”)!)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    • 2016-06-30
    • 1970-01-01
    • 2021-04-03
    相关资源
    最近更新 更多