本篇内容介绍了“android蓝牙简单开发的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
前段时间学习了一些蓝牙开发的知识,记录一下Android中蓝牙的简单开发。下面是最重要的两个类。
BluetoothAdapter : 蓝牙适配器,通过getDefaultAdapter ()去获取一个实例,如果设备不支持蓝牙的话,返回的是一个null对象,通过它,可以打开、关闭蓝牙,扫描设备、向指定设备创建socket通道…
BluetoothDevice : 代表一个设备对象,可以通过它获取设备的名字、地址、类型等,也可以创建匹配,建立socket通道等等。
<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"/>
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 如果设备不支持蓝牙
if (mBluetoothAdapter == null){
return;
}
// 设备支持蓝牙功能,调用startActivityForResult去启动蓝牙
if (!mBluetoothAdapter.isEnabled()){
startBlueTooth.launch(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE));
}
打开蓝牙功能是通过startActivity去启动的,但是startActivity这个函数已经过期了,所以我使用官方推荐的Activity Result替代它
ActivityResultLauncher<Intent> startBlueTooth = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public 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);
}
}
}
});
通过广播去接收蓝牙状态的改变
class BluetoothStateChangeReceiver extends BroadcastReceiver{
public int DEFAULT_VALUE_BLUETOOTH = 1000;
@Override
public 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);
同样通过广播接收,action是BluetoothDevice.ACTION_FOUND
class MyReceiver extends BroadcastReceiver{
@Override
public 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();
public class BondReceiver extends BroadcastReceiver{
@Override
public 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;
}
}
}
}
已经配对的设备会被存储起来,通过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());
}
}
想要在两台设备之间创建连接,必须实现客户端和服务端机制,他们之间使用套接字机制进行连接,服务端开放服务器套接字,客户端通过MAC地址向服务端发起连接。客户端和服务端以不同的方式获得BluetoothSocket
,当客户端和服务端在同一个RFCOMM通道上分别拥有已连接的BluetoothSocket
时,将他们视为彼此已经连接,于是每台设备都获得输入和输出流式传输,并开始传输数据。
连接技术
一种实现技术是自动将每台设备准备为一个服务器,从而使每台设备开放一个服务套接字并侦听连接,在此情况下,任何一台设备都可以发起与另一台设备的连接并称为客户端。
服务器
设置服务器套接字并接受连接,步骤依次如下
1、调用listenUsingRfcommWithServiceRecord()获取一个BluetoothServerSocket
, 该函数需要两个参数,第一个是服务器的名称,自己取一个即可,第二个是UUID,用来对信息做唯一性标识,我们可以从网上众多UUID生成器中随机的生成一个,然后使用UUID.fromString(String)初始化一个UUID。
2、通过accept()函数开始侦听连接请求
只有远程设备发送的连接请求中UUID与使用此套接字注册的UUID相匹配时服务器才会接受请求,accept函数会返回已连接的BluetoothSocket
3、连接成功后调用close()
关闭BluetoothSocket
private class AcceptThread extends Thread{
private final BluetoothServerSocket mmServerSocket;
private String mSocketType;
public AcceptThread(boolean secure){
BluetoothServerSocket tmp = null;
mSocketType = secure ? "secure" : "Insercure";
try{
if (secure){
tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,MY_UUID_SECURE);
}else{
tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME_INSECURE,MY_UUID_INSECURE);
}
} catch (IOException e) {
Log.e(TAG,"socket type"+ mSocketType + "listen() failed",e);
}
mmServerSocket = tmp;
}
@Override
public void run() {
Log.d(TAG, "Socket Type: " + mSocketType +
"BEGIN mAcceptThread" + this);
setName("AcceptThread"+ mSocketType);
BluetoothSocket socket = null;
Log.d(TAG, "run: 开始监听");
while (true){
try{
socket = mmServerSocket.accept();
Log.d("acceptThread", "run: 连接成功");
connected(socket,socket.getRemoteDevice(),mSocketType);
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e);
break;
}
}
Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType);
}
public void cancel() {
Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this);
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e);
}
}
}
上面的secure和Insecure只是使用了不同的UUID而已。
客户端
远程设备开启监听后,我们就发起向此设备的连接,首先必须先获得远程设备的BluetoothDevice对象,然后获取BluetoothSocket发起连接。
基本步骤如下
1、使用BluetoothDevice
通过调用createRfcommSocketToServiceRecord(UUID)
获取 BluetoothSocket
。
2、通过connect发起连接
private class ConnectThread extends Thread{
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
private String mSocketType;
public ConnectThread(BluetoothDevice device, boolean secure){
mmDevice = device;
BluetoothSocket tmp = null;
mSocketType = secure ? "Secure" : "Insecure";
try {
if (secure){
tmp = device.createRfcommSocketToServiceRecord(MY_UUID_SECURE);
}else {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID_INSECURE);
}
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
}
mmSocket = tmp;
}
@Override
public void run() {
Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
setName("ConnectThred"+mSocketType);
// 总是取消发现,因为它会减慢连接
bluetoothAdapter.cancelDiscovery();
// connect
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
Log.d(TAG, "run: socket连接成功");
} catch (IOException e) {
// Close the socket
Log.d(TAG, "run: 关闭socket");
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() " + mSocketType +
" socket during connection failure", e2);
}
return;
}
connected(mmSocket,mmDevice,mSocketType);
}
public void cancel(){
try{
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e);
}
}
}
发送数据
连接成功后,我们就可以通过socket发送数据了,客户端的Socket对象是BluetoothSocket
, 服务端的socket是BluetoothServerSocket
,特别注意不要混淆了。使用getInputStream
和getOutputStream
分别获取通过套接字处理数据传输的InputStream
和OutputStream
。写数据比较简单,但是读数据就需要一个单独的线程一直监听才行。
private class ConnectedThread extends Thread{
private final BluetoothSocket mmSocket;
private InputStream mmInStream;
private OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket, String socketType) throws IOException {
Log.d(TAG, "create ConnectedThread: " + socketType);
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try{
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
if (socket != null){
tmpOut.write(new String("hello").getBytes());
Log.d(TAG, "ConnectedThread: socket不是null");
}
} catch (IOException e) {
Log.e(TAG,"temp socket not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
// mmOutStream.write(new String("hello").getBytes());
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
while (true){
try{
bytes = mmInStream.read(buffer);
// send the bytes to the ui Activity
String text = encodeByteToString(buffer,bytes);
Log.d(TAG, "run: 收到消息:"+ text);
chatItems.add(text);
mHandler.sendMessage(mHandler.obtainMessage());
} catch (IOException e) {
Log.d(TAG, "run: 没有收到消息");
e.printStackTrace();
break;
}
}
}
public String encodeByteToString(byte[] data,int length) {
byte[] temp = new byte[length];
for (int i = 0; i < length; i++) {
temp[i] = data[i];
}
try {
return new String(temp,"utf-8");
} catch (UnsupportedEncodingException e) {
return "";
}
}
public void write(byte[] buffer){
try{
mmOutStream.write(buffer);
// mHandler.obtainMessage(Constants.MESSAGE_WRITE,-1,-1,buffer).sendToTarget();
} catch (IOException e) {
e.printStackTrace();
}
}
public void cancel(){
try{
mmSocket.close();
Log.d(TAG, "cancel: connectedThread");
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
“android蓝牙简单开发的方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。