我们正在开发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数据的问题
答案 0 :(得分:0)
申请证书是您在Apple注册Fairplay时创建的DER格式公共证书。这应放在Web服务器上(AWS S3是理想的),并在每个应用程序会话中检索一次。
这适用于您在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}