1、 使用蓝牙权限
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
2、 打开关闭蓝牙
下面的adapter对象,相当于设备蓝牙的代理,对设备蓝牙的操作都通过这个对象来完成
if(adapter.isEnabled())//判断蓝牙是否打开
{
if(adapter.disable()) //关闭
{
.
}
}
else
{
if(adapter.enable()) //打开
{
.
}
}
打开和关闭蓝牙模块, 都可以通过BluetoothAdapter.ACTION_STATE_CHANGED广播来监听;
3、 设置可被发现
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300);
startActivity(discoverableIntent);
时间附加域值300可以自由指定,但最大300,不指定默认120;
网上没有找到怎么关闭可被发现的,发现目前有些手机的设置里的蓝牙,可以关闭可发现,可以一直被发现。经过测试,可以通过设置这个值来处理,因为这个时间以最新设置的为准。如本来还有250,如果重新执行一下以上操作,传域值1,则1秒后就不可被发现了,且此时不会出现选择是否允许可发现的提示框,只有状态从不可被发现到可被发现才会出现。
4、 搜索设备
if(!adapter.isDiscovering())
{
adapter.startDiscovery();
}
startDiscovery()方法是一个异步方法,调用后会立即返回。该方法会进行对其他蓝牙设备的搜索,该过程会持续12秒。该方法调用后,搜索过程实际上是在一个System Service中进行的,所以可以调用cancelDiscovery()方法来停止搜索(该方法可以在未执行discovery请求时调用)。
请求Discovery后,系统开始搜索蓝牙设备,在这个过程中,系统会发送以下三个广播:
ACTION_DISCOVERY_START:开始搜索
ACTION_DISCOVERY_FINISHED:搜索结束
ACTION_FOUND:找到设备,这个Intent中包含两个extra fields:EXTRA_DEVICE和EXTRA_CLASS,分别包含BluetooDevice和BluetoothClass。
于是可以注册广播,来将搜索到的设备保存起来,示例如下
if(BluetoothDevice.ACTION_FOUND.equals(action))
{
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//lists.add(device);
}
还可以注册下面的广播,跟踪搜索状态的开始和结束
if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action))
{
tvDiscovery.setText("Searching...");
}
if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action))
{
tvDiscovery.setText("Searchfinished!!!");
}
5、 匹配
可以判断设备是否在匹配
if (device.getBondState() ==BluetoothDevice.BOND_NONE)
else if(device.getBondState() ==BluetoothDevice.BOND_BONDED)
利用反射方法调用BluetoothDevice.createBond(BluetoothDeviceremoteDevice);
Method createBondMethod =BluetoothDevice.class.getMethod("createBond");
boolean returnValue = (Boolean)createBondMethod.invoke(device);
同样Method createBondMethod = BluetoothDevice.class.getMethod("removeBond");
Boolean returnValue = (Boolean)createBondMethod.invoke(device);
注册处理匹配状态广播
if(BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action))
{
BluetoothAdapteradapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevicedevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
switch (device.getBondState()){
caseBluetoothDevice.BOND_BONDING:
Log.d("BlueToothTestActivity", "正在配对......");
break;
caseBluetoothDevice.BOND_BONDED:
Log.d("BlueToothTestActivity", "完成配对");
Set<BluetoothDevice>dv = adapter.getBondedDevices();
if(dv.size()>0)
{
for(BluetoothDevice bd:dv)
{
//添加到列表
}
}
//更新匹配列表显示
break;
caseBluetoothDevice.BOND_NONE:
Log.d("BlueToothTestActivity", "取消配对");
//更新匹配列表显示
default:
break;
}
}
6、 连接
客户端主要操作
BluetoothSocket mmSocket =device.createRfcommSocketToServiceRecord(BtServer.MY_UUID);
下面的api在另一个线程中执行
mmSocket.connect();
比较关键的点在:
蓝牙的匹配和连接是分两步走的,基本上所以的蓝牙都是,很多看起来一步走的操作是因为被封装到一起了;
目前android这个版本的蓝牙使用的思路是,先匹配上,再根据具体功能来选择服务连接,以上的MY_UUID就是用来指定具体功能的;
UUID在服务端和客户端必须一样(网上的资料基本上也是称服务端和客户端,这个与android的服务组件不是一个概念,这里指的是连接的一个手机和被连接的另一个手机);
在执行connect之前,需要执行一下cancelDiscovery()以确保没有在执行搜索设备操作,否则连接操作会变的很慢且易出异常;
BluetoothSocket的connect()方法(该方法为block方法)必须在另一个线程中执行,如果正常返回,则表示连接成功。
连接是双方的,客户端在连接的时候,服务端需要accept,
BluetoothServerSocket mmServerSocket =adapter.listenUsingRfcommWithServiceRecord(BtServer.NAME, BtServer.MY_UUID);
//下面的api在另一线程中循环执行
while (true)
{
.
.
socket = mmServerSocket.accept();
.
.
}
if (socket != null) //连接成功
同时可以注册
BluetoothDevice.ACTION_ACL_DISCONNECTED
BluetoothDevice.ACTION_ACL_CONNECTED
这两个广播,来跟踪连接状态的改变
7、 测试socket通信
首先连接时获得的sockeyt对象是要保存下来的,通信就靠它了
1获取输入输出流
mmInStream = socket.getInputStream();
mmOutStream =socket.getOutputStream();
2写
byte[] bytes = {'1', '2', '3', ' ', 't', 'e', 's', 't'};
mmOutStream.write(bytes);
3读
在别一个线程中创建一个while循环,执行
bytes= mmInStream.read(buffer);
其中,bytes是读取到的字节个数,buffer缓冲区保存的读取的数据
另一小问题,在打印显示读写数据时,使用new String(buffer)对象,一般容易这样写buffer.toString,这样显示出来的就是buffer数组的首地址