首页 > 系统 > Android > 正文

android实现主动连接和被动连接的蓝牙聊天功能

2019-10-22 18:10:14
字体:
来源:转载
供稿:网友

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

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

1、程序简单的界面

android,主动连接,被动连接,蓝牙聊天

android,主动连接,被动连接,蓝牙聊天

android,主动连接,被动连接,蓝牙聊天

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。不然启动搜索蓝牙无效。


注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表