————————————————重要通知——————————————
Hello,本人的博客文章已更新至个人网站(www.jonexu.cn)
文章中有问题可以到网站联系博主,后续新的文章也将更新在个人网站
——————————————————————————————————
如果不想自己写,可直接用串口成品库
一、Google官方demo
注意目录里的文件,主要分为图中三块android_serialport_api、libs、jni
参考完google的项目,开始写到我们项目里。
二、先安装下载NDK、CMake
三、上手自己的项目
全程是Project视图下在操作
1、先在你的项目main下java目录中新建package命名为android_serialport_api(必须必这个名字),并把google项目中android_serialport_api目录下的SerialPort.java、SerialPortFinder.java复制过来
2、将Google中libs和jni复制移动到你的项目main目录下,我这边复制过来后,将libs重命名为jniLibs了,这样就不需要在sourceSet里配置dir
3、在app目录下创建一个CMakeLists.txt文件,内容如下
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
#设置生成的so动态库最后输出的路径
#set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/..jniLibs/${CMAKE_ANDROID_ARCH_ABI})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/jniLibs/${ANDROID_ABI})
add_library( # 生成的.so文件的名字!!
serial_port
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/jni/SerialPort.c)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
serial_port
# Links the target library to the log library
# included in the NDK.
${log-lib})
4、在build.gradle中android节点中增加如下配置
android {
// ...默认配置省略
defaultConfig{
//...默认配置省略
ndk {
//abiFilters "armeabi", "armeabi-v7a", "x86"
abiFilters "arm64-v8a", "armeabi-v7a"
}
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
externalNativeBuild {
// ndkBuild { // 使用这个就会生成ndkBuild目录,此为ndk形式
// path 'src/main/jni/Android.mk' //这个是Android.mk文件的路径
// }
cmake {
path "CMakeLists.txt" //这个是Android.mk文件的路径
}
}
sourceSets {
main {
jni.srcDirs = []
// jniLibs.srcDirs = ['libs']因为命名为jniLibs所以不需要额外引入
}
}
}
"arm64-v8a"//是目前最新的64位cpu支持
"armeabi-v7a"//是目前主流cpu支持
所以我只引入了这两种。
官方没有给到arm64-v8a的.so文件,所以自己基于jni里的c文件通过cmake来生成。(主要是.c和.h文件起作用)
5、修改build.gradle后,同步,然后点击工具栏Build—Make Project,成功之后有如图目录型号文件,移动到你缺失的jniLibs里就好了。
6、使用,接收数据
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String[] arr = new SerialPortFinder().getAllDevices();
//获取当前这个设备所有串口地址
SerialPort mSerialPort = new SerialPort(
new File("/dev/ttyS2"),//这个通过上面的arr中得知,设备有多个口,要监听哪一个
9600,0);
final InputStream inputStream = mSerialPort.getInputStream();
// this.mOutputStream = mSerialPort.getOutputStream();//这个可以用来写入
this.mInputStream = mSerialPort.getInputStream();
this.mReadThread = new ReadThread();
this.mReadThread.start();
}
private class ReadThread extends Thread {
@Override
public void run() {
super.run();
while (!isInterrupted()) {
try {
if (mInputStream == null) {
return;
}
int available = mInputStream.available();
if (available > 0) {
byte[] buffer = new byte[available];
int size = mInputStream.read(buffer);
if (size > 0) {
Log.e(TAG, "收到数据: "+new String(buffer, "UTF-8"));
}
} else {
SystemClock.sleep(50);
}
} catch (Throwable e) {
Log.e("接收错误", e.getMessage());
return;
}
}
}
}
附:
1、查看mac已连接的串口
ls /dev | grep tty.usb
2、获取模拟器中所有串口, 通过adb命令可以查看模拟器中所有串口名称
adb shell
cd proc/tty
cat drivers
错误
1、如果报错找不到serial_port.so那么两个问题,
1) build.gradle中没有配置sourceSets,
2) 或者说jniLibs中armeabi等.so文件不全,可以到这个项目里下载更多型号的
2、Install Failed Insufficient Storage
真机的话,那就是想办法腾出手机的内存空间了,
模拟器,1)打开模拟器管理,然后右键当前的模拟器,选择Wipe Data
或 2)右键模拟器Edit, 然后 选择 Show Advanced Settings,修改Memory and Storage
3、No implementation found for java.io.FileDescriptor
SerialPort.java文件没有放到main——java——android_serialport_api目录下,同名
4、java.io.IOException: Cannot run program "/system/bin/su": error=13, Permission denied
没有root权限,AVD模拟器的话,使用命令行cd到你安卓的sdk目录下,MAC如下,参考博客
cd /Users/jonexu/Library/Android/sdk/tools
adb root
//得到restarting adbd as root
adb shell setenforce 0
真机的话得刷机了,按道理你调试串口得有专业的工业板,一般都是root的
5、libserial_port.so text relocations
报错的原因就是没有安卓6.0以上的可读.so文件,需要增加arm64-v8a目录并添加对应.so文件看第1点提到的项目里,可以下载到。
6、Unknown host CPU architecture: arm64
Mac OS里M1芯片中NDK暂不识别arm64、临时解决方案:修改你安卓sdk目录下的ndk中的ndk-build文件
#!/bin/sh
#DIR="$(cd "$(dirname "$0")" && pwd)"
#$DIR/build/ndk-build "$@"
# 新脚本"
DIR="$(cd "$(dirname "$0")" && pwd)"
arch -x86_64 /bin/bash $DIR/build/ndk-build "$@"
7、Execution failed for task ':app:mergeDebugNativeLibs'.如图错误
Build的时候会遇到这个报错,需要在build.gradle中android节点下增加
android {
//...其他配置省略
//主要加入如下配置,defaultConfig.ndk.abiFilters有几种型号就加几种!
packagingOptions {
pickFirst 'lib/armeabi-v7a/libserial_port.so'
pickFirst 'lib/arm64-v8a/libserial_port.so'
}
}
End
推荐关于Android型号arm64-v8a等介绍