C++项目工程(包含opencv库以及项目的依赖库移植)编译成android可以使用的so库并在Android studio上调用so库进行使用(血泪操作总结)

2023-05-16

目录结构

  • 概述
    • 预先准备
    • 编译操作
    • so的函数导出并在android进行调用

概述

  最近负责一个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-android-sdk。
先简单说下Android库的头文件目录和库文件目录的链接导入:
头文件位于:\opencv-3.4.15-android-sdk\OpenCV-android-sdk\sdk\native\jni\include
在这里插入图片描述
库文件位于:
\opencv-3.4.15-android-sdk\OpenCV-android-sdk\sdk\native\3rdparty\libs
\opencv-3.4.15-android-sdk\OpenCV-android-sdk\sdk\native\libs
\opencv-3.4.15-android-sdk\OpenCV-android-sdk\sdk\native\staticlibs
在这里插入图片描述
  上图中第一个附加库目录是我的c++项目需要依赖的库文件libusb,用于调用usb接口进行相应操作,因此也需要将相应库文件添加到附加库目录。这里根据你需要编译的架构类型链接不同版本的库文件,我这里链接的是armeabi-v7a版本,这个版本是比较通用的,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, &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, &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。
所以,接下来就要创建这两个函数的导出:
在这里插入图片描述

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++项目工程(包含opencv库以及项目的依赖库移植)编译成android可以使用的so库并在Android studio上调用so库进行使用(血泪操作总结) 的相关文章

  • golang中的flag模块小结

    1 flag常用函数 无论是c语言还是golang语言或是其他语言 xff0c 启动应用程序时都可以带一些参数 xff0c 然后系统根据传入的参数进行特点的工作 如 xff1a main mode online model bert ch
  • Redis批量操作详解及性能分析

    通过mget批量执行指令可以节约网络连接和数据传输开销 xff0c 在高并发场景下可以节约大量系统资源 本文中 xff0c 我们更进一步 xff0c 比较一下redis提供的几种批量执行指令的性能 1 为什么需要批量执行redis指令 众所
  • NDCG:推荐系统/搜索评价指标

    本文转载自 胖喵 博主 xff0c 详细请看https www cnblogs com by dream p 9403984 html 1 CG xff1a 累计增益 CG xff0c cumulative gain xff0c 只考虑到了
  • 特征共线性问题

    多重共线性是使用线性回归算法时经常要面对的一个问题 在其他算法中 xff0c 例如决策树或者朴素贝叶斯 xff0c 前者的建模过程时逐渐递进 xff0c 每次都只有一个变量参与 xff0c 这种机制含有抗多重共线性干扰的功能 xff1b 后
  • 常见回归和分类损失函数比较

    文章转自知乎作者wdmad xff0c 更多内容建议阅读原文 xff1a https zhuanlan zhihu com p 36431289 本博文属于阅读笔记 xff0c 融合了个人观点 1 损失函数 损失函数的一般表示为 L y f
  • 获取keras中间层输出、模型保存与加载

    1 获取keras中间层输出 model summary and plot import keras from keras models import Model from keras utils import plot model Doc
  • HashMap底层实现和原理

    本文是在阅读知乎老刘作品后的整理 内容基于JDK1 7进行分析 xff0c 1 8做的改动文章末尾进行讲解 1 基本要义 1 1 概述 Hashmap在Map派生中的位置 HashMap基于Map接口实现 xff0c 元素以键值对的方式存储
  • 大疆激光雷达Livox Avia开箱及测试

    大疆激光雷达Livox Avia 箱子 从左至右为 xff1a 大疆激光雷达Livox Avia xff0c 电源转接插座 xff0c 内六角形L型扳手 xff0c 镜头清洁布 xff0c 螺钉包 xff0c 说明书 xff0c 1 5米航
  • Go协程与协程池

    1 Golang协程 golang和其它语言最大区别莫过于goroutine xff0c 也就是go的协程 xff0c example如下 xff1a package main import 34 fmt 34 import 34 time
  • Go协程池设计思路(Task-Job-Worker)

    1 铺垫 xff1a Go 的接收器Receiver 在go语言中 xff0c 没有类的概念 xff0c 但是可以给类型 xff08 结构体 xff0c 自定义类型 xff09 定义方法 所谓方法就是定义了接受者的函数 接受者定义在func
  • 系统间通信1:阻塞与非阻塞式通信A

    版权声明 xff1a 本文引用https yinwj blog csdn net article details 48274255 从这篇博文开始 xff0c 我们将进入一个新文章系列 这个文章系列专门整理总结了目前系统间通信的主要原理 手
  • 系统间通信1:阻塞与非阻塞式通信B

    版权声明 xff1a 本文引用https yinwj blog csdn net article details 48274255 接上篇 xff1a 系统间通信1 xff1a 阻塞与非阻塞式通信A 4 3 NIO通信框架 目前流行的NIO
  • 系统间通信2:通信管理与远程方法调用RMI

    本文引用 https yinwj blog csdn net article details 49120813 RMI Remote Method Invocation xff0c 远程方法调用 RPC Remote Procedure C
  • 系统间通信3:RPC的基本概念

    本文引用 https yinwj blog csdn net article details 49453303 1 概述 经过了详细的信息格式 网络IO模型的讲解 xff0c 并且通过JAVA RMI的讲解进行了预热 从这篇文章开始我们将进
  • 系统间通信4:基本IO通信模型

    本文引用 https blog csdn net yinwenjie article details 48472237 目前常用的IO通信模型包括四种 xff1a 阻塞式同步IO 非阻塞式同步IO 多路复用IO和真正的异步IO 所有IO模式
  • 深入理解Golang中的Context包

    context Context是Go语言中独特的设计 xff0c 在其他编程语言中我们很少见到类似的概念 context Context深度支持Golang的高并发 1 Goroutine和Channel 在理解context包之前 xff
  • ubuntu —— 命令行访问网页

    span class hljs variable style margin 0px padding 0px span sudo apt get install w3m span class hljs variable style margi
  • VINS-Mono 加rgbd

    通过对比VINS Mono与其RGBD版本 xff0c 分析其改动思路 一 feature tracker feature tracker node cpp 头文件加入了ros的多传感器时间戳 include lt message filt
  • MFC使用HttpGet和HttpPost方法与服务器通信

    处理过程封装到CHttpClient类中 同时支持http和https HttpClient h cpp view plain copy HttpClient h ifndef HTTPCLIENT H define HTTPCLIENT
  • 【Micropython】肝货~使用USB_VCP通过USB串口与树莓派或PC端通信

    为什么要使用USB VCP xff1f Micropython有很多串口 xff0c 例如PYboard xff0c 有5个串口可以使用 xff0c 但是 xff0c 平时我们在做一些项目的时候 xff0c 需要使用的引脚较多 xff0c

随机推荐

  • npm 401 BASIC realm=“Sonatype Nexus Repository Manager“

    今天在做vue项目 切换私服nexus npm login时 遇到了下面的问题error Unable to authenticate need BASIC realm 61 34 Sonatype Nexus Repository Man
  • 通过HTTP协议利用VC++ POST通信开发

    转载地址 xff1a https blog csdn net lhsxsh article details 4200486 void CMFCForm1Dlg OnBnClickedOk TODO 在此添加控件通知处理程序代码 CDialo
  • java源码解析JavaParser

    package com bootdo jparser import java io File import java io FileNotFoundException import com github javaparser JavaPar
  • 关于串口通讯查询与中断两种方式

    串口通讯有查询与中断两种方式 2011 09 13 13 31 我们知道串口通讯有查询与中断两种方式 xff0c 但是对于两种方式的区别很多人并不是非常清楚 xff0c 对于两者的实现到底有和不同呢 xff1f 让我们简单的总结如下 xff
  • linux 下postgresql遇到几个问题

    问题1 xff1a Job for postgresql service failed because the control process exited with error code See 34 systemctl status p
  • ActiveMQ连接数过多,导致ActiveMQ无法正常接入数据

    ActiveMQ跑了一段时间 xff0c 会出现连接数据过多的报错 Could not accept connection org apache activemq transport tcp ExceededMaximumConnectio
  • Axure嵌入Echarts图表--javascript (js)注入

    前言 用Axure做Web原型设计时 xff0c 经常会有图表 特别是大屏可视化或者数据可视化的原型中就更为常见 传统的方法是通过既有的图形或者曲线加上文字来实现 由于Axure可以通过javascript注入 的方法进行简单的拓展 xff
  • Axure嵌入Highcharts图表--javascript (js)注入

    前言 上次发现可以通过javascript js 注入实现在Axure 里引用Echarts图表 xff0c 提升原型展现能力 xff0c 特别是在高保真原型 既然可以实现Echarts的图表引用 xff0c 那么能否用同样的方法引用Hig
  • 一个比较好用的网络爬虫软件GooSeeker

    最近要搜集一些新闻语料 xff0c 看论文发现一个叫GooSeeker的爬虫软件还不错 xff0c 看了一天多的教程终于跑起来了 xff0c 趁着这会在抓新浪新闻过来发篇blog 这个爬虫是作为Firefox的插件出现的 一开始还觉得不够强
  • LibreELEC(kodi)安装

    想体验 xff08 折腾 xff09 kodi xff0c 刚好手上有个空置的树莓派 xff0c 而LibreELEC是轻量化kodi分支的开源系统 xff0c 本文介绍自动和手动安装LibreELEC xff08 LE xff09 原文地
  • LibreELEC(kodi)安装 IPTV

    kodi的PVR IPTV Simple Client插件通过直播源可以实现类似电视机顶盒播放电视节目的基本功能 xff0c 本文将介绍LibreELEC xff08 kodi xff09 安装和简单设置的PVR IPTV Simple C
  • Axure中继器组件化GIS地图

    虽然可以使用JavaScript注入的方式将GIS地图嵌入Axure xff0c 但每次使用地图都需要重复嵌入并修改代码 xff0c 不太方便 那么 xff0c 能不能实现组件化呢 xff1f 我们可以使用中继器 xff08 repeate
  • 比特米盒子刷安卓ATV6.0

    最近海鲜市场有很多比特米盒子 xff0c 50多块包邮 xff0c 买来的盒子回来折腾下 xff0c 买回来发现一直卡在 系统启动 34 中无法进入 xff0c 不知道原来的是啥系统 xff0c 看来只能找找线刷的办法 xff0c 重新拯救
  • Visual Studio Code(VSCode) 编辑/编译/调试 C++ 代码

    前言 最近想要切换编辑工具 xff0c 之前工作中使用过 Source Insight xff0c Eclipse xff0c CLion 来写 C 43 43 代码 目前来说 Source Insight 已经非常古老 xff0c 只有编
  • Visual Studio Code(vscode) 格式化C++代码

    前言 vscode 自带的代码格式化工具不太好用 xff0c 因此我们需要有额外的代码格式化插件进行辅助 xff0c 一般情况下都使用 clang format 格式化 xff0c 这里是对 vscode 安装和使用 clang forma
  • C++如何监听http请求

    下面有个例子 xff0c 基于 Windows 的 xff0c 编译完 xff0c 运行 WebSrv 7070 即可 在程序的目录中放一个 index html 文件 Copyright c 2002 2005 by Zhang Huiy
  • 我的网页作品(div+css)

    前段时间为一个育儿网站做了一个个人空间主页 xff0c 这可是我的处女座 呵呵 请点击查看 xff1a Files shiyangxt baobaoke rar
  • 我用Visual Basic做的多模式计算器(应用小软件)!

    前一段时间参加了一个校内组织的IT实践大赛 xff0c 虽然当时没什么成熟的技术 xff0c 但是还是参加了 Visual Basic刚学也没多长时间 xff0c 于是就做了这个多模式计算器 xff0c 虽然技术含量不算高 xff0c 一些
  • C语言实现阶乘累加(1!+2!+3!+....+n!=?)

    最近要期末考试 xff0c 复习C语言 xff0c 见到一个看似很简单的问题 就是C语言实现阶乘累加 xff08 1 xff01 43 2 xff01 43 3 43 43 n 61 xff09 本来觉得这个肯定小意思 xff0c 但是修改
  • C++项目工程(包含opencv库以及项目的依赖库移植)编译成android可以使用的so库并在Android studio上调用so库进行使用(血泪操作总结)

    目录结构 概述预先准备编译操作so的函数导出并在android进行调用 概述 最近负责一个android项目需要使用到之前公司师兄编写的c 43 43 算法库 xff0c 一开始并不知道c 43 43 项目可以移植给android项目使用