Android Studio 14 原生开发 + CrystaX NDK

2024-04-22

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

我已经下载了官方的 hello-jni 示例,该示例旨在与 Android Studio 1.4 一起使用,并尝试对其进行调整以与 CrystaX NDK 一起使用。这些是我的 Gradle 2.5 设置:

项目构建.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()
    }
}

模块构建.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")
    }
}

本地属性

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 显示与消息窗口中完全相同的信息。

有人对这个问题有想法吗?


是的,例如here https://www.crystax.net/en/blog/3有点过时了,因此我们计划很快发布新文章,其中更新了如何将 CrystaX NDK 与新的实验性 Gradle 插件结合使用的描述。在此期间,您可以关注example https://github.com/crystax/android-samples-android-studio我已经推送到github了。该示例中最有趣的部分是应用程序的 build.gradle,因此为了方便起见,我将其复制到此处:

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

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

其实定制copyNativeLibs仅将共享库包含到 apk 中所需的任务;如果您链接静态库,copyNativeLibs根本不需要。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Studio 14 原生开发 + CrystaX NDK 的相关文章

  • 当应用程序停止使用 Sencha Touch 2.2 和 Phonegap 时,LocalStorage 存储不会保留在 Android 手机上

    这在我的浏览器中工作正常 但是当我在手机上安装该应用程序并使用它时 它看起来很好 直到我强制它停止并重新打开该应用程序 然后我的所有记录都消失了 我正在使用 2 2 和 Phonegap 任何帮助将非常感激 这是我的商店 Ext defin
  • 基于 MSVC 10 范围的 for 循环

    目前 在我们正在开发的一个大型 C 项目中 我们有一堆新样式的 for 循环 如下所示 for auto value values 到目前为止 我们一直只使用 gcc 4 6 进行编译 最近 一些代码库正在移植到 Windows 一些开发人
  • 使用 ArrayAdapter 的 ListView 中的按钮

    我有一个使用 POJO 类填充的 ArrayAdapter 列表视图由 2 个布局组成 1 代表菜单项 1 代表类别 带分隔符的列表视图很好 后来我尝试在每个菜单项行中添加一个按钮来编辑其中的详细信息 当我尝试获取单击按钮的行的位置时 我遇
  • Android 中的 XmlPullParser 陷入困境

    经过多个小时的搜索和调试后 我仍然停留在同一个地方 并且 Eclipse 没有帮助我 我试图解析这个 RSS 提要 http fr espnf1 com rss motorsport story feeds 0 xml type 2 这很简
  • 要在进程中运行 dex,Gradle 守护进程需要更大的堆。目前有 910 MB

    实际上主要错误是 java exe完成非零退出值 1 首先我告诉你安装 studio 后遇到的每个问题 三天前 我刚刚安装了 android studio 并创建了新项目 1 首先它抛出错误 插件太旧 请更新到更新的版本 在谷歌上搜索后我改
  • 使用反向无限滚动添加到 ListView 时保持滚动位置

    我正在构建一个类似聊天的 Android 应用程序 类似于环聊 为此 我使用垂直 ListViewstackFromBottom true and transcriptMode normal 该列表按从较旧的消息 顶部 到较新的消息 底部
  • 如何从另一个应用程序向一个应用程序添加视图

    我的应用程序叫做我的好应用 MyNiceApp 主要只是一个加载视图的核心coreView在主活动中onCreate coreView由用户根据需要下载的其他插件的视图填充 我定义了核心视图上的各个区域 这些区域可以通过 MyNiceApp
  • 在android中以编程方式创建布局 - 问题

    我正在使用以下代码动态创建 FrameLayout mylayout java FrameLayout layout new FrameLayout this FrameLayout LayoutParams layoutparams ne
  • 如何使用RecyclerView.State保存RecyclerView滚动位置?

    我有一个关于 Android 的问题RecyclerView State http developer android com reference android support v7 widget RecyclerView State h
  • Android 可检查子菜单选项

    所以我有一个用于选项菜单项的子菜单 我想要一个可检查条目的列表 用户可以根据需要选择 取消选择多个条目 我无法解决的唯一问题是如何防止单击其中一个复选框时关闭选项菜单 我看到 PerformShortcut 有一个 FLAG PERFORM
  • T v{} 初始化

    我正在阅读 C 11 标准 但不知道是否 T x 是值初始化或默认初始化 自动存储 它does说得很清楚 10 其初始化器为一组空括号 即 的对象应进行值初始化 And that 11 如果没有为对象指定初始化器 则该对象被默认初始化 但我
  • GCM(Google 云消息传递)是否需要 Google 帐户?

    我需要编写一个简单的应用程序来获取推送通知 我使用 GCM 它使用 Google Play 服务来获取信息 我的问题是 要访问 GCM 是否需要 Google 帐户 我可以使用其他电子邮件帐户来识别设备吗 有没有其他方法可以获取另一个电子邮
  • Android 连接有时会被拒绝(并非所有时候)

    我编写了一个 WiFi Direct 代码连接并在它们之间创建了一个连接 然后我创建了一个ServerSocket在第一面和一个Socket在客户端并开始在它们之间发送数据 第一次启动应用程序时它工作成功 但是当我关闭应用程序并再次启动它时
  • 为什么设置 MediaRecorder 时显示错误 IllegalStateException?

    我的代码设置 MediaRecorder 它显示行集质量错误 mMediaRecorder new MediaRecorder Step 1 Unlock and set camera to MediaRecorder mCamera st
  • 在 android studio 上单击推送通知后重定向到特定活动

    我正在努力开发一个 Android 应用程序 以便在单击所有传入的推送通知时将应用程序重定向到特定的活动页面 我是 Android 开发新手 对我的编程感到抱歉 下面是推送通知部分的 android manifest xml 如果对此主题有
  • android sqlite 如果不存在则创建表

    创建新表时遇到一点问题 当我使用 CREATE TABLE 命令时 我的新表按应有的方式形成 但是当我退出活动时 应用程序崩溃 并且我在 logcat 中得到一个表已存在 如果我使用 CREATE TABLE IF NOT EXISTS 则
  • Android EditText 不起作用,android:imeOptions="actionNext" android:inputType="phone"

    我已经尝试过了 只有删除android inputType phone 键盘回车可以跳转到下一个EditText 不知道大家之间是否有过一些冲突android imeOptions actionNext and android inputT
  • 运行此 AVD 需要 HAXM

    我在 android studio 中创建了模拟器并在其中创建了一些应用程序 当我运行时 它给我一个错误 参见图 1 当我用谷歌搜索时 它告诉我你的系统不支持虚拟化 但我的系统支持它 参见图 2 现在我的问题是 当我的系统支持虚拟化时 为什
  • 随着速度变化,速度表针规绕其中心旋转

    Hi all 我编写了一个应用程序 其中有一个速度计 其指针垂直设置为 90 度 我试图以每秒变化的速度绕其中心旋转指针 我在文本视图中显示变化的速度 从 0 到 120 随机 我正在从远程服务获取速度并显示在文本视图中 因此 当速度发生变
  • 我的 apk 文件在模拟器中的位置

    我在 eclipse android 中编写了一个小程序 现在我安装并运行我的程序 它是一个 apk 现在我想知道我的 apk 文件在哪里 我什至想将它 拉 到我的系统中 是否可以 如果是这样请帮助我 如果您只想将 apk 安装在手机或类似

随机推荐

  • 在数据库中存储条件逻辑表达式/规则

    如何使用 RDBMS 存储逻辑表达式 我标记对象并希望能够基于这些标记构建事实陈述 这些可能被视为虚拟标签 Tags new for sale used offer Rule second hand goods new or used an
  • 限制 TinyMCE 编辑器中的键盘快捷键

    试图找到在 TinyMCE 编辑器的 jQuery 版本中禁用单个键盘快捷键的位置 目前允许的快捷方式列表是 ctrl z Undo ctrl y Redo ctrl b Bold ctrl i Italic ctrl u Underlin
  • 如何将 Visual Studio 中的结构打包为包含 uint32_t 的 24 位?

    我正在尝试将现有应用程序从 32 位 ARM 微控制器移植到桌面平台 例如 Microsoft Windows GCC 在 ARM 上使用 我能够使用 32 位 MinGW 编译器在 Windows 上成功编译该应用程序 但是我使用 Mic
  • 如何让内部控件不覆盖主控件的事件?

    我有一个UserControl其中包含一些内部控件 像这样的东西 现在当我在我的项目中使用它时 我想要every如果单击 我的控件点会引发相同的单击事件 就像其他控件一样 但问题是 我的处理程序在另一个项目中 仅当我单击背景上的某个位置 而
  • AWS:找不到 iam 的实例元数据

    我正在尝试在我的 ec2 实例上设置 elasticsearch s3 快照 它失败并出现以下错误 nested NotSerializableExceptionWrapper sdk client exception The reques
  • 如何同时远程连接到多个 Glassfish 4+ 实例?

    我正在寻找一种从基于 Swing 的独立客户端 JDK7 SE 同时连接到 Glassfish 4 JDK7 EE 的多个实例的方法 我通过以下方式成功连接到单个实例 这就是初始上下文的构造 private void connect Str
  • 我可以检查安装的 Indy 版本吗?

    我需要使用最新的 Indy 组件库版本 我可以通过某些源代码命令或任何其他技巧来获取库版本 以确保我使用正确的库 我知道我正在使用indy 160 bpl 这是我的 Delphi XE2 将鼠标移动到组件栏上时所说的内容 我从中获取的最新
  • Spring事务中是否需要异常处理?

    我对事务的异常处理有疑问 为了清楚地说明我的问题 我想展示我的配置
  • fn 和 fn* 有什么区别?

    在 Clojure 中 fn 和 fn 有什么区别 当我在语法中引用使用 宏创建的函数时 我看到 fn 例如 在 REPL 中 user gt inc fn p1 342 343 auto clojure core inc p1 342 3
  • JavaFX 滚动表更新性能随着时间的推移而降低

    我有一个 TableView 显示最后 N 个项目 顶部的新项目 从底部删除项目等 似乎发生的情况是 CPU 负载随着时间的推移而增加 导致同一台计算机上的其他 X 应用程序变得缓慢 平台详细信息 Redhat 6 7 32 位 Java
  • 不同长度的时间序列数据的聚类

    我有不同系列长度的时间序列数据 我想根据 DTW 距离进行聚类 但找不到与之相关的 ant 库 sklearn给出直接错误 而 tslearn kmeans 给出错误答案 我的问题是如果我用零填充它就可以解决 但我不确定这在聚类时填充时间序
  • `git svn rebase` 与 `git rebase trunk`

    我正在开发一个使用 subversion 作为存储库的项目 因为我需要进行一些还无法发送到 svn 服务器的更改 所以我开始使用git svn这样我就可以进行本地签到 我的设置如下所示 分支机构 trunk 跟踪 svn trunk mas
  • Java 8 升级后无法获取数据库连接

    我最近将一个应用程序从 java 1 7 升级到 1 8 其余库版本保持不变 升级后我收到以下错误 DEBUG 2015 11 12 09 55 12 BasicResourcePool An exception occurred whil
  • Cassandra - 有没有办法限制异步查询的数量?

    我想知道是否有办法限制 cassandra java 驱动程序同时执行的查询数量 目前 我执行了很多查询 如下所示 PreparedStatement stmt session prepare SELECT FROM users WHERE
  • log4j2 在自定义 Appender 中将 printObject 设置为 true

    HERE https logging apache org log4j 2 x manual extending html它说 如果 toString 方法 附加程序应将 printObject 指定为 true 呈现传递给 Appende
  • OpenLayers 中的复合(complex)功能

    我在玩了一下 OpenLayers 想知道是否有一种方法可以创建自定义 功能 我想要完成的是一个具有多个部分的功能 或者是否有一种方法可以将多个功能 绑定 在一起 我想要实现的目标是 我想在地图上的某个位置显示各种数量的数据 并且我想将其包
  • Chrome 扩展:提交后修改 facebook-chat 中的消息文本

    我正在尝试创建一个 Chrome 扩展程序 当用户在聊天框中按 Enter 键时 该扩展程序会修改提交的消息 文本区域的 HTML 代码
  • Rails 测试(MiniTest)中分配方法的目的是什么?

    用于自动生成的测试 test should create item do login user assert difference Item count do post create item creator item creator ti
  • 如何在for_each方法中使用自己类的函数?

    假设我有这个类 继承自 std Vector 这只是一个例子 include
  • Android Studio 14 原生开发 + CrystaX NDK

    我正在尝试将一个巨大的跨平台 C 11 iOS Android 应用程序项目迁移到 Android Studio 14 我使用 CrystaX NDK 进行 boost 和 C 14 他们网站的博客上有官方 Android Studio C