在项目中经常用到蓝牙的应用,在这里特意写了一个demo。并且封装了代码,可以主动连接和被动连接一起使用,也可以分开使用。方便后面以后查询使用,也重新踩了部分坑。

项目地址:android实现蓝牙聊天功能

1、程序简单的界面

2、客户端,主动连接

package com.bluetooth.tool;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

//蓝牙连接管理类
public class BluetoothManage {
 private static final Object mLock = new Object();
 //蓝牙类的具体实现核心成员
 private BluetoothAdapter mBtAdapter = BluetoothAdapter.getDefaultAdapter();
 //蓝牙类的具体数据核心成员
 private BluetoothSocket mTransferSocket = null;
 //当前连接的蓝牙地址
 String mstrName = "";//当前连接用到的IP地址
 String mstrAddress = "";//当前连接用到的IP地址
 //读线程
 ReadThread mReadThread = null;
 //从数据核心成员拿到的输入输出
 InputStream mInputStream = null;
 OutputStream mOutputStream = null;
 private static BluetoothManage manage = null;

 public static BluetoothManage getInstance(){
 synchronized (BluetoothManage.class){
  if(manage == null)
  manage = new BluetoothManage();
 }
 return manage;
 }

 public boolean sendData(int nLength, byte[] data) {
 if (mOutputStream == null) return false;
 try {
  mOutputStream.write(data, 0, nLength);
  return true;
 } catch (IOException e) {
  e.printStackTrace();
 }
 return false;
 }

 ConnectListener mConnectListener = null;

 public void regConnectListener(ConnectListener arg0) {
 mConnectListener = arg0;
 }

 TopDataIOListener mIOListener = null;

 public void regIOListener(TopDataIOListener arg0) {
 mIOListener = arg0;
 }

 public void unRegIOListener() {
 mIOListener = null;
 }

 public boolean setSelectedDevice(String strDevice) {
 String[] strings = strDevice.split("\\|");

 if (strings.length == 2) {
  mstrName = strings[0];
  mstrAddress = strings[1];
  return true;
 }
 return false;
 }

 public String getSelectedDeviceName() {
 if (mstrAddress.length() == 0) {
  return null;
 }

 return String.format("%s|%s", mstrName, mstrAddress);
 }

 public void connect() {
 if (mstrAddress.length() == 0) return;

 final BluetoothDevice device = mBtAdapter.getRemoteDevice(mstrAddress);
 new Thread(new Runnable() {
  @Override
  public void run() {
  synchronized (mLock) {
   String strLogString = "";
   try {
   try {
    mTransferSocket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
   } catch (IOException e1) {
    mTransferSocket = null;
   }

   if (mTransferSocket == null) {
    if (null != mConnectListener)
    mConnectListener.OnConnectStatusCallBack(false);
    return;
   }
   long nStartMillTime = System.currentTimeMillis();

   //连接
   try {
    mTransferSocket.connect();
   } catch (IOException e1) {
    try {
    mTransferSocket.close();
    } catch (IOException e2) {
    e2.printStackTrace();
    }
    //等待一定时间
    mTransferSocket = null;

    try {
    long havePassTime = System.currentTimeMillis() - nStartMillTime;
    if (havePassTime < 6000) {
     Thread.sleep(7000 - havePassTime);
    }
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
   }
   //连接失败
   if (mTransferSocket == null) {
    if (null != mConnectListener)
    mConnectListener.OnConnectStatusCallBack(false);
    return;
   }

   try {
    mInputStream = mTransferSocket.getInputStream();
    mOutputStream = mTransferSocket.getOutputStream();
    mReadThread = new ReadThread();
    mReadThread.start();

    if (null != mConnectListener)
    mConnectListener.OnConnectStatusCallBack(true);
   } catch (IOException e1) {
    //断开连接
    try {
    if (mTransferSocket != null)
     mTransferSocket.close();
    } catch (IOException e2) {
    e2.printStackTrace();
    }

    mTransferSocket = null;
    e1.printStackTrace();

    if (null != mConnectListener)
    mConnectListener.OnConnectStatusCallBack(false);
   }
   } catch (Exception e) {
   //总体异常
   if (null != mConnectListener)
    mConnectListener.OnConnectStatusCallBack(false);
   }
  }
  }//run()
 }).start();
 }

 //读取数据
 class ReadThread extends Thread {
 public void run() {
  int nMaxBufLength = 1024;
  byte[] buffer = new byte[nMaxBufLength];
  int byteRead = -1;

  synchronized (mLock) {
  while (!isInterrupted()) {
   try {
   if (mInputStream != null) {
    byteRead = mInputStream.read(buffer);
    if (byteRead > 0 && byteRead <= buffer.length) {
    if (mIOListener != null)
     mIOListener.OnIOCallBack(byteRead, buffer);
    } else /*if (byteRead < 0 || byteRead > buffer.length)*/ {
    //连接已断开
    if (mConnectListener != null) {
     mConnectListener.OnDisConnectCallBack();
    }
    break;
    }
   } else {
    break;
   }
   } catch (IOException e) {
   //连接已断开
   if (mConnectListener != null) {
    mConnectListener.OnDisConnectCallBack();
   }
   break;
   }
  }//while(!isInterrupted())
  }//synchronized (mLock)
 }
 }

 //断开蓝牙
 public void disConnect() {
 mConnectListener = null;
 //结束读线程
 if (mReadThread != null) {
  mReadThread.interrupt();
  mReadThread = null;
 }
 //取消所有连接
 if (mTransferSocket != null) {
  try {
  mTransferSocket.close();
  if (mInputStream != null)
   mInputStream.close();
  if (mOutputStream != null)
   mOutputStream.close();
  mInputStream = null;
  mOutputStream = null;
  mTransferSocket = null;
  } catch (IOException e) {
  e.printStackTrace();
  } catch (Exception e) {
  }
 }
 }
} 

主动连接应该是比较简单的,一个类就能实现,包括数据的收发。

3、蓝牙服务端,接收蓝牙连接

/**
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bluetooth.tool;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

/**
 * This class does all the work for setting up and managing Bluetooth
 * connections with other devices. It has a thread that listens for incoming
 * connections, a thread for connecting with a device, and a thread for
 * performing data transmissions when connected.
 */
public class BluetoothChatService {
 // Debugging
 private static final String TAG = "BluetoothChatService";
 private static final boolean D = true;

 // Name for the SDP record when creating server socket
 private static final String NAME = "BluetoothChat";

 // Unique UUID for this application
 // private static final UUID MY_UUID =
 // UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
 private static final UUID MY_UUID = UUID
  .fromString("00001101-0000-1000-8000-00805F9B34FB");
 //

 // Member fields
 private final BluetoothAdapter mAdapter;
 private final Handler mHandler;
 private AcceptThread mAcceptThread;
 private ConnectThread mConnectThread;
 private ConnectedThread mConnectedThread;
 private int mState;
 private BluetoothDevice mBluetoothDevice = null;

 // Constants that indicate the current connection state
 public static final int STATE_NONE = 0; // we're doing nothing
 public static final int STATE_LISTEN = 1; // now listening for incoming
      // connections
 public static final int STATE_CONNECTING = 2; // now initiating an outgoing
       // connection
 public static final int STATE_CONNECTED = 3; // now connected to a remote
       // device

 public static boolean mbIsOpenTimer = false;
 /**
 * Constructor. Prepares a new BluetoothChat session.
 *
 * @param context
 *  The UI Activity Context
 * @param handler
 *  A Handler to send messages back to the UI Activity
 */
 public BluetoothChatService(Context context, Handler handler) {
 mAdapter = BluetoothAdapter.getDefaultAdapter();
 mState = STATE_NONE;
 mHandler = handler;
 }

 /**
 * Set the current state of the chat connection
 *
 * @param state
 *  An integer defining the current connection state
 */
 private synchronized void setState(int state) {
 if (D)
  Log.d(TAG, "setState() " + mState + " -> " + state);
 mState = state;

 // Give the new state to the Handler so the UI Activity can update
 mHandler.obtainMessage(BluetoothChat.MESSAGE_STATE_CHANGE, state, -1)
  .sendToTarget();
 }

 /**
 * Return the current connection state.
 */
 public synchronized int getState() {
 return mState;
 }

 /**
 * Start the chat service. Specifically start AcceptThread to begin a
 * session in listening (server) mode. Called by the Activity onResume()
 */
 public synchronized void start() {
 if (D)
  Log.d(TAG, "start");

 // Cancel any thread attempting to make a connection
 if (mConnectThread != null) {
  mConnectThread.cancel();
  mConnectThread = null;
 }

 // Cancel any thread currently running a connection
 if (mConnectedThread != null) {
  mConnectedThread.cancel();
  mConnectedThread = null;
 }

 // Start the thread to listen on a BluetoothServerSocket
 if (mAcceptThread == null) {
  Log.d(TAG, "start mAcceptThread");
  mAcceptThread = new AcceptThread();
  mAcceptThread.start();
 }
 setState(STATE_LISTEN);
 }

 /**
 * Start the ConnectThread to initiate a connection to a remote device.
 *
 * @param device
 *  The BluetoothDevice to connect
 */
 public synchronized void connect(BluetoothDevice device) {
 if (D)
  Log.d(TAG, "connect to: " + device);

 // Cancel any thread attempting to make a connection
 if (mState == STATE_CONNECTING) {
  if (mConnectThread != null) {
  mConnectThread.cancel();
  mConnectThread = null;
  }
 }

 // Cancel any thread currently running a connection
 if (mConnectedThread != null) {
  mConnectedThread.cancel();
  mConnectedThread = null;
 }

 // Start the thread to connect with the given device
 mConnectThread = new ConnectThread(device);
 mConnectThread.start();
 setState(STATE_CONNECTING);
 mBluetoothDevice = device;
 }

 /**
 * Start the ConnectedThread to begin managing a Bluetooth connection
 *
 * @param socket
 *  The BluetoothSocket on which the connection was made
 * @param device
 *  The BluetoothDevice that has been connected
 */
 public synchronized void connected(BluetoothSocket socket,
  BluetoothDevice device) {
 if (D)
  Log.d(TAG, "connected");

 // Cancel the thread that completed the connection
 if (mConnectThread != null) {
  mConnectThread.cancel();
  mConnectThread = null;
 }

 // Cancel any thread currently running a connection
 if (mConnectedThread != null) {
  mConnectedThread.cancel();
  mConnectedThread = null;
 }

 // Cancel the accept thread because we only want to connect to one
 // device
 if (mAcceptThread != null) {
  mAcceptThread.cancel();
  mAcceptThread = null;
 }

 // Start the thread to manage the connection and perform transmissions
 mConnectedThread = new ConnectedThread(socket);
 mConnectedThread.start();

 // Send the name of the connected device back to the UI Activity
 Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_DEVICE_NAME);
 Bundle bundle = new Bundle();
 bundle.putString(BluetoothChat.DEVICE_NAME, device.getName());
 msg.setData(bundle);
 mHandler.sendMessage(msg);

 setState(STATE_CONNECTED);
 }

 /**
 * Stop all threads
 */
 public synchronized void stop() {
 if (D)
  Log.d(TAG, "stop");
 if (mConnectThread != null) {
  mConnectThread.cancel();
  mConnectThread = null;
 }
 if (mConnectedThread != null) {
  mConnectedThread.cancel();
  mConnectedThread = null;
 }
 if (mAcceptThread != null) {
  mAcceptThread.cancel();
  mAcceptThread = null;
 }
 setState(STATE_NONE);
 }

 /**
 * Write to the ConnectedThread in an unsynchronized manner
 *
 * @param out
 *  The bytes to write
 * @see ConnectedThread#write(byte[])
 */
 public void write(byte[] out) {
 // Create temporary object
 ConnectedThread r;
 // Synchronize a copy of the ConnectedThread
 synchronized (this) {
  if (mState != STATE_CONNECTED)
  return;
  r = mConnectedThread;
 }
 // Perform the write unsynchronized
 r.write(out);
 }

 /**
 * Indicate that the connection attempt failed and notify the UI Activity.
 */
 private void connectionFailed() {
 setState(STATE_LISTEN);

 // Send a failure message back to the Activity
 Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
 Bundle bundle = new Bundle();
 bundle.putString(BluetoothChat.TOAST, "Unable to connect device");
 msg.setData(bundle);
 mHandler.sendMessage(msg);
 }

 /**
 * Indicate that the connection was lost and notify the UI Activity.
 */
 private void connectionLost() {
 setState(STATE_LISTEN);

 // Send a failure message back to the Activity
 Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
 Bundle bundle = new Bundle();
 bundle.putString(BluetoothChat.TOAST, "Device connection was lost");
 msg.setData(bundle);
 mHandler.sendMessage(msg);
 start();
 }

 /**
 * This thread runs while listening for incoming connections. It behaves
 * like a server-side client. It runs until a connection is accepted (or
 * until cancelled).
 */
 private class AcceptThread extends Thread {
 // The local server socket
 private final BluetoothServerSocket mmServerSocket;

 public AcceptThread() {
  BluetoothServerSocket tmp = null;

  // Create a new listening server socket
  try {
  tmp = mAdapter
   .listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
  } catch (IOException e) {
  Log.e(TAG, "listen() failed", e);
  }
  mmServerSocket = tmp;
 }

 public void run() {
  if (D)
  Log.d(TAG, "BEGIN mAcceptThread" + this);
  setName("AcceptThread");
  BluetoothSocket socket = null;

  // Listen to the server socket if we're not connected
  while (mState != STATE_CONNECTED) {
  try {
   // This is a blocking call and will only return on a
   // successful connection or an exception
   if(mmServerSocket != null)
   {
   Log.d(TAG, "waitting accept!");
   socket = mmServerSocket.accept();
   Log.d(TAG, "accpting!");
   }
   else
   {
   setState(STATE_NONE);

   if (mAcceptThread != null) {
    mAcceptThread = null;
   }

   Log.d(TAG, "mmServerSocket = null!");
   break;
   }

  } catch (IOException e) {
   Log.e(TAG, "accept() failed", e);
   break;
  }

  // If a connection was accepted
  if (socket != null) {
   synchronized (BluetoothChatService.this) {
   switch (mState) {
   case STATE_LISTEN:
   case STATE_CONNECTING:
    // Situation normal. Start the connected thread.
    connected(socket, socket.getRemoteDevice());
    break;
   case STATE_NONE:
   case STATE_CONNECTED:
    // Either not ready or already connected. Terminate
    // new socket.
    try {
    socket.close();
    } catch (IOException e) {
    Log.e(TAG, "Could not close unwanted socket", e);
    }
    break;
   }
   }
  }
  }
  if (D)
  Log.i(TAG, "END mAcceptThread");
 }

 public void cancel() {
  if (D)
  Log.d(TAG, "cancel " + this);
  try {
  if(mmServerSocket != null)
   mmServerSocket.close();
  } catch (IOException e) {
  Log.e(TAG, "close() of server failed", e);
  }
 }
 }

 /**
 * This thread runs while attempting to make an outgoing connection with a
 * device. It runs straight through; the connection either succeeds or
 * fails.
 */
 private class ConnectThread extends Thread {
 private final BluetoothSocket mmSocket;
 private final BluetoothDevice mmDevice;

 public ConnectThread(BluetoothDevice device) {
  mmDevice = device;
  BluetoothSocket tmp = null;

  // Get a BluetoothSocket for a connection with the
  // given BluetoothDevice
  try {
  tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
  } catch (IOException e) {
  Log.e(TAG, "create() failed", e);
  }
  mmSocket = tmp;
 }

 public void run() {
  Log.i(TAG, "BEGIN mConnectThread");
  setName("ConnectThread");

  // Always cancel discovery because it will slow down a connection
  mAdapter.cancelDiscovery();

  // 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();
  } catch (IOException e) {
  connectionFailed();
  // Close the socket
  try {
   mmSocket.close();
  } catch (IOException e2) {
   Log.e(TAG,
    "unable to close() socket during connection failure",
    e2);
  }
  // Start the service over to restart listening mode
  BluetoothChatService.this.start();
  return;
  }

  // Reset the ConnectThread because we're done
  synchronized (BluetoothChatService.this) {
  mConnectThread = null;
  }

  // Start the connected thread
  connected(mmSocket, mmDevice);
 }

 public void cancel() {
  try {
  mmSocket.close();
  } catch (IOException e) {
  Log.e(TAG, "close() of connect socket failed", e);
  }
 }
 }

 /**
 * This thread runs during a connection with a remote device. It handles all
 * incoming and outgoing transmissions.
 */
 private class ConnectedThread extends Thread {
 private final BluetoothSocket mmSocket;
 private final InputStream mmInStream;
 private final OutputStream mmOutStream;

 public ConnectedThread(BluetoothSocket socket) {
  Log.d(TAG, "create ConnectedThread");
  mmSocket = socket;
  InputStream tmpIn = null;
  OutputStream tmpOut = null;
  try {
  tmpIn = socket.getInputStream();
  tmpOut = socket.getOutputStream();
  } catch (IOException e) {
  Log.e(TAG, "temp sockets not created", e);
  }

  mmInStream = tmpIn;
  mmOutStream = tmpOut;
 }

 public void run() {
  Log.i(TAG, "BEGIN mConnectedThread");
  byte[] buffer = new byte[1024];
  int bytes;

  // Keep listening to the InputStream while connected
  while (true) {
  try {
   // Read from the InputStream
   if(mmInStream != null ){
   bytes = mmInStream.read(buffer);
   if(bytes > 0 && bytes <= buffer.length)
   {
    onDadaReceive(buffer,0,bytes);
   }
   else{
    Log.i("recieve", "Baddata");
   }
   }
   else{
   Log.i(TAG, "BadInputStream");
   connectionLost();
   break;
   }
  }
  catch (IOException e) {
   Log.i(TAG, "disconnected" + e.toString(), e);
   connectionLost();
   break;
  } catch (Exception e) {
   e.printStackTrace();
  }
  }
 }

 private void onDadaReceive(byte[] buffer, int i, int bytes) {
  if(bytes>0)
  {
  //֪ͨܘַ
  mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes,
   -1, buffer).sendToTarget();

  }
  else
  Log.e("recieve","null");

 }

 /**
  * Write to the connected OutStream.
  *
  * @param buffer
  *  The bytes to write
  */
 public void write(byte[] buffer) {
  try {
  mmOutStream.write(buffer);

  // Share the sent message back to the UI Activity
  mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1,
   buffer).sendToTarget();
  } catch (IOException e) {
  Log.e(TAG, "Exception during write", e);
  }
 }

 public void cancel() {
  try {
  mmSocket.close();
  } catch (IOException e) {
  Log.e(TAG, "close() of connect socket failed", e);
  }
 }
 }

} 

这个蓝牙服务的代码,是标准蓝牙示例demo代码

我根据上面,自已封装了一层,方便管理数据。

package com.bluetooth.tool;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

/**
 * 蓝牙服务,接收蓝牙连接
 */
public class BluetoothChat {
 // Debugging
 private static final String TAG = "BluetoothChat";
 private static final boolean D = true;

 public static final int MESSAGE_STATE_CHANGE = 1;
 public static final int MESSAGE_READ = 2;
 public static final int MESSAGE_WRITE = 3;
 public static final int MESSAGE_DEVICE_NAME = 4;
 public static final int MESSAGE_TOAST = 5;

 // Key names received from the BluetoothChatService Handler
 public static final String DEVICE_NAME = "device_name";
 public static final String TOAST = "toast";

 private String mConnectedDeviceName = null;
 private static StringBuffer mOutStringBuffer;
 private static BluetoothChatService mChatService = null;
 private static Context mContext;
 private volatile static BluetoothChat mBluetoothChat = null;
 TopDataIOListener mIOListener = null;

 public static BluetoothChat GetInstance(Context context) {
 if (mBluetoothChat == null && mContext == null) {
  synchronized (BluetoothChat.class){
  mBluetoothChat = new BluetoothChat();
  mContext = context;
  }
 }
 return mBluetoothChat;
 }


 public void onStart() {
 if (mChatService == null)
  setupChat();
 if (mChatService != null) {
  if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
  mChatService.start();
  }
 }
 }

 private void setupChat() {
 mChatService = new BluetoothChatService(mContext,mHandler);
 mOutStringBuffer = new StringBuffer("");
 }

 public void onDestroy() {
 if (mChatService != null)
  mChatService.stop();
 }

 public void sendMessage(String message) {
 if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
  Log.i("Show", "");
  return;
 }
 if (message.length() > 0) {
  byte[] send = message.getBytes();
  mChatService.write(send);
  mOutStringBuffer.setLength(0);
 }
 }

 private final Handler mHandler = new Handler() {
 @Override
 public void handleMessage(Message msg) {
  switch (msg.what) {
  case MESSAGE_STATE_CHANGE:
  if (D)
   Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
  switch (msg.arg1) {
  case BluetoothChatService.STATE_CONNECTED:
   break;
  case BluetoothChatService.STATE_CONNECTING:
   break;
  case BluetoothChatService.STATE_LISTEN:
   break;
  case BluetoothChatService.STATE_NONE:
   break;
  }
  break;
  case MESSAGE_WRITE:
  byte[] writeBuf = (byte[]) msg.obj;
  String writeMessage = new String(writeBuf);
  break;
  case MESSAGE_READ:
  byte[] readBuf = (byte[]) msg.obj;
  //收到的蓝牙数据,回传给界面显示
  if (mIOListener != null)
   mIOListener.OnIOCallBack(readBuf.length, readBuf);
  break;
  case MESSAGE_DEVICE_NAME:
  mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
  Log.i(TAG, "MESSAGE_DEVICE_NAME " + mConnectedDeviceName);
  break;
  case MESSAGE_TOAST:
  break;
  }
 }
 };

 public void regIOListener(TopDataIOListener arg0) {
 mIOListener = arg0;
 }

} 

还有一个蓝牙的广播。这里就不贴代码了。

4、权限

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- 部分手机6.0以上 蓝牙startDiscovery方法需要加上这个权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> 

蓝牙服务接收广播注册

<receiver android:name=".tool.BluetoothReceiver">
 <intent-filter android:priority="1000">
 <action android:name="android.bluetooth.adapter.action.STATE_CHANGED"/>
 <action android:name="android.bluetooth.device.action.ACL_CONNECTED"/>
 <action android:name="android.bluetooth.device.action.ACL_DISCONNECTED"/>
 <action android:name="android.bluetooth.device.action.BOND_STATE_CHANGED"/>
 </intent-filter>
</receiver> 

5、在上面注释看到了有个bug注释

就是部分手机6.0以上 蓝牙蓝牙startDiscovery方法需要加上这个权限android.permission.ACCESS_COARSE_LOCATION。不然启动搜索蓝牙无效。

02-05 09:11