Nano Hash - криптовалюты, майнинг, программирование

Избегайте виртуального метода registerAnimationCallback с минификацией Glide и Proguard

У нас есть пользовательская библиотека (com.example.mylib), которая включается в качестве внешней зависимости нашим приложением (com.example.myapp). Наша библиотека, в свою очередь, использует библиотеку Glide для обработки GIF. Кроме того, наша библиотека минимизирована Proguard.

Во время выполнения наше приложение вылетает со следующим логарифмом:

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
  • Правила Proguard для Glide скопированы из официального файла readme.

Я вижу автоматически сгенерированные 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(...) не вызывает проблем.


  • Увидев, что registerAnimationCallback принадлежит android.support.graphics.drawable.Animatable2Compat, я также попытался явно добавить implementation 'com.android.support:animated-vector-drawable:28.0.0' as a dependency in myapp build, with no luck. 23.04.2019

Ответы:


1

Итак, это была полная ошибка копирования/вставки detail, когда мы извлекали код и конфигурацию из приложения для создания выделенного библиотечного модуля:

в то время как приложение build.gradle включает зависимость Glide как:

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

когда то же самое портируется в библиотеку, его следует превратить в:

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

Контр-доказательство заключалось в том, что при сохранении ошибки копирования/вставки было достаточно повторно добавить зависимость к приложению, и ошибка времени выполнения исчезла.

23.04.2019
Новые материалы

Кластеризация: более глубокий взгляд
Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

Как написать эффективное резюме
Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

Как я автоматизирую тестирование с помощью Jest
Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..