由于项目的需要Android与蓝牙模块通信,发了时间学习了下,实现了Android与蓝牙模块的通信
1.蓝牙串口模块使用SPP-CA模块
蓝牙串口模块就是使用单片机的TX ,RX与蓝牙模块通信,单片机通过TX发送数据给蓝牙模块,然后蓝牙模块在通过蓝牙协议把数据发送出去,蓝牙模块与Android的通信方式使用spp协议。
2.蓝牙通信
蓝牙的通信需要服务端和客户端,客户端搜索蓝牙设备,链接服务端。主要是通过socket通信,相关的知识可以学习了解下socket通信。链接建立起来,通信时数据的读写是通过输入输出流的方式读写。
3.Android蓝牙架构和api说明
查看《Android系统原理及开发要点详解》和《深入理解Android网络编程》里的蓝牙相关章节,2本书里相关的章节有详细的介绍。
4.uuid
Hint: If you are connecting to a Bluetooth serial board then try using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. However if you are connecting to an Android peer then please generate your own unique UUID.
这是Android官方文档的说明,如果是连接蓝牙串口模块使用通用的uuid 00001101-0000-1000-8000-00805F9B34FB,如果是Android手机间的通信链接,可以使用生成的uuid,客服端和服务端的uuid必须相同,下面通过蓝牙串口助手读取回来的uuid,下面是我的蓝牙串口模块的uuid。
下面是读取手机的蓝牙的uuid,可以看到比较多的uuid,有比较多的服务。
另外下面是其他蓝牙设备的uuid,应该是蓝牙4.0的。
代码部分还是比较简单的,下面是android蓝牙链接的主要部分代码,也是参考网上的。
package gjz.bluetooth;
import gjz.bluetooth.R;
import gjz.bluetooth.Bluetooth.ServerOrCilent;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.UUID;
import android.app.Activity;
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 android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
public class chatActivity extends Activity implements OnItemClickListener ,OnClickListener{
    /** Called when the activity is first created. */
 
 private ListView mListView;
 private ArrayList<deviceListItem>list;
 private Button sendButton;
 private Button disconnectButton;
 private EditText editMsgView;
 deviceListAdapter mAdapter;
 Context mContext;
 
 /* 一些常量,代表服务器的名称 */
 public static final String PROTOCOL_SCHEME_L2CAP = "btl2cap";
 public static final String PROTOCOL_SCHEME_RFCOMM = "btspp";
 public static final String PROTOCOL_SCHEME_BT_OBEX = "btgoep";
 public static final String PROTOCOL_SCHEME_TCP_OBEX = "tcpobex";
 
 private BluetoothServerSocket mserverSocket = null;
 private ServerThread startServerThread = null;
 private clientThread clientConnectThread = null;
 private BluetoothSocket socket = null;
 private BluetoothDevice device = null;
 private readThread mreadThread = null;; 
 private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.chat);
        mContext = this;
        init();
    }
    
 private void init() {     
  list = new ArrayList<deviceListItem>();
  mAdapter = new deviceListAdapter(this, list);
  mListView = (ListView) findViewById(R.id.list);
  mListView.setAdapter(mAdapter);
  mListView.setOnItemClickListener(this);
  mListView.setFastScrollEnabled(true);
  editMsgView= (EditText)findViewById(R.id.MessageText); 
  editMsgView.clearFocus();
  
  sendButton= (Button)findViewById(R.id.btn_msg_send);
  sendButton.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View arg0) {
    // TODO Auto-generated method stub
    String msgText =editMsgView.getText().toString();
    if (msgText.length()>0) {
     sendMessageHandle(msgText); 
     editMsgView.setText("");
     editMsgView.clearFocus();
     //close InputMethodManager
     InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
     imm.hideSoftInputFromWindow(editMsgView.getWindowToken(), 0);
    }else
    Toast.makeText(mContext, "发送内容不能为空!", Toast.LENGTH_SHORT).show();
   }
  });
  
  disconnectButton= (Button)findViewById(R.id.btn_disconnect);
  disconnectButton.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View arg0) {
    // TODO Auto-generated method stub
          if (Bluetooth.serviceOrCilent == ServerOrCilent.CILENT) 
    {
           shutdownClient();
    }
    else if (Bluetooth.serviceOrCilent == ServerOrCilent.SERVICE) 
    {
     shutdownServer();
    }
    Bluetooth.isOpen = false;
    Bluetooth.serviceOrCilent=ServerOrCilent.NONE;
    Toast.makeText(mContext, "已断开连接!", Toast.LENGTH_SHORT).show();
   }
  });  
 }    
    private Handler LinkDetectedHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
         //Toast.makeText(mContext, (String)msg.obj, Toast.LENGTH_SHORT).show();
         if(msg.what==1)
         {
          list.add(new deviceListItem((String)msg.obj, true));
         }
         else
         {
          list.add(new deviceListItem((String)msg.obj, false));
         }
   mAdapter.notifyDataSetChanged();
   mListView.setSelection(list.size() - 1);
        }
        
    };    
    
    @Override
    public synchronized void onPause() {
        super.onPause();
    }
    @Override
    public synchronized void onResume() {
        super.onResume();
        if(Bluetooth.isOpen)
        {
         Toast.makeText(mContext, "连接已经打开,可以通信。如果要再建立连接,请先断开!", Toast.LENGTH_SHORT).show();
         return;
        }
        if(Bluetooth.serviceOrCilent==ServerOrCilent.CILENT)
        {
   String address = Bluetooth.BlueToothAddress;
   if(!address.equals("null"))
   {
    device = mBluetoothAdapter.getRemoteDevice(address); 
    clientConnectThread = new clientThread();
    clientConnectThread.start();
    Bluetooth.isOpen = true;
   }
   else
   {
    Toast.makeText(mContext, "address is null !", Toast.LENGTH_SHORT).show();
   }
        }
        else if(Bluetooth.serviceOrCilent==ServerOrCilent.SERVICE)
        {                
         startServerThread = new ServerThread();
         startServerThread.start();
         Bluetooth.isOpen = true;
        }
    }
 //开启客户端
 private class clientThread extends Thread {   
  public void run() {
   try {
    //创建一个Socket连接:只需要服务器在注册时的UUID号
    // socket = device.createRfcommSocketToServiceRecord(BluetoothProtocols.OBEX_OBJECT_PUSH_PROTOCOL_UUID);
    socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
    //连接
    Message msg2 = new Message();
    msg2.obj = "请稍候,正在连接服务器:"+Bluetooth.BlueToothAddress;
    msg2.what = 0;
    LinkDetectedHandler.sendMessage(msg2);
    
    socket.connect();
    
    Message msg = new Message();
    msg.obj = "已经连接上服务端!可以发送信息。";
    msg.what = 0;
    LinkDetectedHandler.sendMessage(msg);
    //启动接受数据
    mreadThread = new readThread();
    mreadThread.start();
   } 
   catch (IOException e) 
   {
    Log.e("connect", "", e);
    Message msg = new Message();
    msg.obj = "连接服务端异常!断开连接重新试一试。";
    msg.what = 0;
    LinkDetectedHandler.sendMessage(msg);
   } 
  }
 };
 //开启服务器
 private class ServerThread extends Thread { 
  public void run() {
     
   try {
    /* 创建一个蓝牙服务器 
     * 参数分别:服务器名称、UUID  */ 
    mserverSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(PROTOCOL_SCHEME_RFCOMM,
      UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));  
    
    Log.d("server", "wait cilent connect...");
    
    Message msg = new Message();
    msg.obj = "请稍候,正在等待客户端的连接...";
    msg.what = 0;
    LinkDetectedHandler.sendMessage(msg);
    
    /* 接受客户端的连接请求 */
    socket = mserverSocket.accept();
    Log.d("server", "accept success !");
    
    Message msg2 = new Message();
    String info = "客户端已经连接上!可以发送信息。";
    msg2.obj = info;
    msg.what = 0;
    LinkDetectedHandler.sendMessage(msg2);
    //启动接受数据
    mreadThread = new readThread();
    mreadThread.start();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 };
 /* 停止服务器 */
 private void shutdownServer() {
  new Thread() {
   public void run() {
    if(startServerThread != null)
    {
     startServerThread.interrupt();
     startServerThread = null;
    }
    if(mreadThread != null)
    {
     mreadThread.interrupt();
     mreadThread = null;
    }    
    try {     
     if(socket != null)
     {
      socket.close();
      socket = null;
     }
     if (mserverSocket != null)
     {
      mserverSocket.close();/* 关闭服务器 */
      mserverSocket = null;
     }
    } catch (IOException e) {
     Log.e("server", "mserverSocket.close()", e);
    }
   };
  }.start();
 }
 /* 停止客户端连接 */
 private void shutdownClient() {
  new Thread() {
   public void run() {
    if(clientConnectThread!=null)
    {
     clientConnectThread.interrupt();
     clientConnectThread= null;
    }
    if(mreadThread != null)
    {
     mreadThread.interrupt();
     mreadThread = null;
    }
    if (socket != null) {
     try {
      socket.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
     socket = null;
    }
   };
  }.start();
 }
 //发送数据
 private void sendMessageHandle(String msg) 
 {  
  if (socket == null) 
  {
   Toast.makeText(mContext, "没有连接", Toast.LENGTH_SHORT).show();
   return;
  }
  try {    
   OutputStream os = socket.getOutputStream(); 
   os.write(msg.getBytes());
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }   
  list.add(new deviceListItem(msg, false));
  mAdapter.notifyDataSetChanged();
  mListView.setSelection(list.size() - 1);
 }
 //读取数据
    private class readThread extends Thread { 
        public void run() {
         
            byte[] buffer = new byte[1024];
            int bytes;
            InputStream mmInStream = null;
            
   try {
    mmInStream = socket.getInputStream();
   } catch (IOException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
   } 
            while (true) {
                try {
                    // Read from the InputStream
                    if( (bytes = mmInStream.read(buffer)) > 0 )
                    {
                     byte[] buf_data = new byte[bytes];
         for(int i=0; i<bytes; i++)
         {
          buf_data[i] = buffer[i];
         }
      String s = new String(buf_data);
      Message msg = new Message();
      msg.obj = s;
      msg.what = 1;
      LinkDetectedHandler.sendMessage(msg);
                    }
                } catch (IOException e) {
                 try {
      mmInStream.close();
     } catch (IOException e1) {
      // TODO Auto-generated catch block
      e1.printStackTrace();
     }
                    break;
                }
            }
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (Bluetooth.serviceOrCilent == ServerOrCilent.CILENT) 
  {
         shutdownClient();
  }
  else if (Bluetooth.serviceOrCilent == ServerOrCilent.SERVICE) 
  {
   shutdownServer();
  }
        Bluetooth.isOpen = false;
  Bluetooth.serviceOrCilent = ServerOrCilent.NONE;
    }
 public class SiriListItem {
  String message;
  boolean isSiri;
  public SiriListItem(String msg, boolean siri) {
   message = msg;
   isSiri = siri;
  }
 }
 @Override
 public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
  // TODO Auto-generated method stub
 }
 @Override
 public void onClick(View arg0) {
  // TODO Auto-generated method stub
 } 
 public class deviceListItem {
  String message;
  boolean isSiri;
  public deviceListItem(String msg, boolean siri) {
   message = msg;
   isSiri = siri;
  }
 }
}
下面是实现的效果。
1.Android手机通信
一台手机作为服务端,等待客服端链接。
另一台手机作为客户端,链接服务端,链接成功,发送数据
2.Android和蓝牙模块的通信
蓝牙模块作为服务器端,Android手机作为客户端,链接蓝牙模块。
蓝牙模块通过串口线链接PC,通过串口工具接收Android手机端发送数据,Android手机端链接成功信息CONNECTING<<A0:E4:53:18:BB:42 CONNETED,链接成功发送信息hellokitty mina123456789,Android链接断开信息DISC:SUCCESS +READY+PAIRABLE