如何使用Android NDK和Gradle构建单个APK

4

我正在开发一款新的Android应用程序,使用OpenCV(使用C++而不是Java),我对opencv和NDK都很陌生。我已经使用下面的Gradle文件构建(并运行)成功,并且在Android Studio中我可以选择一个变体并进行构建(例如x86)。

我的问题有两个:

  1. Is there a way I can have a variant that builds an APK supporting all architectures? (I know file size will be bigger)
  2. Can i achieve a build without specifying all the same libs for each variant. Is there any way I can make the build system just pick up the libraries each time since they are all inside the project and organised by architecture name?

    apply plugin: 'com.android.application'
    
    android {
    compileSdkVersion 21
    buildToolsVersion "21.0.0"
    
    defaultConfig {
        applicationId "uk.co.xxx.androidcppimagereader"
        minSdkVersion 17
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }
    
    def libsDir = projectDir.path + "/libs/"
    
    productFlavors {
        x86 {
            versionCode Integer.parseInt("3" + defaultConfig.versionCode)
            ndk {
                abiFilter "x86"
                moduleName "Processing"
                stl "gnustl_static"
                cFlags "-I/opt/local/include/opencv -I/opt/local/include"
                ldLibs libsDir + "x86/libopencv_core.a"
                ldLibs libsDir + "x86/libopencv_ts.a"
                ldLibs libsDir + "x86/libopencv_contrib.a"
                ldLibs libsDir + "x86/libopencv_ml.a"
                ldLibs libsDir + "x86/libopencv_java.so"
                ldLibs "log"
                ldLibs "z", "jnigraphics"
            }
        }
        armv7 {
            versionCode Integer.parseInt("2" + defaultConfig.versionCode)
            ndk {
                abiFilter "armeabi-v7a"
                moduleName "Processing"
                stl "gnustl_static"
                cFlags "-I/opt/local/include/opencv -I/opt/local/include"
                ldLibs libsDir + "armeabi-v7a/libopencv_core.a"
                ldLibs libsDir + "armeabi-v7a/libopencv_ts.a"
                ldLibs libsDir + "armeabi-v7a/libopencv_contrib.a"
                ldLibs libsDir + "armeabi-v7a/libopencv_ml.a"
                ldLibs libsDir + "armeabi-v7a/libopencv_java.so"
                ldLibs "log"
                ldLibs "z", "jnigraphics"
            }
        }
        arm {
            versionCode Integer.parseInt("1" + defaultConfig.versionCode)
            ndk {
                abiFilter "armeabi"
                moduleName "Processing"
                stl "gnustl_static"
                cFlags "-I/opt/local/include/opencv -I/opt/local/include"
                ldLibs libsDir + "armeabi/libopencv_core.a"
                ldLibs libsDir + "armeabi/libopencv_ts.a"
                ldLibs libsDir + "armeabi/libopencv_contrib.a"
                ldLibs libsDir + "armeabi/libopencv_ml.a"
                ldLibs libsDir + "armeabi/libopencv_java.so"
                ldLibs "log"
                ldLibs "z",  "jnigraphics"
            }
        }
    
    }
    
        buildTypes {
             release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        compile 'com.android.support:appcompat-v7:21.0.3'
    }
    
2个回答

3
在build.gradle文件中定义所有你计划在你的apk中包含的架构之后,使用关键字“fat”。这将构建一个FAT二进制文件。观看此视频以获取更多细节:https://www.youtube.com/watch?v=kFtxo7rr2HQ
arm {
    versionCode Integer.parseInt("1" + defaultConfig.versionCode)
    ndk {
        abiFilter "armeabi"
        moduleName "Processing"
        stl "gnustl_static"
        cFlags "-I/opt/local/include/opencv -I/opt/local/include"
        ldLibs libsDir + "armeabi/libopencv_core.a"
        ldLibs libsDir + "armeabi/libopencv_ts.a"
        ldLibs libsDir + "armeabi/libopencv_contrib.a"
        ldLibs libsDir + "armeabi/libopencv_ml.a"
        ldLibs libsDir + "armeabi/libopencv_java.so"
        ldLibs "log"
        ldLibs "z",  "jnigraphics"
    }
    fat // <- HERE
}

buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

好的,谢谢你的帮助。我之前尝试过使用“fat”但没有成功,现在我进行了一次清理和重建,它已经出现在我的构建变体中了。关于拆分,如何在更新gradle文件后使其构建所有拆分?我之前没有看到这个选项?它应该出现在“universal”或类似的变体列表下吗? - user2022581

1
为了正确链接库,您需要根据不同的架构声明不同的ldLibs,就像您目前正在做的那样。
不幸的是,如果您同时为所有架构构建,则无法使用当前插件从gradle中执行此操作。
在我看来,最好的解决方案是停用内置(目前已弃用)的ndk支持,改用常规的Android.mk / Application.mk文件。您的build.gradle将如下所示:
import org.apache.tools.ant.taskdefs.condition.Os

apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "21.1"

    defaultConfig {
        applicationId "uk.co.xxx.androidcppimagereader"
        minSdkVersion 17
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }

    sourceSets.main {
        jniLibs.srcDir 'src/main/libs' //set libs as default directory for .so files inclusion, instead of jniLibs
        jni.srcDirs = [] //disable automatic ndk-build call
    }

    // call regular ndk-build(.cmd) script from app directory
    task ndkBuild(type: Exec) {
        if (Os.isFamily(Os.FAMILY_WINDOWS)) {
            commandLine 'ndk-build.cmd', '-C', file('src/main').absolutePath
        } else {
            commandLine 'ndk-build', '-C', file('src/main').absolutePath
        }
    }

    tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn ndkBuild
    }
}

谢谢。所以...如果我使用makefile,那么它应该构建所有架构,然后将输出库复制到src/main/libs中吗?我是NDK开发的新手,对Android.mk的输出结构稍有不清楚。 - user2022581
没错。看看NDK内部的示例,了解如何编写Android.mk和Application.mk文件。 - ph0b

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接