2014-04-08 126 views
13

我會第一個承認我不擅長Gradle和新的Android構建系統,但不幸的是,由於問題,我不得不移動到它(從螞蟻) 21479(https://code.google.com/p/android/issues/detail?id=21479)和評論「這不會被修復,我們正在關注完成基於Gradle的構建系統,它將取代Ant。」不幸的是,我在添加Millenium Media廣告庫後無法再次構建這些東西。除了Android OpenCV庫,Chilkat的加密庫和支持v4庫之外,還有一個可以打破這一切的MMedia庫。Gradle Android構建系統NDK問題

所以,我認爲,很好的理由遷移到新的基於Gradle的構建系統。不幸的是,儘管留下了一個破損的螞蟻構建系統,但新系統似乎尚未完成;特別是ndk的支持。

我正在使用的應用程序使用OpenCV進行一些圖像處理,並且一些操作的運行速度太慢,除非它們被編譯爲本機(LOTS的內存移動並比較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),但我已經嘗試了所有建議的解決方案,但他們都不適合我。因爲我不經常更改本機代碼,所以我剛剛做了一個破解,將生成的本機庫(libndklib.so)從app/src/main/libs複製到/ app/src/main/jni編譯完成後;然後它在apk包中結束。顯然,這有點令人討厭,因爲如果有人將此代碼結束,他們會想知道爲什麼他們對本機代碼的更改永遠不會出現在應用程序中。

所以,我的問題是: 有沒有什麼我可以在我運行ndk命令(gradle-ndk-build)之後執行的gradle腳本中運行,它將從應用程序中複製生成的文件/src/main/libs/armeabi/libndklib.so複製到/app/src/main/jni/armeabi/libndklib.so(對於每個體系結構 - armeabi,armeabi-v7,x86,mips),所以它最終在apk包嗎?

OR

有沒有什麼辦法讓搖籃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) 

我看着搖籃源的插件,但我不能看到很多這些指令支持。

OR

我可以只添加某種黑客運行在搖籃腳本,只是迫使libndklib.so適當副本結束(正確的架構)到生成APK?我可以與後者一起生活,直到ndk的東西完成了Android插件的gradle構建。

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

編輯 - 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:[email protected]' 
} 

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建造(NDK建造的修改版本用於調試參數)

#!/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 
+0

命令行 'gradle這個-NDK建造',MainDirectory, '-j' a。對此的工作冷杉是---/app b。這會導致以下錯誤: 任務':app:ndkBuild'的執行失敗。 >的問題發生起動過程「命令'gradle_ndk_build」 解決方案: 命令行「./gradle-ndk-build」,MainDirectory,‘-j’ 劇本是不是程序本身 –

+0

「我不得不求助於使用ndk-build命令並將其作爲一項任務執行:...這完美地工作......「 如何?爲什麼?我收到這個錯誤:「啓動過程中發生問題」命令'ndk-build''「。我無法弄清楚如何讓這條線正確執行。 –

回答

15

gradle會自動在jniLibs/ABI/內查找.so文件。

你可以改變這種行爲,使其通過將其設定您的的build.gradle內文件使用普通libs目錄:

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

謝謝 - 完美的工作。我會編輯我原來的問題,並添加最終的build.gradle,以防其他人有用。 – Johnny

+0

上帝保佑你! :-) SO對於較老的Gradle版本充滿了不同的解決方案... – JerabekJakub

+0

我得到一個「jniLibs無法解決」的錯誤...首先。 – Josh