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

💡
近期因项目需要,使用Ionic开发安卓app,同时还要调用C/C++层已有的代码库。这就需要使用到JNI,之前没怎么接触过这方面的内容,也是踩了不少的坑。
开发环境配置
鉴于开发环境搭建很繁琐,这里推荐直接安装Android Studio。
安装完毕后,点击 Android Studio -> preferences -> Appearance -> System Settings -> Android SDK -> SDK Tools 如下图所示:

安装 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); // 这里就输出到logcat0x02 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++_static | GAbi++ 运行时(静态)。 | C++ 异常和 RTTI |
| gabi++_shared | GAbi++ 运行时(共享)。 | C++ 异常和 RTTI |
| stlport_static | STLport 运行时(静态)。 | C++ 异常和 RTTI;标准库 |
| stlport_shared | STLport 运行时(共享)。 | C++ 异常和 RTTI;标准库 |
| gnustl_static | GNU STL(静态)。 | C++ 异常和 RTTI;标准库 |
| gnustl_shared | GNU STL(共享)。 | C++ 异常和 RTTI;标准库 |
| c++_static LLVM | libc++ 运行时(静态)。 | C++ 异常和 RTTI;标准库 |
| c++_shared LLVM | libc++ 运行时(共享)。 | 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/"/>
捡到了漂流瓶!
根据《非经营性互联网信息服务备案管理办法》,小岛暂不开放公开留言 / 评论。
想和我聊聊的话,欢迎通过其他渠道找我~