react-native-video v7 DRM 实战:使用 @react-native-video/drm 插件接入 Widevine 与 FairPlay

发布时间:2026/9/28 2:24:28
react-native-video v7 DRM 实战:使用 @react-native-video/drm 插件接入 Widevine 与 FairPlay 音视频移动开发【免费下载链接】react-native-videoA component for react-native项目地址https://gitcode.com/gh_mirrors/re/react-native-video点击查看免费下载本指南以 react-native-video v7 的官方 DRM 文档 skills/react-native-video/references/v7/drm.md 为核心结合仓库内react-native-video/drm插件的 Swift/Kotlin 源码讲解如何安装并启用 DRM 插件、如何通过source.drm配置 WidevineAndroid与 FairPlayiOS播放受保护内容以及DrmParams各字段的语义与底层实现。读完本文你将能够在一行安装命令、一次enable()调用和一个drm配置对象内为你的播放器加上完整的 DRM 鉴权链路并理解 iOS 证书获取、SPC 生成、CKC 回填与 Android L3 降级重试的完整流程。一、先认清 v7 与 v6 的 DRM 架构差异在 v6 中DRM 是内置在Video组件上的drmprop直接挂在播放器组件上使用。而 v7 采用了全新的 Nitro 插件体系DRM 是一个独立的、可插拔的包安装后在应用启动时调用一次enable()注册到核心库的插件注册表随后通过source.drm字段按「每个视频源」配置鉴权参数。这一点在文档开头被特别强调——v6 的drmprop 指南在 v7 下完全不适用请务必按下面的 v7 流程操作。核心库负责播放react-native-video/drm只负责「内容解密许可」这一件事两者的边界通过 packages/react-native-video/ios/core/Plugins/PluginsRegistry.swift 中定义的原生插件接口衔接插件被注册进PluginsRegistrykey 为插件 ID重复注册会覆盖并打印警告当某个source带有drm配置时核心库通过getDrmManager(source:)遍历已注册插件向插件索取一个DRMManagerSpec实例见 HybridVideoPlayerSource.swift如果没有任何插件能提供 DRM 管理器核心库会抛出DRMPluginNotFound错误——这正是「忘记调用enable()」时会遇到的典型报错。二、安装两个包 原生依赖npm install react-native-video react-native-video/drm react-native-nitro-modules cd ios pod install安装后iOS 与 Android 都会自动链接。需要注意的是Expo 项目必须使用prebuildnpx expo prebuild生成原生工程后再安装Expo Go 不支持任何需要原生代码的 DRM 能力react-native-nitro-modules是 Nitro Modules 运行时react-native-video/drm插件通过NitroModules.createHybridObjectPluginManagerSpec(PluginManager)拿到原生对象见 packages/drm-plugin/src/index.tsx因此这个依赖是硬性要求不能省略。三、启动时启用一次在任何播放器创建之前import { enable } from react-native-video/drm; enable(); // iOS 会自动启用Android 必须手动调用该调用是幂等的enable()的实现非常轻量它只是调用原生侧PluginManager.enable()而原生侧会做幂等保护——iOS 端 PluginManager.swift 在isEnabled为真时直接返回仅首次调用才会创建DRMPlugin并注册进PluginsRegistryAndroid 端的DRMPlugin则在构造时直接返回DRMManager见 DRMPlugin.kt。同时包还导出disable()与isEnabled两个 APIindex.tsxdisable()用于反注册插件一般用于测试或热重载场景isEnabled是一个同步布尔值可用来做启动时的条件判断。为什么必须调用从源码看iOS 的PluginManager初始化init()时其实会自动调用一次enable()但 Android 没有这一行为——为了保证跨平台一致文档的建议是无论哪个平台都显式调用一次幂等特性保证了重复调用无副作用。如果漏掉这一步当一个带有drm配置的 source 加载时核心库会在 HybridVideoPlayerSource.swift 中找不到任何 DRM 管理器直接抛出LibraryError.DRMPluginNotFound即文档所说的DRMPluginNotFound-style 错误播放立即失败。四、通过source.drm配置每个视频源启用插件后DRM 参数是挂在每个视频源上的与播放器组件解耦。下面是文档中的完整示例已保留全部细节import { Platform } from react-native; import { useVideoPlayer, VideoView } from react-native-video; import { enable } from react-native-video/drm; enable(); const source Platform.OS android ? { // WidevineDASH .mpd uri: https://example.com/manifest.mpd, drm: { // Android 上 type 默认就是 widevine可省略 licenseUrl: https://license.example.com/widevine, licenseHeaders: { X-AxDRM-Message: token }, // Android这些 header 会随 LICENSE 请求发送 }, } : { // FairPlayHLS .m3u8 uri: https://example.com/master.m3u8, headers: { Authorization: Bearer token }, // iOS用于默认 license 请求 drm: { type: fairplay, // iOS 上必须显式设置 certificateUrl: https://license.example.com/fps-cert, licenseUrl: https://license.example.com/fps, }, }; function Player() { const player useVideoPlayer(source); return VideoView player{player} style{{ flex: 1 }} /; }需要特别留意的两点type的默认值由平台决定。即使你在drm里不写type核心库的 sourceFactory.ts 也会在解析 source 时用Platform.select自动补全Android 补widevineiOS 补fairplay。也就是说「Android 默认 Widevine」是核心库的解析层行为而 iOS 端 DRMManager 则会在 DRMManager.swift 中校验type fairplay其他类型直接抛Unsupported DRM type错误——所以 iOS 上显式写type: fairplay是最稳妥的写法。header 语义两平台不同iOS 的默认 license 请求使用source.headers源码注释明确写道 Use source headers for now, there was some issues with headers in the DRM params见 DRMManager.swiftAndroid 则使用drm.licenseHeaders见下文 Android 实现。不要在两个平台上互换这两个字段。五、DrmParams字段全解含源码级语义DrmParams的类型定义位于 packages/react-native-video/src/core/types/DrmParams.ts以下是文档表格与源码 JSDoc 注释的合并版本字段类型平台说明typewidevine \| fairplay \| string全部Android 默认widevineiOS 需显式设置fairplay。底层是一个DRMType联合类型(string {})保留扩展空间licenseUrlstring全部许可服务器 URL。两个平台的默认 license 流程都要求该字段certificateUrlstringiOS / visionOSFairPlay 应用证书App Certificate地址FairPlay 必需contentIdstringiOS / visionOS内容标识。省略时会从skd://格式的 key URL 自动推导licenseHeadersRecordstring, stringAndroid附加在 license 请求上的 headermultiSessionbooleanAndroid是否允许多个 Widevine session用于 key rotation 场景getLicense(payload) PromisestringiOS自定义 CKC 获取函数需 resolve 一个 base64 编码的 CKC。payload 形如{ contentId, licenseUrl, keyUrl, spc }getLicense的 payload 类型同样定义在 DrmParams.ts 中contentId内容的唯一标识licenseUrl许可服务器 URLkeyUrlkey 请求 URL通常以skd://FairPlay或clearkey://ClearKey开头spcSecure Playback Context即播放环境信息是 base64 编码的字符串。六、iOS FairPlay 实现从证书到 CKC 的完整链路iOS 端 DRM 的核心是DRMManager.swiftpackages/drm-plugin/ios/DRMManager/DRMManager.swift它实现了AVContentKeySessionDelegate见 DRMManagerAVContentKeySessionDelegate.swift每次收到AVContentKeyRequest时按以下顺序处理获取资产 ID优先取drmParams.contentId未设置时从keyRequest.identifier中剥离skd://前缀得到getAssetId方法见 DRMManager.swift#L218-L228。请求应用证书用certificateUrl发起 GET 请求要求 HTTP 200若响应体是 base64 文本则自动解码requestApplicationCertificate。生成 SPC调用keyRequest.makeStreamingContentKeyRequestData(forApp:contentIdentifier:)生成 SPC。两条 license 获取路径若配置了getLicense构造 payloadcontentId、licenseUrl、keyUrl、base64 的spc调用 JS 函数等待返回 base64 的 CKC再Data(base64Encoded:)解码后回填否则走默认 license 请求向licenseUrlPOST SPC 原始数据httpBody spcData请求头取自source.headers要求 200 且响应体非空。回填 key responsekeyRequest.processContentKeyResponse(AVContentKeyResponse(fairPlayStreamingKeyResponseData:))完成解密。此外DRMManagerAVContentKeySessionDelegate.swift 还处理了几种边界重试当 key 请求timedOut、receivedResponseWithExpiredLease或receivedObsoleteContentKey时返回true允许重试持久化 key 请求不支持收到AVPersistableContentKeyRequest会直接报错提示「持久化 key 不在本插件范围内需要离线能力请使用 Offline Video SDK」——这对应文档 Gotchas 中「离线 DRM 不在本插件」的说明模拟器不支持DRMPlugin.swift 在#if targetEnvironment(simulator)下直接返回nil即 iOS 模拟器上拿不到任何 DRM 管理器。七、Android Widevine 实现Media3 与 L3 降级重试Android 端实现基于 Media3ExoPlayer的 DRM 体系核心是 DRMManager.ktgetDRMConfiguration用Util.getDrmUuid(drmParams.type ?: widevine)把 DRM 类型映射为系统 UUID构造DrmConfiguration.Builder设置multiSession、licenseUri与licenseRequestHeaders。buildDrmSessionManager创建FrameworkMediaDrm与HttpMediaDrmCallback(licenseUrl, ...)并把drmParams.licenseHeaders逐一setKeyRequestProperty写进 license 请求。L3 降级与重试源码中有两处关键逻辑——hasDrmFailed标志位一旦置位后续构建 session 时会mediaDrm.setPropertyString(securityLevel, L3)DRMManager.kt#L74-L76buildDrmSessionManager的retryCount参数异常时若retryCount 3则标记失败并递归重试最多 3 次后抛出DRMManager.kt#L83-L90。这正是文档 Gotchas 中「Android 自动重试 license 至多 3 次首次失败后降级到 Widevine L3」的源码出处。header 动态重建shouldRebuildHttpDataSource()会比较source.headers的 hashheader 变化时重建OkHttpDataSource.Factory保证鉴权头始终是最新的。八、实操陷阱与最佳实践GotchasDRM 测试务必使用真机iOS 模拟器无 FairPlay源码层面直接返回 nil见上文第六节必须用真机Android 模拟器一般能正常跑 Widevine但如果遇到异常行为先在真机上验证再怀疑自己的代码。Header 语义两平台不同iOS 用source.headers承载默认 license 请求的鉴权Android 用drm.licenseHeaders——两者不要混淆。Android 的自动容错license 自动重试最多 3 次首次失败后降级 Widevine L3低安全等级这能提高兼容性但安全等级会下降。离线 DRM持久化 license不在本插件范围内iOS 端收到持久化 key 请求会直接报错。需要离线播放 DRM 内容请参考离线 SDK见 skills/react-native-video/references/extensions.md。Token / license 过期不要在headers里写死静态 token。iOS 端应在getLicense内每次现取新鲜 tokenAndroid 端使用短时效的licenseUrl/licenseHeaders。如果播放中途 token 过期通过replaceSourceAsync重新加载 source。播放中更换内容多内容切换时每个 source 独立携带自己的drm配置核心库会为每个带 DRM 的 source 单独创建AVContentKeySession或 Media3 DrmSessionManageriOS 端见createContentKeyRequest的调用时机。九、从 v6 迁移到 v7v6 的drmprop 字段与 v7 的source.drm字段存在直接映射关系本文不再展开完整迁移对照表请见 skills/react-native-video/references/migration-v6-to-v7.md。大致变化方向包括licenseServer→licenseUrl、multiDrm→multiSession、DRM 类型从枚举改为字符串、drmprop 从组件迁移到 source 配置等。十、小结v7 的 DRM 能力遵循「核心库只负责播放、插件只负责鉴权」的清晰边界npm install引入插件 → 启动时enable()注册 → 每个 source 通过source.drm声明鉴权方式 → 核心库在加载时向PluginsRegistry索取 DRM 管理器。iOS 侧走完整的 FairPlay 证书 / SPC / CKC 链路含自定义getLicense回调Android 侧走 Media3 的 Widevine 会话管理含 license header、multiSession 与 L3 降级重试。真机测试、token 动态获取、平台化 header 配置是落地时最容易踩坑的三个点请务必对照第八节逐条检查。赞分享音视频移动开发【免费下载链接】react-native-videoA component for react-native项目地址https://gitcode.com/gh_mirrors/re/react-native-video点击查看免费下载相关推荐React Native Video DRM 实战指南用 react-native-video/drm 集成 Widevine 与 FairPlayReact Native Video DRM 实战指南用 react native video/drm 集成 Widevine 与 FairPlay 本文讲音视频移动开发react-native-video DRM 插件指南Widevine 与 FairPlay 集成实战react native video DRM 插件指南Widevine 与 FairPlay 集成实战 摘要 本文全面讲解 react native vid音视频移动开发react-native-video v7 插件架构PluginsRegistry 原生插件系统与 react-native-video/drm 实战解析react native video v7 插件架构PluginsRegistry 原生插件系统与 react native video/drm 实战解析音视频移动开发上一篇【亲测免费】 《Vue-CMS》开源项目常见问题解决方案下一篇Orga.js 常见问题终极解决方案快速上手与故障排除指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考