第一个月
我的应用程序运行良好,我只是想优化它的大小。
minifyEnabled true
shrinkResources true
字符串build.gradle
经过大量的试验和错误编译包和apk,我终于到达那里。
但现在,在运行时,我有一个错误:
2023-11-04 18:27:45.843 AndroidRuntime E FATAL EXCEPTION: main
Process: XX.XX.XX, PID: 21345
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.String java.lang.CharSequence.toString()' on a null object reference
at java.text.Normalizer.normalize(Normalizer.java:167)
at c4.e.v(SourceFile:1)
at c4.e.a(SourceFile:1)
at c4.d.compare(SourceFile:1)
at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
at java.util.TimSort.sort(TimSort.java:220)
at java.util.Arrays.sort(Arrays.java:1492)
at java.util.ArrayList.sort(ArrayList.java:1470)
at java.util.Collections.sort(Collections.java:206)
at c4.e.D(SourceFile:1)
at b4.g.H(SourceFile:1)
at XX.XX.XX.RangtActivity.C(SourceFile:1)
at XX.XX.XX.services.e$a.b(SourceFile:1)
at o5.g$b$a.f(SourceFile:1)
at o5.g$b$a.d(SourceFile:1)
at o5.h.run(SourceFile:1)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
型
但是,我使用minifyEnabled false
没有问题。否则我可以试着纠正错误。
我甚至不知道我的代码的哪一部分出错了。
我唯一的解决方案是不要试图减少应用程序的大小吗?
你会明白的,我根本不是Maven。
build.gradle:
apply plugin: 'com.android.application'
android {
compileSdk 33
signingConfigs {
release {
storeFile file(RELEASE_STORE_FILE)
storePassword RELEASE_STORE_PASSWORD
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
// Optional, specify signing versions used
v1SigningEnabled true
v2SigningEnabled true
}
}
defaultConfig {
applicationId "XX.XX.XX"
minSdkVersion 22
targetSdkVersion 33
versionCode 251
versionName '2.5.1'
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
vectorDrawables.useSupportLibrary = true
}
buildTypes {
debug {
buildConfigField "String", "VARIANT", "\"dev\""
buildConfigField "boolean", "DEV", "true"
// buildConfigField "int", "FOO", "52"
}
release {
signingConfig signingConfigs.release
buildConfigField "String", "VARIANT", "\"\""
buildConfigField "boolean", "DEV", "false"
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
android.applicationVariants.all { variant ->
def appName
//Check if an applicationName property is supplied; if not use the name of the parent project.
if (project.hasProperty("applicationName")) {
appName = applicationName
} else {
appName = parent.name
}
variant.outputs.all { output ->
// outputFileName = "${appName}-${output.baseName}-${variant.versionName}.apk"
outputFileName = "${appName}-${variant.versionName}.apk"
// def formattedDate = new Date().format('yyyyMMddHHmmss')
// outputFileName = "${appName}-${output.baseName}-${variant.versionName}-${formattedDate}.apk"
}
}
}
}
productFlavors {
demo {
applicationId "XX.XX.XXdemo"
// dimension 'app'
versionNameSuffix '-demo'
}
full {
// dimension 'app'
}
}
compileOptions {
targetCompatibility = 1.8
sourceCompatibility = 1.8
}
packagingOptions {
resources {
excludes += ['META-INF/LICENSE.md', 'META-INF/NOTICE.md']
}
}
namespace 'XX.XX.XX'
flavorDimensions += 'app'
}
dependencies {
modules {
module("org.jetbrains.kotlin:kotlin-stdlib-jdk7") {
replacedBy("org.jetbrains.kotlin:kotlin-stdlib", "kotlin-stdlib-jdk7 is now part of kotlin-stdlib")
}
module("org.jetbrains.kotlin:kotlin-stdlib-jdk8") {
replacedBy("org.jetbrains.kotlin:kotlin-stdlib", "kotlin-stdlib-jdk8 is now part of kotlin-stdlib")
}
}
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.recyclerview:recyclerview:1.3.2'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'androidx.recyclerview:recyclerview:1.3.2'
implementation 'androidx.preference:preference:1.2.1'
implementation 'org.droidparts:droidparts-misc:3.2.5'
implementation 'joda-time:joda-time:2.12.5'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'com.google.android.gms:play-services-vision:20.1.3'
//noinspection GradleDependency
implementation 'com.google.android.material:material:1.9.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.sun.mail:android-mail:1.6.7'
implementation 'com.sun.mail:android-activation:1.6.7'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.annotation:annotation:1.7.0'
implementation 'com.github.yalantis:ucrop:2.2.6'
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
}
allprojects {
repositories {
maven { url "https://jitpack.io" }
}
}
configurations {
configureEach {
exclude group: 'androidx.lifecycle', module: 'lifecycle-viewmodel-ktx'
}
}
static String firstMatchingSubstring(String taskName, String[] keys) {
def lcName = taskName.toLowerCase()
for(String key: keys) { if(lcName.contains(key.toLowerCase())) return key }
return null
}
/**
*
* @param taskName e.g., bundleMyFlavorRelease or bundleRelease
* @return
*/
String getBuildType(String taskName) {
return firstMatchingSubstring(taskName, getBuildTypeNames())
}
/**
*
* @param taskName e.g., bundleMyFlavorRelease
* @return
*/
String getFlavor(String taskName) {
return firstMatchingSubstring(taskName, getProductFlavorNames())
}
String[] getBuildTypeNames() {
def types = []
android.buildTypes.configureEach { type -> types.add(type.name) }
return types
}
String[] getProductFlavorNames() {
def flavors = []
android.productFlavors.configureEach { flavor -> flavors.add(flavor.name) }
return flavors
}
tasks.configureEach { task ->
def name = task.name
//Skip some unnecessary tasks
if (name.startsWith("bundle")
&& !name.contains("Classes")
&& !name.contains("Resources")
&& name != "bundle") {
def renameTaskName = "rename${task.name.capitalize()}Aab"
def version = "${android.defaultConfig.versionName}"
def flavor = getFlavor(name)
def type = getBuildType(name)
if(flavor == null || type == null) return
def outputName
if (flavor == "full")
outputName = "DontEat-$version"
else
outputName = "DontEat-$version-$flavor"
tasks.register(renameTaskName) {
def path = "${rootDir}/app/${flavor}/${type}/"
def originalFile = "$path/app-${flavor}-${type}.aab"
doLast {
if (file("$originalFile").exists()) {
ant.move file: "$originalFile",
tofile: "$path/${outputName}.aab"
}
}
}
task.finalizedBy(renameTaskName)
}
}
型
proguard-rules.pro:
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-dontwarn org.joda.convert.**
-dontwarn org.joda.time.**
-keep class org.joda.time.** { *; }
-keep interface org.joda.time.** { *;}
# Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
# EnclosingMethod is required to use InnerClasses.
-keepattributes Signature, InnerClasses, EnclosingMethod
# Retrofit does reflection on method and parameter annotations.
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
# Keep annotation default values (e.g., retrofit2.http.Field.encoded).
-keepattributes AnnotationDefault
# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
@retrofit2.http.* <methods>;
}
# Ignore annotation used for build tooling.
#-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
# Ignore JSR 305 annotations for embedding nullability information.
-dontwarn javax.annotation.**
# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
-dontwarn kotlin.Unit
# Top-level functions that can only be used by Kotlin.
-dontwarn retrofit2.KotlinExtensions
-dontwarn retrofit2.KotlinExtensions$*
# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
# and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>
# Keep inherited services.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface * extends <1>
# With R8 full mode generic signatures are stripped for classes that are not
# kept. Suspend functions are wrapped in continuations where the type argument
# is used.
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
# R8 full mode strips generic signatures from return types if not kept.
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>
# With R8 full mode generic signatures are stripped for classes that are not kept.
-keep,allowobfuscation,allowshrinking class retrofit2.Response
# JSR 305 annotations are for embedding nullability information.
-dontwarn javax.annotation.**
# A resource is loaded with a relative path so the package of this class must be preserved.
-adaptresourcefilenames okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz
# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
-dontwarn org.codehaus.mojo.animal_sniffer.*
# OkHttp platform used only on JVM and when Conscrypt and other security providers are available.
-dontwarn okhttp3.internal.platform.**
-dontwarn org.conscrypt.**
-dontwarn org.bouncycastle.**
-dontwarn org.openjsse.**
型
编辑:
感谢@sgjesse(*)的宝贵帮助,我终于能够找到更多关于错误的信息:
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.String java.lang.CharSequence.toString()' on a null object reference
at java.text.Normalizer.normalize(Normalizer.java:167)
型
现在已经更正了,但我在R8上运行应用程序时仍然有问题。我试图理解并纠正它们,但这在这个问题中偏离了主题。
(*)将-dontobfuscate
添加到prodguard-rules.pro,将应用程序下载到我的智能手机,将智能手机连接到android-studio以查看logcat
1条答案
按热度按时间iqxoj9l91#
如果你打算使用minifyEnabled和shrinkResources,你应该事先计划好。这两个工具的作用是,它们试图通过某种算法压缩你的apk大小,从而以某种方式压缩你的模型类和其他属性。当这些模型类被压缩时,你的应用会出现错误,你会在这里或那里得到异常。
有一些标志应该与你的模型类一起使用,这可以防止它们被压缩。我不知道它们的确切位置,但你可以搜索它们。