结束与起始之界

🐟 鱼上钩了,提竿!

🎸 K.K. 在调吉他弦……

🦋 轻轻挥动捕虫网……

📝 moudicat2017 年 10 月 25 日更新于 2026-05-274 次阅读

使用Cordova、Java JNI调用C/C++代码中的坑

使用Cordova、Java JNI调用C/C++代码中的坑

💡

近期因项目需要,使用Ionic开发安卓app,同时还要调用C/C++层已有的代码库。这就需要使用到JNI,之前没怎么接触过这方面的内容,也是踩了不少的坑。

开发环境配置

鉴于开发环境搭建很繁琐,这里推荐直接安装Android Studio。

安装完毕后,点击 Android Studio -> preferences -> Appearance -> System Settings -> Android SDK -> SDK Tools 如下图所示:

preferences

安装 Android SDK Build-Tools, Android SDK Tools, NDK

不过在此之前 由于众所周知的原因 需要将以下地址写入 /etc/hosts

203.208.43.66  dl-ssl.google.com
203.208.43.66  dl.google.com

插件目录结构

这里简单以cordova-plugin-fast-fourier-transform这个项目,介绍一下插件的目录结构

  • plugin.xml - 指定Cordova项目的平台,并复制相应源文件与库到插件目录

  • compile-android - 将C源代码重新编译

  • src/ -

    • common/ - C源代码目录(Android/IOS公用代码)
    • android/ - 安卓平台的编译脚本与源代码
      • build-extras.gradle - Gradle构建脚本与NDK配置文件,以便在Android Studio中调试C代码
      • FFTPlugin.java - 提供原生Java调用接口
      • FFTJni.java - 提供Java层JNI接口
        • jni/ - JNI C层及构建脚本
          • FFTJni.c - 实现JNI接口
          • Android.mk - NDK Make script 将C代码构建到特定架构的共享库中
  • www - fft.js - JS层->Java层调用接口

0x01 如何在各层输出调试内容

JS层

console.log - 这没什么好说的, 在run语句后加上 -l -c 即可输出log到控制台。

Java层 (FFTPlugin.java)

使用 android.util.Log

protected static final String TAG = "FFTPlugin";
 
Log.v(TAG, "output");
Log.d(TAG, "output");
Log.i(TAG, "output");
Log.w(TAG, "output");
Log.e(TAG, "output");

连接手机后 运行 adb logcat | grep FFTPlugin 可捕获所有Log

native层 (C/C++)

想要输出log需要在Android.mk文件中加入

LOCAL_LDLIBS := -llog LOCAL_SHARED_LIBRARIES := libcutils libutils

这里要注意,一定要加在include $(CLEAR_VARS)之后,否则会被清除。

接下来在FFTJni.c文件中加入以下几行

#include <android/log.h>
#define LOG_TAG "FFTJni"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
LOGE("cpxOut[%d]: r: %lf, i: %lf", i, cpxOut[i].r, cpxOut[i].i); // 这里就输出到logcat

0x02 C++ 标准库的编译

当native code是C++时,可能会引入一些标准库的头文件 如complex, 此时如果不做任何修改会导致编译失败,提示找不到文件complex。

这是由于NDK默认是system最小支持的C++ runtime,其中并不包含一些复杂的库,这时我们就需要引入Application.mk文件,定义NDK环境。

APP_PLATFORM := android-21
APP_ABI := all
 
# c++ lib
APP_STL := c++_shared

其中APP_STL可选值有system stlport_static stlport_shared gnustl_static gnustl_shared c++_static c++_shared none

名称说明功能
libstdc++(默认)默认最小系统 C++ 运行时库。不适用
gabi++_staticGAbi++ 运行时(静态)。C++ 异常和 RTTI
gabi++_sharedGAbi++ 运行时(共享)。C++ 异常和 RTTI
stlport_staticSTLport 运行时(静态)。C++ 异常和 RTTI;标准库
stlport_sharedSTLport 运行时(共享)。C++ 异常和 RTTI;标准库
gnustl_staticGNU STL(静态)。C++ 异常和 RTTI;标准库
gnustl_sharedGNU STL(共享)。C++ 异常和 RTTI;标准库
c++_static LLVMlibc++ 运行时(静态)。C++ 异常和 RTTI;标准库
c++_shared LLVMlibc++ 运行时(共享)。C++ 异常和 RTTI;标准库

具体可参考C++ 库支持

编译过后,每个平台下都会多出一个libc++_shared.so文件 记得将他们引入plugin.xml, 否则会提示错误could not load library "libc++_shared.so" needed by "libxxx.so"

0x03 C++异常

当我们C++程序中使用了异常处理,NDK就会报错,因为NDK的异常处理默认关闭,需要手动打开,可按照下面的方法打开

# Application.mk
APP_CPPFLAGS += -fexceptions
 
#Android.mk
LOCAL_CPP_FEATURES += exceptions

将添加的文件加入plugin.xml ->

<source-file src="src/android/jni/Application.mk" target-dir="src/yourlib/android/jni/"/>

捡到了漂流瓶!

根据《非经营性互联网信息服务备案管理办法》,小岛暂不开放公开留言 / 评论。

想和我聊聊的话,欢迎通过其他渠道找我~