Search code examples
androidproguardandroid-glideandroid-proguard

Avoid No virtual method registerAnimationCallback with Glide and Proguard minification


We have a custom library (com.example.mylib) being included as an external dependency by our app (com.example.myapp). Our library in turn uses Glide GIF handling library. Also, our library is minified by Proguard.

At runtime our app crashes with the following 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)

I cannot figure out why GifDrawable.registerAnimationCallback(...) method is obfuscated.

I think we followed all suggested proguard/Glide rules:

  • custom class extending LibraryGlideModule
  • build dependencies like 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-specific Proguard rules copied from official readme

I can see automatically generated Glide-files under build\ directory. Also, inspecting generated JAR file under packaged-classes\, I cannot see anything suspicious: only our custom public components are kept in clear, other custom private/anonymous/etc. components are minified.

Even if it should not make a lot of sense in building our library, I also kept unminified the following, with no luck:

# 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 *;
}

For those not used to Glide or wondering what's the interesting bit of code, here it is:

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);

Being registerAnimationCallback a relatively new addition to Glide library, I'm wondering if this issue has to do with the library itself. Not sure yet what it means, but the preceding setLoopCount(...) method invocation causes no issue.


Solution

  • Ok, this was a total copy/paste error from us of a detail when we extracted code & configuration from the app to create a dedicated library module:

    while app build.gradle included Glide dependency as:

    implementation 'com.github.bumptech.glide:glide:4.9.0'
    

    when the same is ported to the library, it should be turned to:

    api 'com.github.bumptech.glide:glide:4.9.0'
    

    The counter-proof was that, with the copy/paste error still in place, it was enough to re-add the dependency to the app as well, and the runtime error was gone.