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

Sha*_*yaz 17 java-native-interface android opencv native image-processing

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

我检查了应用程序文件,我可以看到的是,规模过大,由于libopencv_java3.so在像所有架构文件amr64,armeabi,mips,x86等.

在此输入图像描述

我只使用opneCv进行图像处理.这个库还有许多其他功能,如视频处理,3D图像,对象检测等等,我不需要在我的应用程序中使用

如果我删除所有这些文件并构建APK,那么大小将减少50 MB,但为了使这个应用程序工作,我需要安装OpenCVManager来运行我的应用程序.

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

或者只是提取OpenCV我感兴趣的功能并.so为这些功能创建?

ali*_*dro 9

您无法删除库libopencv_java3.so,这是必需的.

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

在不修改库的情况下libopencv_java3.so,您可以为不同的体系结构构建多个apks,而不是打包平面APK.只有一个拱门libopencv_java3.so将打包到您的拆分APK.例如,你可以使用下面的配置打造只为x86,armeabi-v7amips架构在build.gradle

splits {
    abi {
      enable true
      reset()
      include "x86", "armeabi-v7a", "mips"
      universalApk false
    }
  }
Run Code Online (Sandbox Code Playgroud)

有关通过拆分减少apk大小的更多信息,请参见此处.

或者只是从OpenCV中提取我感兴趣的功能并为这些功能创建.so?

当然是.建设过程opencv完全定制.如果您已经知道如何为Android构建opencv,请直接转到步骤2.

步骤1

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

注意

构建过程需要android命令来构建apk,因此Android SDK工具版本必须少于25.3.0,from 25.3.0,android命令已被删除.

第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
    
    Run Code Online (Sandbox Code Playgroud)

这个小版本包括core,image codecs并且image proc带有一个大小的4.1M条带,但完整版libopencv_java3.so的大小为9.8M.

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

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


Sha*_*yaz 8

对我来说,alijandro回答第二个答案是最好的解决方案,但我陷入了困境.所以,我通过apk拆分解决了这个问题.您需要上传与平台相关的apk以及通用apk.It将是理想的,因为OpenCV不提供模块级别的添加依赖性.

如果平台不匹配,将下载Universal apk.这里有关于apk publishing mutiple 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
    }
}
}
Run Code Online (Sandbox Code Playgroud)

步骤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
   }
  }
Run Code Online (Sandbox Code Playgroud)

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

 armeabi -> 3001
 armeabi-v7a -> 4001
 arm64-v8a -> 5001
 mips -> 6001
 x86 -> 7001
 x86_64 -> 8001
Run Code Online (Sandbox Code Playgroud)

你的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
}
}
Run Code Online (Sandbox Code Playgroud)

现在你需要逐个在playstore上发布所有apk.

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