使用NDK 13

时间:2016-12-10 11:38:48

标签: android android-studio android-ndk native ndk-build

使用NDK 10版本,我曾经使用ndk-build为许多不同的ABI和多个API级别编译独立的二进制文件。这些二进制文件将包含在一个应用程序中。但是,我在新开发机器上安装了NDK described in this article。这导致我的Android SDK目录中有一个文件夹ndk-bundle。我曾经从命令行编译代码,然后将二进制文件复制到我的Android Studio项目的资源中,但我无法弄清楚如何使用NDK 13执行此操作,因此我尝试按照the tutorial to include my native code in the Android Studio project进行操作。但是,几乎所有最近的指令都假设一个人想要构建一个库,而不是一个独立的二进制文件,所以我没有走得太远。

如果我弄清楚如何让它工作,我会切换到CMake。我的本机项目具有以下(简化)结构:

  • 天然

    • Android.mk

      LOCAL_PATH := $(call my-dir)/my_tool/src
      include $(CLEAR_VARS)
      LOCAL_MODULE    := my_tool
      LOCAL_SRC_FILES := main.c
      include $(BUILD_EXECUTABLE)
      
    • Application.mk

      APP_ABI := all
      APP_PLATFORM := android-21
      
    • my_tool

      • SRC
        • 的main.c

如何在Windows 10开发机器上使用Android Studio或NDK从命令行编译?

修改

我在build.gradle中使用它:

externalNativeBuild {
    ndkBuild {
        path "../native/Android.mk"
    }
}

Gradle创建一个包含构建配置的目录.externalNativeBuild,但我无法找到如何实际构建本机代码。我运行gradle时没有创建二进制文件。

我无法找到有关ndk-build的gradle配置的任何信息。

2 个答案:

答案 0 :(得分:4)

我试图尽可能地遵循您的简化结构。

以下是 app / build.gradle 文件:

apply plugin: 'com.android.library'

android {
    compileSdkVersion 24
    buildToolsVersion "25.0.1"
    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 24
        externalNativeBuild {
            ndkBuild {
                targets "my_tool"
                abiFilters "armeabi-v7a"
            }
        }
    }
    externalNativeBuild {
        ndkBuild {
            path "../native/Android.mk"
        }
    }
}

native / Android.mk 文件与您的文件相同:

LOCAL_PATH := $(call my-dir)/my_tool/src
include $(CLEAR_VARS)
LOCAL_MODULE    := my_tool
LOCAL_SRC_FILES := main.c
include $(BUILD_EXECUTABLE)

我还有 native / main.c 文件和最小的 app / src / main / AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="my.tool" />

我没有触及Android Studio向导生成的根 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:2.3.0-alpha3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

现在我可以构建项目了,这就是我得到的:

$> file ./app/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/my_tool
ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped

Android Studio在默认视图中的 cpp 文件夹中显示 main.c

enter image description here

更新:要将可执行文件剥离并打包在APK中,必须更改 native / Android.mk

LOCAL_PATH := $(call my-dir)/my_tool/src

install: LIB_PATH := $(call my-dir)/libs

include $(CLEAR_VARS)
LOCAL_MODULE    := my_tool
LOCAL_SRC_FILES := main.c
include $(BUILD_EXECUTABLE)

install: $(LOCAL_INSTALLED)
    -mkdir $(LIB_PATH)
    -rm -r $(LIB_PATH)
    mv $< $(<:my_tool=lib-my_tool-.so)
    mv $(realpath $(dir $<)..) $(LIB_PATH)

.PHONY: install

此外, app / build.gradle 需要进行一些调整:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "25.0.1"
    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 24
        externalNativeBuild {
            ndkBuild {
                targets "my_tool"
                abiFilters "armeabi-v7a"
                arguments 'V=1', 'install'
            }
        }
    }
    externalNativeBuild {
        ndkBuild {
            path "../native/Android.mk"
        }
    }
    sourceSets {
        main {
            jniLibs.srcDirs = ['../native/libs']
        }
    }
}

这取决于old hack,这取决于NDK的未记录行为,并且可能在未来NDK升级时中断而不另行通知。

答案 1 :(得分:2)

如果你所做的只是改变NDK版本,那么我相信这非常简单,而且我们错过了一些简单的东西。我认为您需要更新PATH环境变量以指向新的ndk-bundle路径并尝试再次运行ndk-build

根据我的经验,我无法让Cmake for Android生成可执行文件(独立二进制文件)或静态库作为最终输出。因为我希望最终输出是可执行文件,所以我不得不切换回使用NDK而忘记Cmake。

<强>更新

这是使用Android Studio和NDK构建C ++可执行文件的方法。这是没有使用CMake,即使你没有JNI代码也是如此。

应用程序/的build.gradle

sourceSets.main {
    // Do not run default ndkbuild
    jni.srcDirs = []
    // Place where .so libs are available
    jniLibs.srcDir 'src/main/libs'
}

task buildNative(type: Exec, description: 'Compile JNI source via NDK') {
    def ndkDir = android.ndkDirectory
    commandLine "$ndkDir/ndk-build.cmd", 'V=1',
            '-C', file('src/main/jni').absolutePath,
            '-j', Runtime.runtime.availableProcessors(),
            'all',
            'NDK_DEBUG=1'
}

task cleanNative(type: Exec, description: 'Clean JNI object files') {
    def ndkDir = android.ndkDirectory
    commandLine "$ndkDir/ndk-build.cmd",
            '-C', file('src/main/jni').absolutePath,
            'clean'
}

目录结构

您需要一个名为app/src/main/jni的文件夹。如您所见,上面的gradle代码只是针对该目录调用ndk-build。以下是我建议您设置目录的方法:

  • JNI

    • Android.mk

      LOCAL_PATH := $(call my-dir)
      include $(call all-subdir-makefiles)
      
    • Application.mk

      APP_ABI := all
      APP_PLATFORM := android-21
      
    • 天然

      • my_tool
        • SRC
          • 的main.c
      • Android.mk

        include $(CLEAR_VARS)
        LOCAL_C_INCLUDES := my_tool/src
        LOCAL_PATH := $(call my-dir)
        LOCAL_MODULE := my_tool
        LOCAL_SRC_FILES := my_tool/src/main.c
        include $(BUILD_EXECUTABLE)
        

建筑

要构建,您可以从ndk-build目录运行app/src/main/jni,也可以从项目的根目录运行gradle buildNative。你可以看到,在我上面显示的gradle代码中,有一个名为buildNative的任务,因此它将成为执行的gradle代码。

顶级Android.mk文件有助于您在app/src/main/jni下添加要构建的更多模块,它会遍历该目录中的所有子目录并调用任何其他Android.mk个文件它找到了。