DRM
DRM Example
We provide a sample implementation in the example app demonstrating how to use DRM with react-native-video. You’ll need a valid token—visit our site to obtain a free 24-hour token.
DRM Offline
If you need DRM-protected content available offline, our Offline Video SDK enables downloading, storing, and managing streams with and without DRM. It also handles many edge cases you may encounter over time.
Prerequisites:
- Use
react-native-videov6 or v7. If you're still on v5 or lower, contact us for assistance.
Supporting our software kits helps maintain this open-source project. Thank you!
Providing DRM Data (Tested with HTTP/HTTPS Assets)
You can configure DRM playback by providing a DRM object with the following properties. This feature disables the use of TextureView on Android.
DRM Properties
base64Certificate
Platforms: iOS | visionOS
Type: boolean
Default: false
Indicates whether the certificate URL returns data in Base64 format.
certificateUrl
Platforms: iOS | visionOS
Type: string
Default: undefined
The URL used to fetch a valid certificate for FairPlay.
getLicense
Platforms: iOS | visionOS
Type: function
Default: undefined
Instead of setting licenseServer, you can manually acquire the license in JavaScript and send the result to the native module for FairPlay DRM configuration.
The following parameters are available in getLicense:
contentId: The content ID from the DRM object orloadingRequest.request.url?.hostloadedLicenseUrl: The URL retrieved fromloadingRequest.request.URL.absoluteString, starting withskd://orclearkey://licenseServer: The URL passed in the DRM objectspcString: The SPC used for DRM validation
You should return a Base64-encoded CKC response, either directly or as a Promise.
Example:
getLicense: (spcString, contentId, licenseUrl, loadedLicenseUrl) => {
const base64spc = Base64.encode(spcString);
const formData = new FormData();
formData.append("spc", base64spc);
return fetch(`https://license.pallycon.com/ri/licenseManager.do`, {
method: "POST",
headers: {
"pallycon-customdata-v2": "your-custom-header",
"Content-Type": "application/x-www-form-urlencoded",
},
body: formData,
})
.then((response) => response.text())
.then((response) => response)
.catch((error) => console.error("Error", error));
};
contentId
Platforms: iOS | visionOS
Type: string
Default: undefined
Sets the content ID for the stream. If not specified, the system uses the host value from loadingRequest.request.URL.host.
headers
Platforms: Android | iOS | visionOS
Type: Object
Default: undefined
Custom headers for the license server request.
Example:
drm: {
type: DRMType.WIDEVINE,
licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
headers: {
'X-AxDRM-Message': 'your-drm-header',
},
}
licenseServer
Platforms: Android | iOS | visionOS
Type: string
Default: undefined
The license server URL that authorizes protected content playback.
multiDrm
Platform: Android
Type: boolean
Default: false
Indicates whether the DRM system should support key rotation. See Android Developer Docs for more details.
type
Platforms: Android | iOS
Type: DRMType
Default: undefined
Defines the DRM type:
- Android:
DRMType.WIDEVINE,DRMType.PLAYREADY,DRMType.CLEARKEY - iOS:
DRMType.FAIRPLAY
localSourceEncryptionKeyScheme
Platforms: iOS | visionOS
Type: string
Sets the URL scheme for stream encryption keys used in local assets.
Example:
localSourceEncryptionKeyScheme = "my-offline-key";
Common Usage Scenarios
Sending Cookies to the License Server
You can send cookies using the headers prop.
Example:
drm: {
type: DRMType.WIDEVINE,
licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
headers: {
'Cookie': 'PHPSESSID=your-session-id; csrftoken=mytoken; _gat=1; foo=bar'
},
}
Custom License Acquisition (iOS Only)
Example:
drm: {
type: DRMType.FAIRPLAY,
getLicense: (spcString) => {
const base64spc = Base64.encode(spcString);
return fetch('YOUR_LICENSE_SERVER_URL', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
getFairplayLicense: {
foo: 'bar',
spcMessage: base64spc,
}
})
})
.then(response => response.json())
.then((response) => {
if (response?.getFairplayLicenseResponse?.ckcResponse) {
return response.getFairplayLicenseResponse.ckcResponse;
}
throw new Error('No valid response');
})
.catch((error) => console.error('CKC error', error));
}
}