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.