如何为Fairplay实现生成iOS应用程序证书

时间:2017-05-09 06:40:57

标签: drm fairplay

我们正在开发iOS音乐应用。对于内容保护,我们将使用Apples fairplay DRM系统。我正在关注苹果的HDLCatalog示例以供参考。实现时我注意到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数据的问题

2 个答案:

答案 0 :(得分:0)

申请证书

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

CKC数据

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

答案 1 :(得分: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}