2、环境搭建与权限:AndroidManifest配置、存储权限、依赖库导入

好,咱们正式开始动手了。这一章其实特别关键,但很多人容易忽略。我见过不少新手,代码写了大半天,一运行直接崩溃,最后发现是AndroidManifest里少写了一行权限。嗯,这种坑咱们今天一次性填平。

2.1 项目创建与最低版本要求

我个人习惯用Android Studio直接创建新项目。选一个空Activity模板就行,别整那些花里胡哨的。

关于最低版本,我建议你至少设到API 21(Android 5.0)。为什么?因为MediaExtractor在API 16就有了,但有些高级特性(比如HDR、HEVC)在API 21之后才稳定。你想想看,现在市面上低于5.0的设备几乎绝迹了,所以设到API 21既安全又省心。

app/build.gradle 里,这样配:

android {
    compileSdk 34
    defaultConfig {
        applicationId "com.example.mediaextractordemo"
        minSdk 21
        targetSdk 34
        versionCode 1
        versionName "1.0"
    }
}

这里有个小细节——compileSdk 尽量用最新的,这样你能用到最新的API。但 targetSdk 别乱升,要测试过再改。我在项目中遇到过,升了targetSdk后存储权限全变了,代码跑不起来,折腾了一下午。

2.2 AndroidManifest 权限配置

做音视频提取,说白了就是要读文件。读文件就需要权限。Android的权限分两种:普通权限危险权限。咱们这个场景,核心就两个:

  • READ_EXTERNAL_STORAGE — 读取外部存储的文件
  • WRITE_EXTERNAL_STORAGE — 写入提取后的文件(如果需要保存)

AndroidManifest.xml 里,加在 <manifest> 标签下:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
⚠️ 注意: 从 Android 10(API 29)开始,WRITE_EXTERNAL_STORAGE 对应用自己的文件目录已经没用了。系统默认给了「分区存储」机制。如果你只是提取视频里的音频,然后保存到应用私有目录,其实连 READ_EXTERNAL_STORAGE 都不需要。但为了兼容老设备,我建议还是都写上。

我曾经有个项目,在Android 11手机上死活读不到SD卡里的视频文件。查了半天,发现是忘了加 MANAGE_EXTERNAL_STORAGE 权限。如果你需要管理所有文件(比如用户选择任意目录),Android 11以上还得加这个:

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

但这个权限审核比较严,Google Play上架可能被拒。一般场景用 READ_EXTERNAL_STORAGE 就够了。

2.3 运行时权限申请

光在Manifest里声明还不够。Android 6.0以上,危险权限需要运行时弹窗让用户同意。这个逻辑咱们得写代码里。

我一般这样写:

// 检查权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
    != PackageManager.PERMISSION_GRANTED) {
    // 请求权限
    ActivityCompat.requestPermissions(this,
        new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
        REQUEST_CODE_STORAGE);
} else {
    // 已有权限,直接开始提取
    startExtract();
}

然后重写回调方法:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                       @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_CODE_STORAGE) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            startExtract();
        } else {
            Toast.makeText(this, "没有存储权限,无法提取", Toast.LENGTH_SHORT).show();
        }
    }
}
💡 小技巧: 如果用户拒绝了权限,你可以引导他去设置里手动开启。用 shouldShowRequestPermissionRationale() 判断是否要弹解释对话框。我一般会在用户拒绝两次后,直接跳转到应用设置页面。

2.4 依赖库导入

MediaExtractor 是 Android 框架自带的类,不需要额外导入第三方库。但咱们做音视频提取,往往不只是提取,还要处理、播放、保存。这时候就需要一些辅助库了。

我个人常用的依赖:

库名 用途 是否必需
androidx.core 运行时权限、兼容性 ✅ 必需
androidx.appcompat UI兼容 ✅ 必需
exoplayer 播放提取后的音视频 ❌ 可选
mp4parser 解析MP4文件结构 ❌ 可选

app/build.gradledependencies 块里加:

dependencies {
    implementation 'androidx.core:core:1.12.0'
    implementation 'androidx.appcompat:appcompat:1.6.1'
    
    // 可选:ExoPlayer 用于播放
    // implementation 'com.google.android.exoplayer:exoplayer:2.19.1'
    
    // 可选:mp4parser 用于深度解析
    // implementation 'com.googlecode.mp4parser:isoparser:1.1.22'
}

这里要提醒一下:别一股脑把所有库都加进来。我见过一个项目,build.gradle里躺了二十多个依赖,编译一次五分钟。咱们做音视频提取,核心就靠MediaExtractor,其他库按需添加就行。

2.5 知识体系总览

这一章的内容其实就三个块:权限声明、权限申请、依赖管理。我画了个图帮你理清关系:

环境搭建与权限配置知识体系 AndroidManifest配置 运行时权限申请 依赖库导入 READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE MANAGE_EXTERNAL_STORAGE (可选) checkSelfPermission() requestPermissions() onRequestPermissionsResult() androidx.core (必需) ExoPlayer (可选) mp4parser (可选) 三者缺一不可,但运行时权限只针对 Android 6.0+

2.6 常见问题与避坑

最后,我把自己踩过的坑列一下,你遇到了直接对照排查:

  • 权限声明了但运行时没弹窗 — 检查一下是不是忘了在Activity里调用 requestPermissions()。光写Manifest是不够的。
  • Android 10以上读不到文件 — 分区存储机制搞的鬼。试试用 MediaStore 的URI方式访问,别直接用文件路径。
  • 编译报错:Duplicate class — 依赖库版本冲突了。我一般用 ./gradlew app:dependencies 命令查看依赖树,找到冲突的库然后排除掉。
  • 提取出来的音频文件是0字节 — 大概率是写入权限没拿到。检查一下 WRITE_EXTERNAL_STORAGE 有没有被用户拒绝。

嗯,环境搭建这块就这些。别看内容不多,但每一步都关系到后面能不能顺利跑起来。配好了,后面写代码就一路畅通了。


公众号:蓝海资料掘金营,微信deep3321