NDK开发入门终极教程

栏目: C++ · 发布时间: 6年前

内容简介:同参见之前的博客:

NDK 技术的渊源始于3年前,使用 so 文件的时候了解到 NDK 技术,并且 C 语言一直是强项,就鼓捣起 NDK 开发。在 AndroidStduio 还没推广的年代,基于 eclipse 搭建 NDK 开发环境需要安全依赖开发工具,并且调试起来具备难度。随后 AndroidStudio 也先后支持 nkd-buildcmake 使用 NDK 开发。

参见之前的博客:

eclipse下使用NDK开发so库

AndroidStudio配置NDK开发环境

1 准备工作

1.1 下载 NDK

当前 NDK 稳定版已经 发布到 r15c 。附上各个平台的下载地址:

  1. android-ndk-r15c-windows-x86

  2. android-ndk-r15c-windows-x86_64

  3. android-ndk-r15c-darwin-x86_64

  4. android-ndk-r15c-linux-x86_64

1.2 添加NDK依赖

解压下载好的文件在本地,在 AndroidStudio 工程配置( 注意不是 AndroidStudio 工具配置 )中指定 NDK 路径。

NDK开发入门终极教程

或者在 local.properties 文件中指定NDK路径。

NDK开发入门终极教程

1.3 添加cmake支持

在 AndroidStudio 工具配置中,选择 Android SDK -> SDK Tools 中,勾选CMake并安装。

NDK开发入门终极教程

2 新建支持NDk工程

现在的 AndroidStduio 更支持一种极简方式集成 NDK 开发支持,即在下图中勾选 include C++ support 。然后选择 C++ 标准。如 C++ 11 。建选默认的 ToolChain Default

NDK开发入门终极教程 NDK开发入门终极教程

之后正常 run 即可将 C 语言部分生成出 so 文件并打包到 apk 文件中。

3 给工程添加NDK支持

上述方式适合在新的工程中添加 NDK 支持。如何要在现有的项目中添加 NDK 支持,现提供 cmakendk-build 两种方式。

由于在同一个工程中,同时支持 cmakendk-build 两种方式编译 so 文件,因此将 C 源码单独放在 cpp-src 目录。且将 cmakendk-build 区分不同的 module 进行编译。

NDK开发入门终极教程

3.1 cmake

这是目前最受欢迎的集成方式,AndroidStduio 在创建新工程时默认使用该方式添加 NDK 支持。但在现有的工程中添加 NDK支持,需要手动配置。

NDK开发入门终极教程

创建 cmake module 添加个三个文件。

  1. CMakeLists.txt cmake编译配置文件
cmake_minimum_required(VERSION 3.4.1)

add_library(
        hello-jni # so 库的名称 libhello-jni.so
        SHARED # 设置为分享库
        # 指定C源文件的路径,指向公共cpp-src目录
        ../../../../cpp-src/hello-jni.c
)

find_library(
        log-lib # 设置路径变量名称
        log # 指定CMake需要加载的NDK库
)

# 链接hello-jni库依赖的库,注意下面变量名的配置
target_link_libraries(hello-jni
        ${log-lib}
)
复制代码
  1. AndroidManifest.xml 每个module必须的配置文件,指定packageName。
<?xml version="1.0" encoding="UTF-8" ?>
<manifest package="com.flueky.cmake">

</manifest>
复制代码
  1. Build.gradle 每个module必须的配置文件,用于构建项目。
apply plugin: 'com.android.library'

android {
    compileSdkVersion 28

    defaultConfig{
        externalNativeBuild {
            cmake {
                // 指定配置参数,更多参数设置见 https://developer.android.google.cn/ndk/guides/cmake
                arguments "-DCMAKE_BUILD_TYPE=DEBUG"
                // 添加CPP标准
//                cppFlags "-std=c++11"
            }
        }
    }

    externalNativeBuild {
        cmake {
            // 指定CMake编译配置文件路径
            path "src/main/cpp/CMakeLists.txt"
        }
    }
}
复制代码

关于 CMake 编译参数的设置,更多内容请阅读官方资料。

眼尖的小伙伴已经发现两处配置了 externalNativeBuild 。其中第二处的 externalNativeBuild 配置是生成 Gradle Task 可以不运行工程,直接在 ndk-cmake -> Tasks -> other 找到编译 so 文件有关的四个任务。

NDK开发入门终极教程 NDK开发入门终极教程

双击 exeternalNativeBuildDebug 执行任务,如图:

NDK开发入门终极教程

根据路径即可找到生成的so文件。

3.2 ndk-build

这是最传统的 ndk 编译方式。在配置得当的情况下,可以在不打开 AndroidStudio 情况下完成so文件的编译和输出。

NDK开发入门终极教程

创建 ndk-build module ,添加4个文件。

  1. Android.mk
# 讲真,这个参数我看不懂。从 官方demo 抄来的。用于指定源文件的时候使用
abspath_wa = $(join $(filter %:,$(subst :,: ,$1)),$(abspath $(filter-out %:,$(subst :,: ,$1))))

# 指定当前路径
LOCAL_PATH := $(call my-dir)

# 指定源文件路径
JNI_SRC_PATH := $(call abspath_wa, $(LOCAL_PATH)/../../../../cpp-src)

# 声明 clear 变量
include $(CLEAR_VARS)

# 指定 so 库的名称 libhello-jni.so
LOCAL_MODULE    := hello-jni
# 指定 c 源文件
LOCAL_SRC_FILES := $(JNI_SRC_PATH)/hello-jni.c
# 添加需要依赖的NDK库
LOCAL_LDLIBS := -llog -landroid
# 指定为分享库
include $(BUILD_SHARED_LIBRARY)
复制代码

关于Android.mk 编译参数的设置,更多内容请阅读官方资料

  1. Application.mk
# 指定编译的的so版本
APP_ABI := all
# 指定 APP 平台版本。比 android:minSdkVersion 值大时,会有警告
APP_PLATFORM := android-28
复制代码

关于Application.mk 编译参数的设置,更多内容请阅读官方资料

  1. AndroidManifext.xml
<?xml version="1.0" encoding="UTF-8" ?>
<manifest package="com.flueky.ndk">

</manifest>
复制代码
  1. build.gradle
apply plugin: 'com.android.library'

android {
    compileSdkVersion 28
    externalNativeBuild {
        ndkBuild {
            // 指定mk文件路径
            path 'src/main/jni/Android.mk'
        }
    }
    defaultConfig {
    }
}
复制代码

上面的 externalNativeBuild 作用同 CMake 方式的一样,用于编译生成 so 文件。 但是 ndk-build 还支持使用命令 ndk-build 编译 so 文件。 需要将 NDK 路径添加至环境变量。

需要在 jni 目录下执行该命令:

NDK开发入门终极教程

最后生成的so文件路径如图;

NDK开发入门终极教程

4 实践

4.1 生成头文件

在主 module 中的 MainActivity中添加 native 方法 。使用 javah 编译出头文件。 使用 -d 参数指定头文件的输出目录。

public class MainActivity extends Activity {

    static {
        // 加载 JNI 库
        System.loadLibrary("hello-jni");
    }

    ......

    // 声明 Native 方法
    private native String hello();
}
复制代码

app/src/main/java 目录下执行命令 javah

NDK开发入门终极教程

4.2 编写 C 源码

hello-jni.c 文件引用生成的头文件,并编写测试代码。

#include <string.h>
#include <jni.h>
#include "com_flueky_demo_MainActivity.h"
#include "util/log.h"

/**
 * JNI 示例,演示native方法返回一个字符串,Java 源码见
 *
 * ndk-sample/app/src/main/java/com/flueky/demo/MainActivity.java
 */
JNIEXPORT jstring JNICALL
Java_com_flueky_demo_MainActivity_hello( JNIEnv* env,
                                                  jobject thiz )
{
#if defined(__arm__)
    #if defined(__ARM_ARCH_7A__)
        #if defined(__ARM_NEON__)
            #if defined(__ARM_PCS_VFP)
                #define ABI "armeabi-v7a/NEON (hard-float)"
            #else
                #define ABI "armeabi-v7a/NEON"
            #endif
        #else
            #if defined(__ARM_PCS_VFP)
                #define ABI "armeabi-v7a (hard-float)"
            #else
                #define ABI "armeabi-v7a"
            #endif
        #endif
    #else
        #define ABI "armeabi"
    #endif
#elif defined(__i386__)
    #define ABI "x86"
#elif defined(__x86_64__)
    #define ABI "x86_64"
#elif defined(__mips64)  /* mips64el-* toolchain defines __mips__ too */
    #define ABI "mips64"
#elif defined(__mips__)
    #define ABI "mips"
#elif defined(__aarch64__)
    #define ABI "arm64-v8a"
#else
    #define ABI "unknown"
#endif

    LOGD("日志输出示例");

    return (*env)->NewStringUTF(env, "Hello from JNI !  Compiled with ABI " ABI ".");
}
复制代码

4.3 运行截图

页面截图:

NDK开发入门终极教程

日志截图:

NDK开发入门终极教程

5 源码获取

工程源码已开放在GitHub, 下载地址 。如果您有多余的CSDN积分,不防从这里下载。可以直接编写 C 源码并进行调试和生成 so 文件。

Google 官方资料需要翻墙才可以阅读。想了解翻墙方法,请点 SSR

觉得有用?那打赏一个呗。我要打赏

此处是广告 : Flueky的技术小站


以上所述就是小编给大家介绍的《NDK开发入门终极教程》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Dynamic Programming

Dynamic Programming

Richard Bellman / Dover Publications / 2003-03-04 / USD 19.95

An introduction to the mathematical theory of multistage decision processes, this text takes a "functional equation" approach to the discovery of optimum policies. The text examines existence and uniq......一起来看看 《Dynamic Programming》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具