如何减少 Android 需要 openCv lib 的应用程序的 apk 大小(仅用于图像处理)

How to reduce the apk size of Android app which need openCv lib( only for Image processing)

我正在使用 min SDK 15 构建一个 Android 应用程序,它使用 OpenCV library.The 问题是当我构建它的 apk 大小超过 60 MB不是很大。

我检查了应用程序文件,我可以看到由于 libopencv_java3.so 文件在所有体系结构中太大,例如 amr64armeabimipsx86 等等

我只对图像使用 opneCv processing.This 库有很多其他功能,如视频处理、3d 图像、对象检测等等,我的应用程序不需要这些功能,比如

如果我删除所有这些文件并构建 APK,那么大小将减少 50 MB,但要使此应用正常运行,我需要安装 OpenCVManager 到 运行 我的应用。

有什么方法可以减小我的 apk 大小吗?

或者是否可以仅从 OpenCV 中提取我感兴趣的特征并为这些特征创建 .so

您不能删除库 libopencv_java3.so,它是必需的。

Is there any way by which I can reduce my apk size?

无需修改库 libopencv_java3.so,您可以为不同的架构构建多个 apk,而不是打包一个平面 APK。只有 libopencv_java3.so 的一个拱门将被打包到您的拆分 APK 中。例如,您可以使用下面的配置只为 x86armeabi-v7amips 架构构建 build.gradle

splits {
    abi {
      enable true
      reset()
      include "x86", "armeabi-v7a", "mips"
      universalApk false
    }
  }

有关通过拆分减小 apk 大小的更多信息,请参阅 here

Or is it possible just to extract only the feature from OpenCV which I am interested in and create .so for those features?

当然可以。 opencv 的构建过程是完全自定义的。如果您已经知道如何为 Android 构建 opencv,请直接转到 步骤 2

步骤 1

  1. 获取 opencv
  2. 的来源
  3. 创建目录opencv_build
  4. 更改为您刚刚克隆的 opencv 的根目录
  5. 调用构建脚本platforms/android/build_sdk.py --ndk_path $ANDROID_NDK_ROOT --sdk_path $ANDROID_SDK_ROOT ../opencv_build .

备注

构建过程需要android命令来构建apk,所以AndroidSDK工具版本必须小于25.3.0,来自25.3.0android命令已被删除。

第 2 步

假设 运行 上面的 步骤 1 正确。这里我以armeabi-v7a为例。

  1. 转到目录opencv_build/o4a/lib/armeabi-v7a
  2. 你会发现许多*.a 用于不同的 opencv 模块,库 libopencv_java3.so 也在这个目录中
  3. 从您需要的模块创建一个小型版本共享库,例如

    $ arm-linux-androideabi-gcc -shared -o libopencv_tiny.so --sysroot=$ANDROID_NDK_ROOT/platforms/android-9/arch-arm -Wl,--whole-archive libopencv_core.a libopencv_imgcodecs.a libopencv_imgproc.a -Wl,--no-whole-archive
    $ du -h libopencv_tiny.so 
    5.2M    libopencv_tiny.so
    $ arm-linux-androideabi-strip --strip-unneeded libopencv_tiny.so 
    $ du -h libopencv_tiny.so 
    4.1M    libopencv_tiny.so
    $ du -h libopencv_java3.so 
    9.8M    libopencv_java3.so
    

包含 coreimage codecsimage proc 的微型版本在剥离后的大小为 4.1M,但完整版本 libopencv_java3.so 的大小为9.8M.

我使用libopencv_tiny.so作为名称只是为了方便,您必须在您的项目中使用相同的名称libopencv_java3.so。否则Java中System.loadLibrary找不到原生库

对于您需要的其余架构,例如 arm64-v8a,执行相同的操作。

对我来说, 第二个答案是最好的解决方案,但我陷入了这个过程。所以,我通过apk split解决了这个问题。您需要上传与平台相关的 apk,并且通用 apk.It 将是理想的,因为 OpenCV 不提供在模块级别添加依赖项。

如果平台不匹配,将下载通用apk。Here 写得很好关于apk 发布多个apk 的博客。您需要维护相同的应用程序 ID、密钥库、相同的应用程序版本但不同的代码版本

步骤 1。为 spk 拆分添加 gradle 代码。包括您要为其创建单独的 apk 的体系结构。

android{
//......
splits {
    abi {
        enable true
        reset()
        include "armeabi","armeabi-v7a",'arm64-v8a',"mips","x86","x86_64",'arm64-v8a'
        universalApk true
    }
}
}

步骤 2。为不同平台的不同代码版本添加以下代码。

android{
//......
}
ext.versionCodes = ['armeabi': 3, 'armeabi-v7a': 4, 'arm64-v8a': 5, 
mips: 6, 'x86': 7, 'x86_64': 8]
import com.android.build.OutputFile
// For each APK output variant, override versionCode with a combination 
// of ABI APK value * 1000 + defaultConfig.versionCode
android.applicationVariants.all { variant ->
// assign different version code for each output
variant.outputs.each { output ->
    def abiFilter = output.getFilter(OutputFile.ABI)
    def abiMultiplier = 0
    if (abiFilter != null) {
        abiMultiplier = project.ext.versionCodes.get(abiFilter)
    }
    output.versionCodeOverride =
            abiMultiplier * 1000 + android.defaultConfig.versionCode
   }
  }

例如,如果初始版本代码为 1,则生成的代码将为:

 armeabi -> 3001
 armeabi-v7a -> 4001
 arm64-v8a -> 5001
 mips -> 6001
 x86 -> 7001
 x86_64 -> 8001

你的 Gradle 代码看起来像这样。

 android{
//......
splits {
abi {
    enable true
    reset()
    include "armeabi","armeabi-v7a",'arm64-
v8a',"mips","x86","x86_64",'arm64-v8a'
    universalApk true
 }
 }

 ext.versionCodes = ['armeabi': 3, 'armeabi-v7a': 4, 'arm64-v8a': 5, 
mips: 6, 'x86': 7, 'x86_64': 8]
import com.android.build.OutputFile
android.applicationVariants.all { variant ->
variant.outputs.each { output ->
def abiFilter = output.getFilter(OutputFile.ABI)
def abiMultiplier = 0
if (abiFilter != null) {
    abiMultiplier = project.ext.versionCodes.get(abiFilter)
}
output.versionCodeOverride =
        abiMultiplier * 1000 + android.defaultConfig.versionCode
}
}

现在您需要将所有apk 一个一个地发布到playstore 上。

注意:发布时请确保保留所有平台和通用 apk。