Android Studio 14原生开发+ CrystaX NDK

时间:2015-10-02 15:52:42

标签: android c++11 android-studio android-ndk

我正在尝试将庞大的跨平台C ++ 11(iOS + Android)应用程序项目迁移到Android Studio 14.我使用CrystaX NDK进行boost和C ++ 14。在他们网站的博客here上有一个官方的Android Studio + CrystaX教程,但它已经过时了。

我已下载官方hello-jni示例,该示例旨在与Android Studio 1.4配合使用,并尝试使其适用于与CrystaX NDK配合使用。这些是我的Gradle 2.5设置:

项目build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
       jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle-experimental:0.2.0'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

module build.gradle

apply plugin: 'com.android.model.application'

model {
    android {
        compileSdkVersion = 23
        buildToolsVersion = "23.0.1"

        defaultConfig.with {
            applicationId = "com.tableair.app"
            minSdkVersion.apiLevel = 4
            targetSdkVersion.apiLevel = 23
        }
    }

    compileOptions.with {
        sourceCompatibility=JavaVersion.VERSION_1_7
        targetCompatibility=JavaVersion.VERSION_1_7
    }

    /*
     * native build settings
     */
    android.ndk {
        moduleName = "tableair-framework"
        cppFlags += "-std=c++11"
        cppFlags += "-Werror"
        ldLibs = ["android", "log", "GLESv2", "crystax"]
        stl = "gnustl_static"
        /*
         * Other ndk flags configurable here are
         * cppFlags += "-fno-rtti"
         * cppFlags += "-fno-exceptions"
         * ldLibs    = ["android", "log"]
         * stl       = "system"
         */
    }
    android.buildTypes {
        release {
            minifyEnabled = false
            proguardFiles  += file('proguard-rules.txt')
        }
    }
    android.productFlavors {
        // for detailed abiFilter descriptions, refer to "Supported ABIs" @
        // https://developer.android.com/ndk/guides/abis.html#sa
        create("arm") {
            ndk.abiFilters += "armeabi"
        }
        create("arm7") {
            ndk.abiFilters += "armeabi-v7a"
        }
        create("arm8") {
            ndk.abiFilters += "arm64-v8a"
        }
        create("x86") {
            ndk.abiFilters += "x86"
        }
        create("x86-64") {
            ndk.abiFilters += "x86_64"
        }
        create("mips") {
            ndk.abiFilters += "mips"
        }
        create("mips-64") {
            ndk.abiFilters += "mips64"
        }
        // To include all cpu architectures, leaves abiFilters empty
        create("all")
    }
}

local.properties

ndk.dir=/Users/vilius/Software/Android/crystax-ndk-10.2.1
sdk.dir=/Users/vilius/Library/Android/sdk

当我尝试运行该应用时。我收到这个错误:

....
:app:generateAllDebugAndroidTestSources UP-TO-DATE
:app:copyArm64-v8aDebugAllTableair-frameworkSharedLibraryGdbServer UP-TO-DATE
:app:createArm64-v8aDebugAllTableair-frameworkSharedLibraryGdbsetup
:app:compileArm64-v8aDebugAllTableair-frameworkSharedLibraryTableair-frameworkMainC UP-TO-DATE
:app:linkArm64-v8aDebugAllTableair-frameworkSharedLibrary
/Users/vilius/Software/Android/crystax-ndk-10.2.1/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/../lib/gcc/aarch64-linux-android/4.9/../../../../aarch64-linux-android/bin/ld:     cannot find -lcrystax
/Users/vilius/Software/Android/crystax-ndk-10.2.1/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/../lib/gcc/aarch64-linux-android/4.9/../../../../aarch64-linux-android/bin/ld:     cannot find -lcrystax
Error:error: ld returned 1 exit status
Error:Execution failed for task ':app:linkArm64-v8aDebugAllTableair-frameworkSharedLibrary'.
> A build operation failed.
      Linker failed while linking libtableair-framework.so.
  See the complete log at: file:///Users/vilius/TableAir/Mobile/app/android-studio-project/app/build/tmp/linkArm64-v8aDebugAllTableair-frameworkSharedLibrary/output.txt    

... / output.txt显示与消息窗口中完全相同的信息。

有没有人对此问题有任何想法?

2 个答案:

答案 0 :(得分:8)

是的,示例here有点过时,所以我们计划尽快发布新文章,并提供有关如何使用CrystaX NDK和新实验性Gradle插件的更新说明。在此期间,您可以查看example我已经推送到github。该示例中最有趣的部分是app的build.gradle,因此为方便起见,我将其复制到此处:

public class BMIprogram {

  public static void main(String[] args) {

    double BMI;
    double weight;
    double height;

    Scanner bodymassScan = new Scanner(System.in);

    System.out.println("Enter weight in pounds: ");
    weight = bodymassScan.nextInt();

    System.out.println("Enter height in inches: ");
    height = bodymassScan.nextInt();

    BMI = ((weight/Math.pow(height, 2)) * 703);

    System.out.println(BMI + " is the BMI");

    }
}

我已经使用Android Studio 1.4和gradle实验插件0.2.0进行了测试。

实际上,自定义import org.gradle.internal.os.OperatingSystem; apply plugin: 'com.android.model.application' final APP_ABIS = ["armeabi", "armeabi-v7a", "x86"] final BOOST_SHARED_LIBS = ["boost_serialization"] model { android { compileSdkVersion = 23 buildToolsVersion = "23.0.1" defaultConfig.with { applicationId = "net.crystax.testboost2" minSdkVersion.apiLevel = 15 targetSdkVersion.apiLevel = compileSdkVersion.asType(Integer) versionCode = 1 versionName = "1.0" } } compileOptions.with { sourceCompatibility = JavaVersion.VERSION_1_7 targetCompatibility = JavaVersion.VERSION_1_7 } android.ndk { moduleName = "test-boost2" cppFlags += "-std=c++11" cppFlags += "-fexceptions" cppFlags += "-frtti" cppFlags += "-Werror" cppFlags += "-I" + getBoostIncDir() ldLibs.addAll BOOST_SHARED_LIBS ldLibs += "log" stl = "gnustl_shared" } android.buildTypes { release { minifyEnabled = false proguardFiles += file('proguard-rules.pro') } } android.productFlavors { APP_ABIS.each { abi -> create(getFlavorName(abi)) { ndk.with { abiFilters += abi getPrebuiltLibPaths(abi).each { path -> ldFlags += "-L" + path } } } } } } tasks.all { task -> if (task.name.startsWith('link')) { task.dependsOn copyNativeLibs, stripNativeLibs } } task copyNativeLibs { ["debug", "release"].each { buildType -> APP_ABIS.each { abi -> def libs = [:] BOOST_SHARED_LIBS.each { name -> libs[name] = "${getBoostLibDir(abi)}/lib${name}.so" } libs.crystax = getLibCrystax(abi) libs.each { name, file -> dependsOn tasks.create(name: "copy-native-library-${name}-${abi}-${buildType}", type: Copy) { from file into getTargetLibDir(abi, buildType) } } } } } task stripNativeLibs(dependsOn: copyNativeLibs) { ["debug", "release"].each { buildType -> APP_ABIS.each { abi -> def libs = [] libs.addAll(BOOST_SHARED_LIBS) libs += "crystax" libs.each { name -> dependsOn tasks.create(name: "strip-native-library-${name}-${abi}-${buildType}", type: Exec) { commandLine getStripExecutable(abi), "--strip-unneeded", "${getTargetLibDir(abi, buildType)}/lib${name}.so" } } } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.0.1' compile 'com.android.support:design:23.0.1' } def getNdkDir() { if (System.env.ANDROID_NDK_ROOT != null) return System.env.ANDROID_NDK_ROOT Properties properties = new Properties() properties.load(project.rootProject.file('local.properties').newDataInputStream()) def ndkdir = properties.getProperty('ndk.dir', null) if (ndkdir == null) throw new GradleException("""\ NDK location not found. Define location with ndk.dir in the local.properties file or with an ANDROID_NDK_ROOT environment variable.""") return ndkdir } def getCrystaxNdkDir() { def ndkDir = getNdkDir() if (!(new File(ndkDir, "sources/crystax").exists())) throw new GradleException("""\ '${ndkDir}' is not a CrystaX NDK. Edit ndk.dir in local.properties or set ANDROID_NDK_ROOT environment variable pointing to CrystaX NDK""") return ndkDir } def getFlavorName(abi) { switch (abi) { case "armeabi": return "arm"; case "armeabi-v7a": return "arm7" case "arm64-v8a": return "arm64" default: return abi.replaceAll('-', '_') } } def getToolchainName(abi) { switch (abi) { case ~/^armeabi.*/: return "arm-linux-androideabi" case ~/^arm64.*/: return "aarch64-linux-android" case "mips": return "mipsel-linux-android" case "mips64": return "mips64el-linux-android" case ["x86", "x86_64"]: return abi default: throw new GradleException("Unsupported ABI: '${abi}'") } } def getToolchainPrefix(abi) { switch (abi) { case ~/^armeabi.*/: return "arm-linux-androideabi" case ~/^arm64.*/: return "aarch64-linux-android" case "mips": return "mipsel-linux-android" case "mips64": return "mips64el-linux-android" case "x86": return "i686-linux-android" case "x86_64": return "x86_64-linux-android" default: throw new GradleException("Unsupported ABI: '${abi}'") } } def getHostOS() { if (OperatingSystem.current().isLinux()) return "linux" if (OperatingSystem.current().isMacOsX()) return "darwin" if (OperatingSystem.current().isWindows()) return "windows" throw new GradleException("Unsupported host OS") } def getHostArch() { def arch = System.getProperty("os.arch") switch (arch) { case ["x86_64", "amd64"]: return "x86_64" case ~/^i[3456]86/: case "x86": return "x86" default: throw new GradleException("Can't detect host's CPU architecture: '${arch}'") } } def getHostTag() { def tag = getHostOS() def arch = getHostArch() if (tag != "windows" || arch != "x86") tag += "-${arch}" return tag } def getStripExecutable(abi) { def ndk = getCrystaxNdkDir() def toolchainName = getToolchainName(abi) def toolchainPrefix = getToolchainPrefix(abi) def hostTag = getHostTag() def strip = "${ndk}/toolchains/${toolchainName}-4.9/prebuilt/${hostTag}/bin/${toolchainPrefix}-strip" if (OperatingSystem.current().isWindows()) strip = strip.replaceAll('/', '\\\\') + '.exe' return strip } def getPrebuiltLibPaths(abi) { def paths = [] paths += getBoostLibDir(abi) paths += getLibCrystaxDir(abi) return paths } def getTargetLibDir(abi, buildType) { return "${buildDir}/intermediates/binaries/${buildType}/${getFlavorName(abi)}/lib/${abi}" } def getLibCrystaxDir(abi) { return "${getCrystaxNdkDir()}/sources/crystax/libs/${abi}" } def getLibCrystax(abi) { return "${getLibCrystaxDir(abi)}/libcrystax.so" } def getBoostDir() { return "${getCrystaxNdkDir()}/sources/boost/1.58.0" } def getBoostIncDir() { return "${getBoostDir()}/include" } def getBoostLibDir(abi) { return "${getBoostDir()}/libs/${abi}" } 任务只需要将共享库包含到apk中;如果您与静态库链接,则根本不需要copyNativeLibs

更新:我添加了copyNativeLibs任务只是因为我意识到APK包含了带有调试信息的未经剥离的库,使其大小太大而没有任何实际需要。

答案 1 :(得分:0)

@ dmitry-moskalchuk你好Dmitry我用你的代码编译build.gradle并在local.properties中定义了crystax-ndk-10.2.1 ndk.dir = /选择/ Android的SDK-LINUX / crystax-NDK-10.2.1

我总是收到错误: 错误:配置项目':app'。

时出现问题
  

android.compileSdkVersion丢失!

但它在android部分以及androidmanifest.xml中定义

谢谢。