bumptech / glide

An image loading and caching library for Android focused on smooth scrolling
https://bumptech.github.io/glide/
Other
34.67k stars 6.13k forks source link

GeneratedAppGlideModuleImpl is implemented incorrectly. #3266

Closed vladp closed 6 years ago

vladp commented 6 years ago

Glide Version: 4.7.1 Integration libraries: Okhttp 3.11.0 (via retrofit 2.4.0)

Device/Android Version: Android emulator API 27 (not testing on any particular device yet)

Issue details / Repro steps / Use case background: I am using self-signed certificates. To implement this, I have a custom OkHTTP client that manages these self signed certiciates explicity for the HTTPS connection. I am also using React-native (you will see it in pro-guard rules).

My code is following the exact example here (as was suggested in other replies on this subject):

https://futurestud.io/tutorials/glide-module-example-accepting-self-signed-https-certificates

I am getting an error, in Release mode only (in debug I do not get this)

08-13 02:31:11.778 31201-31201/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.myappU1b, PID: 31201
    java.lang.IllegalStateException: GeneratedAppGlideModuleImpl is implemented incorrectly. If you've manually implemented this class, remove your implementation. The Annotation processor will generate a correct implementation.
        at com.bumptech.glide.Glide.a(SourceFile:305)
        at com.bumptech.glide.Glide.c(SourceFile:295)
        at com.bumptech.glide.Glide.a(SourceFile:225)
        at com.bumptech.glide.Glide.b(SourceFile:219)
        at com.bumptech.glide.Glide.a(SourceFile:180)
        at com.bumptech.glide.Glide.get(SourceFile:164)
        at com.bumptech.glide.Glide.c(SourceFile:671)
        at com.bumptech.glide.Glide.with(SourceFile:698)

If I disable the Module code, and use just Glide (not GlideApp that is generated by the annotation) -- I stop getting the error, but then, obviously I do not get any images -- as Glide cannot negotiate a connection to my backend without the custom OkHttpClient.

My Module code:


import android.content.Context;

import com.bumptech.glide.Glide;

import com.bumptech.glide.Registry;
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
import com.bumptech.glide.load.model.GlideUrl;

import com.bumptech.glide.annotation.GlideModule;

import com.bumptech.glide.module.AppGlideModule;
import com.myappU1b.AppU1b;

import java.io.InputStream;
import okhttp3.OkHttpClient;
//https://futurestud.io/tutorials/glide-module-example-accepting-self-signed-https-certificates

/* annotating this module allows me to use it as
AppGlide.with(... ) instead of Glide.with when I load images
So the overrides and other configs that I do here apply
when I use the autogenerated AppGlide class
*/

@GlideModule
public class OkHttpGlideModule extends AppGlideModule{
    @Override
    public void registerComponents(Context context, Glide glide, Registry registry) {
        OkHttpClient client = AppU1b.getApplicationComponent().okHttpClient();
        registry.replace(GlideUrl.class, InputStream.class,
                new OkHttpUrlLoader.Factory(client));
    }

}

Pro-guard.rules


# General config ===========================================================================================================================
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-flattenpackagehierarchy
-allowaccessmodification
-keepattributes *Annotation*
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
-repackageclasses ''

# In most cases these warnings aren't really helpful. Ignore them.
-ignorewarnings

# Android specific config ==================================================================================================================
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-dontnote com.android.vending.licensing.ILicensingService

# Explicitly preserve all serialization members. The Serializable interface is only a marker interface, so it wouldn't save them.
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

# Preserve all native method names and the names of their classes.
-keepclasseswithmembers class * {
    native <methods>;
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

# Preserve static fields of inner classes of R classes that might be accessed through introspection.
-keepclassmembers class **.R$* {
  public static <fields>;
}

# Preserve the special static methods that are required in all enumeration classes.
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-keep public class * {
    public protected *;
}

-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}

# AppU1b specific config ======================================================================================================================

##---------------Begin: proguard configuration for Retrofit  ----------
# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on RoboVM on iOS. Will not be used at runtime.
-dontnote retrofit2.Platform$IOS$MainThreadExecutor
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions
# Other
-dontwarn rx.internal.util.**
-dontwarn retrofit2.adapter.rxjava.CompletableHelper$**
-dontwarn okio.**
##---------------End: proguard configuration for Retrofit  ----------

##-------------Begin: proguard configuration for Retrolambda  ----------
-dontwarn java.lang.invoke.*
##---------------End: proguard configuration for Retrolambda  ----------

##---------------Begin: proguard configuration for Gson  ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

# Gson specific classes
-keep class sun.misc.Unsafe { *; }

# Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
##---------------End: proguard configuration for Gson  ----------

##--------------- React Native

# Keep our interfaces so they can be used by other ProGuard rules.

# See http://sourceforge.net/p/proguard/bugs/466/

-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip

-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters

-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip

# Do not strip any method/class that is annotated with @DoNotStrip

-keep @com.facebook.proguard.annotations.DoNotStrip class *

-keep @com.facebook.common.internal.DoNotStrip class *

-keepclassmembers class * {

    @com.facebook.proguard.annotations.DoNotStrip *;

    @com.facebook.common.internal.DoNotStrip *;

}

-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {

  void set*(***);

  *** get*();

}

-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }

-keep class * extends com.facebook.react.bridge.NativeModule { *; }

-keepclassmembers,includedescriptorclasses class * { native <methods>; }

-keepclassmembers class *  { @com.facebook.react.uimanager.UIProp <fields>; }

-keepclassmembers class *  { @com.facebook.react.uimanager.annotations.ReactProp <methods>; }

-keepclassmembers class *  { @com.facebook.react.uimanager.annotations.ReactPropGroup <methods>; }

-dontwarn com.facebook.react.**

## VSP added to prevent crash in release  https://github.com/facebook/react-native/issues/12994
## I was getting
## Caused by: java.lang.NoSuchFieldError: no "Lcom/facebook/jni/HybridData;" field "mHybridData" in class "Lcom/facebook/react/cxxbridge/CatalystInstanceImpl;" or its superclasses
 -keep class com.facebook.react.cxxbridge.CatalystInstanceImpl { *; }
 -keep class com.facebook.react.cxxbridge.JavaScriptExecutor { *; }
 -keep class com.facebook.react.bridge.queue.NativeRunnable { *; }
 -keep class com.facebook.react.bridge.ExecutorToken { *; }
 -keep class com.facebook.react.bridge.ReadableType { *; }

##----------------------- end react-native

##--glide

-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}

#If you're targeting any API level less than Android API 27, also include:

-dontwarn com.bumptech.glide.load.resource.bitmap.VideoDecoder

# for DexGuard only
#vsp I am not using DexGuard, and this is generating an error in Proguard
# so removing.. but keeping for memory
# -keepresourcexmlelements manifest/application/meta-data@value=GlideModule

## --end glide

# okhttp

-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**

# okio

-keep class sun.misc.Unsafe { *; }
-dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn okio.**

Gradle dependencies section:


dependencies {
    implementation "com.android.support:support-v4:$versions.supportLibrariesVersion"
    implementation "com.android.support:appcompat-v7:$versions.supportLibrariesVersion"
    implementation "com.android.support:support-annotations:$versions.supportLibrariesVersion"
    implementation "com.android.support:recyclerview-v7:$versions.supportLibrariesVersion"

    implementation ("com.crashlytics.sdk.android:crashlytics:2.9.1@aar"){
        transitive=true;
    }

    implementation ("com.crashlytics.sdk.android:answers:1.4.1@aar"){
                transitive=true;
            }

    implementation "com.google.dagger:dagger:$versions.daggerVersion"
    annotationProcessor "com.google.dagger:dagger-compiler:$versions.daggerVersion"
    implementation "com.jakewharton.timber:timber:$versions.timberVersion"

    implementation "com.hannesdorfmann.mosby3:mvp:$versions.mosbyMvpVersion"
    implementation "com.hannesdorfmann.mosby3:viewstate:$versions.mosbyMvpVersion"
    implementation "com.hannesdorfmann.mosby3:mvp-nullobject-presenter:$versions.mosbyMvpVersion"
    implementation "com.jakewharton:butterknife:$versions.butterknifeVersion"
    annotationProcessor "com.jakewharton:butterknife-compiler:$versions.butterknifeVersion"

    // RetroFit
    implementation "com.squareup.retrofit2:retrofit:$versions.retrofitVersion"
    implementation "com.squareup.retrofit2:converter-gson:$versions.retrofitVersion"
    implementation "com.squareup.okhttp3:logging-interceptor:$versions.loggingInterceptorVersion"

    // Rx
    implementation "io.reactivex.rxjava2:rxandroid:$versions.rxAndroidVersion"
    // Already has RxJava, but still better to explicitly get latest version.
    implementation "io.reactivex.rxjava2:rxjava:$versions.rxJavaVersion"
    implementation "com.squareup.retrofit2:adapter-rxjava2:$versions.retrofitVersion"
    //for assemblyTracking in debug
    implementation "com.github.akarnokd:rxjava2-extensions:$versions.rxjava2ExtentionsVersion"

    // Image loading

    implementation "com.github.bumptech.glide:glide:$versions.glideVersion"
    implementation "com.github.bumptech.glide:okhttp3-integration:$versions.glideVersion"
    annotationProcessor "com.github.bumptech.glide:compiler:$versions.glideVersion"

    // Auto value for generating immutable objects.
    compileOnly "com.google.auto.value:auto-value:$versions.autoValueVersion"
    annotationProcessor "com.google.auto.value:auto-value:$versions.autoValueVersion"

    //React Native  -- start
    implementation ("com.facebook.react:react-native:0.56.+"){
                exclude group:'com.facebook.stetho', module:'stetho'
    }

    implementation "com.android.support:multidex:1.0.1"

    implementation project (':react-native-vector-icons')

    implementation "com.android.support.test.espresso:espresso-idling-resource:$versions.espressoVersion"

    implementation "net.danlew:android.joda:$versions.jodaTimeVersion"

    // Stetho
    debugImplementation("com.facebook.stetho:stetho:$versions.stethoVersion") {
        exclude module: 'jsr305'
    }
    debugImplementation("com.facebook.stetho:stetho-okhttp3:$versions.stethoOkHttpVersion") {
        exclude module: 'jsr305'
    }
    qaImplementation("com.facebook.stetho:stetho:$versions.stethoVersion") {
        exclude module: 'jsr305'
    }
    qaImplementation("com.facebook.stetho:stetho-okhttp3:$versions.stethoOkHttpVersion") {
        exclude module: 'jsr305'
    }

    // Rx lint is a single lint check that checks if an rxjava subscriber is handling the onError() callback.
    debugImplementation "nl.littlerobots.rxlint:rxlint:$versions.rxLintVersion"

    debugImplementation "com.squareup.retrofit2:retrofit-mock:$versions.retrofitVersion"
    qaImplementation "com.squareup.retrofit2:retrofit-mock:$versions.retrofitVersion"

// test deps
    testImplementation "junit:junit:$versions.jUnitVersion"

    // Fluent way of writing assertions
    testImplementation "org.assertj:assertj-core:$versions.assertJJava8Version"

    // Mocking framework to mock and verify calls.
    testImplementation "org.mockito:mockito-core:$versions.mockitoVersion"

    // Robolectric for running tests that contain android components.
    testImplementation "org.robolectric:robolectric:$versions.robolectricVersion"
    // For robolectric issue. See https://github.com/robolectric/robolectric/issues/1932

    // Mocking the backend
    testImplementation "com.squareup.okhttp3:mockwebserver:$versions.okhttpMockWebServerVersion"

    // Fork of JodaTime for Android. See https://github.com/dlew/joda-time-android
    testImplementation "net.danlew:android.joda:$versions.jodaTimeVersion"

    // INSTRUMENTATION TESTS DEPENDENCIES **************************************************************************************************
    // Main espresso test support
    androidTestImplementation "com.android.support.test.espresso:espresso-core:$versions.espressoVersion"

    // Espresso-intents for validation and stubbing of Intents
    androidTestImplementation "com.android.support.test.espresso:espresso-intents:$versions.espressoVersion"

    // Android JUnit Runner
    androidTestImplementation "com.android.support.test:runner:$versions.espressoTestRunnerVersion"

    // JUnit4 Rules
    androidTestImplementation "com.android.support.test:rules:$versions.espressoTestRulesVersion"

    // Espresso library with external contributions that contain DatePicker, RecyclerView and Drawer actions, Accessibility checks, and
    // CountingIdlingResource.
    androidTestImplementation("com.android.support.test.espresso:espresso-contrib:$versions.espressoVersion") {
        exclude module: 'support-annotations'
        exclude module: 'support-v4'
        exclude module: 'support-v13'
        exclude module: 'recyclerview-v7'
        exclude module: 'design'
    }

    // Force specific library version for instrumentation tests. Fixes version conflict issue.
    androidTestImplementation "com.android.support:support-annotations:$versions.supportLibrariesVersion"

   // Fluent way of writing assertions. For instrumentation tests the java 7 compiled library is used to avoid dex errors
    androidTestImplementation "org.assertj:assertj-core:$versions.assertJJava7Version"

    // Mocking the backend
    androidTestImplementation "com.squareup.okhttp3:mockwebserver:$versions.okhttpMockWebServerVersion"

    implementation "com.android.support:design:$versions.supportLibrariesVersion"
    testImplementation 'org.khronos:opengl-api:gl1.1-android-2.1_r1'

}

Versions

        retrolambdaPluginVersion  : '3.7.0',
        dexCountPluginVersion     : '0.8.1',
        playPublisherPluginVersion: '1.2.0',
        fabricPluginVersion       : '1.22.0',
        jacocoPluginVersion       : '0.7.7.201606060606',

        supportLibrariesVersion: '27.1.0',
      //vsp move to inline  crashlyticsVersion        : '2.9.1',
        //vsp moved to inline answersAnalyticsVersion   : '1.3.10',
        butterknifeVersion        : '8.8.1',
        assertJJava8Version       : '3.5.2',
        assertJJava7Version       : '2.5.0',
        jUnitVersion              : '4.12',
        espressoVersion           : '2.2.2',
        espressoTestRulesVersion  : '0.5',
        espressoTestRunnerVersion : '0.5',
        timberVersion             : '4.5.1',
        mosbyMvpVersion           : '3.0.0',
        annotationsVersion        : '3.0.2',
        daggerVersion             : '2.11',
        retrofitVersion           : '2.4.0',
        rxJavaVersion             : '2.1.3',
        rxAndroidVersion          : '2.0.1',
        rxjava2ExtentionsVersion  : '0.16.2',
        loggingInterceptorVersion : '3.4.2',
        stethoVersion             : '1.5.0',
        stethoOkHttpVersion       : '1.5.0',
        robolectricVersion        : '3.3',
        glideVersion              : '4.7.1',
        autoValueVersion          : '1.3',
        rxLintVersion             : '1.2',
        okhttpMockWebServerVersion: '3.11.0',
        jodaTimeVersion           : '2.9.7',
        mockitoVersion            : '2.6.3',
vladp commented 6 years ago

wanted to check to see if others are successful in following this article https://futurestud.io/tutorials/glide-module-example-accepting-self-signed-https-certificates, or there other alternatives (for me, the recommendation there, causes the above error in the release mode)

sjudd commented 6 years ago

It definitely seems like a proguard issue. It looks like your proguard config for Glide's classes at least matches what I'd expect.

It's probably that one of the other rules is causing some optimization or change that Glide doesn't expect. You could try adding rules to keep the generated class explicitly, though that isn't usually necessary.

The exception is thrown for one of the causes here: https://github.com/bumptech/glide/blob/914996cac11108ec1a02c21a10af53ebc4980d7f/library/src/main/java/com/bumptech/glide/Glide.java#L294. You might be able to narrow down which one by looking at the deobfuscated cause of the exception.

vladp commented 6 years ago

@sjudd thank you for the follow up. Indeed, my proguard caused this. after some trial/error, I removed -repackageclasses '' and I now passed that error.

pratikbutani commented 5 years ago

First thing:

Have you changed annotationProcessor dependency:

implementation 'com.github.bumptech.glide:glide:4.10.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'

Second things:

Have you added proguard rules as follow:

-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}

Hope it will helps you. Thank you.