You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何在Android VideoView中播放解密后的byte[]并确保仅应用内可见?

嘿,我来帮你搞定这个加密视频播放的问题!你提到的两个方案都是可行的,下面我给你详细拆解实现步骤:

方案1:创建私有临时文件(退出应用自动删除)

这个思路是把解密后的byte[]写入一个仅本应用可访问的临时文件,播放完成或应用退出时自动删除,既满足VideoView需要文件路径的要求,又能保证视频文件不会泄露给其他应用。

具体实现步骤:

  1. 创建私有临时文件:用getCacheDir()(缓存目录,系统可能在空间不足时自动清理)或者getFilesDir()(应用私有文件目录)创建文件,默认权限就是私有,其他应用无法访问。也可以用File.createTempFile()生成随机临时文件名。
  2. 写入解密后的字节数据:通过FileOutputStreamoutputBytes写入临时文件。
  3. 给VideoView设置路径播放:直接调用videoView.setVideoPath(tempFile.getAbsolutePath())即可启动播放。
  4. 自动删除文件:在Activity的onDestroy()方法里手动删除文件,搭配tempFile.deleteOnExit()做双重保险,确保退出应用时文件被清理。

代码示例:

// 1. 创建临时文件,存在应用缓存目录
File tempVideoFile = new File(getCacheDir(), "temp_encrypted_video.mp4");
tempVideoFile.deleteOnExit(); // 标记JVM退出时删除

// 2. 将解密后的byte[]写入文件
try (FileOutputStream fos = new FileOutputStream(tempVideoFile)) {
    fos.write(outputBytes);
    fos.flush();
} catch (IOException e) {
    e.printStackTrace();
}

// 3. 启动VideoView播放
VideoView videoView = findViewById(R.id.video_view);
videoView.setVideoPath(tempVideoFile.getAbsolutePath());
videoView.start();

// 4. Activity销毁时手动删除文件(双重保险)
@Override
protected void onDestroy() {
    super.onDestroy();
    if (tempVideoFile != null && tempVideoFile.exists()) {
        tempVideoFile.delete();
    }
}

注意点:

  • 敏感视频建议用getFilesDir()存储,缓存目录的文件可能被系统主动清理,但手动删除更稳妥。
  • 无需额外设置文件权限,默认创建的文件就是MODE_PRIVATE,其他应用无法读取。
方案2:扩展VideoView支持直接播放byte[]

VideoView底层依赖MediaPlayer,而MediaPlayer支持通过MediaDataSource自定义数据源,所以我们可以自定义一个CustomVideoView,添加直接接收byte[]的方法,跳过物理文件的生成步骤。

具体实现步骤:

  1. 自定义CustomVideoView类:继承原生VideoView,初始化内部的MediaPlayer,并添加setVideoBytes()方法。
  2. 实现自定义数据源:通过MediaDataSource包装解密后的byte[],让MediaPlayer直接从内存读取数据。
  3. 在布局和代码中使用自定义View:替换布局里的原生VideoView,调用setVideoBytes()即可播放。

代码示例:

public class CustomVideoView extends VideoView {
    private MediaPlayer mediaPlayer;

    public CustomVideoView(Context context) {
        super(context);
        initMediaPlayer();
    }

    public CustomVideoView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initMediaPlayer();
    }

    private void initMediaPlayer() {
        mediaPlayer = new MediaPlayer();
        setMediaPlayer(mediaPlayer);
    }

    // 添加支持byte[]播放的方法
    public void setVideoBytes(byte[] videoBytes) {
        try {
            mediaPlayer.reset();
            // 用MediaDataSource包装byte[],供MediaPlayer读取
            mediaPlayer.setDataSource(new MediaDataSource() {
                @Override
                public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
                    if (position >= videoBytes.length) {
                        return -1; // 表示数据读取完毕
                    }
                    // 计算本次可读取的字节数,避免越界
                    int readSize = (int) Math.min(size, videoBytes.length - position);
                    System.arraycopy(videoBytes, (int) position, buffer, offset, readSize);
                    return readSize;
                }

                @Override
                public long getSize() throws IOException {
                    return videoBytes.length;
                }

                @Override
                public void close() throws IOException {
                    // 无需额外操作,byte[]在内存中由GC处理
                }
            });
            mediaPlayer.prepareAsync();
            mediaPlayer.setOnPreparedListener(mp -> start());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

布局中替换为自定义View:

<com.yourpackage.CustomVideoView
    android:id="@+id/custom_video_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

Activity中调用播放:

CustomVideoView customVideoView = findViewById(R.id.custom_video_view);
customVideoView.setVideoBytes(outputBytes);

注意点:

  • 如果视频体积较大,直接把byte[]放在内存中容易触发OOM(内存溢出),这种情况下方案1更稳妥。
  • 不同Android版本的MediaPlayer API可能有细微差异,建议在目标版本上测试适配。

两种方案各有优劣:如果视频不大,方案2更高效(省去IO操作);如果视频较大,方案1能避免内存压力。两者都能保证视频仅在你的应用内可见。

内容的提问来源于stack exchange,提问作者Nikola Samardzija

火山引擎 最新活动