在 Android 上将游戏资源下载到 SD 卡

发布于 2024-08-30 11:44:21 字数 438 浏览 3 评论 0原文

我正在开发一款Android 游戏,它必须将一些资源下载到SD 卡,以保持应用程序的大小尽可能小。我正在考虑使用未压缩的 zip 文件来捆绑所有资源。

客户的要求是尽可能保护这些资产。作为 apk 的一部分被认为是足够的保护,但如果我这样做,apk 大小将是巨大的。如果我只是将 zip 包放入 SD 卡中,那么任何人都可以解压缩它并探索其内容。

有没有一种简单的方法可以做到这一点,而不需要反驳可怕的 DRM?

显然,如果有人真的想要检查 Android 游戏的资源,他们就可以做到。我只是在寻找一个简单的解决方案以避免让这件事变得很容易。

I'm developing an Android game that has to download some assets to the SD card to keep the size of the app as small as possible. I was thinking of using an uncompressed zip file to bundle all the assets.

A requirement from the client is to protect these assets as much as possible. Being part of the apk is considered enough protection, but if I do this the apk size will be enormous. If I just put a zip bundle in the SD card, then anyone can unzip it and explore its contents.

Is there a simple way to do this without retorting to horrid DRM?

Obviously if someone really wants to check the resources of an Android game, they can. I'm just looking for a simple solution to avoid making this very easy.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

年少掌心 2024-09-06 11:44:21

您可以使用 AES 加密 ZIP 文件,但会出现提取资产的开销可能是一个问题,因为在编写游戏时性能通常相当重要。

然而,正如您所说,使用安全加密并不真正值得,因为如果有人真正感兴趣,他们可以在您的应用程序的源代码中找到密钥。因此,您可以自己编写一个 InputStreamOutputStream 来对 ZIP 文件的字节执行一些简单的转换。这在读取文件时可以快速撤消,但会“损坏”ZIP 文件,足以阻止某人浏览他们的 SD 卡。

使用它时,您可以将流放在 FileZIPInputStream 之间,例如:

File assets = new File(Environment.getExternalStorageDirectory(),"assets");
ZipInputStream zip = new ZipInputStream(new TranslateInputStream(assets));

作为翻译示例,您可以将所有字节与已知值进行异或:

private static final byte MAGIC_NUMBER = 13;

private void translateBuffer(byte[] buffer) {
    for (int i = 0;i < buffer.length;i++) {
        buffer[i] ^= MAGIC_NUMBER;
    }
}

private class TranslateOutputStream extends FileOutputStream {
    public TranslateOutputStream(File file) throws FileNotFoundException {
        super(file);
    }

    @Override
    public void write(int oneByte) throws IOException {
        oneByte ^= MAGIC_NUMBER;
        super.write(oneByte);
    }

    //In Android write(byte[]) calls this method so we don't need to override both        
    @Override
    public void write(byte[] buffer, int offset, int count)
            throws IOException {
        translateBuffer(buffer);
        super.write(buffer, offset, count);
    }
}

private class TranslateInputStream extends FileInputStream {

    public TranslateInputStream(File file) throws FileNotFoundException {
        super(file);
    }

    @Override
    public int read() throws IOException {
        return super.read() ^ MAGIC_NUMBER;
    }

    //In Android read(byte[]) calls this method so we don't need to override both        
    @Override
    public int read(byte[] buffer, int offset, int count)
            throws IOException {
        int bytesRead = super.read(buffer, offset, count);
        translateBuffer(buffer);
        return bytesRead;
    }
}

或者,您不能使用 ZIP,因为您不关心压缩。只需将所有资源连接到一个大块中即可。创建 blob 时,将每个资产的开始和结束位置写入索引文件。然后,索引文件将包含在您的 .apk 文件中,以便从应用程序的大文件中获取所需的数据。由于大斑点不是标准格式,因此人们无法轻松地从中提取文件。为了更加确定,您始终可以在文件的开头填充一些其他数据(也许只是一些纯文本),以使 blob 看起来像其他东西。

You could encrypt the ZIP file with AES but there would an overhead in extracting the assets which might be a problem since performance is usually fairly important when writing a game.

However, as you've said yourself using a secure encryption isn't really worthwhile since if someone's really interested they can find the keys in the source code of your application. So you could write an InputStream and OutputStream yourself to perform some trivial translation on the bytes of the ZIP file. This would be quick to undo when reading the file but would "corrupt" the ZIP file enough to deter someone just browsing through their SD card.

When using it you'd put your stream in between the File and ZIPInputStream, e.g.:

File assets = new File(Environment.getExternalStorageDirectory(),"assets");
ZipInputStream zip = new ZipInputStream(new TranslateInputStream(assets));

As an example translation, you could just XOR all the bytes with a known value:

private static final byte MAGIC_NUMBER = 13;

private void translateBuffer(byte[] buffer) {
    for (int i = 0;i < buffer.length;i++) {
        buffer[i] ^= MAGIC_NUMBER;
    }
}

private class TranslateOutputStream extends FileOutputStream {
    public TranslateOutputStream(File file) throws FileNotFoundException {
        super(file);
    }

    @Override
    public void write(int oneByte) throws IOException {
        oneByte ^= MAGIC_NUMBER;
        super.write(oneByte);
    }

    //In Android write(byte[]) calls this method so we don't need to override both        
    @Override
    public void write(byte[] buffer, int offset, int count)
            throws IOException {
        translateBuffer(buffer);
        super.write(buffer, offset, count);
    }
}

private class TranslateInputStream extends FileInputStream {

    public TranslateInputStream(File file) throws FileNotFoundException {
        super(file);
    }

    @Override
    public int read() throws IOException {
        return super.read() ^ MAGIC_NUMBER;
    }

    //In Android read(byte[]) calls this method so we don't need to override both        
    @Override
    public int read(byte[] buffer, int offset, int count)
            throws IOException {
        int bytesRead = super.read(buffer, offset, count);
        translateBuffer(buffer);
        return bytesRead;
    }
}

Alternatively, you could not use ZIP as you don't care about compression. Just concatenate all the assets together in one large blob. As you create the blob write the start and end location of each asset out to an index file. The index file would then be included in your .apk file allowing to get the data you needed from the big file in your application. As the big blob wouldn't be in a standard format people wouldn't be able to easily extract files from it. To be extra sure you could always pad the beginning of the file with some other data - perhaps just some plain text - to make the blob look like something else.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文