概述

  最近负责一个android项目需要使用到之前公司师兄编写c++算法库,一开始并不知道c++项目可以移植android项目使用,竟然天真的打算将c++算法库用java进行重写。。。
  通过查询大量资料得知可以通过项目移植的方法将c++项目编译成so库后在android项目上进行调用网上资料纷繁复杂,大部分回答提出的一种解决方案通过android studio新建一个c++ native项目,通过cpp目录下创建cpp文件实现相应函数通过native.cpp文件实现jni接口将相应需要使用到c++函数jni接口暴露出去给相应的android项目使用,文件结构下图所示

在这里插入图片描述

   笔者不推荐这种方法,这种方法实现的前提是c++项目就是由本人所编写,对于其中的内容结构已经了然于心,否则在将c++项目直接复制到cpp目录下进行编译打包so库会出现许多头疼问题,对于初学者非常不友好。
   本文介绍的是一种通过visual studio上的跨平台android进行c++项目的移植打包so库并给android studio调用方法

预先准备


1:c++项目的预处理
   请注意,对于你要进行移植的c++项目你要先了解此项目是基于Windows还是linux下进行编写的。由于android是一种基于Linux内核(不包含GNU组件)的自由及开放源代码操作系统,如果你的c++项目是基于windows下进行编写那么你可能需要对c++源码进行一定量修改例如windows引入的库需要替换linux下的库进行使用,否则android ndk编译器将找不到相应的库。
在这里插入图片描述

   如上图所示,可以通过ifdef定义进行条件判断此时项目所运行在的操作系统从而进行不同处理操作
   如果你的c++项目非常大,建议不要将整个项目进行移植移植的项目内容越多,出现问题概率也就越大,后期积重难返。最好是你的android项目需要调用哪些算法函数就将相应的cpp文件移植进行使用。

2:环境搭建

本次移植时在visual studio 2019上安装android ndk-16b进行操作
  在visual studio2019上先打开VS installer
在这里插入图片描述

选中C++移动开发
在这里插入图片描述

如果VS没有下载NDK和SDK的,需要在VS里面配置
在这里插入图片描述
在这里插入图片描述

3:创建安卓项目

在这里插入图片描述

创建好后如下所示:
在这里插入图片描述

重定向到你的NDK版本:
在这里插入图片描述
配置项目属性
在这里插入图片描述

4:导入项目

具体导入项目方法可以参考篇文章导入项目方法导入后的项目目录如下图所示:
在这里插入图片描述


5:链接opencv库以及项目相应的依赖库

  如果你的项目中有使用的opencv库,那么你需要重新链接相应的OpenCV库,下载android版本opencv,我使用的是opencv-3.4.15-androidsdk
简单说下Android库的头文件目录和库文件目录链接导入
头文件位于:opencv-3.4.15-androidsdkOpenCV-androidsdksdknativejniinclude
在这里插入图片描述
库文件位于:
opencv-3.4.15-androidsdkOpenCV-androidsdksdknative3rdpartylibs
opencv-3.4.15-android-sdkOpenCV-android-sdksdknativelibs
opencv-3.4.15-android-sdkOpenCV-android-sdksdknativestaticlibs
在这里插入图片描述
  上图中第一个附加库目录是我的c++项目需要依赖的库文件libusb用于调用usb接口进行相应操作,因此也需要将相应库文件添加附加库目录。这里根据你需要编译架构类型链接不同版本的库文件,我这里链接的是armeabiv7a版本,这个版本是比较通用的,2010之后的android设备部分都是用这个cpu架构

最后就是添加附加库:
在这里插入图片描述
  附加依赖项就是链接上述附加库目录中需要使用的.so动态库与.a静态库文件,注意android项目是无法使用windows下的dll以及lib第三方库文件的,必须全部替换替换安卓端的.so和.a文件。
   添加附加依赖项的命名规范libopencv_java3.so添加到附加依赖项则修改为-l+去掉lib后的文件名称,无需添加后缀名静态库的添加同理。
在这里插入图片描述

动态库文件

在这里插入图片描述

静态库文件

完整opencv库添加到附加依赖项列表:

-lopencv_java4
-lopencv_calib3d
-lopencv_core
-lopencv_dnn
-lopencv_features2d
-lopencv_flann
-lopencv_highgui
-lopencv_imgcodecs
-lopencv_imgproc
-lopencv_ml
-lopencv_objdetect
-lopencv_photo
-lopencv_stitching
-lopencv_video
-lopencv_videoio
-lcpufeatures
-lIlmImf
-littnotify
-llibjasper
-llibjpeg-turbo
-llibpng
-llibprotobuf
-llibtiff
-llibwebp
-lquirc
-ltbb
-ltegra_hal
-lz
-ldl
-lm
-llog

  如果你的c++项目有依赖其他的库请记得一定要找到相应版本的依赖库并按上述方法添加到附加库目录以及附加依赖项中,例如我是在项目中用到了libusb库,要编译一份armeabi-v7a版本的c++项目so库,就要在项目中添加了libusb.h后在附加库目录以及附加依赖项中添加amreabi-v7a版本的libusb的so库,这样才是真正完成了库的链接并可以调用其中的函数


编译操作

  下图修改你要编译的so库版本,我选择的是ARM版本,即armeabi-v7a版本so库。
在这里插入图片描述
  

  一开始编译遇到一些c++设置问题,因此需要在配置中进行一些修改操作。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  编译控制台出现如上显示就表明编译成功,如果有遇到其他问题也可以发在评论区,或许可以提供一些帮助。
  

so的函数导出并在android进行调用


1:导出函数编写

  新建android项目中自动生成了一个cpp文件,其中的JNIEXPORT jfloat JNICALL Java_com_jniexample_JNIInterface_***(JNIEnv env, jclass type, jfloatArray buf) 方法就是导出java进行调用的方法。文件内容如下

#include "opencvTest2.h"
#include <jni.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/resource.h>
#include <android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "opencvTest2", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "opencvTest2", __VA_ARGS__))

using namespace cv;
using namespace std;
//这里extern就是将你需要使用到的c++算法中的函数进行导出进行使用。
extern float TestOpencv(float* buf, int len);
extern float TestMath();
extern int ScanIDCardMoveToReadPosition(int timeout);
extern "C" {
	/*此简单函数返回平台 ABI,此动态本地库为此平台 ABI 进行编译。*/
	const char * opencvTest2::getPlatformABI()
	{
	#if defined(__arm__)
	#if defined(__ARM_ARCH_7A__)
	#if defined(__ARM_NEON__)
		#define ABI "armeabi-v7a/NEON"
	#else
		#define ABI "armeabi-v7a"
	#endif
	#else
		#define ABI "armeabi"
	#endif
	#elif defined(__i386__)
		#define ABI "x86"
	#else
		#define ABI "unknown"
	#endif
		LOGI("This dynamic shared library is compiled with ABI: %s", ABI);
		return "This native library is compiled with ABI: %s" ABI ".";
	}

	//C++导出给Java类使用的命名规范
	//Java_packagename_classname_functionname
	//第一个传参总是JNIEnv* env
	//第二个传参 如果是static成员函数就是jclass type,
	//		    如果是非static成员函数就是jobject thiz,
	//第三传参才是真正的参数
	JNIEXPORT jfloat JNICALL
		Java_com_jniexample_JNIInterface_CVTestSum(JNIEnv* env, jclass type, jfloatArray buf) //这个用来导出给Java使用
	{
		auto len = env->GetArrayLength(buf);
		jboolean notcopy = JNI_FALSE;
		float* fptr = env->GetFloatArrayElements(buf, &amp;notcopy);//从Java内存转换到native指针
		return TestOpencv(fptr, len);
	}
	JNIEXPORT jfloat JNICALL
		Java_com_jniexample_JNIInterface_TestSum(JNIEnv* env, jclass type, jfloatArray buf)//这个用来导出给Java使用
	{
		auto len = env->GetArrayLength(buf);
		jboolean notcopy = JNI_FALSE;
		float* fptr = env->GetFloatArrayElements(buf, &amp;notcopy);
		float sum = 0;
		for (size_t i = 0; i < len; i++)
		{
			sum += fptr[i];
		}
		return sum;
	}
	//测试动态库是否可以使用
	JNIEXPORT jfloat JNICALL
		Java_com_jniexample_JNIInterface_TestMath(JNIEnv* env, jclass type)//这个用来导出给Java使用
	{
		return TestMath();
	}
	//ScanIDCardMoveToReadPosition测试c++项目中的函数能否使用
	JNIEXPORT jint JNICALL
		Java_com_jniexample_JNIInterface_ScanIDCardMoveToReadPosition(JNIEnv* env, jclass type, jint timeout)//这个用来导出给Java使用
	{
		int i= ScanIDCardMoveToReadPosition(timeout);
		return i;
	}

	void opencvTest2()
	{
	}
	opencvTest2::opencvTest2()
	{
	}
	opencvTest2::~opencvTest2()
	{
	}
}


2:android项目中进行导入
  在android根目录创建libs文件夹,并在动态库下创建相应版本的文件夹用于存放下图中的动态库。
在这里插入图片描述
在这里插入图片描述

修改android跟目录下的build.gradle:
在这里插入图片描述

  在上图中蓝色文件夹java中添加一个Java类,请注意创建java类的包路径以及类名必须要按照步骤1中编写的JNIEXPORT方法中的Java_com_jniexample_JNIInterface名进行创建,否则无法找到so库的导出方法。
在这里插入图片描述


  这个用来对接.so中的导出函数: Java_com_jniexample_JNIInterface_CVTestSum和 Java_com_jniexample_JNIInterface_TestSum。
所以,接下来就要创建这两个函数的导出:
在这里插入图片描述

在项目中进行使用:
在这里插入图片描述

成功调用并输出结果
在这里插入图片描述

原文地址:https://blog.csdn.net/ccjjjjdff/article/details/129746119

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_47836.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注