簡體   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