当我使用 proguard 并启用 minify 和 shrinkresources 时,Retrofit 的 Retrofit body 请求为空
Retrofit body request is blank with Retrofit, when I use proguard and enable minify and shrinkresources
当我将 minifyEnabled & shrinkResources
设置为 true
时,发送的 Retrofit 正文 JSON 请求是空白的,当它设置为 false 时,它工作得很好。
我已经发布了整个 gradle 文件,您可以帮我指出我做错了什么。
当 minifyEnabled & shrinkResources
为 true
时,我的改造请求 json 正文如下所示:
{}
当minifyEnabled & shrinkResources
为false
时工作正常:
{"Data":"demoToken","Key":"demokey","Token":"2a9a8677-ac79-49d6-9947-d797b3e4d8e5"}
我的 gradle 看起来像这样:
apply {
plugin 'com.android.application'
plugin 'kotlin-android'
plugin 'kotlin-android-extensions'
plugin 'kotlin-kapt'
plugin 'io.fabric'
plugin 'com.google.firebase.firebase-perf'
}
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.something.theapp"
minSdkVersion 21
targetSdkVersion 28
versionCode 43
versionName "0.6.7"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
flavorDimensions "server"
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
javaCompileOptions {
annotationProcessorOptions {
includeCompileClasspath = true
}
}
}
signingConfigs {
kaira {
storeFile file('key_tts.jks')
storePassword 'android'
keyAlias 'tts_key'
keyPassword 'android'
}
}
buildTypes {
debug {
signingConfig signingConfigs.kaira
minifyEnabled true
shrinkResources true
buildConfigField "boolean", "ALLOW_DATABASE", "false"
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
signingConfig signingConfigs.kaira
minifyEnabled true
shrinkResources true
buildConfigField "boolean", "ALLOW_DATABASE", "false"
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
local {
//buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.136:6264/siteapp/api/\""
// buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.21:5678/api/\""
// buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.233:5677/api/\""
// buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.26:5678/api/\""
//buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.25:5678/api/\""
// buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.37:5678/api/\""
// buildConfigField "String", "WebServiceUrl", "\"https://api.forsell.in/api/\""
// buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.23:5678/api/\""
buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.29:5678/api/\""
buildConfigField "String", "WebUrl", "\"https://someurl.in/\""
buildConfigField "String", "ServerName", "\"-Local\""
dimension "server"
copy {
from "src/local"
include "google-services.json"
into "."
}
}
temp {
buildConfigField "String", "WebServiceUrl", "\"http://api.lezza.in/api/\""
buildConfigField "String", "WebUrl", "\"https://someurl.in/\""
buildConfigField "String", "ServerName", "\"-Local\""
dimension "server"
copy {
from "src/local"
include "google-services.json"
into "."
}
}
live {
buildConfigField "String", "WebServiceUrl", "\"https://api.someurl.in/api/\""
buildConfigField "String", "WebUrl", "\"https://someurl.in/\""
buildConfigField "String", "ExtClientNameNew", "\"ExtClientName:TTS\""
dimension "server"
copy {
from "src/livegcm"
include "google-services.json"
into "."
}
}
staging {
//buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.233:85/api/\""//sunil
// buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.233:5677/api/\""//devang
// buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.233:85/api/\""
buildConfigField "String", "WebServiceUrl", "\"https://stageapi.someurl.in/api/\""
buildConfigField "String", "WebUrl", "\"https://stageweb.someurl.in/\""
buildConfigField "String", "ServerName", "\"-Staging\""
dimension "server"
copy {
from "src/local"
include "google-services.json"
into "."
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
dexOptions {
preDexLibraries = false
javaMaxHeapSize "4g" // 2g should be also OK
}
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
lintOptions {
abortOnError false
disable 'MissingTranslation'
}
}
repositories {
mavenCentral()
maven { url 'https://maven.fabric.io/public' }
}
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == 'com.android.support') {
if (!requested.name.startsWith("multidex")) {
details.useVersion '28.0.0'
}
}
}
}
dependencies {
def lifecycle_version = "2.0.0"
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.core:core-ktx:1.0.2'
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.vectordrawable:vectordrawable:1.0.0-alpha1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.2') {
exclude group: 'com.google.code.findbugs'
}
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.github.bumptech.glide:glide:4.5.0'
implementation 'com.karumi:dexter:5.0.0'
implementation 'com.google.android.gms:play-services-maps:16.1.0'
implementation 'com.google.android.gms:play-services-location:16.0.0'
implementation 'com.google.android.gms:play-services-auth:16.0.1'
implementation 'org.jetbrains.anko:anko-common:0.9'
implementation 'com.google.android.gms:play-services-ads:17.2.0'
implementation 'androidx.multidex:multidex:2.0.1'
implementation project(path: ':imagepicker')
implementation 'androidx.percentlayout:percentlayout:1.0.0'
implementation 'com.google.firebase:firebase-core:16.0.9'
implementation 'com.google.firebase:firebase-inappmessaging-display:17.2.0'
implementation 'com.google.firebase:firebase-messaging:18.0.0'
implementation 'com.google.firebase:firebase-config:17.0.0'
implementation 'com.google.firebase:firebase-perf:17.0.2'
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation 'com.google.android.gms:play-services-places:16.1.0'
implementation 'com.google.android.libraries.places:places:1.1.0'
api 'com.theartofdev.edmodo:android-image-cropper:2.8.+'
implementation 'com.github.faruktoptas:RetrofitRssConverterFactory:0.1.0'
implementation 'com.wang.avi:library:2.1.3'
implementation 'com.facebook.android:facebook-android-sdk:5.4.0'
implementation('com.crashlytics.sdk.android:crashlytics:2.9.8@aar') {
transitive = true
}
implementation 'com.haozhang.libary:android-slanted-textview:1.2'
implementation 'com.facebook.shimmer:shimmer:0.4.0'
implementation 'com.github.freshdesk:freshchat-android:1.5.3'
implementation 'commons-io:commons-io:2.4'
implementation 'com.getkeepsafe.taptargetview:taptargetview:1.12.0'
implementation 'com.razorpay:checkout:1.5.6'
implementation 'com.google.android.gms:play-services-analytics:17.0.0'
}
apply plugin: 'com.google.gms.google-services'
下面是我的主模型class
class ServiceRequest {
var Key: String? = "SiteAdminAppkey"
var Token: String? = ""
// var Slug: String? = "admin"
var Data: Any? = null
}
我可以通过添加 @SerializeName
注释来实现这一点,但我必须在每个模型中都这样做 class。在我的另一个项目中,Proguard 和一切都无需序列化即可工作。
由于您正在使用 Gson 将 Json 转换为您的模型,因此您需要确保反射是在这些 classes 上正常工作(因为我假设您还没有为这些创建自定义适配器)。
保留 class 和字段名称的最简单方法,您可以使用 @Keep
来自 AndroidX Annotations:
的注释模型
Denotes that the annotated element should not be removed when the code is minified at build time. This is typically used on methods and classes that are accessed only via reflection so a compiler may think that the code is unused.
Add below line in your proguard-rules.pro
File
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
Also add below line in gradle.properties file.
android.enableR8=false
我遇到了同样的问题,并在文件中添加了上面一行,它对我有用。
在 proguard-rules 中添加以下行
-keepclassmembers class <yourpackagename>.** { <fields>; }
将 yourpackagename 替换为所有模型所在的目录路径 类 ,就像我的例子
-keepclassmembers class com.demo.app.model.** { <fields>; }
使用最新版本的改装库:
com.squareup.retrofit2:改造:2.7.1
如果您使用的是 R8,则会自动包含收缩和混淆规则。
Latest Retrofit lib
另外,Gson 实现的变化 'com.google.code.gson:gson:2.8.6'
Latest GSON lib
查看 R8 兼容性常见问题 r8-compatibility-faq for GSON
如果您使用的是 OkHttp3,请更改为最新版本 okhttp3LibVersion = '4.3.1
这对我有用。
# Retrofit2
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
-keepclassmembernames interface * {
@retrofit2.http.* <methods>;
}
# GSON Annotations
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
出于某种原因,如果没有 GSON 注释设置,它就无法工作,即使直接在模型上添加 @Keep 注释 class 也是如此。
这是一个更新的答案(05/20),因为在我的情况下似乎没有任何效果。
使用 Retrofit 文档中的 Proguard 规则 here。
保持你的模型class喜欢丑寒的回答
对于我的情况,这是解决方案:
# For GSON annotation
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
当我将 minifyEnabled & shrinkResources
设置为 true
时,发送的 Retrofit 正文 JSON 请求是空白的,当它设置为 false 时,它工作得很好。
我已经发布了整个 gradle 文件,您可以帮我指出我做错了什么。
当 minifyEnabled & shrinkResources
为 true
时,我的改造请求 json 正文如下所示:
{}
当minifyEnabled & shrinkResources
为false
时工作正常:
{"Data":"demoToken","Key":"demokey","Token":"2a9a8677-ac79-49d6-9947-d797b3e4d8e5"}
我的 gradle 看起来像这样:
apply {
plugin 'com.android.application'
plugin 'kotlin-android'
plugin 'kotlin-android-extensions'
plugin 'kotlin-kapt'
plugin 'io.fabric'
plugin 'com.google.firebase.firebase-perf'
}
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.something.theapp"
minSdkVersion 21
targetSdkVersion 28
versionCode 43
versionName "0.6.7"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
flavorDimensions "server"
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
javaCompileOptions {
annotationProcessorOptions {
includeCompileClasspath = true
}
}
}
signingConfigs {
kaira {
storeFile file('key_tts.jks')
storePassword 'android'
keyAlias 'tts_key'
keyPassword 'android'
}
}
buildTypes {
debug {
signingConfig signingConfigs.kaira
minifyEnabled true
shrinkResources true
buildConfigField "boolean", "ALLOW_DATABASE", "false"
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
signingConfig signingConfigs.kaira
minifyEnabled true
shrinkResources true
buildConfigField "boolean", "ALLOW_DATABASE", "false"
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
local {
//buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.136:6264/siteapp/api/\""
// buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.21:5678/api/\""
// buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.233:5677/api/\""
// buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.26:5678/api/\""
//buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.25:5678/api/\""
// buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.37:5678/api/\""
// buildConfigField "String", "WebServiceUrl", "\"https://api.forsell.in/api/\""
// buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.23:5678/api/\""
buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.29:5678/api/\""
buildConfigField "String", "WebUrl", "\"https://someurl.in/\""
buildConfigField "String", "ServerName", "\"-Local\""
dimension "server"
copy {
from "src/local"
include "google-services.json"
into "."
}
}
temp {
buildConfigField "String", "WebServiceUrl", "\"http://api.lezza.in/api/\""
buildConfigField "String", "WebUrl", "\"https://someurl.in/\""
buildConfigField "String", "ServerName", "\"-Local\""
dimension "server"
copy {
from "src/local"
include "google-services.json"
into "."
}
}
live {
buildConfigField "String", "WebServiceUrl", "\"https://api.someurl.in/api/\""
buildConfigField "String", "WebUrl", "\"https://someurl.in/\""
buildConfigField "String", "ExtClientNameNew", "\"ExtClientName:TTS\""
dimension "server"
copy {
from "src/livegcm"
include "google-services.json"
into "."
}
}
staging {
//buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.233:85/api/\""//sunil
// buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.233:5677/api/\""//devang
// buildConfigField "String", "WebServiceUrl", "\"http://192.168.1.233:85/api/\""
buildConfigField "String", "WebServiceUrl", "\"https://stageapi.someurl.in/api/\""
buildConfigField "String", "WebUrl", "\"https://stageweb.someurl.in/\""
buildConfigField "String", "ServerName", "\"-Staging\""
dimension "server"
copy {
from "src/local"
include "google-services.json"
into "."
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
dexOptions {
preDexLibraries = false
javaMaxHeapSize "4g" // 2g should be also OK
}
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
lintOptions {
abortOnError false
disable 'MissingTranslation'
}
}
repositories {
mavenCentral()
maven { url 'https://maven.fabric.io/public' }
}
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == 'com.android.support') {
if (!requested.name.startsWith("multidex")) {
details.useVersion '28.0.0'
}
}
}
}
dependencies {
def lifecycle_version = "2.0.0"
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.core:core-ktx:1.0.2'
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.vectordrawable:vectordrawable:1.0.0-alpha1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.2') {
exclude group: 'com.google.code.findbugs'
}
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.github.bumptech.glide:glide:4.5.0'
implementation 'com.karumi:dexter:5.0.0'
implementation 'com.google.android.gms:play-services-maps:16.1.0'
implementation 'com.google.android.gms:play-services-location:16.0.0'
implementation 'com.google.android.gms:play-services-auth:16.0.1'
implementation 'org.jetbrains.anko:anko-common:0.9'
implementation 'com.google.android.gms:play-services-ads:17.2.0'
implementation 'androidx.multidex:multidex:2.0.1'
implementation project(path: ':imagepicker')
implementation 'androidx.percentlayout:percentlayout:1.0.0'
implementation 'com.google.firebase:firebase-core:16.0.9'
implementation 'com.google.firebase:firebase-inappmessaging-display:17.2.0'
implementation 'com.google.firebase:firebase-messaging:18.0.0'
implementation 'com.google.firebase:firebase-config:17.0.0'
implementation 'com.google.firebase:firebase-perf:17.0.2'
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation 'com.google.android.gms:play-services-places:16.1.0'
implementation 'com.google.android.libraries.places:places:1.1.0'
api 'com.theartofdev.edmodo:android-image-cropper:2.8.+'
implementation 'com.github.faruktoptas:RetrofitRssConverterFactory:0.1.0'
implementation 'com.wang.avi:library:2.1.3'
implementation 'com.facebook.android:facebook-android-sdk:5.4.0'
implementation('com.crashlytics.sdk.android:crashlytics:2.9.8@aar') {
transitive = true
}
implementation 'com.haozhang.libary:android-slanted-textview:1.2'
implementation 'com.facebook.shimmer:shimmer:0.4.0'
implementation 'com.github.freshdesk:freshchat-android:1.5.3'
implementation 'commons-io:commons-io:2.4'
implementation 'com.getkeepsafe.taptargetview:taptargetview:1.12.0'
implementation 'com.razorpay:checkout:1.5.6'
implementation 'com.google.android.gms:play-services-analytics:17.0.0'
}
apply plugin: 'com.google.gms.google-services'
下面是我的主模型class
class ServiceRequest {
var Key: String? = "SiteAdminAppkey"
var Token: String? = ""
// var Slug: String? = "admin"
var Data: Any? = null
}
我可以通过添加 @SerializeName
注释来实现这一点,但我必须在每个模型中都这样做 class。在我的另一个项目中,Proguard 和一切都无需序列化即可工作。
由于您正在使用 Gson 将 Json 转换为您的模型,因此您需要确保反射是在这些 classes 上正常工作(因为我假设您还没有为这些创建自定义适配器)。
保留 class 和字段名称的最简单方法,您可以使用 @Keep
来自 AndroidX Annotations:
Denotes that the annotated element should not be removed when the code is minified at build time. This is typically used on methods and classes that are accessed only via reflection so a compiler may think that the code is unused.
Add below line in your
proguard-rules.pro
File
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
Also add below line in gradle.properties file.
android.enableR8=false
我遇到了同样的问题,并在文件中添加了上面一行,它对我有用。
在 proguard-rules 中添加以下行
-keepclassmembers class <yourpackagename>.** { <fields>; }
将 yourpackagename 替换为所有模型所在的目录路径 类 ,就像我的例子
-keepclassmembers class com.demo.app.model.** { <fields>; }
使用最新版本的改装库: com.squareup.retrofit2:改造:2.7.1 如果您使用的是 R8,则会自动包含收缩和混淆规则。 Latest Retrofit lib
另外,Gson 实现的变化 'com.google.code.gson:gson:2.8.6' Latest GSON lib
查看 R8 兼容性常见问题 r8-compatibility-faq for GSON
如果您使用的是 OkHttp3,请更改为最新版本 okhttp3LibVersion = '4.3.1
这对我有用。
# Retrofit2
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
-keepclassmembernames interface * {
@retrofit2.http.* <methods>;
}
# GSON Annotations
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
出于某种原因,如果没有 GSON 注释设置,它就无法工作,即使直接在模型上添加 @Keep 注释 class 也是如此。
这是一个更新的答案(05/20),因为在我的情况下似乎没有任何效果。
使用 Retrofit 文档中的 Proguard 规则 here。
保持你的模型class喜欢丑寒的回答
对于我的情况,这是解决方案:
# For GSON annotation
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}