第一章:权限不足播放现象全景

现象识别 —— 五类“无感”失败

权限不足导致的播放失败之所以难以排查,是因为它的表象与网络异常、解码器缺失或资源损坏高度重叠。以下五种现象是权限不足的典型“伪装”,任何一条出现都应优先怀疑权限层:

现象编号 用户可见表现 权限端可能根源
P1 播放黑屏 + 无声音,控件可操作 文件/网络Uri无读取权限,MediaSource初始化为空
P2 弹窗不显示(权限请求对话框从未弹出) AndroidManifest未声明危险权限,或运行时未触发请求
P3 日志无ERROR级别输出,只有 INFO 或 DEBUG ExoPlayer内部将权限失败吞并为“数据源不可用”,不向上抛异常
P4 UI 持续显示“加载中”,无超时回调 权限缺失导致数据源open()阻塞在挂起状态
P5 网络播放立即失败,但WIFI已连接 INTERNET 权限未声明;VPN/企业网络需额外授权
⚠ 关键判断规则: 如果播放器在 Android 6.0+ 上从未弹出过权限请求弹窗,且目标Uri指向外部存储或网络,那么 P2 + P1 的组合几乎100%指向权限不足。

数据采集 —— 从用户到日志的证据链

在正式定位前,收集以下三类数据。注意:权限数据只靠 checkSelfPermission 一个接口往往不够,必须结合实际文件访问测试。

  1. 运行时权限状态快照:调用 ContextCompat.checkSelfPermission() 检查 READ_EXTERNAL_STORAGE / INTERNET 等权限。
  2. ExoPlayer 事件日志:通过 AnalyticsListener 的 onPlayerError 和 onLoadError 捕获底层错误码。
  3. 系统授权日志:adb指令采集用户授权状态。
    adb shell dumpsys package your.package.name | grep -A 5 "runtime permissions"
    
🔍 数据采集典型盲区: 即使 checkSelfPermission 返回 PERMISSION_GRANTED,如果用户通过“仅允许使用期间”授权,后台播放仍可能被系统拒绝。此场景需额外采集 MediaDrm 或 ContentResolver 的打开实际句柄状态。

原因定位 —— 故障树分析

下图以故障树形式展示从“播放失败”到“权限不足”的排查路径。每个叶子节点对应一个判定动作,蓝色节点为权限相关,红色节点为资源型错误排除。

权限不足播放失败故障树 播放异常(黑屏/无声音/加载中) Uri读取失败 权限未被授予 系统策略限制 声明缺失 未请求运行时权限 用户拒绝授权 路径/权限无效 后台限制/省电 播放失败 定位为权限问题 排查核心 从“Uri读取失败”和“权限未被授予”两条路径向下追溯

修复动作 —— 针对五类现象的预案

根据故障树定位结果,执行对应修复。下表列出每种现象的快速修复操作和验证命令:

现象 修复动作 验证方式
P1 黑屏无声音 在 AndroidManifest 添加 READ_EXTERNAL_STORAGE(或 READ_MEDIA_*),并运行时请求 播放一个本地视频文件,观察画面和音频输出
P2 弹窗无显示 检查 ActivityCompat.requestPermissions() 调用时机(必须在播放前且不在 onResume 之前) 调用后观察系统弹窗;使用 onRequestPermissionsResult 回调日志
P3 日志无报错 添加 AnalyticsListener 的 onLoadError 回调,打印详细错误信息 过滤 logcat 中 ExoPlayerImpl 或自定义 tag
P4 持续加载中 设置 DefaultLoadControl 超时策略,或使用 ProgressiveMediaSource 替代 ExtractorMediaSource 观察 Player.STATE_BUFFERING 持续时间不应超过 30s
P5 网络播放失败 在 Manifest 添加 INTERNET 和 ACCESS_NETWORK_STATE;检查代理配置 用 curl 或浏览器测试相同 Url 可访问

复测 —— 闭环验证清单

修复后必须执行以下四次验证,缺一不可:

  • 首次安装测试:清除数据 → 安装 → 首次请求 → 授权 → 播放
  • 拒绝授权测试:拒绝权限后播放预期应显示错误提示而非黑屏/卡死
  • 后台/锁屏测试:授权后切至后台再返回,播放不应中断
  • 不同网络环境测试:WiFi / 移动数据 / VPN 下均能正常播放
💡 自动化复测脚本片段: 使用 adb 授予或撤销权限后重播:
adb shell pm grant your.package.name android.permission.READ_EXTERNAL_STORAGE
adb shell am start -n your.package.name/.MainActivity

预防 —— 从根源拦截权限不足

将以下预防措施嵌入开发流程:

  1. 权限清单自动化检查:在 CI 中运行自定义 lint 或使用 aapt dump permissions 对比预期权限。
  2. 播放前预校验:在 prepare() 前主动调用 checkSelfPermission,若未授权则提前弹窗引导。
  3. 统一错误映射:在 Player.Listener.onPlayerError 中将 PlaybackException 的 errorCode 映射为中文用户提示,避免显示“加载中”。
  4. 权限降级策略:若用户拒绝 READ_EXTERNAL_STORAGE,自动降级为 ContentResolver 的 openFileDescriptor,利用 SAF 授权。
📌 本章核心: 权限不足的五种表象具有高度伪装性。排查时不要被“无报错”或“加载中”迷惑,应直接查看权限授权状态与Uri实际可读性。故障树中的蓝色节点(权限未被授予)是最高频根本原因,占所有权限播放失败的 80% 以上。