Android 应用可通过 Bluetooth API 执行以下操作:
- 扫描其他蓝牙设备
- 查询本地蓝牙适配器的配对蓝牙设备
- 建立 RFCOMM 通道
- 通过服务发现连接到其他设备
- 与其他设备进行双向数据传输
- 管理多个连接
AndroidManifest.xml中添加:
<manifest>
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- If your app targets Android 9 or lower, you can declare
ACCESS_COARSE_LOCATION instead. -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>
AcceptThread.java
import static androidx.constraintlayout.motion.utils.Oscillator.TAG;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.util.Log;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.UUID;
import java.util.logging.Handler;
public class AcceptThread extends Thread{
private final BluetoothServerSocket mmServerSocket;
private BluetoothAdapter bluetoothAdapter;
private static final String NAME="cyx";
private static final UUID MY_UUID=UUID.fromString("07690e75-8d5a-4655-bc77-5e75ac3d578c");
private Handler mHandler;
public AcceptThread(Handler UIhandler) {
// Use a temporary object that is later assigned to mmServerSocket
// because mmServerSocket is final.
mHandler=UIhandler;
BluetoothServerSocket tmp = null;
bluetoothAdapter=BluetoothAdapter.getDefaultAdapter();
try {
// MY_UUID is the app's UUID string, also used by the client code.
tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
Log.e(TAG, "Socket's listen() method failed", e);
}
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned.
while (true) {
mHandler.setEncoding();
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "Socket's accept() method failed", e);
break;
}
if (socket != null) {
// A connection was accepted. Perform work associated with
// the connection in a separate thread.
try {
manageMyConnectedSocket(socket);
}catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
mmServerSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
private void manageMyConnectedSocket(BluetoothSocket socket) throws UnsupportedEncodingException {
// 通知主线程连接上了服务端socket,更新UI
mHandler.setEncoding("Constant.MSG_CONNECTED_TO_SERVER");
// 新建一个线程进行通讯,不然会发现线程堵塞
mConnectedThread = new ConnectedThread(socket,mHandler);
mConnectedThread.start();
}
// Closes the connect socket and causes the thread to finish.
public void cancel() {
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the connect socket", e);
}
}
}
}
ConnectThread.java
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
import android.util.Log;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.UUID;
public class ConnectThread extends Thread{
private static final UUID MY_UUID = UUID.fromString("07690e75-8d5a-4655-bc77-5e75ac3d578c");
private final BluetoothSocket mmSoket;
private final BluetoothDevice mmDevice;
private BluetoothAdapter mBluetoothAdapter;
private final Handler mHandler;
private ConnectedThread mConnectedThread;
public ConnectThread(BluetoothDevice device, BluetoothAdapter bluetoothAdapter, Handler mUIhandler) {
mmDevice = device;
mBluetoothAdapter = bluetoothAdapter;
mHandler = mUIhandler;
BluetoothSocket tmp = null;
try {
// 创建客户端Socket
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
e.printStackTrace();
}
mmSoket = tmp;
}
@Override
public void run() {
super.run();
mBluetoothAdapter.cancelDiscovery();
try {
// 连接服务器
mmSoket.connect();
} catch (IOException e) {
// 连接异常就关闭
try {
mmSoket.close();
} catch (IOException e1) {
}
return;
}
manageConnectedSocket(mmSoket);
}
private void manageConnectedSocket(BluetoothSocket mmSoket) {
// 通知主线程连接上了服务端socket,更新UI
mHandler.sendEmptyMessage(Integer.parseInt("cyx"));
// 新建一个线程进行通讯,不然会发现线程堵塞
mConnectedThread = new ConnectedThread(mmSoket,mHandler);
mConnectedThread.start();
}
public void cancle() {
try {
mmSoket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendData(byte[] data) {
if(mConnectedThread != null) {
mConnectedThread.write(data);
}
}
}
ConnectedThread.java
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class ConnectedThread extends Thread{
private final BluetoothSocket mmSokcet;
private final InputStream mmInputStream;
private final OutputStream mmOutputStream;
private Handler mHandler;
private String TAG = "ConnectedThread";
public ConnectedThread(BluetoothSocket socket,Handler handler) {
mmSokcet = socket;
mHandler = handler;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
mmInputStream = tmpIn;
mmOutputStream = tmpOut;
}
@Override
public void run() {
super.run();
byte[] buffer = new byte[1024];
while (true) {
try {
// 读取数据
int bytes = mmInputStream.read(buffer);
if(bytes > 0) {
String data = new String(buffer,0,bytes,"utf-8");
// 把数据发送到主线程, 此处还可以用广播
Message message = mHandler.obtainMessage(Integer.parseInt("cyx"));
mHandler.sendMessage(message);
}
Log.d(TAG, "messge size :" + bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void cancle() {
try {
mmSokcet.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void write(byte[] data) {
try {
mmOutputStream.write(data);
} catch (IOException e) {
e.printStackTrace();
}
}
}
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(receiver, filter);
}
private final BroadcastReceiver receiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Discovery has found a device. Get the BluetoothDevice
// object and its info from the Intent.
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String deviceName = device.getName();
String deviceHardwareAddress = device.getAddress(); // MAC address
}
}
};
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
}