IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> cmake编译NDK初体验 -> 正文阅读

[Java知识库]cmake编译NDK初体验

?本文用一个demo验证Android?Studio如何编译生成一个C++动态库文件(so文件)?给?Java应用层使用。然后这个so库内部又如何调用?一个预有so库中的?C语言函数。


1. 新建一个NDK工程


?1.1 ?新建一个android studio Native C++工程

在main/cpp目录下默认有一个native-lib.cpp,还有一个CMakeList.txt文件(编译脚本),其中

native-lib.cpp实现了从JNI里返回一个C++字符串,具体代码如下:

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring
Java_com_example_ndktest_MainActivity_stringFromJNI(JNIEnv* env,jobject) {
?? ?std::string hello = "Hello from cppmain";
? ? return env->NewStringUTF(hello.c_str());
}

其中env->NewStringUTF(hello.c_str());将C++字符串hello转换成了jstring类型(JNI可以传递给JAVA的字符串类型)

?1.2 配置build.gradle

我们把CMakeList.txt移动到app moudle的根目录下,即与app模块下的build.gradle放在同一目录下,在以下脚本3中设置cmake中的path(CMakeList.txt编译脚本的存放路径),path值直接就是CMakeList.txt。


?android--defaultcofig--下添加如下脚本
?
?脚本1:

? ?externalNativeBuild {
? ? ? ? ? ? cmake {
? ? ? ? ? ? ? ? abiFilters 'armeabi-v7a'
? ? ? ? ? ? }
? ?}
?注解:表示只编译armeabi-v7a CPU架构下已经存放的的so库。
?
?脚本2:
?
? ?ndk{
? ? ? ?abiFilters 'armeabi-v7a'
? ?}
? ?注解:表示只生成armeabi-v7a CPU架构下的so库,并打包到APP里。
?同时,添加这个脚本是为了解决这个问题:用android studio直接运行项目会报错,找不到最终生成的libnative-lib.so,只有build生成apk,然后传到手机上运行才不报错。
?添加了这个ndk脚本后就一切正常了。具体原因还需进一步研究下。
?
?脚本3(在android配置下添加):
?
? ? externalNativeBuild {
? ? ? ? cmake {
? ? ? ? ? ? path "CMakeLists.txt"
? ? ? ? ? ? version "3.10.2"
? ? ? ? }
? ? }
注解:其中path是CMakeLists编译脚本文件的路径,以 path "CMakeLists.txt"为例,表示CMakeLists.txt文件在android studio工程的主app模块根目录下,与app模块的build.gradle文件在同一目录下。version "3.10.2"使用的CMake编译工具的版本。
?? ?


2. 在native-lib.cpp中的stringFromJNI数里调用另一个so库libTest.so中的test()方法


2.1 修改native.cpp的stringFromJNI函数:调用test()

#include <jni.h>
#include <string>
#include <android/log.h>

extern "C"{
? ?extern int test();
}

extern "C" JNIEXPORT jstring
Java_com_example_ndktest_MainActivity_stringFromJNI(JNIEnv* env,jobject) {
? ? std::string hello = "Hello from cppmain";
? ? __android_log_print(ANDROID_LOG_ERROR,"jni","libtest.so 里面的 test 方法:%d",test());
? ? return env->NewStringUTF(hello.c_str());
}

(1)相比之前加了这样代码: ?__android_log_print(ANDROID_LOG_ERROR,"jni","libTest.so 里面的 test 方法:%d",test()); 折行代码用于打印日志,输出test()方法返回的int值。

(2)要调用test()方法,首先得用extern声明外部原型,因为test()函数的实现是在其它C语言文件里。加了一个extern "C"是因为test()是一个C语言程序,要在C++里调用C代码必须得声明关键字extern "C".


2.2 拷贝libTest.so库到我们新建的NDK项目中

将libTest.so复制到src/main/jniLibs/armeabi-v7a目录下,我们在此只编译armeabi-v7a CPU架构的so库


2.3 修改CMakeList.txt编译脚本,引入第三方库libTest.so,并链接到本地要生成的libnative-lib.so库

?脚本如下:

cmake_minimum_required(VERSION 3.10.2)?

#声明项目名 ?
project("ndktest") ? ? ??

#将.C文件与C++(就是cpp)文件的查找路径赋值给一个变量source,多个文件路径用空格隔开。
file(GLOB source src/main/cpp/*.c src/main/cpp/*.cpp src/main/cpp/a/*.cpp ) ?

#将C/C++源码编译,生成一个本地so动态库,库名是native-lib,源码路径就是上面那个source变量的值,${source}取值,SHARED表示将cmake要编译生成的动态库(so文件)
add_library( # Sets the name of the library.
? ? ? ? native-lib
? ? ? ? SHARED
? ? ? ? ${source}) ? # 在此项目中也可直接在此填写? src/main/cpp/native-lib.cpp

?# 将下面的log库的路径赋值给log-lib, 用于target_link_libraries中链接到将要生成的本地native- lib库

find_library(?
? ? ? ? log-lib? ? ? ?
? ? ? ? log ? ? ?# log库的路径,因为log为系统库,所以只需要名字,cmake就知道其路径了
?? ??? ?)
?? ??? ?
?? ??? ?
#配置第三方Test.so库的链接路径,我们的Test.so库放在了armeabi-v7a下,2.1中已经提到。
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a")


#将Test库,log库与本地将要生成的动态库链接在一起,这样native-lib库里的stringFromJNI函数就可以调用test()函数与log库中的__android_log_print()函数了。
target_link_libraries( # Specifies the target library.
? ? ? ? native-lib
? ? ? ? Test

? ? ? ? # Links the target library to the log library?included in the NDK.
? ? ? ? ${log-lib}

? ? ? ? )
?? ??? ?
?? ??? ?
3. 在java层调用本地库native-lib.so中的JNI函数stringFromJNI

?public class MainActivity extends AppCompatActivity {
? ? static {
? ? ? ? System.loadLibrary("native-lib");
? ? }
? ? @Override
? ? protected void onCreate(Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? setContentView(R.layout.activity_main);
? ? ? ? TextView tv = findViewById(R.id.sample_text);
? ? ? ? tv.setText(stringFromJNI());
? ? }
? ? public native String stringFromJNI();
}

??

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-09-03 11:46:23  更:2021-09-03 11:47:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:00:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码