繁体   English   中英

Gradle Android Build System NDK问题

[英]Gradle Android Build System NDK issues

我会第一个承认我对Gradle和新的Android构建系统并不是非常专业,但不幸的是,由于问题21479( https://code.google ),我不得不转移到它(来自ant) .com / p / android / issues / detail?id = 21479 )和评论“这将不会被修复。我们正专注于完成将取代Ant的基于Gradle的构建系统。” 不幸的是,在我添加了Millenium Media广告库之后,我无法重新构建这些东西。 这是Android OpenCV库,Chilkat的加密库和支持v4库的补充,但MMedia库是破坏它的一个。

所以,我认为,这是一个很好的理由,可以迁移到新的基于Gradle的构建系统。 不幸的是,尽管留下了破坏的蚂蚁构建系统,新系统似乎还没有完成; 特别是ndk的支持。

我正在使用的应用程序使用OpenCV进行一些图像处理,并且一些操作运行得太慢,除非它们被编译为本机(很多内存移动并比较在JNI边界上太慢)。 因此,我不是试图在VM和本机代码之间来回传递数据,而是将所有这些内容留在本机端,只需从VM调用一次即可获得结果。

第一个问题是编译ndk的东西。 我无法使ndk闭包中的设置工作,所以我不得不求助于使用ndk-build命令并将其作为任务执行:

task ndkBuild(type: Exec) {
    String MainDirectory = System.getProperty("user.dir") + '/app/src/main'
    println "Main app directory for NDK build " + MainDirectory
    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
       commandLine 'gradle-ndk-build.cmd', MainDirectory, '-j'
    }
    else {
       commandLine 'gradle-ndk-build', MainDirectory, '-j'
    }
}

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

这很完美; 它编译ndk代码并生成.so库而不会出错。 不幸的是,它不会将最终的.so文件放在最终的包中。 它把所有其他本地库都放在了,但不是这个 - 不知道为什么。

我发现了许多针对此问题的修复程序,例如:

tasks.withType(com.android.build.gradle.tasks.PackageApplication) { pkgTask ->
    pkgTask.jniFolders = new HashSet<File>()
    pkgTask.jniFolders.add(new File(buildDir, 'native-libs'))
}

但是添加它只会产生一个apk文件,根本没有本机库。 我见过其他人有同样的问题(比如https://groups.google.com/forum/#!msg/adt-dev/QbDHM41QT2E/J4jHCC_RuIEJ )但是我已经尝试了所有提出的解决方案,但没有一个为我工作。

因为我不经常更改本机代码,所以我刚刚做了一个hack,将生成的本机库(libndklib.so)从app / src / main / libs复制到/ app / src / main / jni之后编制; 然后它最终在apk包中。 显然,这有点令人讨厌,如果有人接受这个代码,他们会想知道为什么他们对本机代码的更改永远不会出现在应用程序中。

所以,我的问题是:在我运行ndk命令(gradle-ndk-build)之后,我可以在gradle脚本中运行一些东西,它将从app / src / main /复制生成的文件libs / armeabi / libndklib.so到/app/src/main/jni/armeabi/libndklib.so(对于每个架构 - armeabi,armeabi-v7,x86,mips)所以它最终在apk包中?

要么

有没有办法让Gradle ndk闭包正确处理以下ndk make文件: Application.mk

APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := all
APP_PLATFORM := android-8

Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# OpenCV
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
OPENCV_LIB_TYPE:=SHARED
include /home/myname/tools/OpenCV-2.4.8-android-sdk/sdk/native/jni/OpenCV.mk
LOCAL_MODULE    := ndklib
LOCAL_SRC_FILES := ndklib.cpp motion.cpp
LOCAL_LDLIBS +=  -lm -llog
include $(BUILD_SHARED_LIBRARY)
# Add prebuilt chilkat library
include $(CLEAR_VARS)
LOCAL_MODULE := lib-chilkat
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libchilkatemail.so
include $(PREBUILT_SHARED_LIBRARY)

我查看了插件的Gradle源代码,但我看不到支持的许多指令。

要么

我可以添加一些在Gradle脚本结束时运行的hack,它只会强制libndklib.so(对于正确的架构)的适当副本进入生成的apk吗? 我可以使用后者,直到完成了用于gradle构建的Android插件的ndk内容。

=======================================

编辑 - 在ph0b的回答之后这是最终的build.gradle文件,其中包含建议的mod。 创建.apk的完美build.gradle (在app目录中)

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.9.+'
    }
}

apply plugin: 'android'

import org.apache.tools.ant.taskdefs.condition.Os

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.3"

    signingConfigs {
        debug {
            storeFile file("dbgkeystore")
            storePassword "nopass"
            keyAlias "mainkeyname"
            keyPassword "nopass"
        }

        release {
            storeFile file("keystore")
            storePassword "xxxxxxxx"
            keyAlias "mainkeyname"
            keyPassword "yyyyyyyy"
        }
    }

    // Autoincrement the version properties file
    // ******************************************
    def versionPropsFile = file('version.properties')
    def code = 1

    def majorversion = 1
    def minorversion = 1

    defaultConfig {
        versionCode code
        versionName "${majorversion}.${minorversion}.${code}"
        minSdkVersion 10
        targetSdkVersion 19
    }

    buildTypes {
        release {
            runProguard true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
            signingConfig signingConfigs.release
        }

        debug {
           runProguard false
           proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
           packageNameSuffix ".debug"
           versionNameSuffix "-debug"
           signingConfig signingConfigs.debug
        }
    }

    sourceSets {
        main {
            jni.srcDirs = []
            // jniLibs.srcDir 'src/main/jni' // - Doesn't work, leaves out the .so files generated by ndk-build
            jniLibs.srcDir 'src/main/libs'
        }
    }

    flavorDimensions "version", "abi"

    productFlavors {
        pro {
            flavorDimension "version"
            packageName "org.somedomainname.myAppPro1"
        }

        lite {
            flavorDimension "version"
            packageName "org.somedomainname.myAppLite1"
        }

        arm {
            flavorDimension "abi"

            ndk {
                abiFilter "armeabi"
            }

            if (versionPropsFile.canRead()){
                def Properties versionProps = new Properties()

                versionProps.load(new FileInputStream(versionPropsFile))

                code = versionProps['VERSION_CODE'].toInteger() + 1

                versionProps['VERSION_CODE']=code.toString()
                versionProps.store(versionPropsFile.newWriter(), null)

                versionCode code
                versionName "${majorversion}.${minorversion}.${code}"
            }
            else {
                throw new GradleException("Could not read version.properties!")
            }

        }

        armv7 {
            flavorDimension "abi"

            ndk {
                abiFilter "armeabi-v7a"
            }

            if (versionPropsFile.canRead()){
                def Properties versionProps = new Properties()

                versionProps.load(new FileInputStream(versionPropsFile))

                code = versionProps['VERSION_CODE'].toInteger() + 1

                versionProps['VERSION_CODE']=code.toString()
                versionProps.store(versionPropsFile.newWriter(), null)

                versionCode code
                versionName "${majorversion}.${minorversion}.${code}"
            }
            else {
                throw new GradleException("Could not read version.properties!")
            }
        }

        x86 {
            flavorDimension "abi"

            ndk {
                abiFilter "x86"
            }

            if (versionPropsFile.canRead()){
                def Properties versionProps = new Properties()

                versionProps.load(new FileInputStream(versionPropsFile))

                code = versionProps['VERSION_CODE'].toInteger() + 1

                versionProps['VERSION_CODE']=code.toString()
                versionProps.store(versionPropsFile.newWriter(), null)

                versionCode code
                versionName "${majorversion}.${minorversion}.${code}"
            }
            else {
                throw new GradleException("Could not read version.properties!")
            }
        }
    }

    lintOptions {
        checkReleaseBuilds false
        // Or, if you prefer, you can continue to check for errors in release builds,
        // but continue the build even when errors are found:
        abortOnError false
    }

repositories {
    mavenCentral()
    flatDir {
        dirs '/home/myname/maindrive/work/dynamic/android/UtilLib/aarlib'
    }
}

dependencies {
    compile 'com.android.support:appcompat-v7:+'
    compile fileTree(dir: 'libs', include: ['*.jar'])

    // Note: org.somedomainname.UtilLib on the depency below is ignored when usng flatdir
    compile 'org.somedomainname.UtilLib:library:1.0.0@aar'
}

task ndkBuild(type: Exec) {
    String MainDirectory = System.getProperty("user.dir") + '/app/src/main'
    println '************************************************************************'
    println "Main app directory for NDK build " + MainDirectory
    println '************************************************************************'

    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
       commandLine 'gradle-ndk-build.cmd', MainDirectory, '-j'
    }
    else {
       commandLine 'gradle-ndk-build', MainDirectory, '-j'
    }
}

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


android.applicationVariants.all { variant ->
    variant.assemble.doLast {
           rename_and_moveout_apk(variant)
    }
}

// allprojects {
//     tasks.withType(Compile) {
//         options.compilerArgs << "-Xlint:deprecation"
//     }
// }

def rename_and_moveout_apk(targetVariant) {
    // replace output apk name to <product>-<version>-<buildtype>-<githash>.apk
    def versionSuffix = targetVariant.buildType.versionNameSuffix ? targetVariant.buildType.versionNameSuffix : ""
    def versionName = targetVariant.mergedFlavor.versionName + versionSuffix;

    if (targetVariant.zipAlign) {
        def apkFinal = targetVariant.outputFile;
        def apkFinalNewName = "myApp-" + apkFinal.name.replace(targetVariant.buildType.name, versionName);
        copy {
            from "$apkFinal"
            into "$rootProject.projectDir/apk_release"
            rename ("$apkFinal.name", "$apkFinalNewName")
            println "*************** Renaming zipalign apk file from: ${apkFinal.name} to ${apkFinalNewName}"
        }
    }

}

gradle-ndk-build(用于调试参数的ndk-build的修改版本)

#!/bin/bash
export NDK_PROJECT_PATH=$1
export NDK_PROJECT_DIRECTORY=$1
bash -c "ndk-build"

目录结构

------ apk_release
------ app
-- -- ---- src
--     ------ lite
--     --  -- ---- java
--     --      -- ---- org
--     --          -- ---- somedomainname
--     --              -- ---- myApp
--     ------ main
--     --  ------ assets
--     --  ------ java
--     --  --  -- ---- org
--     --  --      ------ chilkatsoft
--     --  --      -- ---- somedomainname
--     --  --          -- ---- myApp
--     --  ------ jni
--     --  --  ------ armeabi
--     --  --  ------ armeabi-v7a
--     --  --  ------ mips
--     --  --  -- ---- x86
--     --  ------ libs
--     --  --  ------ armeabi
--     --  --  ------ armeabi-v7a
--     --  --  ------ mips
--     --  --  -- ---- x86
--     --  ------ obj
--     --  --  -- ---- local
--     --  --      ------ armeabi
--     --  --      --  -- ---- objs
--     --  --      --      -- ---- ndklib
--     --  --      ------ armeabi-v7a
--     --  --      --  -- ---- objs
--     --  --      --      -- ---- ndklib
--     --  --      ------ mips
--     --  --      --  -- ---- objs
--     --  --      --      -- ---- ndklib
--     --  --      -- ---- x86
--     --  --          -- ---- objs
--     --  --              -- ---- ndklib
--     --  -- ---- res
--     --      ------ drawable
--     --      ------ drawable-hdpi
--     --      ------ drawable-ldpi
--     --      ------ drawable-mdpi
--     --      ------ drawable-xhdpi
--     --      ------ drawable-xxhdpi
--     --      ------ layout
--     --      ------ raw
--     --      ------ values
--     --      -- ---- xml
--     -- ---- pro
--         -- ---- java
--             -- ---- somedomainname
--                 -- ---- myApp

gradle将自动在jniLibs/ABI/查找.so文件。

您可以通过在build.gradle文件中设置它来更改此行为以使其使用常规libs目录:

android {
    sourceSets.main {
        jniLibs.srcDir 'src/main/libs'
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM