一直想写一份技术文档,但由于自感能力有限而无从下笔,最近做了个关于Android平台下实现与C语言的通讯来操作蓝牙模块的项目,中间碰到了许多问题,也在网上查了许多资料,在完成主要功能后,也有一些人在网上问我一些问题,这里写下这篇文档算是一个阶段性的总结。如果反响好,后续将会发上Android Stub与新版Android HAL的学习文档。
由于蓝牙模块是串口通讯机制,使用C语言来访问,而Android的应用层采用Java,无法直接操作硬件。故使用JNI的技术实现主要功能。Android的JNI应该属于Android HAL的一部分,由于Android的HAL机制目前还没完全摸索透,所以这里的程序架构算是老版本的HAL机制。程序架构如下图。
一、 什么是JNI?
JNI是Java Native Interface的缩写,中文为JAVA本地调用。从Java1.1开始,Java Native Interface(JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。(以上内容摘自百度百科)
二、 如何使用JNI?
1、在使用JNI之前,你要确保你的电脑中安装以下软件环境:
Android SDK :版本与你硬件测试环境版本相同,在Google的Android官网下载
Android NDK :用于编译C文件为.so的共享库,如果你是在Linux下进行开发而又具有Android的完全SDK,则不需要
Cygwin :用于编译C文件
Android 开发环境 :android开发环境的配置网上一大堆,这里不再赘述
2、程序中由于只用到Java调C,而不需要C调Java,所以在应用层调C的函数很简单,只需要在一个方法前加入native关键字(native的方法不能有方法体),然后将编译的共享库导入即可。
如下:
public class BluetoothJNI {
static{
System.loadLibrary("jni");
}
public native static int bluetoothOn(String strAT);
public native static void bluetoothOff(String strAT);
public native static String readSerial();
public native static void write(String strAT);
}
3、Eclipse在保存工程后,会自动把Java文件编译为class文件,我们使用javah命令把class文件编译成C头文件。如下:
执行此命令后将会在工程的bin目录下生成一个.h的C头文件。头文件中会生成对应Java native方法的函数声明。新建一个与头文件同名的C文件并实现所有函数。
4、由于Android的底层是基于Linux内核,所以一些Windows下的系统函数不可用,Linux下的串口通讯文章网上有很多,此处代码繁多,就不贴出来了。,我们在C文件中引入jni.h与刚生成的头文件以确保JNI能调用。注意:整个程序的核心部分便是在此处,C语言与蓝牙模块的串口通讯处,我在此处碰到的问题也是最多的。
三、编译C文件
1、在Android-ndk-r5b\samples\下新建目录Bluetooth\jni,将C文件与头文件复制过来,新建Makefile。如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
LOCAL_LDLIBS := -lm -llog
LOCAL_MODULE := jni
LOCAL_SRC_FILES := com_android_semisky_bluetooth_util_BluetoothJNI.c
include $(BUILD_SHARED_LIBRARY)
2、打开Cygwin bash shell,进入Bluetooth目录,执行ndk-build进行编译。
3、将libs/armeabi下生成的libjni.so文件拷入到Android工程的libs/armeabi目录下。安装apk到开发板,执行程序。
四、可能出现的问题
1、串口读写权限的问题
网上的方法是在Java中获取su账号来改权限或者在init.rc中添加命令来修改权限最后编译成img烧录进开发板,而这两种方法我都没成功,最后没办法在dos下执行shell命令来修改
2、C文件的串口读写问题
我不知道是我的程序有问题还是蓝牙模块的问题,在蓝牙模块返回数据稍大的时候,会出现数据有时返回有时不返回的情况。
3、乱码问题
蓝牙返回的数据时而出现乱码,未解决。
4、串口号的问题
如果你open的时候返回的fd小于1,确保你的开发板串口号是否正确,协议是否正确,权限是否修改。
5、最大大大的问题
读取串口代码段的算法问题,优化问题,不然数据会返回不正常。