Android蓝牙编程
- 格式:doc
- 大小:281.50 KB
- 文档页数:27
AndroidStudio蓝⽛开发实例——基于Android6.0因项⽬需要做⼀个Android 的蓝⽛app来通过⼿机蓝⽛传输数据以及控制飞⾏器,在此,我对这段时间⾥写的蓝⽛app的代码进⾏知识梳理和出现错误的总结。
该应⽤的Compile Sdk Version 和targetSdkVersion均为26,Min Sdk Version为22,基于Android studio平台开发。
⼀、声明蓝⽛权限⾸先,要在新建项⽬中的AndroidManifest.xml中声明两个权限:BLUETOOTH权限和BLUETOOTH_ADMIN权限。
其中,BLUETOOTH权限⽤于请求连接和传送数据;BLUETOOTH_ADMIN权限⽤于启动设备、发现或进⾏蓝⽛设置,如果要拥有该权限,必须现拥有BLUETOOTH权限。
其次,因为android 6.0之后采⽤新的权限机制来保护⽤户的隐私,如果我们设置的targetSdkVersion⼤于或等于23,则需要另外添加ACCESS_COARSE_LOCATION和ACCESS_FINE_LOCATION权限,否则,可能会出现搜索不到蓝⽛设备的问题。
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/><uses-permission android:name="android.permission.BLUETOOTH"/><uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/><uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>⼆、启动和关闭蓝⽛1.⾸先,要获取BluetoothAdapter蓝⽛适配器的对象,然后检测设备是否⽀持蓝⽛。
Android bluetooth介绍(二)android 蓝牙代码架构及其uart 到rfcomm 流程一、Android Bluetooth Architecture蓝牙代码架构部分(google 官方蓝牙框架)Android的蓝牙系统,自下而上包括以下一些内容如上图所示:1、串口驱动Linux的内核的蓝牙驱动程、Linux的内核的蓝牙协议的层2、BlueZ的适配器BlueZ的(蓝牙在用户空间的函式库)bluez代码结构Bluetooth协议栈BlueZ分为两部分:内核代码和用户态程序及工具集。
(1)、内核代码:由BlueZ核心协议和驱动程序组成Bluetooth协议实现在内核源代码 kernel/net/bluetooth中。
包括hci,l2cap,hid,rfcomm,sco,SDP,BNEP等协议的实现。
(2)、驱动程序:kernel/driver/bluetooth中,包含Linuxkernel对各种接口的Bluetooth device的驱动,如:USB接口,串口等。
(3)、用户态程序及工具集:包括应用程序接口和BlueZ工具集。
BlueZ提供函数库以及应用程序接口,便于程序员开发bluetooth应用程序。
BlueZ utils是主要工具集,实现对bluetooth设备的初始化和控制。
3、蓝牙相关的应用程序接口Android.buletooth包中的各个Class(蓝牙在框架层的内容-----java)同样下图也是一张比较经典的蓝牙代码架构图(google官方提供)二、蓝牙通过Hciattach启动串口流程:1、hciattach总体流程2、展讯hciattach代码实现流程:三、具体代码分析1、initrc中定义idh.code\device\sprd\sp8830ec_nwcn\init.sc8830.rc1.service hciattach /system/bin/hciattach -n /dev/sttybt0 sprd_shark2.socket bluetooth stream 660 bluetooth bluetoother bluetooth4.group wifi bluetooth net_bt_admin net_bt inet net_raw net_admin system5.disabled6.oneshotadb 下/dev/ttybt0(不同平台有所不同)PS 进程中:hicattch2、/system/bin/hciattach 执行的Main函数idh.code\external\bluetooth\bluez\tools\hciattach.cservice hciattach /system/bin/hciattach -n /dev/sttybt0sprd_shark 传进两个参数,/dev/sttybt0 和 sprd_shark1.i nt main(int argc, char *argv[])2.{3.………………4.for (n = 0; optind < argc; n++, optind++) {5.char *opt;6.7.opt = argv[optind];8.9.switch(n) {10. case 0://(1)、解析驱动的位置;11. dev[0] = 0;12. if (!strchr(opt, '/'))13. strcpy(dev, "/dev/");14. strcat(dev, opt);15. break;16.17. case 1://(2)、解析串口的配置相关参数;18. if (strchr(argv[optind], ',')) {19. int m_id, p_id;20. sscanf(argv[optind], "%x,%x",&m_id, &p_id);21. u = get_by_id(m_id, p_id);22. } else {23. u = get_by_type(opt);24. }25.26. if (!u) {27. fprintf(stderr, "Unknown device type or id\n");28. exit(1);29. }30.31. break;32.33. case 2://(3)、通过对前面参数的解析,把uart[i]中的数值初始化;34. u->speed = atoi(argv[optind]);35. break;36.37. case 3:38. if (!strcmp("flow", argv[optind]))39. u->flags |= FLOW_CTL;40. else41. u->flags &= ~FLOW_CTL;42. break;43.44. case 4:45. if (!strcmp("sleep", argv[optind]))46. u->pm = ENABLE_PM;47. else48. u->pm = DISABLE_PM;49. break;50.51. case 5:52. u->bdaddr = argv[optind];53. break;54. }55. }56.57.………………58. if (init_speed)//初始化串口速率;59. u->init_speed = init_speed;60.………………61. n = init_uart(dev, u, send_break, raw);//(4)、初始化串口;62.………………63.64. return 0;65.}(1)、解析驱动的位置;1.if (!strchr(opt, '/'))2.strcpy(dev, "/dev/");3.service hciattach /system/bin/hciattach -n /dev/sttybt0 sprd_shark4.dev = /dev/ttyb0(2)、解析串口的配置相关参数;获取参数对应的结构体;1.u = get_by_id(m_id, p_id);2.static struct uart_t * get_by_id(int m_id, int p_id)3.{4.int i;5.for (i = 0; uart[i].type; i++) {6.if (uart[i].m_id == m_id && uart[i].p_id== p_id)7.return &uart[i];8.}9.return NULL;10.}这个函数比较简单,通过循环对比,如传进了的参数sprd_shark和uart结构体中的对比,找到对应的数组。
Android中⽂API(70)——BluetoothDevice[蓝⽛]前⾔声明 欢迎转载,但请保留⽂章原始出处:)正⽂ ⼀、结构public static class BluetoothDevice extends Object implements Parcelableng.Objectandroid.bluetooth.BluetoothDevice ⼆、概述 代表⼀个远程蓝⽛设备。
让你创建⼀个带有各⾃设备的BluetoothDevice或者查询其皆如名称、地址、类和连接状态等信息。
对于蓝⽛硬件地址⽽⾔,这个类仅仅是⼀个瘦包装器。
这个类的对象是不可改变的。
这个类上的操作会使⽤这个⽤来创建BluetoothDevice类的BluetoothAdapter类执⾏在远程蓝⽛硬件上。
为了获得BluetoothDevice,类,使⽤BluetoothAdapter.getRemoteDevice(String)⽅法去创建⼀个表⽰已知MAC地址的设备(⽤户可以通过带有BluetoothAdapter类来完成对设备的查找)或者从⼀个通过 BluetoothAdapter.getBondedDevices()得到返回值的有联系的设备集合来得到该设备。
注意:需要权限 参见 三、常量String ACTION_ACL_CONNECTED⼴播活动:指明⼀个与远程设备建⽴的低级别(ACL)连接。
总是包含附加域ACL连接通过Android蓝⽛栈⾃动进⾏管理需要权限接收常量值: "android.bluetooth.device.action.ACL_CONNECTED"String ACTION_ACL_DISCONNECTED⼴播活动:指明⼀个来⾃于远程设备的低级别(ACL)连接的断开总是包含附加域ACL连接通过Android蓝⽛栈⾃动进⾏管理需要权限接收常量值: "android.bluetooth.device.action.ACL_DISCONNECTED"String ACTION_ACL_DISCONNECT_REQUESTED⼴播活动:指明⼀个为远程设备提出的低级别(ACL)的断开连接请求,并即将断开连接。
Bluetooth Low Energy——蓝牙低功耗Android4.3(API级别18)引入内置平台支持BLE的central角色,同时提供API和app应用程序用来发现设备,查询服务,和读/写characteristics。
与传统蓝牙(ClassicBluetooth)不同,蓝牙低功耗(BLE)的目的是提供更显著的低功耗。
这使得Android 应用程序可以和具有低功耗的要求BLE设备,如接近传感器,心脏速率监视器,健身设备等进行通信。
关键术语和概念下面是关键BLE术语和概念的总结:通用属性规范(GATT)—GATTprofile是一个通用规范用于在BLE链路发送和接收被称为―属性(attributes)‖的数据片。
目前所有的低功耗应用profile都是基于GATT。
蓝牙SIG定义了许多profile用于低功耗设备。
Profile(配置文件)是一个规范,规范了设备如何工作在一个特定的应用场景。
注意:一个设备可以实现多个profile。
例如,一个设备可以包含一个心脏监测仪和电池电平检测器。
属性协议(ATT )—GATT是建立在属性协议(ATT )的顶层,通常也被称为GATT/ ATT 。
ATT进行了优化用于在BLE设备上运行。
为此,它采用尽可能少的字节越好。
每个attribute 属性被UUID(通用唯一标识符)唯一标识,UUID是标准128-bit格式的ID用来唯一标识信息。
attributes 被ATT 格式化characteristics和services形式进行传送。
特征(Characteristics)—一个characteristics包含一个单独的value值和0 –n个用来描述characteristic 值(value)的descriptors。
一个characteristics可以被认为是一种类型的,类似于一个类。
描述符(descriptor)—descriptor是被定义的attributes,用来描述一个characteristic的值。
Android蓝牙AVRCP功能的实现作者:MacroLiu AVRCP的按键定义:\sdk\emulator\keymaps\AVRCP.klkey200MEDIA_PLAY_PAUSEWAKEkey201MEDIA_PLAY_PAUSEWAKEkey166MEDIA_STOPWAKEkey163MEDIA_NEXTWAKEkey165MEDIA_PREVIOUSWAKEkey168MEDIA_REWINDWAKEkey208MEDIA_FAST_FORWARDWAKEBCM(broadcom)宏定义需要打开:BOARD_HAVE_BLUETOOTH_BCM:=trueBT音频控制的代码external\bluetooth\bluez\audio\control.c(1)按键的MAPstaticstruct{constchar*name;uint8_tavrcp;uint16_tuinput;}key_map[]={{"PLAY", PLAY_OP, KEY_PLAYCD},{"STOP", STOP_OP, KEY_STOPCD},{"PAUSE", PAUSE_OP, KEY_PAUSECD},{"FORWARD", FORWARD_OP, KEY_NEXTSONG},{"BACKWARD", BACKWARD_OP, KEY_PREVIOUSSONG}, {"REWIND", REWIND_OP, KEY_REWIND},{"FASTFORWARD", FAST_FORWARD_OP, KEY_FASTFORWARD}, {NULL}};(2)按键处理staticvoidhandle_panel_passthrough(structcontrol*control,{…for(i=0;key_map[i].name!=NULL;i++){uint8_tkey_quirks;if((operands[0]&0x7F)!=key_map[i].avrcp)continue;DBG("AVRCP:%s%s",key_map[i].name,status);key_quirks=control->key_quirks[key_map[i].avrcp];if(key_quirks&QUIRK_NO_RELEASE){if(!pressed){DBG("AVRCP:Ignoringrelease");break;}DBG("AVRCP:treatingkeypressaspress+release");send_key(control->uinput,key_map[i].uinput,1);send_key(control->uinput,key_map[i].uinput,0);break;}send_key(control->uinput,key_map[i].uinput,pressed);break;}…}HCIDUMP数据分析以Sony耳机DRC-BT15为例#adbshell#hcidump–X左键:>ACLdata:handle12flags0x02dlen12L2CAP(d):cid0x0042len8[psm0]0000:30110e00487c4c000...H|L.<HCICommand:ExitSniffMode(0x02|0x0004)plen20000:0c00..<ACLdata:handle12flags0x00dlen120000:08004b0032110e09487c4c00..K.2...H|L.>HCIEvent:MaxSlotsChange(0x1b)plen30000:0c0005...>HCIEvent:ModeChange(0x14)plen60000:000c00000000......>HCIEvent:CommandStatus(0x0f)plen40000:0c010408....>ACLdata:handle12flags0x02dlen12L2CAP(d):cid0x0042len8[psm0]0000:40110e00487ccc00@...H|?<ACLdata:handle12flags0x00dlen120000:08004b0042110e09487ccc00..K.B...H|?>HCIEvent:NumberofCompletedPackets(0x13)plen5 0000:010c000200.....播放/暂停:>ACLdata:handle12flags0x02dlen12L2CAP(d):cid0x0042len8[psm0]0000:50110e00487c4b00P...H|K.<ACLdata:handle12flags0x00dlen120000:08004b0052110e09487c4b00..K.R...H|K.>ACLdata:handle12flags0x02dlen12L2CAP(d):cid0x0042len8[psm0]0000:60110e00487ccb00`...H|?<ACLdata:handle12flags0x00dlen120000:08004b0062110e09487ccb00..K.b...H|?>HCIEvent:NumberofCompletedPackets(0x13)plen5 0000:010c000200.....右键:>ACLdata:handle12flags0x02dlen12L2CAP(d):cid0x0042len8[psm0]0000:70110e00487c4600p...H|F.<ACLdata:handle12flags0x00dlen120000:08004b0072110e09487c4600..K.r...H|F.>ACLdata:handle12flags0x02dlen12L2CAP(d):cid0x0042len8[psm0]0000:80110e00487cc600....H|?<ACLdata:handle12flags0x00dlen120000:08004b0082110e09487cc600..K.....H|?>HCIEvent:NumberofCompletedPackets(0x13)plen5 0000:010c000200.....>HCIEvent:MaxSlotsChange(0x1b)plen30000:0c0001...>HCIEvent:ModeChange(0x14)plen60000:000c0002c800....?然后将control.c的日志打印出来:按一次”“播放/暂停键”:D/ACRVP(237):---handle_panel_passthrough----D/ACRVP(237):operands[0]=46对应PAUSE_OPD/ACRVP(237):key_quirks=0,pressed=1按键按下D/ACRVP(237):control->uinput=fffffffe,send_key=201对应MEDIA_PLAY_PAUSED/ACRVP(237):---handle_panel_passthrough----D/ACRVP(237):operands[0]=c6(=0x46|0x80表示按键释放了)D/ACRVP(237):key_quirks=0,pressed=0按键释放D/ACRVP(237):control->uinput=fffffffe,send_key=201对应MEDIA_PLAY_PAUSE再按一次”“播放/暂停键”:D/ACRVP(237):---handle_panel_passthrough----D/ACRVP(237):operands[0]=44对应PLAY_OPD/ACRVP(237):key_quirks=0,pressed=1按键按下D/ACRVP(237):control->uinput=fffffffe,send_key=200对应MEDIA_PLAY_PAUSED/ACRVP(237):---handle_panel_passthrough----D/ACRVP(237):operands[0]=c4D/ACRVP(237):key_quirks=0,pressed=0按键释放D/ACRVP(237):control->uinput=fffffffe,send_key=200对应MEDIA_PLAY_PAUSEnextkey:D/ACRVP(237):---handle_panel_passthrough----D/ACRVP(237):operands[0]=4b对应FORWARD_OPD/ACRVP(237):key_quirks=0,pressed=1D/ACRVP(237):control->uinput=fffffffe,send_key=163对应MEDIA_NEXT D/ACRVP(237):---handle_panel_passthrough----D/ACRVP(237):operands[0]=cbD/ACRVP(237):key_quirks=0,pressed=0D/ACRVP(237):control->uinput=fffffffe,send_key=163prevkey:D/ACRVP(237):---handle_panel_passthrough----D/ACRVP(237):operands[0]=4c对应BACKWARD_OPD/ACRVP(237):key_quirks=0,pressed=1D/ACRVP(237):control->uinput=fffffffe,send_key=165对应D/ACRVP(237):---handle_panel_passthrough----D/ACRVP(237):operands[0]=ccD/ACRVP(237):key_quirks=0,pressed=0D/ACRVP(237):control->uinput=fffffffe,send_key=165MEDIA_PREVIOUS 从上面可以看到bluetooth的协议栈blueZ是没有问题的将frameworks\base\libs\ui\EventHub.cpp的LOG打开,只能看到了control.c的日志,EventHub的getEvent完全不响应观察所有log日志发现,openDevice里也没有装载AVRCP.kl初步判断event有问题event分析:$adbshell#cd/proc/bus/input#catdevicescatdevices#catdevicescatdevicesI:Bus=0019Vendor=0001Product=0001Version=0001参考s3c-keypad.c N:Name="s3c-keypad" input_dev->name=DEVICE_NAME;P:Phys=s3c-keypad/input0input_dev->phys="s3c-keypad/input0";S:Sysfs=/devices/virtual/input/input0virtual的?U:Uniq=H:Handlers=event0B:EV=3B:KEY=40004000I:Bus=0019Vendor=0001Product=0001Version=0100参考vpad_buttons.cN:Name="s3c-eintkey"input->name=pdev->name,gpio_keys_device_dri ="s3c-eintkey",P:Phys=gpio-keys/input0input->phys="gpio-keys/input0"S:Sysfs=/devices/platform/s3c-eintkey/input/input1为什么这里是platform目录?U:Uniq=H:Handlers=event1B:EV=3B:KEY=100000000I:Bus=0018Vendor=0000Product=0000Version=0000参考amri_ts.cN:Name="amri_ts"amri_ts_="amri_ts"P:Phys=没有定义S:Sysfs=/devices/platform/s3c2440-i2c.0/i2c-0/0-0033/input/input2为什么这里是platform目录?U:Uniq=H:Handlers=event2B:EV=bB:KEY=4000000040000800400010000B:ABS=26500000I:Bus=0000Vendor=0000Product=0000Version=0000N:Name="ecompass_data"P:Phys=S:Sysfs=/devices/virtual/input/input3U:Uniq=H:Handlers=event3B:EV=9B:ABS=307bf从上面可以看到,完全没有AVRCP的event。
ble简介和androidble编程一.BLE和BT区别其实我知道许多程序员不太喜欢阅读除了代码以外的文档,因为有时这些过于冗长的文档对编程并没有更多的好处,有了协议,接口,demo差不多很多人就能写出很好质量的代码了。
但其实更深入的编程是少了阅读的,阅读文档可以解决很多编程中遇到的困难,比如在大数据大流量情况下,很多正常的程序会表现出不可靠的一面,这已经不是够编程能解决的了,硬件的配置,服务器带宽,使用的数据库,调用的接口都有可能是瓶颈。
比如BLE,同样的蓝牙,但却有着本质区别,一个表现就是不是所有蓝牙设备都支持BLE,编程如果不考虑这个问题,程序出错就会迷茫。
再比如连接到BLE或者蓝牙上的设备是有数量限制的,如果不知道这个限制,在连接不上时,也会六神无主。
BLE在智家居中和移动设备中的应用方兴未艾,做深入的研究推广到更多的应用上,还是有意义的。
1蓝牙的历史:蓝牙的创始公司是爱立信。
1994年爱立信开始对小范围无线通信技术进行研发,在1997年,爱立信的研究激发了其他公司的浓厚兴趣,于是1998年2月,一些跨国大公司包括诺基亚、苹果、三星组成的一个特殊兴趣小组(SIG),他们共同的目标是建立一个全球性的小范围无线通信技术,该项技术就是蓝牙。
2.BLE 是Bluetooth LowEnergy的缩写,又叫蓝牙4.0,区别于蓝牙3.0和之前的技术。
BLE前身是NOKIA开发的Wibree技术,主要用于实现移动智能终端与周边配件之间的持续连接,是功耗极低的短距离无线通信技术,并且有效传输距离被提升到了100米以上,同时只需要一颗纽扣电池就可以工作数年之久。
3. BLE是在蓝牙技术的基础上发展起来的,既同于蓝牙,又区别于传统蓝牙。
BLE设备分单模和双模两种,双模简称BR,商标为Bluetooth Smart Ready,单模简称BLE或者LE,商标为Bluetooth Smart。
Android是在4.3后才支持BLE,这可以解释不是所有蓝牙手机都支持BLE,而且支持BLE的蓝牙手机一般是双模的。
Android之蓝牙驱动开发总结二Android Bluetooth架构 (1)2.1 Bluetooth架构图 (1)2.2 Bluetooth代码层次结构 (3)三Bluetooth协议栈分析 (4)3.1 蓝牙协议栈 (4)3.2 Android与蓝牙协议栈的关系 (5)四Bluetooth之HCI层分析 (5)4.1 HCI层与基带的通信方式 (6)4.2 包的分析及研究 (7)4.3 通信过程的研究与分析 (8)五Bluetooth之编程实现 (8)5.1 HCI层编程 (8)5.2 L2CAP层编程 (10)5.3 SDP层编程 (12)六Bluetooth之启动过程实现 (13)6.1 Bluetooth启动步骤 (14)6.2 Bluetooth启动流程 (14)6.3 Bluetooth数据流向 (14)6.4 Bluez控制流程 (14)6.5 Bluetooth启动过程分析 (15)七Bluetooth之驱动移植 (15)7.1 android系统配置 (15)7.2 启动项修改 (16)7.3 电源管理rfkill驱动 (16)7.4 Rebuild Android image and reboot (16)7.5 实现BT睡眠唤醒机制 (16)7.6 系统集成 (17)八Bluetooth之调试与编译 (17)8.1 Bluetooth驱动调试 (17)九Bluetooth之应用程序开发 (18)9.1 Bluetooth的API开发 (18)9.2 The Basics开发 (18)9.3 Bluetooth Permissions开发 (19)9.4 Setting Up Bluetooth服务 (19)9.5 Finding Devices服务 (20)9.6 Connecting Devices服务 (22)9.7 Managing a Connection服务 (26)9.8 Working with Profiles服务 (28)十总结与疑问 (29)一Bluetooth基本概念蓝牙是无线数据和语音传输的开放式标准,它将各种通信设备、计算机及其终端设备、各种数字数据系统、甚至家用电器采用无线方式联接起来。
android蓝⽛简单开发⽰例教程⽬录概述1、权限申请2、打开蓝⽛3、接收蓝⽛状态的改变4、扫描其他的设备5、蓝⽛配对6、获取已经配对的设备7、连接设备概述前段时间学习了⼀些蓝⽛开发的知识,记录⼀下Android中蓝⽛的简单开发。
下⾯是最重要的两个类。
BluetoothAdapter : 蓝⽛适配器,通过getDefaultAdapter ()去获取⼀个实例,如果设备不⽀持蓝⽛的话,返回的是⼀个null对象,通过它,可以打开、关闭蓝⽛,扫描设备、向指定设备创建socket通道…BluetoothDevice : 代表⼀个设备对象,可以通过它获取设备的名字、地址、类型等,也可以创建匹配,建⽴socket通道等等。
1、权限申请<uses-permission android:name="android.permission.BLUETOOTH"/> 使⽤蓝⽛所需要的权限<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> 使⽤扫描和设置蓝⽛的权限(申明这⼀个权限必须申明上⾯⼀个权限)Android6以上版本,扫描其他蓝⽛还需要位置权限// Android 9 以下版本<user-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>// Android 9 以上<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>2、打开蓝⽛mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();// 如果设备不⽀持蓝⽛if (mBluetoothAdapter == null){return;}// 设备⽀持蓝⽛功能,调⽤startActivityForResult去启动蓝⽛if (!mBluetoothAdapter.isEnabled()){unch(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE));}打开蓝⽛功能是通过startActivity去启动的,但是startActivity这个函数已经过期了,所以我使⽤官⽅推荐的Activity Result替代它ActivityResultLauncher<Intent> startBlueTooth = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),new ActivityResultCallback<ActivityResult>() {@Overridepublic void onActivityResult(ActivityResult result) {if (result==null){Toast.makeText(BlueToothActivity.this, "open failed", Toast.LENGTH_SHORT).show();}else {if (result.getResultCode() == RESULT_CANCELED){Toast.makeText(BlueToothActivity.this,"⽤户取消",Toast.LENGTH_SHORT);}}}});3、接收蓝⽛状态的改变通过⼴播去接收蓝⽛状态的改变class BluetoothStateChangeReceiver extends BroadcastReceiver{public int DEFAULT_VALUE_BLUETOOTH = 1000;@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)){int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,DEFAULT_VALUE_BLUETOOTH); switch(state){case BluetoothAdapter.STATE_ON:Log.d(TAG, "onReceive: open");break;case BluetoothAdapter.STATE_OFF:Log.d(TAG, "onReceive: off");break;case BluetoothAdapter.STATE_TURNING_ON :Log.d(TAG, "onReceive: 正在打开");break;case BluetoothAdapter.STATE_TURNING_OFF:Log.d(TAG, "onReceive: 正在关闭");break;}}}}别忘了⼴播的注册和解注册IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);stateReceiver = new BluetoothStateChangeReceiver() ;registerReceiver(stateReceiver,filter);4、扫描其他的设备同样通过⼴播接收,action是BluetoothDevice.ACTION_FOUNDclass MyReceiver extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (BluetoothDevice.ACTION_FOUND.equals(action)) {// 从intent对象中获取蓝⽛设备的信息BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);// 当发现新设备不存在于配对列表中时添加if (device.getBondState() != BluetoothDevice.BOND_BONDED) {blueNames.add(device.getName()+"\t"+device.getAddress());}blueAdpater.notifyDataSetChanged();Log.d(TAG, "onReceive: " + device.getName());}}}动态注册⼴播IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);registerReceiver(mReceiver,filter);开启扫描mBluetoothAdapter.startDiscovery();5、蓝⽛配对public class BondReceiver extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent) {if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())){BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);switch(device.getBondState()){case BluetoothDevice.BOND_BONDED:Log.d(TAG, "onReceive: 配对完成");break;case BluetoothDevice.BOND_BONDING:Log.d(TAG, "onReceive: 正在配对");break;case BluetoothDevice.BOND_NONE:Log.d(TAG, "onReceive: 取消配对");break;}}}}6、获取已经配对的设备已经配对的设备会被存储起来,通过BluetoothAdpater直接获取即可Set<BluetoothDevice> paireDevices = mBluetoothAdapter.getBondedDevices();if (paireDevices.size()>0){for (BluetoothDevice pairedDevice : pairedDevices) {blueNames.add(pairedDevice.getName()+" "+pairedDevice.getAddress());Log.d(TAG, "onClick: "+pairedDevice.getName());}}7、连接设备想要在两台设备之间创建连接,必须实现客户端和服务端机制,他们之间使⽤套接字机制进⾏连接,服务端开放服务器套接字,客户端通过MAC地址向服务端发起连接。
ANDROID 蓝牙编程用BluetoothAdapter类,你能够在Android设备上查找周边的蓝牙设备然后配对(绑定),蓝牙通讯是基于唯一地址MAC来相互传输的,考虑到安全问题Bluetooth通讯时需要先配对。
然后开始相互连接,连接后设备将会共享同一个RFCOMM通道以便相互传输数据,目前这些实现在Android 2.0或更高版本SDK 上实现。
一、查找发现 findding/discovering devices对于Android查找发现蓝牙设备使用BluetoothAdapter类的startDiscovery()方法就可以执行一个异步方式获取周边的蓝牙设备,因为是一个异步的方法所以我们不需要考虑线程被阻塞问题,整个过程大约需要12秒时间,这时我们紧接着注册一个 BroadcastReceiver 对象来接收查找到的蓝牙设备信息,我们过滤ACTION_FOUND这个 Intent动作来获取每个远程设备的详细信息,通过附加参数在Intent字段EXTRA_DEVICE 和 EXTRA_CLASS, 中包含了每个BluetoothDevice 对象和对象的该设备类型BluetoothClass ,示例代码private final BroadcastReceiver cwjReceiver = new BroadcastReceiver() {public void onReceive(Context context, Intent intent) {String action = intent.getAction();if (BluetoothDevice.ACTION_FOUND.equals(action)) {BluetoothDevice device =intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);myArrayAdapter.add(device.getName() + " android123 " + device.getAddress()); //获取设备名称和mac地址}}};// 注册这个 BroadcastReceiverIntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);registerReceiver(cwjReceiver, filter);最后android123提醒大家需要注意的是,记住在Service或Activity中重写onDestory()方法,使用unregisterReceiver方法反注册这个BroadcastReceiver对象保证资源被正确回收。
一些其他的状态变化有 ACTION_SCAN_MODE_CHANGED 额外参数 EXTRA_SCAN_MODE 和EXTRA_PREVIOUS_SCAN_MODE以及SCAN_MODE_CONNECTABLE_DISCOVERABLE、 SCAN_MODE_CONNECTABLE和SCAN_MODE_NONE, 蓝牙模块二、配对绑定 bnded/paired device在Android中配对一个蓝牙设备可以调用BluetoothAdapter类的getBondedDevices()方法可以获取已经配对的设备,该方法将会返回一个BluetoothDevice数组来区分每个已经配对的设备,示例代码如下:Set<BluetoothDevice> pairedDevices = cwjBluetoothAdapter.getBondedDevices();if (pairedDevices.size() > 0) //如果获取的结果大于0,则开始逐个解析{for (BluetoothDevice device : pairedDevices) {myArrayAdapter.add(device.getName() + " android123 " + device.getAddress()); //获取每个设备的名称和MAC地址添加到数组适配器myArrayAdapter中。
}}蓝牙模块很多网友不明白如何让自己的手机被其他蓝牙设备发现如何设置,下面我们就一起来说说三、允许发现 enabling discoverability如果需要用户确认操作,不需要获取底层蓝牙服务实例,可以通过一个Intent来传递ACTION_REQUEST_DISCOVERABLE参数,这里通过startActivityForResult来强制获取一个结果,重写startActivityForResult()方法获取执行结果,返回结果有RESULT_OK和RESULT_CANCELLED分别代表开启和取消(失败),当然最简单的方法是直接执行,示例代码如下Intent cwjIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);cwjIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);startActivity(cwjIntent);接下来系统会提示用户是否允许,对话框如下从Android 2.0开始提供最全面的蓝牙开发接口,API Level为5的系统才能调用,目前Android Bluetooth API包含了主要以下几类:BluetoothAdapterBluetoothDevice、BluetoothSocket 、BluetoothServerSocket 和BluetoothClass 它们均在android.bluetooth这个包中出现。
我们调用时除了需要考虑API Level至少为5外,还需注意添加相应的权限,比如使用通讯需要在androidmanifest.xml加入<uses-permission android:name="android.permission.BLUETOOTH" />,而开关蓝牙需要android.permission.BLUETOOTH_ADMIN权限。
三、建立通讯 establishing对于建立一个蓝牙通讯,必须经过以下四个步骤:获取本地蓝牙设备、查找远程设备、配对(已配对设备将会忽略这步的细节)、连接设备和传输数据.在Android平台中首先我们需要查找本地活动的蓝牙适配器,通过BluetoothAdapter类的getDefaultAdapter() 方法获得一个系统默认可用的蓝牙设备,示例代码如下BluetoothAdapter cwjBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();if (cwjBluetoothAdapter == null) {// Android开发网提示大家本机没有找到蓝牙硬件或驱动存在问题}当然有了这步仍然不能建立连接,因为我们还不知道手机中的蓝牙功能是否被开启,可以通过cwjBluetoothAdapter的.isEnabled方法来判断,如果没有开启,我们可以通过下面的代码提醒用户启用:if (!cwjBluetoothAdapter.isEnabled()) {Intent TurnOnBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(TurnOnBtIntent, REQUEST_ENABLE_BT);}这时用户会收到类似下面的窗口:我们通过startActivityForResult()方法发起的Intent将会在onActivityResult()回调方法中获取用户的选择,比如用户单击了Yes开启,那么将会收到RESULT_OK 的结果,如果RESULT_CANCELED则代表用户不愿意开启蓝牙,当然android123提醒大家还可以通过其他方式来开启,比如说用 BluetoothDevice 获取蓝牙服务接口对象,是用enable()方法来开启,无需询问用户,这时就需要用到android.permission.BLUETOOTH_ADMIN权限。
如何判断系统蓝牙的状态呢? 建立BroadcastReceiver对象,接收ACTION_STATE_CHANGED动作,在EXTRA_STATE和 EXTRA_PREVIOUS_STATE包含了现在状态和过去的状态,最终的结果定义是STATE_TURNING_ON正在开启, STATE_ON已经开启, STATE_TURNING_OFF正在关闭和 STATE_OFF已经关闭,如果有什么不明白的可以在我们的论坛中交流。
Android 蓝牙中的 RFCOMM一RFCOMM通道:RFCOMM协议一个基于欧洲电信标准协会ETSI07.10规程的串行线性仿真协议。
此协议提供RS232控制和状态信号,如基带上的损坏,CTS以及数据信号等,为上层业务(如传统的串行线缆应用)提供了传送能力。
RFCOMM是一个简单传输协议,其目的是针对如何在两个不同设备上的应用之间保证一条完整的通信路径,并在它们之间保持一通信段。
RFCOMM协议概述RFCOMM通信段RFCOMM是为了兼容传统的串口应用,同时取代有线的通信方式,蓝牙协议栈需要提供与有线串口一致的通信接口而开发出的协议。
RFCOMM协议提供对基于L2CAP协议的串口仿真,基于ETSI07.10。
可支持在两个BT设备之间同时保持高达60路的通信连接。
目的:在两个不同设备(通信设备的两端)上的应用之间保证一条完整的通信路径,并在他们之间保持一通信段。
下图是一条完整的通信路径。
RFCOMM只针对直接互连设备之间的连接,或者是设备与网络接入设备之间的互连。
通信两端设备必须兼容于RFCOMM协议,有两类设备:DTE (Data Terminal Endpoint,通信终端,如PC,PRINTER)和DCE (Data Circuit Endpoint,通信段的一部分,如Modem)。
此两类设备不作区分。
RFCOMM服务RFCOMM仿真RS232串口,仿真过程包括非数据通路状态的传输,RFCOMM内置空Modem仿真标准框架。
RFCOMM中的仿真RS-232通路多串口仿真两个采用RFCOMM通信的BT设备有可能同时打开多个串口,RFCOMM支持同时打开60个端口。