1. 需求
最近有项目需要实现windows机器和Android开发版进行UART串口通信,经过3天查找尝试,特记录一下最终方案,希望之后的同行少走弯路,最后在git上回开源我最终的方案希望大家支持。
2. 环境
Android 3.0.1
Gradle 4.1
ARM开发版 : RK3399
PC机器:Win10
开发机器:MAC 10.13.3
3. 解决方法
-
Android Things
Android Things 谷歌于2018年5月发布1.0正式版,让开发者可以使用Android开发工具开发嵌入式设备。需要比较高的Android API支持 ( >24 )。很多树莓派3用这个做开发,普遍应用于物联网领域。
因为是官方的原因,感觉应该靠谱些,且集成方便,Git上参考了https://github.com/androidthings/sample-uartloopback这个项目。但是,每个卵用。简直白折腾。首先需要API 27以上的设备,现在手上的开发版很少有Android 8.0以上版本的。(为此,还刷了固件,做了尝试)最大的坑是:这个项目最后基本安装不到国内的Android 系统上,原因:需要Google Service。强依赖
<uses-library android:name="com.google.android.things"/>
。考虑日后上线产品的维护,果断放弃。 -
android-serialport-api,是两个Eclipse项目,导入进去之后,设置好设备和波特律之后直接就可以使用,也看到别人分享的项目经验,这个可用。具体讲解可以参考这篇文章https://blog.csdn.net/qiwenmingshiwo/article/details/49557889,两个项目分别是编译底层JNI项目android-sercd,另一个侧重根据JNI的API实现Java端功能。如果只实现功能就看android-serialport-api
缺点:项目比较老,需要JNI编译
经过尝试导入库中已编译好的so,运行可以跑通UART通信。但遇到了一下几个‘坑’ 导入JNI的时候注意事项就不说了,包名这些的都不能改。
-
Run 使用已有的so的项目时候会报错
dlopen failed: "has text relocations"
-
遇到无法获取port,请重新配置Serial port类似的报错
解决方法:
-
关于dlopen failed: "has text relocations" 的简单解决办法,降级targetSdkVersion 23一下。Android 6.0 机制的问题。根本解决版本使用高版本的NDK重新编译so来解决,后文中我重新编译了一把。这里是gradle文件修改的关键地方。
compileSdkVersion 22 defaultConfig { applicationId "com.attrsc.braincs.androidserialport" minSdkVersion 21 targetSdkVersion 22 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" ndk { abiFilters "armeabi-v7a" } }
-
关于无法获取port的报错
一开始我怀疑是我的so没有加载成功,后来断点发现无法从sharePreference中获取到设置的 Device和baudrates。修改
SerialPortPreferences
Activity如下:public class SerialPortPreferences extends PreferenceActivity { private Application mApplication; private SerialPortFinder mSerialPortFinder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mApplication = (Application) getApplication(); mSerialPortFinder = mApplication.mSerialPortFinder; addPreferencesFromResource(R.xml.serial_port_preferences); final SharedPreferences sp = getSharedPreferences("android_serialport_api.sample_preferences", MODE_PRIVATE); // Devices final ListPreference devices = (ListPreference)findPreference("DEVICE"); String[] entries = mSerialPortFinder.getAllDevices(); String[] entryValues = mSerialPortFinder.getAllDevicesPath(); devices.setEntries(entries); devices.setEntryValues(entryValues); devices.setSummary(devices.getValue()); devices.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object newValue) { preference.setSummary((String)newValue); sp.edit().putString("DEVICE",(String) newValue).apply();//此处添加 return true; } }); // Baud rates final ListPreference baudrates = (ListPreference)findPreference("BAUDRATE"); baudrates.setSummary(baudrates.getValue()); baudrates.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object newValue) { preference.setSummary((String)newValue); sp.edit().putString("BAUDRATE",(String) newValue).apply();//此处添加 return true; } }); } } ```
-
4. 终极解决方案
先上图




由于android-serialport-api项目中的so使用较old的ndk编译,所以在对于Android 6.0 以上版本兼容的时候会报错dlopen failed: "has text relocations"
。且使用的mk进行编译,特升级为用cmake编译。
升级
android-serialport-api
-
ndk 17.0.4xxx jni编译
-
cmake 编译链
-
EClipse项目-> Android Studio项目
项目结构:
.
├── AndroidSerialLibrary.iml
├── androidserial
│ ├── CMakeLists.txt
│ ├── androidserial.iml
│ ├── build
│ ├── build.gradle
│ ├── libs
│ ├── proguard-rules.pro
│ └── src
├── app
│ ├── app.iml
│ ├── build
│ ├── build.gradle
│ ├── libs
│ ├── proguard-rules.pro
│ └── src
├── build
│ └── android-profile
├── build.gradle
├── gradle
│ └── wrapper
├── gradle.properties
├── gradlew
├── gradlew.bat
├── local.properties
└── settings.gradle
app对应原项目中的各个Activity, androidserial 是module 对应编译之前的so,还有API的封装。可以直接引用androidserial,调用方法参考app目录下的activity。
注意
关于权限!
当接入开发板后如果发现 Error You do not have read/write permission to the serial port
需要root 权限,在开发者模式中开启root 权限 adb和应用
使用一下命令开启Android对串口的读写权限
❯ adb shell
rk3399_firefly_mid:/ $ su
rk3399_firefly_mid:/ # chmod 777 /dev/ttyS4
rk3399_firefly_mid:/ # setenforce 0
rk3399_firefly_mid:/ #
setenforce 0
: 关闭防火墙,有人说关键是这,但是我的环境不用关闭,只要给权限就可以
注意
关于ttyS1 - 6 ttyS1 - 6 对应的是 UART 串口1-6 一般都是一一对应的。这个具体要看一下开发板的说明。
记录的比较糙,还请见谅,如有问题请留言,我看到后肯定回复。项目主要看结构,剩下的都是复制黏贴的事。git地址:https://github.com/braincs/AndroidSerialLibrary
网友评论