AndroidNDK开发——使用Cmake编译生成so文件

news2024/11/16 0:03:09

文章目录

  • AndroidNDK开发——使用Cmake编译生成so文件
  • 1.添加Cmake文件:
  • 2.添加Cmake依赖:
  • 3.jni文件如下:
  • 4.Android.mk文件:
  • 5.Application.mk文件
  • 6.SerialPort.c文件:
  • 7.SerialPort.h文件:
  • 8.运行项目:
  • 9.项目中引入so文件:
  • 10.Java调用so的测试代码如下:
  • 11.运行效果如下:
  • 12.打印日志如下:
  • 13.总结:
  • 14.项目源码如下:

AndroidNDK开发——使用Cmake编译生成so文件

最近做串口开发需要编译不同的so文件,于是查找了各种资料,学习了一下so编译.

1.添加Cmake文件:

cmake_minimum_required(VERSION 3.4.1) //cmake版本

include_directories(src/main/jni/serial_port)   //引入的jni文件路径
aux_source_directory(src/main/jni SRC_FILE)		//src文件路径

add_library(serial_port SHARED ${SRC_FILE})
find_library(log-lib log)

target_link_libraries(serial_port ${log-lib})

在这里插入图片描述

2.添加Cmake依赖:

externalNativeBuild {
    cmake {
        cppFlags ""

        abiFilters "arm64-v8a","armeabi-v7a"//生成的so平台类型

    }
}

在这里插入图片描述

externalNativeBuild {
    cmake {
        path 'CMakeLists.txt'//Cmake地址
    }
}

在这里插入图片描述

3.jni文件如下:

在这里插入图片描述

4.Android.mk文件:

#
# Copyright 2009 Cedric Priscal
# 
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
# http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License. 
#

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

TARGET_PLATFORM := android-3
LOCAL_MODULE    := serial_port  //模块名称
LOCAL_SRC_FILES := SerialPort.c
LOCAL_LDLIBS    := -llog

include $(BUILD_SHARED_LIBRARY)

5.Application.mk文件

APP_ABI := arm64-v8a,armeabi-v7a//配置abi平台

6.SerialPort.c文件:

/*
 * Copyright 2009-2011 Cedric Priscal
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>

#include "SerialPort.h"

#include "android/log.h"
static const char *TAG="serial_port";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO,  TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)

static speed_t getBaudrate(jint baudrate)
{
   switch(baudrate) {
   case 0: return B0;
   case 50: return B50;
   case 75: return B75;
   case 110: return B110;
   case 134: return B134;
   case 150: return B150;
   case 200: return B200;
   case 300: return B300;
   case 600: return B600;
   case 1200: return B1200;
   case 1800: return B1800;
   case 2400: return B2400;
   case 4800: return B4800;
   case 9600: return B9600;
   case 19200: return B19200;
   case 38400: return B38400;
   case 57600: return B57600;
   case 115200: return B115200;
   case 230400: return B230400;
   case 460800: return B460800;
   case 500000: return B500000;
   case 576000: return B576000;
   case 921600: return B921600;
   case 1000000: return B1000000;
   case 1152000: return B1152000;
   case 1500000: return B1500000;
   case 2000000: return B2000000;
   case 2500000: return B2500000;
   case 3000000: return B3000000;
   case 3500000: return B3500000;
   case 4000000: return B4000000;
   default: return -1;
   }
}

/*
 * Class:     android_serialport_SerialPort
 * Method:    open
 * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;
 */
JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open
  (JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint flags)
{
   int fd;
   speed_t speed;
   jobject mFileDescriptor;

   /* Check arguments */
   {
      speed = getBaudrate(baudrate);
      if (speed == -1) {
         /* TODO: throw an exception */
         LOGE("Invalid baudrate");
         return NULL;
      }
   }

   /* Opening device */
   {
      jboolean iscopy;
      const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);
      LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);
      fd = open(path_utf, O_RDWR | flags);
      LOGD("open() fd = %d", fd);
      (*env)->ReleaseStringUTFChars(env, path, path_utf);
      if (fd == -1)
      {
         /* Throw an exception */
         LOGE("Cannot open port");
         /* TODO: throw an exception */
         return NULL;
      }
   }

   /* Configure device */
   {
      struct termios cfg;
      LOGD("Configuring serial port");
      if (tcgetattr(fd, &cfg))
      {
         LOGE("tcgetattr() failed");
         close(fd);
         /* TODO: throw an exception */
         return NULL;
      }

      cfmakeraw(&cfg);
      cfsetispeed(&cfg, speed);
      cfsetospeed(&cfg, speed);

      if (tcsetattr(fd, TCSANOW, &cfg))
      {
         LOGE("tcsetattr() failed");
         close(fd);
         /* TODO: throw an exception */
         return NULL;
      }
   }

   /* Create a corresponding file descriptor */
   {
      jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");
      jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>", "()V");
      jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");
      mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);
      (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd);
   }

   return mFileDescriptor;
}

/*
 * Class:     cedric_serial_SerialPort
 * Method:    close
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_close
  (JNIEnv *env, jobject thiz)
{
   jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
   jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");

   jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
   jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");

   jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);
   jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);

   LOGD("close(fd = %d)", descriptor);
   close(descriptor);
}

jstring Java_com_example_compilesodemo_MainActivity_sayHello(JNIEnv* env,jobject jobj){
   char* text="I am from C";
   return (*env)->NewStringUTF(env,text);
}

7.SerialPort.h文件:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class android_serialport_api_SerialPort */

#ifndef _Included_android_serialport_api_SerialPort
#define _Included_android_serialport_api_SerialPort
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     android_serialport_api_SerialPort
 * Method:    open
 * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;
 */
JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open
  (JNIEnv *, jclass, jstring, jint, jint);

/*
 * Class:     android_serialport_api_SerialPort
 * Method:    close
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_close
  (JNIEnv *, jobject);


#ifdef __cplusplus
}
#endif
#endif

8.运行项目:

直接跑项目或者使用gradle构建so生成的so文件如下:这里大家根据自己的需求配置生成so文件,本文只是举例没有全部生成.
在这里插入图片描述

9.项目中引入so文件:

如果不引入so文件初始化和调用时会报错,提示找不到so文件,一定要记得配置!一定要记得配置!一定要记得配置!
在这里插入图片描述
在这里插入图片描述

10.Java调用so的测试代码如下:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getName();

    {
        System.loadLibrary("serial_port");//加载so库
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        TextView textView =  ((TextView)findViewById(R.id.tv_test));
        textView.setText(sayHello());
        Log.d(TAG,"-----传入的数据为:------"+ textView.getText().toString());
    }

    public native String sayHello();//调用jni方法
}

11.运行效果如下:

在这里插入图片描述

12.打印日志如下:

在这里插入图片描述

13.总结:

可以看到项目demo成功运行,期前也遇到不少问题,so的加载和调用,jni初始化,数据传递等等,如果有兴趣的同学可以自己去试试,学到手的东西才是自己的。本文是以串口通信的so为例,所以里面的头文件及数据调用的方法都是在加载串口数据,不过我为了测试所以暂时只写了一个简单的,因为测试串口需要设备和串口通信助手,这里先不讲,后面有空会逐一讲解串口通信流程和实战demo.

14.项目源码如下:

https://gitee.com/jackning_admin/compilesodemo

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/420251.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

剑指 Offer II 049. 从根节点到叶节点的路径数字之和

中等题题目 &#xff1a; 给定一个二叉树的根节点 root &#xff0c;树中每个节点都存放有一个 0 到 9 之间的数字。 每条从根节点到叶节点的路径都代表一个数字&#xff1a; 例如&#xff0c;从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。计算从根节点到叶节点生…

BloombergGPT: 首个金融垂直领域大语言模型

BloombergGPT: 首个金融垂直领域大语言模型 Bloomberg 刚刚发布了一篇研究论文&#xff0c;详细介绍了他们最新的突破性技术 BloombergGPT。BloombergGPT是一个大型生成式人工智能模型&#xff0c;专门使用大量金融数据进行了训练&#xff0c;以支持金融行业自然语言处理 (NLP…

ORACLE EBS 系统架构与应用实践(一)

一、从ERP到EBS 从上世纪70年代晚期的物料需求计划MRP&#xff08;Material Requirements Planning&#xff09;到80年代的MRP II&#xff0c;再到90年代的企业资源计划ERP&#xff08;Enterprise Resource Planning&#xff09;&#xff0c;企业管理软件&#xff08;或曰应用…

直播|StarRocks 3.0 极速统一的湖仓新范式

近期&#xff0c;StarRocks V3.0 RC 版本发布。自此&#xff0c;StarRocks 开启了从 OLAP 到 Lakehouse 演进的新篇章。 全新升级的 StarRocks 3.0&#xff1a; 通过存算分离架构&#xff0c;帮助用户降低存储成本、提升计算弹性 通过数据湖分析、物化视图等特性简化湖仓融合…

从“高内聚,低耦合”说起

从“高内聚&#xff0c;低耦合”说起 记得在上学的时候&#xff0c;⽼师就说过“⾼内聚&#xff0c;低耦合”&#xff0c;但当初对这句话的理解⽐较浅显。⼯作之后&#xff0c;为了说服别⼈采⽤⾃⼰设计的⽅案&#xff0c;常常说“……这样就做到了⾼内聚&#xff0c;低耦合……

【C语言 - 初阶指针 概念、类型、野指针、指针运算】

C语言 - 初阶指针一 指针概念注意&#xff1a;指针变量的大小&#xff1a;&#xff08;与指向的数据类型无关&#xff09;二 指针类型2.1指针类型的含义&#xff1a;2.1.1 不同指针类型决定解引用时候权限不同&#xff1a;总结&#xff1a;2.1.2 任何类型的指针变量都能存放地址…

10 个高级 Python 面试问题

随着 Python 最近变得越来越流行&#xff0c;你们中的许多人可能正在接受与 Python 打交道的技术面试。在这篇文章中&#xff0c;我将列出十个高级 Python 面试问题和答案。 这些内容可能会令人困惑&#xff0c;并且针对的是中级开发人员&#xff0c;他们需要对 Python 作为一…

RB-PEG-COOH,罗丹明聚乙二醇羧基化学试剂简介;RhodamineB-PEG-acid

RB-PG-COOH, 罗丹明聚乙二醇羧基 中文名称&#xff1a;罗丹明-聚乙二醇-羧基 英文名称&#xff1a;RhodamineB-PEG-acid RB-PEG-COOH 性状&#xff1a;固体或粘性液体&#xff0c;取决于分子量 溶剂&#xff1a;溶于水和DCM、DMF、DMSO等常规性有机溶剂 分子量&#xff1…

归排、计排深度理解

归并排序&#xff1a;是创建在归并操作上的一种有效的排序算法。算法是采用分治法&#xff08;Divide and Conquer&#xff09;的一个非常典型的应用&#xff0c;且各层分治递归可以同时进行。归并排序思路简单&#xff0c;速度仅次于快速排序&#xff0c;为稳定排序算法&#…

ICMP隧道技术实现防火墙穿透

1.在mac os的虚拟机里准备三台kali 三台主机ip地址分别是 192.168.1.15&#xff0c;192.168.1.16&#xff0c;192.168.1.17&#xff0c; 为方便描述 依次把他们暂且命名为主机A,主机B,主机C 2.在主机C 上打开终端&#xff0c;输入 cd /usr/local/src 然后新建一个hello.txt 文…

最新版人脸识别小程序 图片识别 生成二维码签到 地图上选点进行位置签到 计算签到距离 课程会议活动打卡日常考勤 上课签到打卡考勤口令签到

技术选型 1&#xff0c;前端 小程序原生MINA框架 css JavaScript Wxml 2&#xff0c;管理后台 云开发Cms内容管理系统 web网页 3&#xff0c;数据后台 小程序云开发 云函数 云开发数据库&#xff08;基于MongoDB&#xff09; 云存储 4&#xff0c;人脸识别算法 基于百度…

xxl-job定时任务调度中心的配置以及整合到自己的项目中实现远程调用

目录 前言&#xff1a; xxl-job配置与启动&#xff1a; xxl-job-admin: xxl-job-execultor--sample-springboot: 启动任务调度中心&#xff1a; ​编辑 调用定时任务&#xff1a; ​编辑 在自己的项目中配置xxl-job&#xff1a; 项目结构&#xff1a; ​编辑 AdUp…

【CSS】更改用户界面样式 ② ( 取消轮廓线 outline | 取消轮廓线设置方式 outline: 0; | 代码示例 )

文章目录一、更改轮廓线 outline二、轮廓线代码示例三、取消轮廓线代码示例一、更改轮廓线 outline 轮廓线 是 元素 边框 外面 的一条线 , 其作用是 选中后突出元素 ; 一般情况下都会去掉 轮廓线 显示 ; outline 样式后可设置 1 ~ 3 个参数 , 按照顺序分别是 : outline-color…

JavaScript-DOM基础

DOM介绍 事件介绍 文档加载 DOM查询 DOM介绍 DOM&#xff0c;全称Document Object Model文档对象模型。浏览器已经提供了文档节点对象 时window属性&#xff0c;可以在页面中直接使用&#xff08;document文档节点代表整个网页&#xff09; <button id "btn&qu…

【Linux 裸机篇(三)】I.MX6ULL 启动方式

目录一、启动方式选择1. 串行下载2. 内部 BOOT 模式2.1 BOOT ROM 初始化内容2.2 启动设备二、镜像烧写1. IVT2. Boot data3. DCD数据一、启动方式选择 I.MX6ULL 芯片上电后&#xff0c;芯片会根据 BOOT_MODE[1:0]的设置来选择 BOOT 方式。BOOT_MODE[1:0]的值是可以改变的&#…

【ONE·C++ || list (一)】

总言 主要介绍list的基本函数使用及部分函数接口模拟实现(搭框架)。 文章目录总言1、常用接口与举例演示1.1、接口总览1.2、部分例子1.2.1、头删、头插、尾删、尾插、遍历1.2.2、pos插入删除、迭代器失效问题1.2.3、一些相对陌生接口简介&#xff08;std::sort和list::sort比较…

D. Captain Flint and Treasure(拓扑排序 + 贪心)

Problem - D - Codeforces 芬特队长参与了另一个寻宝活动&#xff0c;但只发现了一个奇怪的问题。这个问题可能与宝藏的位置有关&#xff0c;也可能不是。这就是为什么弗林特船长决定把解决问题的工作交给他的船员&#xff0c;并提供了一个高得离谱的奖励:休息一天。问题本身听…

【日常】我的扬马最后一小时

文章目录1 Approxmation, Regularization and Relaxation赛前风波惨痛的主场之战释然的痛苦之路后记1 Approxmation, Regularization and Relaxation 在算法理论研究中&#xff0c;为了使得降低问题的求解复杂度&#xff0c;常常会选择牺牲算法的选择求解精度&#xff0c;这种…

Redis-----什么是Redis?

什么是Redis&#xff1f; redis是一个基于内存的key-value结构数据库。 基于内存存储&#xff0c;读写性能高适合存储热点数据&#xff08;热点商品、资讯、新闻&#xff09;企业应用广泛 Redis入门 redis简介 redis是一个开源的内存中的数据结构存储系统&#xff0c;数据库…

ASP宿舍管理系统设计与实现

学生宿舍的管理工作也将成为一项十分繁重的工作&#xff0c;建立一个学生宿舍管理系统是非常必要的&#xff0c;可行的。计算机能够极大地提高学生宿舍管理的办事效率&#xff0c;学校要想与先进科学技术接轨&#xff0c;就得科学化、正规化的进行管理。随着社会信息化步伐的加…