1

我们正在开发一款 iOS 音乐应用。对于内容保护,我们将使用 Apple 的 fairplay DRM 系统。我正在关注苹果的 HDLCalog 示例以供参考。在实现时,我注意到类中有两种方法AssetLoaderDelegate需要实现。如果有人可以帮助我了解如何实现以下两种方法,我将不胜感激。提前致谢。

1.)

public func fetchApplicationCertificate() -> Data? {

    // MARK: ADAPT: YOU MUST IMPLEMENT THIS METHOD.
    let applicationCertificate: Data? = nil

    if applicationCertificate == nil {
        fatalError("No certificate being returned by \(#function)!")
    }        


    return applicationCertificate
}

2.)

public func contentKeyFromKeyServerModuleWithSPCData(spcData: Data, assetIDString: String) -> Data? {

    // MARK: ADAPT: YOU MUST IMPLEMENT THIS METHOD.
    let ckcData: Data? = nil

    if ckcData == nil {
        fatalError("No CKC being returned by \(#function)!")
    }


    return ckcData
}

我在这里更新我们设法实现了 fetchApplicationCertificate() 方法。现在我们面临生成 ckc 数据的问题

4

2 回答 2

0

申请证书

应用程序证书是您在 Apple 注册 Fairplay 时创建的 DER 格式的公共证书。这应该放置在 Web 服务器上(AWS S3 是理想的)并在每个应用程序会话中检索一次。

CKC数据

这特定于您使用 Fairplay 许可服务的任何人。他们将指定一个接口,用于将 SPC 数据从您的客户端发送到他们的许可证服务器。这可以是 JSON over REST、SOAP、MQ 或他们选择的任何东西。您将不得不向他们询问 API 规范。

于 2017-05-22T07:46:55.780 回答
0

步骤1 :

 let queue                       = DispatchQueue(label: "fairplay.resourcerequests", attributes: [])

    let url                         = URL(string: videoUrl)!   // Streaming the video from this URL

    let videoAsset                  = AVURLAsset(url: url, options: nil)
    videoAsset.resourceLoader.setDelegate(self, queue: queue)

第2步:

extension PlayerViewController : AVAssetResourceLoaderDelegate{

func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {

    let url = loadingRequest.request.url
    var error: NSError?
    print("Player Delegate Method")
    print("URL Schema Is  \(url?.scheme! ?? "")")
    if((url?.scheme ?? "") == "skd"),
        let assetString = url!.host, let assetID = assetString.data(using: String.Encoding.utf8) // Get the URI for the content key.{guard let fetchedCertificate = self.fetchedCertificate else { return false} // Get the application certificate from the server.

            let requestedBytes = try loadingRequest.streamingContentKeyRequestData(forApp: fetchedCertificate, contentIdentifier: assetID, options: nil)


            do{

                print("Online Video Streaming Going On")

                let responseData = try contentKeyFromKeyServerModuleWithRequestData(requestedBytes, assetString: assetString, expiryDuration: expiryDuration)
                guard let dataRequest = loadingRequest.dataRequest else {
                    //                        print("Failed to get instance of AVAssetResourceLoadingDataRequest (loadingRequest.dataRequest).")
                    return false
                }

                dataRequest.respond(with: responseData)

                if let infoRequest = loadingRequest.contentInformationRequest,
                    expiryDuration != 0.0
                {

                    infoRequest.renewalDate = Date(timeIntervalSinceNow: expiryDuration)

                    infoRequest.contentType = "application/octet-stream"
                    infoRequest.contentLength = Int64(responseData.count)
                    infoRequest.isByteRangeAccessSupported = false
                }

                // Treat the processing of the requested resource as complete.
                loadingRequest.finishLoading()

                // The resource request has been handled regardless of whether the server returned an error.
                return true

            }catch let e as NSError
            {
                error = e
                //                    print("content key  error\(error)")
            }
        }catch let e as NSError {
            error = e
            // Resource loading failed with an error.
            //                print("streamingContentKeyRequestDataForApp failure: \(error.localizedDescription)")

        }}}

第 3 步:

func contentKeyFromKeyServerModuleWithRequestData(_ requestBytes: Data, assetString: String, expiryDuration: TimeInterval?=0.0, persitent:Bool?=true) throws -> Data {
    // If the key server provided a CKC, return it.
    //        if let ckcData = ckcData {
    //            return ckcData
    //        }
    //        else
    //        {
    let base64Decoded = requestBytes.base64EncodedString(options: NSData.Base64EncodingOptions())

    //MARK: Get Fairplay license for the current user
    NSLog("using ticket: %@", streamTicket )
    if let returnData:Data = mediaMakerDRMLicenseCall(base64Decoded, ticket: streamTicket)
    {
        if returnData.count <= 0
        {

            //                 Otherwise, the CKC was not provided by key server. Fail with bogus error.
            //                 Generate an error describing the failure.

            throw NSError(domain: "com.example.apple-samplecode", code: 0, userInfo: [
                NSLocalizedDescriptionKey: NSLocalizedString("Item cannot be played.", comment: "Item cannot be played."),
                NSLocalizedFailureReasonErrorKey: NSLocalizedString("Could not get the content key from the Key Server.", comment: "Failure to successfully send the SPC to the Key Server and get the content key from the returned Content Key Context (CKC) message.")
                ])
        }
        else
        {
            return returnData
        }
    }
    //}
}

第4步:

func mediaMakerDRMLicenseCall(_ playerSPC : String, ticket : String) -> Data{// API Call to fetch license from client server}
于 2018-12-03T10:00:11.500 回答