Android蓝牙应用开发

来源:互联网 发布:学历史的软件 编辑:程序博客网 时间:2024/05/21 10:50
本文介绍如何使用Android的蓝牙API来完成使用蓝牙通信所需要的四项主要任务:设置蓝牙、查找已配对或区域内可用的蓝牙设备、连接设备、设备间传输数据。使用蓝牙API,Android应用程序能够执行以下功能:
1. 扫描其他蓝牙设备
2. 查询本地已经配对的蓝牙适配器
3. 建立RFCOMM通道
4. 通过服务发现来连接其他设备
5. 在设备间传输数据

6. 管理多个蓝牙连接

主要的类和方法:

1、BluetoothAdapter

是所有蓝牙交互的入口。使用这个类,你能够发现其他的蓝牙设备,查询已配对设备的列表,使用已知的MAC地址来实例化一个BluetoothDevice对象,并且创建一个BluetoothServerSocket对象来监听与其他设备的通信。

2、BluetoothDevice
代表一个远程的蓝牙设备。使用这个类通过BluetoothSocket或查询诸如名称、地址、类和配对状态等

3、BluetoothSocket
代表蓝牙socket的接口(类似TCP的Socket)。这是允许一个应用程序跟另一个蓝牙设备通过输入流和输出流进行数据交换的连接点

4、BluetoothServerSocket
代表一个打开的监听传入请求的服务接口(类似于TCP的ServerSocket)。为了连接两个Android设备,一个设备必须用这个类打开一个服务接口。

需要声明的权限

<uses-permission android:name="android.permission.BLUETOOTH"/><uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
操作步骤

1、设置蓝牙

  获得BluetoothAdapter对象getDefaultAdapter(),getDefaultAdapter()方法返回null,那么该设备不支持蓝牙;

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();if (mBluetoothAdapter == null) {    // Device does not support Bluetooth}
启用蓝牙功能,调用isEnabled()方法来检查当前蓝牙是否可用。如果这个方法返回false,那么蓝牙是被禁用的。要申请启用蓝牙功能,就要调用带有ACTION_REQUEST_ENABLE操作意图的startActivityForResult()方法

 if (!mBluetoothAdapter.isEnabled()) {    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);}
传递给startActivityForResult()方法的REQUEST_ENABLE_BT常量,是一个你的应用程序中定义的整数(它必须大于0)

2、查找设备

在执行设备发现之前,应该先查询已配对的设备集合,来看期望的设备是否是已知的。调用getBondedDevices()方法来完成这件工作。这个方法会返回一个代表已配对设备的BluetoothDevice对象的集合。

Set pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if(pairedDevices.size()>0){
// Loop through paired devices
for(BluetoothDevice device : pairedDevices){
// Add the name and address to an array adapter to show in a ListView
mArrayAdapter.add(device.getName()+"\n"+ device.getAddress());
}
}

调用startDiscovery()方法就可以开始发现设备,为了接收每个被发现设备的的信息,你的应用程序必须注册一个ACTION_FOUND类型的广播接收器。

// Create a BroadcastReceiver for ACTION_FOUNDprivate final BroadcastReceiver mReceiver = new BroadcastReceiver() {    public void onReceive(Context context, Intent intent) {        String action = intent.getAction();        // When discovery finds a device        if (BluetoothDevice.ACTION_FOUND.equals(action)) {            // Get the BluetoothDevice object from the Intent            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);            // Add the name and address to an array adapter to show in a ListView            mArrayAdapter.add(device.getName() + "\n" + device.getAddress());        }    }};// Register the BroadcastReceiverIntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
执行设备发现,对于蓝牙适配器来说是一个沉重的过程,它会消耗大量的资源。一旦发现要连接设备,在尝试连接之前一定要确认用cancelDiscovery()方法来终止发现操作。

3.启用设备的可发现性

如果要让本地设备可以被其他设备发现,那么就要调用ACTION_REQUEST_DISCOVERABLE操作意图的startActivityForResult(Intent, int)方法,默认情况下,设备的可发现模式会持续120秒,通过给Intent对象添加EXTRA_DISCOVERABLE_DURATION附加字段,可以定义不同持续时间。应用程序能够设置的最大持续时间是3600秒,0意味着设备始终是可发现的。任何小于0或大于3600秒的值都会自动的被设为120秒。例如,以下代码把持续时间设置为300秒:

Intent discoverableIntent = newIntent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);startActivity(discoverableIntent);
注意:如果设备没有开启蓝牙功能,那么开启设备的可发现模式会自动开启蓝牙,如果作为服务器端必须实现可发现;如果你想要在可发现模式被改变时获得通知,那么你可以注册一个ACTION_SCAN_MODE_CHANGED类型的Intent广播。这个Intent对象中包含了EXTRA_SCAN_MODE和EXTRA_PREVIOUS_SCAN_MODE附加字段,它们会分别告诉你新旧扫描模式。它们每个可能的值是:SCAN_MODE_CONNECTABLE_DISCOVERABLE,SCAN_MODE_CONNECTABLE或SCAN_MODE_NONE,它们分别指明设备是在可发现模式下,还是在可发现模式下但依然可接收连接,或者是在可发现模式下并不能接收连接。

为了让两个设备上的两个应用程序之间建立连接,你必须同时实现服务端和客户端机制,因为一个设备必须打开服务端口,同时另一个设备必须初始化跟服务端设备的连接(使用服务端的MAC地址来初始化一个连接)。当服务端和客户端在相同的RFCOMM通道上有一个BluetoothSocket连接时,才能够被认为是服务端和客户端之间建立了连接。这时,每个设备能够获得输入和输出流,并且能够彼此开始传输数据。

3.蓝牙设备连接

作为服务器端:

1. 调用listenUsingRfcommWithServiceRecord(String, UUID)方法来获得一个BluetoothServerSocket对象。

2. 通过调用accept()方法,启动连接请求,accept()方法会返回一个被连接的BluetoothSocket对象。

3. 调用close()方法。

private class AcceptThread extends Thread {    private final BluetoothServerSocket mmServerSocket;     public AcceptThread() {        // Use a temporary object that is later assigned to mmServerSocket,        // because mmServerSocket is final        BluetoothServerSocket tmp = null;        try {            // MY_UUID is the app's UUID string, also used by the client code            tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);        } catch (IOException e) { }        mmServerSocket = tmp;    }     public void run() {        BluetoothSocket socket = null;        // Keep listening until exception occurs or a socket is returned        while (true) {            try {                socket = mmServerSocket.accept();            } catch (IOException e) {                break;            }            // If a connection was accepted            if (socket != null) {                // Do work to manage the connection (in a separate thread)                manageConnectedSocket(socket);                mmServerSocket.close();                break;            }        }    }     /** Will cancel the listening socket, and cause the thread to finish */    public void cancel() {        try {            mmServerSocket.close();        } catch (IOException e) { }    }}

作为客户端:

1. 通过调用BluetoothDevice的createRfcommSocketToServiceRecord(UUID)方法,获得一个BluetoothSocket对象。

2. 通过调用connect()方法来初始化连接。

在调用connect()方法时,应该始终确保设备没有正在执行设备发现操作,在建立连接之前要调用cancelDiscovery()方法。

private class ConnectThread extends Thread {    private final BluetoothSocket mmSocket;    private final BluetoothDevice mmDevice;     public ConnectThread(BluetoothDevice device) {        // Use a temporary object that is later assigned to mmSocket,        // because mmSocket is final        BluetoothSocket tmp = null;        mmDevice = device;         // Get a BluetoothSocket to connect with the given BluetoothDevice        try {            // MY_UUID is the app's UUID string, also used by the server code            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);        } catch (IOException e) { }        mmSocket = tmp;    }     public void run() {        // Cancel discovery because it will slow down the connection        mBluetoothAdapter.cancelDiscovery();         try {            // Connect the device through the socket. This will block            // until it succeeds or throws an exception            mmSocket.connect();        } catch (IOException connectException) {            // Unable to connect; close the socket and get out            try {                mmSocket.close();            } catch (IOException closeException) { }            return;        }         // Do work to manage the connection (in a separate thread)        manageConnectedSocket(mmSocket);    }     /** Will cancel an in-progress connection, and close the socket */    public void cancel() {        try {            mmSocket.close();        } catch (IOException e) { }    }}

数据传输:

1. 分别通过getInputStream()和getOutputStream()方法来获得通过套接字来处理传输任务的InputStream和OutputStream对象;
2. 用read(byte[])和write(byte[])方法来读写流中的数据。

private class ConnectedThread extends Thread {    private final BluetoothSocket mmSocket;    private final InputStream mmInStream;    private final OutputStream mmOutStream;     public ConnectedThread(BluetoothSocket socket) {        mmSocket = socket;        InputStream tmpIn = null;        OutputStream tmpOut = null;         // Get the input and output streams, using temp objects because        // member streams are final        try {            tmpIn = socket.getInputStream();            tmpOut = socket.getOutputStream();        } catch (IOException e) { }         mmInStream = tmpIn;        mmOutStream = tmpOut;    }     public void run() {        byte[] buffer = new byte[1024];  // buffer store for the stream        int bytes; // bytes returned from read()         // Keep listening to the InputStream until an exception occurs        while (true) {            try {                // Read from the InputStream                bytes = mmInStream.read(buffer);                // Send the obtained bytes to the UI activity                mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)                        .sendToTarget();            } catch (IOException e) {                break;            }        }    }     /* Call this from the main activity to send data to the remote device */    public void write(byte[] bytes) {        try {            mmOutStream.write(bytes);        } catch (IOException e) { }    }     /* Call this from the main activity to shutdown the connection */    public void cancel() {        try {            mmSocket.close();        } catch (IOException e) { }    }}



1 0
原创粉丝点击