android - 避免使用 Glide 和 Proguard 缩小的虚拟方法 registerAnimationCallback
问题描述
我们有一个自定义库(com.example.mylib)被我们的应用程序(com.example.myapp)作为外部依赖项包含在内。我们的库反过来使用Glide GIF 处理库。此外,我们的库被 Proguard 缩小了。
在运行时,我们的应用程序因以下 logcat 崩溃:
2019-04-23 15:47:46.642 11066-11066/com.example.myapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myapp, PID: 11066
java.lang.NoSuchMethodError: No virtual method registerAnimationCallback(Landroid/support/graphics/drawable/Animatable2Compat$AnimationCallback;)V in class Lcom/bumptech/glide/load/resource/gif/GifDrawable; or its super classes (declaration of 'com.bumptech.glide.load.resource.gif.GifDrawable' appears in /data/app/com.example.myapp-C3jnO5_79zyarj8XR40khQ==/split_lib_dependencies_apk.apk)
at com.example.mylib.MyComponent$1.onResourceReady(SourceFile:4)
at com.example.mylib.MyComponent$1.onResourceReady(SourceFile:1)
at com.bumptech.glide.request.SingleRequest.onResourceReady(SingleRequest.java:574)
at com.bumptech.glide.request.SingleRequest.onResourceReady(SingleRequest.java:549)
at com.bumptech.glide.load.engine.EngineJob.handleResultOnMainThread(EngineJob.java:218)
at com.bumptech.glide.load.engine.EngineJob$MainThreadCallback.handleMessage(EngineJob.java:324)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
我无法弄清楚为什么GifDrawable.registerAnimationCallback(...)
方法被混淆了。
我认为我们遵循了所有建议的 proguard/Glide 规则:
- 自定义类扩展
LibraryGlideModule
- 构建依赖项,例如
com.github.bumptech.glide:glide:4.9.0
,com.github.bumptech.glide:compiler:4.9.0
com.zlc.glide:webpdecoder:0.0.8.4.7.1
- 从官方自述文件中复制的 Glide 特定的 Proguard 规则
我可以在目录下看到自动生成的 Glide 文件build\
。另外,检查下生成的 JAR 文件packaged-classes\
,我看不到任何可疑的东西:只有我们的自定义公共组件保持清晰,其他自定义私有/匿名/等。组件被缩小。
即使在构建我们的库时它应该没有多大意义,我也保留了以下内容,但没有运气:
# our custom, anonymous RequestListeners
-keep class * implements com.bumptech.glide.request.RequestListener {
public *;
}
# GifDrawable itself by Glide
-keep class com.bumptech.glide.load.resource.gif.GifDrawable {
public *;
}
对于那些不习惯 Glide 或想知道什么是有趣的代码的人,这里是:
Glide.with(myContext)
.asGif()
.load(myResourceId)
.listener(new RequestListener<GifDrawable>() {
@Override
public boolean onResourceReady(GifDrawable resource,
Object model,
Target<GifDrawable> target,
DataSource dataSource,
boolean isFirstResource) {
myReadyGif = resource;
resource.setLoopCount(1);
resource.registerAnimationCallback(
new Animatable2Compat.AnimationCallback() {
@Override
public void onAnimationEnd(Drawable drawable) {
super.onAnimationEnd(drawable);
// do something
}
});
return false;
}
//...
})
.into(myViewTarget);
作为registerAnimationCallback
Glide 库的一个相对较新的补充,我想知道这个问题是否与库本身有关。尚不确定这意味着什么,但前面的setLoopCount(...)
方法调用不会导致任何问题。
解决方案
好的,当我们从应用程序中提取代码和配置以创建专用库模块时,这是我们对一个细节的完全复制/粘贴错误:
而 app build.gradle 包含 Glide 依赖项:
implementation 'com.github.bumptech.glide:glide:4.9.0'
当它被移植到图书馆时,它应该变成:
api 'com.github.bumptech.glide:glide:4.9.0'
反证是,在复制/粘贴错误仍然存在的情况下,将依赖项也重新添加到应用程序就足够了,运行时错误就消失了。
推荐阅读
- drake - 可以检索符号变量值吗?
- swift - Swift 关联类型继承
- angular - Angular 8 Metronic 绑定未更新
- javascript - 从列表中删除文件后,文件上传控制会话不删除
- python - Gekko 无法访问服务器,本地解决 json 文件错误
- java - 不确定为什么会出现类、接口或枚举预期错误?
- rest - 如何使用restApi和python在pagerduty中创建计划
- swift - 如何将图像方向应用于 CIImage?
- javascript - 在 html 中设置一个变量以用作图像 src
- c - 关于 char *s 和 char s[] 如何在低级别工作的困惑