Proguard破坏了assets或raw中的音频文件

7

我有一个使用MediaPlayer播放蜂鸣声的活动,在之前的proguarded生产版本中都可以正常运行。但在最新版本中,它突然崩溃并显示:

Caused by: android.content.res.Resources$NotFoundException: File res/raw/beep.ogg from drawable resource ID #0x7f060000
at android.content.res.Resources.openRawResourceFd(Resources.java:994)
at android.media.MediaPlayer.create(MediaPlayer.java:855)
at com.digikey.mobile.activity.CaptureActivity.onCreate(SourceFile:135)
at android.app.Activity.performCreate(Activity.java:5206)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2064)
... 11 more
Caused by: java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed
at android.content.res.AssetManager.openNonAssetFdNative(Native Method)
at android.content.res.AssetManager.openNonAssetFd(AssetManager.java:428)
at android.content.res.Resources.openRawResourceFd(Resources.java:991)
... 16 more

我尝试了多种不同的方式来加载和播放声音,包括将其存储在资产中而不是原始res/raw文件夹中,它们在未经混淆的应用程序中使用时都有效,但它们在经过混淆、zipalign和签名的发布版本中均失败了。

我的proguard文件非常大,并且其中包含了常见的修复方法。

-keepclassmembers class **.R$* {public static <fields>;}
-keep class **.R$*

有人有任何想法或遇到过类似的情况吗?

更新:我也尝试了MP3文件,结果出现相同的问题。

更新2:有趣的是,似乎需要相当长的时间(接近1秒)才会崩溃并显示此消息。好像正在搜索或处理某个文件之类的东西,但这个文件实际上很小,所以很奇怪。


1
这个文件有多大?另外,作为自定义构建脚本的一部分,你是否调整了任何 aapt 开关? - CommonsWare
它非常小,我没有调整aapt开关。但是,正如您所想象的那样,我正在使用Android Maven插件。是否有任何有用的aapt开关? - Manfred Moser
感觉这个文件在不应该被压缩的情况下被压缩了。**aapt** 以前总是知道 .ogg 文件并且不会压缩它们。我不知道为什么/如何 ProGuard/zipalign 会影响到这一点。除非你使用的是 DexGuard 而不是 ProGuard,因为我不知道他们的资源加密可能会对此产生什么影响。 - CommonsWare
顺便说一下,只使用ProGuard仍然会遇到mp3文件相同的问题。 - Manfred Moser
3个回答

17

错误提示表明,zip条目beep.ogg被压缩了,但其不应该被压缩。

在zip文件中,各个条目可以选择是否进行压缩。通常情况下,读取zip文件的应用程序不会受到这种压缩的影响。然而,Android直接访问一些类型的文件(如.ogg和.mp3),而不是对它们进行解压缩,这只有当它们没有被压缩时才能正常工作。

您可以使用以下命令查看哪些条目被压缩:

unzip -lv MyApplication.apk
在“方法”一栏中,“Defl”表示压缩,“Stored”表示未压缩。ProGuard不执行apk文件的最终打包--aapt、apkbuilder、jarsigner、zipalign和可能的后处理步骤会执行此操作。在适当的阶段,它们应该将.ogg和.mp3文件保持未压缩状态。您可能需要检查它们在Maven构建过程中的集成情况。DexGuard偶然执行最终打包。它有一个选项-dontcompress来控制哪些文件或文件类型保持未压缩状态。默认配置保持.ogg和.mp3文件未压缩。 (我是ProGuard和DexGuard的开发人员)Manfred Moser的更新:这确实是问题所在。结果表明,这与proguard集成或Android Maven插件无关。问题是由我使用的Maven Jarsigner插件配置引起的。我已将removeExistingSignatures设置为true,这不是默认值,并导致存档中的所有文件都被压缩。在此阶段,我认为这是jarsigner插件的奇怪错误。无论如何...默认配置是为此参数设置为false,因此除非您像我一样将其设置为true,否则没有人应该遇到任何问题;-)

谢谢你回答,Eric。我需要进一步调查这个问题。顺便说一句,我当然知道你是ProGuard的作者;-) - Manfred Moser
哇...难以置信。我进行了检查,似乎现在所有东西都被压缩了。这可能是我管理的Android Maven插件中的某种退步,所以我现在要进行一个错误调试;-) 非常感谢Eric。 - Manfred Moser
为了让其他人受益,我正在使用Android Maven插件的3.8.2版本。一旦我找出问题,我会在这里和邮件列表中发布。 - Manfred Moser
Proguard混淆了我的assets文件夹下的db文件。你能否提供任何方法来避免assets文件的混淆?或者有其他方法可以防止我的assets文件夹被Proguard混淆。 - Aman Gupta - ΔMΔN
通过从Proguard中排除模型类进行修复。 - Aman Gupta - ΔMΔN

7
我曾遇到一个类似的情况,在ProGuard(即使在debug模式下已被明确关闭)之后,我的应用程序出现了退化。
错误信息如下:08-30 22:10:32.360 561-18619/? E/FileSource: Failed to open file 'android.resource://com.mycompany.myapp/2131230720'. (No such file or directory) 最终,我不得不添加 keep.xml 文件,如 此处 所建议的那样,在自定义要保留哪些资源下。
keep.xml文件内容如下(位于 /res/raw/keep.xml):
    <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@raw/*">
</resources>

当然,你可以更明确地设置它,但是我只在我的RAW文件夹中有mp3文件。

我的unzip -lv app-release.apk显示我的mp3文件如下:

0 Stored 0 0% 00-00-1980 00:00 00000000 res/raw/audio.mp3

这很奇怪(0字节?!)。


1
我觉得它告诉你那是一个可绘制资源有点奇怪:

来自可绘制资源ID的文件res/raw/beep.ogg

我认为你需要告诉它也要保留R类。这是我在一个也从raw加载.ogg文件的应用程序中使用的方法。
-keep class *.R

-keepclasseswithmembers class **.R$* {
    public static <fields>;
}

这已经像您在问题中看到的那样配置好了,是的...错误消息很奇怪。 - Manfred Moser
不,这个配置和你的不一样。 - Nick Palmer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接