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

这篇具有很好参考价值的文章主要介绍了AndroidNDK开发——使用Cmake编译生成so文件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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})

cmake生成so文件,Android串口开发,android,kotlin,android studio

2.添加Cmake依赖:

externalNativeBuild {
    cmake {
        cppFlags ""

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

    }
}

cmake生成so文件,Android串口开发,android,kotlin,android studio

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

cmake生成so文件,Android串口开发,android,kotlin,android studio

3.jni文件如下:

cmake生成so文件,Android串口开发,android,kotlin,android studio

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文件,本文只是举例没有全部生成.
cmake生成so文件,Android串口开发,android,kotlin,android studio

9.项目中引入so文件:

如果不引入so文件初始化和调用时会报错,提示找不到so文件,一定要记得配置!一定要记得配置!一定要记得配置!
cmake生成so文件,Android串口开发,android,kotlin,android studio
cmake生成so文件,Android串口开发,android,kotlin,android studio

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.运行效果如下:

cmake生成so文件,Android串口开发,android,kotlin,android studio

12.打印日志如下:

cmake生成so文件,Android串口开发,android,kotlin,android studio

13.总结:

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

14.项目源码如下:

https://gitee.com/jackning_admin/compilesodemo文章来源地址https://www.toymoban.com/news/detail-609126.html

到了这里,关于AndroidNDK开发——使用Cmake编译生成so文件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • CMake学习笔记-VSCode使用Cmake编译C++工程

    Win + MinGW + CMake + Git 官方教程1: https://cmake.org/cmake/help/latest/guide/tutorial/A%20Basic%20Starting%20Point.html 官方教程2: https://cmake.org/cmake/help/book/mastering-cmake/cmake/Help/guide/tutorial/index.html 官方练习材料1:https://github.com/Kitware/CMake.git 官方练习材料2:https://github.com/Kitware/CMake/blob/master/Help/guide

    2024年02月11日
    浏览(42)
  • vscode Cmake 多目录,多文件夹,多文件联合编译配置

    前言:网上好多同学发的都是单目录(一个文件夹下),多个cpp文件的联合编译。对于多文件夹,多目录,多个CPP文件的编译可查询的资料查起来不是很容易。 现在来总结一下: 一、单文件夹(即单目录)下的多.cpp使用code runner 运行代码的方式。               其他博文有

    2024年01月15日
    浏览(40)
  • (不用手动下文件)opencv用CMake编译下载失败解决

    报错信息: 解决思路: 更改cmake文件,使用GitHub Proxy 代理加速 (ghproxy.com)对网址进行转发。、 解决步骤: ① 打开opencv-4.7.0cmakeOpenCVDownload.cmake,在157行下方增加两行: (opencv-4.7.0为 源码文件夹 ,不同版本的名称会不一样,如opencv-4.6.0等等) ② 修改完如下图所示(修改完

    2024年02月03日
    浏览(27)
  • CMake不生成QT的UI头文件

    QT版本5.14.2:: MSVC_2017_64 编译器VS2019 因为学习QT开发的时候要查看x.ui文件转换成ui_x.h头文件的内容,但是编译器编译的时候没有生成ui_x.h头文件。查看代码发现: 已经引用到了该文件了。可能是编译过程中,生成了,使用了,然后又删掉了。 学习过程,想看到里面的内容 打开

    2024年02月12日
    浏览(34)
  • C++服务器框架开发11——编译调试1/cmake学习

    该专栏记录了在学习一个开发项目的过程中遇到的疑惑和问题。 其教学视频见:[C++高级教程]从零开始开发服务器框架(sylar) 上一篇:C++服务器框架开发10——日志系统1~9代码 学习到第6个视频的00:59,由于不了解编译,这次先学习下cmake。下图是CMakeLists.txt中的内容。 参考自文

    2024年02月16日
    浏览(42)
  • Visual Studio连接Linux服务器编译CMake项目,生成在Linux上运行的程序

    window系统:Windows 10 企业版 64位操作系统 Linux系统:BigCloud Enterprise Linux 7.8 (Core) Visual Studio:Microsoft Visual Studio Enterprise 2019 版本 16.10.4 根据Microsoft官网文档介绍, 开始之前 首先,请确保已安装 Visual Studio Linux 工作负载,包括 CMake 组件。 它属于 Visual Studio 安装程序中的“使用

    2024年02月13日
    浏览(70)
  • Windows使用cmake编译dll

    CMake MinGW CMake工具负责将CMakeLists.txt配置文件转换成相关的MakeFile脚本,本身并不参与编译,而是使用MinGW工具进行编译。 在Linux系统使用CMake编译需要执行以下命令即可编译出相关产物,但在Windows要使用MinGW工具编译需要在执行cmake命令时,添加相关的参数,即 -G \\\"MinGW Makefil

    2024年02月11日
    浏览(49)
  • Ubuntu使用cmake和vscode开发自己的项目,引用自己的头文件和openCV

    创建文件夹 继续创建include 和 src文件夹,形成如下的目录结构 用vscode打开项目 创建add.h add.cpp main.cpp 形成这样的目录结构 在my_proj中创建CMakeLists.txt,写入如下内容 BUILD_TYPR 设置为Debug可以打断点调试 在my_proj中创建build.sh,写入如下内容 修改build.sh文件的权限 运行build.sh 在

    2024年02月07日
    浏览(32)
  • CMake教程系列-02-使用cmake代码生成二进制

    参考:Cmake安装以及升级(Ubuntu) Win10安装文件: 创建的目录以及代码如下: CMakeLists.txt sample.cpp 目录结构如下:注意多创建一个build目录存放中间文件和最终二进制文件 点击“Configure 我的的vs是2019,在Configure中选择了 点击“Configure”右边的“Generate”。 点击“Generate”右边

    2024年02月04日
    浏览(45)
  • 【VSCode】Windows环境下,VSCode 搭建 cmake 编译环境(通过配置文件配置)

    除了之前的使用 VSCode 插件来编译工程外,我们也可以使用配置文件来编译cmake工程,主要依赖 launch.json 和 tasks.json 文件。 目录 一、下载编译器 1、下载 Windows GCC 2、选择编译器路径 二、配置 debug 环境 1、配置 lauch.json 文件 2、配置 tasks.json 文件 三、编译工程 1、测试工程结

    2024年02月03日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包