2014-04-08 32 views
13

Tôi sẽ là người đầu tiên thừa nhận rằng tôi không phải là chuyên gia khủng khiếp với Gradle và hệ thống Android mới, nhưng, thật không may, tôi phải chuyển sang nó (từ kiến) vì vấn đề 21479 (https://code.google.com/p/android/issues/detail?id=21479) và chú thích "Điều này sẽ không được sửa. Chúng tôi đang tập trung hoàn thiện hệ thống xây dựng dựa trên Gradle sẽ thay thế Ant." Thật không may, tôi không thể tải lại nội dung đó sau khi tôi thêm thư viện quảng cáo Millenium Media. Điều này là ngoài thư viện Android OpenCV, thư viện mã hóa của Chilkat và thư viện hỗ trợ v4 nhưng thư viện MMedia là thư viện đã phá vỡ tất cả.Gradle Android Build System Các vấn đề NDK

Vì vậy, tôi nghĩ, một lý do tốt để chuyển sang hệ thống xây dựng dựa trên Gradle mới. Thật không may, mặc dù để lại một hệ thống xây dựng kiến ​​bị hỏng, hệ thống mới dường như chưa hoàn thành; đặc biệt là hỗ trợ ndk. Ứng dụng tôi đang làm việc trên sử dụng OpenCV cho một số xử lý hình ảnh và một vài hoạt động chạy quá chậm trừ khi chúng được biên dịch thành bản địa (LOTS di chuyển bộ nhớ và so sánh quá chậm trên JNI ranh giới). Vì vậy, thay vì cố gắng chuyển dữ liệu trở lại và chuyển tiếp giữa máy ảo và mã nguồn gốc, tôi để lại tất cả những thứ này ở phía gốc và chỉ có một cuộc gọi từ máy ảo để nhận kết quả.

Vấn đề đầu tiên là nhận công cụ ndk để biên dịch. Tôi không thể có được các thiết lập trong việc đóng cửa ndk để làm việc vì vậy tôi đã phải sử dụng lệnh ndk-build và thực hiện điều này như một nhiệm vụ:

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 
} 

Điều này làm việc hoàn hảo; nó biên dịch mã ndk và tạo thư viện .so mà không có lỗi. Thật không may, nó sẽ không đặt kết quả .so tập tin trong gói cuối cùng. Nó đặt tất cả các thư viện bản địa khác, nhưng không phải là cái này - không biết tại sao.

tôi đã tìm thấy rất nhiều cáo buộc sửa chữa cho vấn đề này như:

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

Nhưng thêm này chỉ dẫn đến một tập tin apk với NO thư viện có nguồn gốc ở đâu cả. Tôi đã nhìn thấy những người khác có cùng một vấn đề (chẳng hạn như https://groups.google.com/forum/#!msg/adt-dev/QbDHM41QT2E/J4jHCC_RuIEJ) nhưng tôi đã thử tất cả các giải pháp được đề xuất và không ai trong số họ làm việc cho tôi.

Vì tôi không thay đổi mã gốc thường xuyên, tôi vừa thực hiện một bản hack để sao chép thư viện gốc được tạo (libndklib.so) từ app/src/main/libs sang/app/src/main/jni sau khi nó được biên soạn; sau đó nó kết thúc trong gói apk. Rõ ràng, điều này hơi khó chịu, nếu ai đó lấy mã này, họ sẽ tự hỏi tại sao những thay đổi của họ đối với mã gốc không bao giờ xuất hiện trong ứng dụng.

Vì vậy, câu hỏi của tôi là: Có điều gì tôi có thể chạy trong tập lệnh gradle sẽ thực thi sau khi tôi đã chạy lệnh ndk (gradle-ndk-build) sẽ sao chép (các) tệp được tạo từ ứng dụng /src/main/libs/armeabi/libndklib.so đến /app/src/main/jni/armeabi/libndklib.so (cho mỗi kiến ​​trúc - armeabi, armeabi-v7, x86, mips) để nó kết thúc trong Gói apk?

HOẶC

Có cách nào để làm cho việc đóng cửa Gradle ndk xử lý như sau ndk tạo file ảnh đúng cách: 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) 

tôi nhìn vào nguồn Gradle cho các plug-in nhưng tôi không thể nhìn thấy rất nhiều các chỉ thị được hỗ trợ.

HOẶC

Tôi có thể chỉ cần thêm một số loại hack mà chạy ở phần cuối của kịch bản Gradle mà chỉ buộc các bản sao thích hợp libndklib.so (đối với kiến ​​trúc chính xác) vào apk tạo? Tôi có thể sống với thứ hai cho đến khi công cụ ndk được hoàn thành cho trình cắm thêm Android để xây dựng gradle.

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

Edit - Sau câu trả lời của ph0b Đây là tệp build.gradle cuối cùng có mod được đề xuất trong đó. Tạo của .apk hoàn hảo build.gradle (trong thư mục ứng dụng)

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-build (phiên bản sửa đổi của ndk-build dùng để gỡ rối các thông số)

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

Cấu trúc thư mục

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

commandline 'gradle-ndk-build', MainDirectory, '-j' a. cây thông làm việc cho việc này là ---/app b. điều này gây ra lỗi sau: Thực hiện không thành công cho tác vụ ': app: ndkBuild'. > Một vấn đề xảy ra bắt đầu quá trình 'lệnh 'gradle_ndk_build'' Giải pháp: commandline './gradle-ndk-build', MainDirectory, '-j' kịch bản không phải là chương trình tự –

+0

"Tôi đã phải nghỉ mát để sử dụng lệnh ndk-build và thực hiện tác vụ này dưới dạng tác vụ: ... Công cụ này hoàn toàn hoạt động ... " Làm cách nào? Tại sao? Tôi nhận được lỗi này: "Đã xảy ra sự cố khi bắt đầu quá trình 'lệnh' ndk-build ''". Tôi không thể tìm ra cách để có được dòng đó để thực thi chính xác. –

Trả lời

15

gradle sẽ tự động tìm kiếm các tệp .so bên trong jniLibs/ABI/.

Bạn có thể thay đổi hành vi này để làm cho nó sử dụng libs thư mục thường xuyên của bạn bằng cách thiết lập nó bên build.gradle bạn file:

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

Cảm ơn - đã hoạt động hoàn hảo. Tôi sẽ chỉnh sửa câu hỏi ban đầu của mình và thêm build.gradle cuối cùng trong trường hợp nó hữu ích cho bất kỳ ai khác. – Johnny

+0

Chúa ban phước cho bạn! :-) SO là đầy đủ các giải pháp khác nhau cho phiên bản Gradle cũ hơn ... – JerabekJakub

+0

Tôi nhận được một lỗi "jniLibs không thể được giải quyết" ... để bắt đầu với. – Josh

Các vấn đề liên quan