Apache Commons Compress 无法在 Android N 之前解析 Class SeekableInMemoryByteChannel
Apache Commons Compress Cannot Resolve Class SeekableInMemoryByteChannel Prior to Android N
每当我尝试使用 Apache commons-compress 包中的 SeekableInMemoryByteChannel
class 时,应用程序都会崩溃并出现 java.lang.NoClassDefFoundError: org.apache.commons.compress.utils.SeekableInMemoryByteChannel
异常。
这个特别有趣的部分,至少对我来说,是这个问题不会出现在设备 运行 Android 7+ 上,但会出现在我测试过的所有其他版本上。更具体地说,我观察到此问题发生在 Android 6.0.1、6.0、5.1.1 上,但 不会发生 Android 7.0 或 7.1 上。 1.这些设备中的每一个都来自不同的供应商。
所以我面临着严重的鬼案class。起初我认为这可能与我的应用程序使用 MultiDex 或构建过程配置不正确有关。但同样的情况也会发生在一个没有这些功能的全新项目上。我尝试使用同一个包中的不同 classes 并且它们被成功解析。我将包添加到 ProGuard,但没有成功。
这是重现问题的代码:
package lt.kaz.compresstest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ZipArchiveEntry zipEntry = new ZipArchiveEntry("hello");
zipEntry.setSize(600);
SevenZArchiveEntry sevenZipEntry = new SevenZArchiveEntry();
sevenZipEntry.setName("sevenZip");
try {
MainActivity.class.getClassLoader().loadClass("org.apache.commons.compress.utils.ChecksumCalculatingInputStream");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
SeekableInMemoryByteChannel channel = new SeekableInMemoryByteChannel(new byte[]{5, 10, 15, 10});
// App never gets here prior to Android N
Log.d("lt.kaz", channel.toString());
}
}
...和 gradle 文件 ...
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
defaultConfig {
applicationId 'lt.kaz.compresstest'
minSdkVersion 19
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:26.+'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.android.support:design:26.+'
compile 'org.apache.commons:commons-compress:1.14'
testCompile 'junit:junit:4.12'
}
...和混淆器...
-keep public class org.apache.commons.compress
任何帮助将不胜感激。这种行为的原因可能是什么?如何解决?
显然,java.nio.channels
包的 SeekableByteChannel
接口是 only available 来自 Android API 级别 24(因此 android N) .
我的最终解决方案,因为我的初衷是使用 SevenZFile
class,是将 commons-compress 降级到 1.12 版,因为那里的实现不使用 SeekableByteChannel
class.
每当我尝试使用 Apache commons-compress 包中的 SeekableInMemoryByteChannel
class 时,应用程序都会崩溃并出现 java.lang.NoClassDefFoundError: org.apache.commons.compress.utils.SeekableInMemoryByteChannel
异常。
这个特别有趣的部分,至少对我来说,是这个问题不会出现在设备 运行 Android 7+ 上,但会出现在我测试过的所有其他版本上。更具体地说,我观察到此问题发生在 Android 6.0.1、6.0、5.1.1 上,但 不会发生 Android 7.0 或 7.1 上。 1.这些设备中的每一个都来自不同的供应商。
所以我面临着严重的鬼案class。起初我认为这可能与我的应用程序使用 MultiDex 或构建过程配置不正确有关。但同样的情况也会发生在一个没有这些功能的全新项目上。我尝试使用同一个包中的不同 classes 并且它们被成功解析。我将包添加到 ProGuard,但没有成功。
这是重现问题的代码:
package lt.kaz.compresstest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ZipArchiveEntry zipEntry = new ZipArchiveEntry("hello");
zipEntry.setSize(600);
SevenZArchiveEntry sevenZipEntry = new SevenZArchiveEntry();
sevenZipEntry.setName("sevenZip");
try {
MainActivity.class.getClassLoader().loadClass("org.apache.commons.compress.utils.ChecksumCalculatingInputStream");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
SeekableInMemoryByteChannel channel = new SeekableInMemoryByteChannel(new byte[]{5, 10, 15, 10});
// App never gets here prior to Android N
Log.d("lt.kaz", channel.toString());
}
}
...和 gradle 文件 ...
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
defaultConfig {
applicationId 'lt.kaz.compresstest'
minSdkVersion 19
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:26.+'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.android.support:design:26.+'
compile 'org.apache.commons:commons-compress:1.14'
testCompile 'junit:junit:4.12'
}
...和混淆器...
-keep public class org.apache.commons.compress
任何帮助将不胜感激。这种行为的原因可能是什么?如何解决?
显然,java.nio.channels
包的 SeekableByteChannel
接口是 only available 来自 Android API 级别 24(因此 android N) .
我的最终解决方案,因为我的初衷是使用 SevenZFile
class,是将 commons-compress 降级到 1.12 版,因为那里的实现不使用 SeekableByteChannel
class.