How to reduce the apk size of Android app which need openCv lib( only for Image processing)
You can not remove the library libopencv_java3.so
, it's mandatory.
Is there any way by which I can reduce my apk size?
Without modify the library libopencv_java3.so
, you can build multiple apks for different architectures rather than package a flat APK. Only one arch of libopencv_java3.so
will be packaged into your split APK. For example, you can use the configuration below to build only for x86
, armeabi-v7a
and mips
architectures in your build.gradle
splits {
abi {
enable true
reset()
include "x86", "armeabi-v7a", "mips"
universalApk false
}
}
More information about reduce apk size by splitting, see here.
Or is it possible just to extract only the feature from OpenCV which I am interested in and create .so for those features?
Yes, of course. The building process for opencv
is fully customized. If you have already know how to build opencv for Android, go to step 2 directly.
step 1
- get the source of opencv
- create directory
opencv_build
- change to root directory of
opencv
you just cloned - invoke the build script
platforms/android/build_sdk.py --ndk_path $ANDROID_NDK_ROOT --sdk_path $ANDROID_SDK_ROOT ../opencv_build .
Note
The build procedure need android
command to build apk, so the Android SDK tool version must less than 25.3.0
, from 25.3.0
, android
command has been removed.
step 2
Assume the step 1 above run properly. Here I take armeabi-v7a
as an example.
- Go to directory
opencv_build/o4a/lib/armeabi-v7a
- You will find many *.a for different opencv module, the library
libopencv_java3.so
also in this directory Create a tiny version share library from the module you need, e.g
$ 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
The tiny version which include core
, image codecs
and image proc
has a size 4.1M
after strip, but the full version libopencv_java3.so
has a size of 9.8M
.
I use libopencv_tiny.so
as the name just for convenience, you have to use the same name libopencv_java3.so
in your project. Otherwise System.loadLibrary
in Java can not find the native library.
For the rest of the architecture you need, e.g arm64-v8a
, do the same.
For me, alijandro answer 2nd answer was the best solution but I got stuck in the process. So, I solved the issue by apk split. You need to upload apk's related to the platform and also a universal apk.It would be ideal , since OpenCV doesn't provide adding dependency at module level.
Universal apk will be downloaded in case platform does not match.Here is nicely written blog about apk publishing mutiple apk. You need to maintain same app id , Keystore, same app version but different code version
Step 1.Add gradle code for spk split. Include the architecture for which you want to create separate apk.
android{
//......
splits {
abi {
enable true
reset()
include "armeabi","armeabi-v7a",'arm64-v8a',"mips","x86","x86_64",'arm64-v8a'
universalApk true
}
}
}
Step 2.Add below code for different Code version for different platform.
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
}
}
For Example, if the initial version code was 1, then generated codes will be:
armeabi -> 3001
armeabi-v7a -> 4001
arm64-v8a -> 5001
mips -> 6001
x86 -> 7001
x86_64 -> 8001
All together your Gradle code will look like this.
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
}
}
Now you need to publish all the apk on playstore one by one.
Note: While publishing make sure you retain all the platform and universal apk.