签名的应用程序崩溃和未签名的 apk 运行

Signed app crashing and unsigned apk running

这个问题可能与一些 SO 问题有关,因为我在这里搜索了很多,但没有任何 post 帮助我。我的应用程序 运行 未签名时正在运行,但当我 运行 已签名的 APK 时它会立即崩溃。我把它 debuggable true 放在 gradle 中并检查我发现了这个错误 logcat.

java.lang.NoSuchFieldError: No static field REPLACE of type Lcom/a/a/a$a; in class Lcom/a/a/a$a; or its superclasses (declaration of 'com.a.a.a$a' appears in /data/app/com.aami.aruman.com-J1sPXkw9O_ZNL4zfcpqgMQ==/base.apk)
    at java.lang.reflect.Field.getAnnotationNative(Native Method)
    at java.lang.reflect.Field.getAnnotation(Field.java:847)
    at com.a.g.<init>(Unknown Source:94)
    at com.a.f.a(Unknown Source:97)
    at com.a.f.a(Unknown Source:126)
    at com.a.f.<init>(Unknown Source:27)
    at com.a.b.a(Unknown Source:22)
    at com.a.a.a(Unknown Source:3)
    at com.a.a.a(Unknown Source:1)
    at com.a.a.a(Unknown Source:9)
    at com.a.b.a.onCreate(Unknown Source:3)
    at com.aami.aruman.com.codingnation.base.DroiderApplication.onCreate(Unknown Source:0)
    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1120)
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5747)
    at android.app.ActivityThread.-wrap1(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1656)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6501)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
07-12 22:22:18.355 13073-13073/com.aami.aruman.com E/UncaughtException: java.lang.NoSuchFieldError: No static field REPLACE of type Lcom/a/a/a$a; in class Lcom/a/a/a$a; or its superclasses (declaration of 'com.a.a.a$a' appears in /data/app/com.aami.aruman.com-J1sPXkw9O_ZNL4zfcpqgMQ==/base.apk)
    at java.lang.reflect.Field.getAnnotationNative(Native Method)
    at java.lang.reflect.Field.getAnnotation(Field.java:847)
    at com.a.g.<init>(Unknown Source:94)
    at com.a.f.a(Unknown Source:97)
    at com.a.f.a(Unknown Source:126)
    at com.a.f.<init>(Unknown Source:27)
    at com.a.b.a(Unknown Source:22)
    at com.a.a.a(Unknown Source:3)
    at com.a.a.a(Unknown Source:1)
    at com.a.a.a(Unknown Source:9)
    at com.a.b.a.onCreate(Unknown Source:3)
    at com.aami.aruman.com.codingnation.base.DroiderApplication.onCreate(Unknown Source:0)
    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1120)
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5747)
    at android.app.ActivityThread.-wrap1(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1656)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6501)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

我在 posts 中看到,posting build.gradle 可以很容易地理解错误,所以这里是。

buildscript {
repositories {
    maven { url 'https://maven.fabric.io/public' }
}

dependencies {
    classpath 'io.fabric.tools:gradle:1.+'
 }
}

apply plugin: 'com.android.application'
apply plugin: 'io.fabric'

repositories {
    maven { url 'https://maven.fabric.io/public' }
}


android {
    compileSdkVersion 26
    useLibrary 'org.apache.http.legacy'
    buildToolsVersion '27.0.3'
    defaultConfig {
        multiDexEnabled true
        applicationId "com.aami.aruman.com"
        minSdkVersion 16
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"


    }
    android {
        lintOptions {
            checkReleaseBuilds false
            abortOnError false
        }
        packagingOptions {
            exclude 'META-INF/DEPENDENCIES.txt'
            exclude 'META-INF/LICENSE.txt'
            exclude 'META-INF/maven/pom.properties'
            exclude 'META-INF/NOTICE.txt'
            exclude 'META-INF/NOTICE'
            exclude 'META-INF/LICENSE'
            exclude 'META-INF/DEPENDENCIES'
            exclude 'META-INF/notice.txt'
            exclude 'META-INF/license.txt'
            exclude 'META-INF/dependencies.txt'
            exclude 'META-INF/LGPL2.1'
            exclude 'META-INF/gson/FieldAttributes.class'
            exclude '.readme'
        }
    }
    buildTypes {
        release {
            debuggable true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.google.firebase:firebase-messaging:12.0.1'
    implementation 'com.android.support:appcompat-v7:26.1.+'
    implementation 'com.android.support:gridlayout-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    implementation 'com.facebook.android:facebook-android-sdk:4.10.0'
    implementation 'com.android.support:design:26.1.+'
    implementation 'com.android.support:recyclerview-v7:26.1.0'
    implementation 'com.android.support:cardview-v7:26.1.0'
    implementation 'de.hdodenhof:circleimageview:1.3.0'
    implementation 'com.google.android.gms:play-services-places:12.0.1'
    implementation 'com.android.support:support-v4:26.1.0'
    implementation 'com.google.android.gms:play-services-maps:12.0.1'
    implementation 'com.android.volley:volley:1.1.0'
    implementation 'com.github.bumptech.glide:glide:3.7.0'
    implementation 'com.squareup.picasso:picasso:2.71828'
    implementation 'com.github.lzyzsd:circleprogress:1.2.1'
    implementation 'com.romandanylyk:pageindicatorview:0.2.0'
    implementation 'com.nshmura:snappysmoothscroller:1.0.0'
    implementation 'com.codemybrainsout.rating:ratingdialog:1.0.8'
    implementation 'org.adw.library:discrete-seekbar:1.0.1'
    implementation 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'
    implementation 'com.squareup.retrofit2:converter-gson:2.0.2'
    implementation 'com.jakewharton:butterknife:8.8.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
    implementation 'com.google.firebase:firebase-auth:12.0.1'
    implementation 'com.google.firebase:firebase-storage:12.0.1'
    implementation 'com.google.firebase:firebase-core:12.0.1'
    implementation 'com.facebook.fresco:fresco:1.3.0'
    implementation 'com.google.android.gms:play-services-auth:12.0.1'
    implementation 'com.google.android.gms:play-services-location:12.0.1'
    implementation 'com.rengwuxian.materialedittext:library:2.1.4'
    implementation 'com.nispok:snackbar:2.11.+'
    implementation 'com.github.ybq:Android-SpinKit:1.1.0'
    implementation 'com.gmail.samehadar:iosdialog:1.0'
    implementation 'com.android.support:multidex:1.0.3'
    implementation 'joda-time:joda-time:2.9.4'
    implementation 'com.crystal:crystalrangeseekbar:1.1.3'
    implementation 'com.google.firebase:firebase-crash:12.0.1'
    implementation 'com.github.clans:fab:1.6.2'
    implementation('com.crashlytics.sdk.android:crashlytics:2.9.2@aar')      {
        transitive = true
    }
    implementation 'com.github.florent37:singledateandtimepicker:2.0.5'
    implementation 'com.getbase:floatingactionbutton:1.10.1'
    implementation 'com.payumoney.sdkui:plug-n-play:1.3.0'
    implementation 'com.amitshekhar.android:jackson-android-networking:1.0.1'
    implementation 'com.daasuu:animateHorizontalProgressBar:0.2.4'
}
apply plugin: 'com.google.gms.google-services'

最后是 proguard

-dontwarn org.apache.**
-dontwarn javax.annotation.**
-dontwarn com.squareup.picasso.**
-dontwarn okio.**
-keep class com.google.**
-dontwarn com.google.**
-keepattributes Signature
-dontwarn retrofit2.Platform$Java8
# For using GSON @Expose annotation
-keepattributes *Annotation*
-dontwarn org.**
-dontwarn javax.**
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }


-keep class com.squareup.okhttp.{ *; }
-dontwarn com.squareup.okhttp.**
-keep class com.facebook.{ *; }
-dontwarn com.facebook.**
-keep class ohttp3.{ *; }
-dontwarn okhttp3.**
-keep class org.joda.{ *; }
-dontwarn org.joda.**
-keepclassmembers class * {

    private <fields>;
    }
    # Proguard configuration for Jackson 2.x (fasterxml package instead of codehaus package)
    -keep class com.fasterxml.jackson.databind.ObjectMapper {
        public <methods>;
        protected <methods>;
    }
    -keep class com.fasterxml.jackson.databind.ObjectWriter {
        public ** writeValueAsString(**);
    }
    -keepnames class com.fasterxml.jackson.** { *; }

-keepclassmembers class com.aami.aruman.com.codingnation.beans.** { *; }


-dontwarn com.fasterxml.jackson.databind.**
-dontwarn org.springframework.**

关于 Proguard

Proguard 通过做两件事基本上使您的代码更小,更难逆向工程:

  1. 剥离未使用的代码
  2. 通过将您编写的人类可读符号重命名为尽可能小(且难以阅读)的名称来混淆包和符号名称。

关于您的问题

看起来有些东西正在使用 Java 反射来查找名为 REPLACE 的字段,但是这个字段被混淆器混淆了。

根据您发布的堆栈跟踪,这:

com.a.g.<init>(Unknown Source:94)

是进行反射调用的代码。

那么 com.a.g.<init> 到底是什么?这是 class 的混淆名称。 <init> 告诉我这是某种 class 构造函数。

但是为了弄清楚 ag 是什么,您需要在实际符号和混淆器分配的符号之间进行某种映射。

解决方案

当proguard 运行时,它会生成一个符号映射文件。您可以使用 retrace.sh 脚本(如果您在 Windows 上进行开发,则为 retrace.bat)取消混淆您的堆栈跟踪,如果您使用 Android SDK 随附的混淆器工具我仍然有这个映射文件并找出它在您的代码中的位置。

类似于:

<androidsdkroot>/tools/proguard/bin/retrace.sh -verbose mapping.txt stacktrace.txt > out.txt

其中:

  • mapping.txt是proguard在运行
  • 时创建的映射文件
  • stacktrace.txt 包含您在问题中发布的原始堆栈跟踪
  • out.txt 是接收未混淆堆栈跟踪的文件名。

一旦你弄清楚了,你需要添加一个 keep rule 到你的 proguard 配置文件,以防止它被混淆。或者,如果可以的话,去掉反射代码。

最后,如果进行反射调用的代码来自您不拥有的库,我会查看该库的文档,看看它是否调用了您应该添加的任何保留规则你的 proguard 配置文件并添加它们。

请参阅 Android Shrink Code 文档以获取有关解码模糊堆栈跟踪的更多信息。