Qt应用开发(安卓篇)——调用ioctl、socket等C函数

一、前言

        在 Qt for Android 中没办法像在嵌入式linux中一样直接使用 ioctl 等底层函数,这是因为因为 Android 平台的安全性和权限限制。

        在 Android 中,访问设备硬件和系统资源需要特定的权限,并且需要通过 Android 系统提供的 API 来进行。Android 平台为了保障系统的安全性和稳定性,限制了应用程序对底层硬件和系统的直接访问。

        Qt for Android 是建立在 Android NDK 和 Java 层之上的,它提供了一种跨平台的开发框架,允许开发者使用 C++ 和 Qt API 来开发 Android 应用程序。但是,由于 Android 平台的限制,Qt for Android 也受到了 Android 平台的限制,无法直接访问底层设备或调用底层系统函数。

        我们需要通过 Java 层的 JNI 接口来间接访问,通过 JNI 接口调用底层的系统函数或设备驱动程序,主要分两步:

  1. 实现 JNI 方法: 在 C 语言中实现这些本地方法。

  2. 加载并链接 JNI 库: 在 Qt 项目中加载并链接 JNI 库,以便在 Qt/C++ 代码中调用本地方法。

        下面我们通过一个socketcan的调用实例才讲解。

二、编写 JNI 接口

        在Android路径下,新建一个jni文件夹,新建文件socketcan_native.c,部分代码内容如下:

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <fcntl.h>
#include <string.h>#define	STATUS_OK					0
#define STATUS_ERR					-1static int sock_fd;
static int m_isopen;void sockcan_close()
{close(sock_fd);system(ip_cmd_can_close);m_isopen = STATUS_ERR;
}
int sockcan_open(int bitrate)
{//创建套接口sock_fd = socket(AF_CAN,SOCK_RAW,CAN_RAW);if(sock_fd < 0){return STATUS_ERR;}//绑定can0设备与套接口struct ifreq ifr;struct sockaddr_can addr;strcpy(ifr.ifr_name,"can0");ioctl(sock_fd,SIOCGIFINDEX,&ifr);ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name);addr.can_family = AF_CAN;addr.can_ifindex = ifr.ifr_ifindex;if(bind(sock_fd,(struct sockaddr *)&addr,sizeof(addr))<0){perror("bind error!\n");return STATUS_ERR;}//配置int flags;flags = fcntl(sock_fd,F_GETFL,0);// flags |= O_NONBLOCK;//非阻塞flags &= ~O_NONBLOCK;//阻塞fcntl(sock_fd,F_SETFL,flags);m_isopen = STATUS_OK;return STATUS_OK;
}JNIEXPORT jint JNICALL
JJava_com_example_socketcan_SocketCANJNI_socketCanOpen(JNIEnv *env, jobject thiz, jint baudrate)
{return sockcan_open(baudrate);
}JNIEXPORT jint JNICALL
Java_com_example_socketcan_SocketCANJNI_socketCanWrite
(JNIEnv *env, jobject thiz, jint canId,jint dataLen,jint externFlag,jint remoteFlag,jbyteArray datas)
{if(sock_fd <= 0)return -1;if(dataLen > 8)return -2;//获取实例的变量array的值int nArrLen = (*env)->GetArrayLength(env,datas);char *chArr = (char*)(*env)->GetByteArrayElements(env,datas, 0);struct can_frame txframe;memcpy(txframe.data, chArr, nArrLen);txframe.can_id = canId;if(externFlag)txframe.can_id |= CAN_EFF_FLAG;if(remoteFlag)txframe.can_id |= CAN_RTR_FLAG;txframe.can_dlc = dataLen;return write(sock_fd, &txframe, sizeof(struct can_frame));
}

        如果是cpp的文件,在JNIEXPORT jint JNICALL前面需要添加extern "C" ,并且有一些指针写法需要小改。

        在Android/jni文件夹下,新建文件Android.mk,内容如下:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := socketcan_native
LOCAL_SRC_FILES := socketcan_native.cinclude $(BUILD_SHARED_LIBRARY)

        然后在该目录使用ndk对其进行打包生成so文件,在libs文件夹下,会生成四个不同环境下的的so文件。

5625fc6983dd4a5b99fb3600a07984be.png

 a4e6576586c54f4bba493d17270690ce.png

60f5cd37710c45fdb5b1ecf78e08673b.png

 858f5940bab048dd90563643ecc09d6a.png

986cfd8307964db8838e8c742541e157.png

三、加载并链接 JNI 库

        Qt侧声明接口,直接调用!!!

extern "C" JNIEXPORT jint JNICALL
JJava_com_example_socketcan_SocketCANJNI_socketCanOpen
(JNIEnv *env, jobject thiz, jint baudrate);extern "C" JNIEXPORT jint JNICALL
Java_com_example_socketcan_SocketCANJNI_socketCanWrite
(JNIEnv *env, jobject thiz, jint canId,jint dataLen,jint externFlag,jint remoteFlag,jbyteArray datas);
jint attachResult = QAndroidJniEnvironment::javaVM()->AttachCurrentThread(reinterpret_cast<JNIEnv**>(&env), NULL);
if (attachResult != JNI_OK) {qDebug() << "Failed to attach current thread to JVM";
}
JJava_com_example_socketcan_SocketCANJNI_socketCanOpen(env, NULL, 500000);

四:其他

        在其他的教程中,还有一种方法,QT调用java代码,java代码调用lib,在这方法中,我们需要在Android下新建src文件夹,新建SocketCANJNI.java文件,Qt側使用QAndroidJniObject::callStaticMethod调用java代码,这条路理论上也行得通,但是我没有成功实现,大家有空可以研究以下,撒花!

// SocketCANJNI.java
package com.example.socketcan;public class SocketCANJNI {static {System.loadLibrary("socketcan_native");}public native void socketCanOpen(int bitrate);
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端开发实战基础——模块

文章目录 概要模块标识符模块依赖模块加载入口 CommonJS语法单例 AMD语法 UMD核心语法 ES6模块化模块标签及定义模块导出和导入命名导出和导入默认导出和导入命名导出和默认导出混用 模块行为 小结 概要 模块化&#xff0c;就是将代码拆分成独立的块&#xff0c;各自在代码块中…

Android Jetpack Compose之底部导航栏的实现

目录 1.概述2. 效果展示3. 代码实现3.1 定义底部导航栏的tab项3.2 整体页面架构搭建3.3 底部导航栏的实现3.4 所有代码 4.总结 1.概述 写过一段Android jetpack compose 界面的小伙伴应该都用过Compose的脚手架Scaffold&#xff0c;利用它我们可以很快的实现一个现代APP的主流…

MySQL窗口函数--lead()函数

lead()函数&#xff1a; 查询当前行向下偏移n行对应的结果 该函数有三个参数&#xff1a;第一个为待查询的参数列名&#xff0c;第二个为向下偏移的位数&#xff0c;第三个参数为超出最下面边界的默认值。 如下代码&#xff1a; 查询向下偏移 2 位的年龄 SELECT user_id,user…

路灯哪个牌子好?2024年大路灯推荐合集

经常晚上学习的学生党、加班加点的打工人以及三更半夜备考的考公考研人士都看过来&#xff01;你是否经常会出现眼睛酸痛、干涩、疲劳的情况&#xff0c;并且注意力不集中&#xff0c;长期下来不仅工作学习效率低&#xff0c;而且视力也受到了影响。这是一大部分原因是因为长期…

前端通过nginx,访问一个文件夹里面的全部数据,nginx 咋配置

目录 1 问题2 实现 1 问题 前端通过nginx,访问一个文件夹里面的全部数据&#xff0c;nginx 咋配置 2 实现 location /logs {alias /mnt/www/logs/;autoindex on; }

配置了静态ip地址后,通过ssh连接到虚拟机比较慢

配置了静态ip地址后&#xff0c;通过ssh连接到虚拟机比较慢 [rootlocalhost ~]# vim /etc/ssh/sshd_config#快速方式找到UsePAM&#xff0c;输入“/UsePAM”而后回车&#xff0c;直接跳到UsePAM位置&#xff0c;将yes修改成no #键盘输入" i "开始编译 #"Esc&qu…

Redis核心技术与实战【学习笔记】 - 9.如何避免单线程模型的阻塞

概述 Redis 被广泛应用的原因是因为它支持高性能访问。所以&#xff0c;我们要重视所有可能影响 Redis 性能的因素&#xff08;如命令操作、系统配置、关键机制、硬件配置等&#xff09;。 影响 Redis 性能的 5 大方面的潜在因素分别是&#xff1a; Redis 内部的阻塞式操作C…

二叉树-堆应用(1)

目录 堆排序 整体思路 代码实现 Q1建大堆/小堆 Q2数据个数和下标 TopK问题 整体思路 代码实现 Q1造数据CreateData Q2建大堆/小堆 建堆的两种方法这里会用到前面的向上/向下调整/交换函数。向上调整&向下调整算法-CSDN博客 堆排序 整体思路 建堆&#xff08;直…

【经典项目】Java小游戏 —— 会说话的汤姆猫

一、游戏回顾 【预期效果】 【玩法介绍】 1、 和它说话&#xff0c;它将用有趣的声音重复你的话。 2、打它的头&#xff0c;它会装成被打的样子&#xff0c;连续打还会晕倒&#xff1b;抚摸肚子&#xff0c;它会打呼噜&#xff1b;打肚子&#xff0c;它会装肚子疼&#xff1b…

AVR 328pb定时器0基本介绍和使用

AVR 328pb定时器0基本介绍和使用 &#x1f4cc;参考ATmega328PB文档.&#x1f4cd;结合参考同架构lgt8f328p中文文档&#xff1a;http://www.prodesign.com.cn/wp-content/uploads/2023/03/LGT8FX8P_databook_v1.0.4.pdf &#x1f4d7;定时器0基本功能描述 两个独立的输出比较…

记一次java项目本地正常执行,打完包之后执行发现没有对应的类或配置的问题

1、起因 线上有个spark的任务出了问题&#xff08;该任务是通过sparkstreaming读取kafka中的数据&#xff0c;处理完之后推到es中&#xff09;&#xff0c;问题出在kafka中数据是有更新的&#xff0c;但是es中的对应索引中的数据却只更新到月初&#xff0c;因此我需要排查处理…

JavaSE-项目小结-IP归属地查询(本地IP地址库)

一、项目介绍 1. 背景 IP地址是网络通信中的重要标识&#xff0c;通过分析IP地址的归属地信息&#xff0c;可以帮助我们了解访问来源、用户行为和网络安全等关键信息。例如应用于网站访问日志分析&#xff1a;通过分析访问日志中的IP地址&#xff0c;了解网站访问者的地理位置分…