有关蓝牙:
蓝牙可以让两个设备在一定距离内进行连接,以传输数据。这个数据可以互相传输,你传给我,我也可以传给你。
两个连接的设备,一个作为服务器端,一个作为客户端。
使用蓝牙,需要以下步骤
第一步打开蓝牙。
第二步发现对方蓝牙设备。服务端需要使自己置于可被发现状态(注意打开蓝牙并不一定可被发现),然后客户端去寻找蓝牙。
第三步客户端去连接服务端。
第四步传输数据。
第五部结束连接。
这些步骤都可以使用代码实现,不需要用户在安卓“设置”里面去操作。
如何实现:
首先需要分清谁是服务器端,谁是客户端。
服务端和客户端的区别在于,客户端是攻,服务端是受,对话都是客户端发起的。
注意的是两端是通过Socket连接,一般如果长时间没有数据交互的话要把Socket关闭,等下次要交互再重新创建Socket连接。
还有在manifest中声明蓝牙权限,代码如下
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
1 服务器端首先要做的是打开蓝牙、置于可被发现状态。
代码为
// 打开本机的蓝牙发现功能(默认打开120秒,可以将时间最多延长至300秒)
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
// 设置持续时间(最多300秒)
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivityForResult(discoverableIntent, 0x1);
如果一开始没有打开,使用该代码也会自动打开蓝牙。
这个代码会弹出一个对话框询问是否打开蓝牙并可被发现。默认持续120秒可被发现,最多设置300秒。
然后在Activity的onActivityResult中
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
resultCode为持续可被发现的时间,如上面传输打开300秒,返回的resultCode就为300秒。启用失败或者用户在对话框中选择拒绝则返回0。
2 客户端要打开蓝牙,然后去寻找服务端。
客户端不像服务端两行代码会自动打开蓝牙,他需要先打开蓝牙才能去寻找服务端。
打开蓝牙有两种方式:第一种方式会弹出是否打开蓝牙弹出框,确认后才能代开;第二种方式直接打开,不询问用户。
第一种打开蓝牙方式,询问用户是否打开蓝牙的方式
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, 0x2);
然后在onActivityResult中会有返回码,告诉成功还是失败。
如果蓝牙已经打开,则不会弹出询问框。
可以使用BluetoothAdapter.getDefaultAdapter().isEnabled();查看蓝牙当前是否打开。
第二种方式直接打开蓝牙而不询问用户
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
// 直接打开蓝牙,同步执行
adapter.enable();
可以使用BluetoothAdapter.getDefaultAdapter().isEnabled();查看蓝牙当前是否打开。
打开蓝牙成功后,去寻找服务器端
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
adapter.startDiscovery();
该寻找过程是在异步线程中执行的,总共只会持续寻找12秒,寻找到的话会发广播出来。
因此需要注册广播接收蓝牙寻找结果
<receiver
android:name="com.example.testbluetooth.BlueToothReceiver">
<intent-filter >
<action android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED"/>
<action android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED"/>
<action android:name="android.bluetooth.device.action.FOUND" />
</intent-filter>
</receiver>
蓝牙广播接收器代码
public class BlueToothReceiver extends BroadcastReceiver
{
private static List<BluetoothDevice> mDeviceArr = new ArrayList<BluetoothDevice>();
@Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED))
{
// 开始寻找蓝牙
mDeviceArr.clear();
MainActivity mainActivity = MainActivity.getInstance();
if (mainActivity != null)
{
mainActivity.refreshList(mDeviceArr);
}
}
else if (intent.getAction().equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED))
{
// 结束寻找
}
else if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND))
{
// 找到一个设备
// 从Intent中获取设备对象
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getName().isEmpty() || mDeviceArr.contains(device))
{
return;
}
// 将设备名称和地址放入array adapter,以便在ListView中显示
mDeviceArr.add(device);
MainActivity mainActivity = MainActivity.getInstance();
if (mainActivity != null)
{
mainActivity.refreshList(mDeviceArr);
}
}
}
}
到此为止客户端已经找到服务端了,最好把寻找到的服务器地址给记录下来,下次就不需要再去寻找服务器端了。
通过device.getAddress()可以获取服务器地址,而找到过的历史服务器下次可以通过BluetoothAdapter.getDefaultAdapter().getBondedDevices()获取。
也就是下次可以通过BluetoothAdapter.getDefaultAdapter().getBondedDevices()去寻找这个BluetoothDevice。
现在要让客户端去连接服务端了。
3 客户端连接服务端
连接服务端前需要停止搜索,不然可能连接失败。
if (adapter.isDiscovering())
{
adapter.cancelDiscovery();
}
创建Socket:
try
{
mSocket = mDevice.createRfcommSocketToServiceRecord(MY_UUID);
}
catch (IOException e)
{
e.printStackTrace();
}
其中这个MY_UUID可以通过UUID.fromString("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");获取一个。x为十六进制数1-f。
服务器端与客户端必须使用相同的UUID才能连接成功。
尝试连接:
try
{
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mSocket.connect();
}
catch (IOException connectException)
{
connectException.printStackTrace();
}
connect是同步执行,在没有连接结果返回前一直阻塞,所以需要创建一个线程来执行connect()。
如果没有配对过该设备连接会弹出对话框询问是否进行配对,如果曾经配对过则直接连接成功不弹出询问框。
如果connect通过以后可以调用mSocket.getOutputStream()与mSocket.getInputStream()获取输入输出流,通过这两个流与服务器端交换数据。
需要注意的是这个Stream是同步的,如果发送了对方没有接受,或者在接收可是没有接收到任何信息都会一直阻塞。
inputStream与outputStream就不再详述。
4 服务端接受客户端的连接
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
BluetoothServerSocket serverSocket;
BluetoothSocket socket = null;
try
{
serverSocket = adapter.listenUsingRfcommWithServiceRecord("TestBluetooth", MY_UUID);
socket = serverSocket.accept();
}
catch (IOException e)
{
e.printStackTrace();
}
该accept方法是阻塞的,需要创建一个线程来执行。
MY_UUID必须与客户端的MY_UUID相同,两个设备才能进行连接。
如果两个设备连接成功过则不弹出对话框询问是否配对,否则会弹出对话框询问是否配对设备。
然后通过socket.getInputStream();和socket.getOutputStream();获取输入流输出流。
需要注意的是这个Stream是同步的,如果发送了对方没有接受,或者在接收可是没有接收到任何信息都会一直阻塞。
不再详述他们的用法。