当前位置: 首页 > 编程笔记 >

Android在类微信程序中实现蓝牙聊天功能的示例代码

洪增
2023-03-14
本文向大家介绍Android在类微信程序中实现蓝牙聊天功能的示例代码,包括了Android在类微信程序中实现蓝牙聊天功能的示例代码的使用技巧和注意事项,需要的朋友参考一下

项目要求

1.初次打开程序时右上角标题栏显示“无连接”,点击旁边的按钮选择“我的好友”,进入配对界面;
2.选择好友之后,返回主界面,标题栏会显示已连接的手机型号;
3.两部手机间可通过蓝牙聊天

效果展示


项目结构

主要代码

1.在清单文件中注册权限

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />

2.在文件res / values / strings.xml里,添加程序运行过程中的状态描述文本及配色代码等

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <string name="app_name">蓝牙Demo</string> 
 <string name="send">发送</string>
 <string name="not_connected">你没有链接一个设备</string>
 <string name="bt_not_enabled_leaving">蓝牙不可用,离开聊天室</string>
 <string name="title_connecting">链接中...</string>
 <string name="title_connected_to">连接到:</string>
 <string name="title_not_connected">无链接</string> 
 <string name="scanning">蓝牙设备搜索中...</string>
 <string name="select_device">选择一个好友链接</string>
 <string name="none_paired">没有配对好友</string>
 <string name="none_found">附近没有发现好友</string>
 <string name="title_paired_devices">已配对好友</string>
 <string name="title_other_devices">其它可连接好友</string>
 <string name="button_scan">搜索好友</string>
 <string name="connect">我的好友</string>
 <string name="discoverable">设置在线</string>
 <string name="back">退出</string>
 <string name="startVideo">开始聊天</string>
 <string name="stopVideo">结束聊天</string> 
</resources>

用于蓝牙会话的服务组件ChatService.java中有三个内部类:AcceptThread(接受新连接)、ConnectThread(发出连接)和ConnectedThread (已连接)。

// 创建监听线程,准备接受新连接。使用阻塞方式,调用 BluetoothServerSocket.accept()
 private class AcceptThread extends Thread {
  private final BluetoothServerSocket mmServerSocket;

  public AcceptThread() {
   BluetoothServerSocket tmp = null;
   try {
    //使用射频端口(RF comm)监听
    tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
   } catch (IOException e) {
   }
   mmServerSocket = tmp;
  }

  @Override
  public void run() {
   setName("AcceptThread");
   BluetoothSocket socket = null;
   while (mState != STATE_CONNECTED) {
    try {
     socket = mmServerSocket.accept();
    } catch (IOException e) {
     break;
    }
    if (socket != null) {
     synchronized (ChatService.this) {
      switch (mState) {
       case STATE_LISTEN:
       case STATE_CONNECTING:
        connected(socket, socket.getRemoteDevice());
        break;
       case STATE_NONE:
       case STATE_CONNECTED:
        try {
         socket.close();
        } catch (IOException e) {
         e.printStackTrace();
        }
        break;
      }
     }
    }
   }
  }

  public void cancel() {
   try {
    mmServerSocket.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 }

 /*
  连接线程,专门用来对外发出连接对方蓝牙的请求和处理流程。
  构造函数里通过 BluetoothDevice.createRfcommSocketToServiceRecord() ,
  从待连接的 device 产生 BluetoothSocket. 然后在 run 方法中 connect ,
  成功后调用 BluetoothChatSevice 的 connected() 方法。定义 cancel() 在关闭线程时能够关闭相关socket 。
  */
 private class ConnectThread extends Thread {
  private final BluetoothSocket mmSocket;
  private final BluetoothDevice mmDevice;

  public ConnectThread(BluetoothDevice device) {
   mmDevice = device;
   BluetoothSocket tmp = null;
   try {
    tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
   } catch (IOException e) {
    e.printStackTrace();
   }
   mmSocket = tmp;
  }

  @Override
  public void run() {
   setName("ConnectThread");
   mAdapter.cancelDiscovery();
   try {
    mmSocket.connect();
   } catch (IOException e) {
    connectionFailed();
    try {
     mmSocket.close();
    } catch (IOException e2) {
     e.printStackTrace();
    }
    ChatService.this.start();
    return;
   }
   synchronized (ChatService.this) {
    mConnectThread = null;
   }
   connected(mmSocket, mmDevice);
  }

  public void cancel() {
   try {
    mmSocket.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 }

 /*
  双方蓝牙连接后一直运行的线程;构造函数中设置输入输出流。
  run()方法中使用阻塞模式的 InputStream.read()循环读取输入流,然后发送到 UI 线程中更新聊天消息。
  本线程也提供了 write() 将聊天消息写入输出流传输至对方,传输成功后回写入 UI 线程。最后使用cancel()关闭连接的 socket
  */
 private class ConnectedThread extends Thread {
  private final BluetoothSocket mmSocket;
  private final InputStream mmInStream;
  private final OutputStream mmOutStream;

  public ConnectedThread(BluetoothSocket socket) {
   mmSocket = socket;
   InputStream tmpIn = null;
   OutputStream tmpOut = null;
   try {
    tmpIn = socket.getInputStream();
    tmpOut = socket.getOutputStream();
   } catch (IOException e) {
    e.printStackTrace();
   }
   mmInStream = tmpIn;
   mmOutStream = tmpOut;
  }

  @Override
  public void run() {
   byte[] buffer = new byte[1024];
   int bytes;
   while (true) {
    try {
     bytes = mmInStream.read(buffer);
     mHandler.obtainMessage(weixinFragment.MESSAGE_READ, bytes, -1, buffer).sendToTarget();
    } catch (IOException e) {
     connectionLost();
     break;
    }
   }
  }

  public void write(byte[] buffer) {
   try {
    mmOutStream.write(buffer);
    mHandler.obtainMessage(weixinFragment.MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }

  public void cancel() {
   try {
    mmSocket.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 }

新建Activity组件DeviceList,实现拾取与之会话的蓝牙设备。本程序供菜单项主界面的选项菜单“我的友好”调用,用于:

(1)显示已配对的好友列表;
(2)搜索可配对的好友进行配对
(3)新选择并配对的蓝牙设备将刷新好友列表

注意:发现新的蓝牙设备并请求配对时,需要对应接受

关键技术:动态注册一个广播接收者,处理蓝牙设备扫描的结果

public class DeviceList extends Activity{
  private BluetoothAdapter mBtAdapter;
  private ArrayAdapter<String> mPairedDevicesArrayAdapter;
  private ArrayAdapter<String> mNewDevicesArrayAdapter;
  public static String EXTRA_DEVICE_ADDRESS = "device_address"; //Mac地址
  //定义广播接收者,用于处理扫描蓝牙设备后的结果
  private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
   @Override
   public void onReceive(Context context, Intent intent) {
    String action = intent.getAction();
    if (BluetoothDevice.ACTION_FOUND.equals(action)) {
     BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
     if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
      mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
     }
    } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
     if (mNewDevicesArrayAdapter.getCount() == 0) {
      String noDevices = getResources().getText(R.string.none_found).toString();
      mNewDevicesArrayAdapter.add(noDevices);
     }
    }
   }
  };
  @Override
  protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.device_list);
   //在被调用活动里,设置返回结果码
   setResult(Activity.RESULT_CANCELED);
   init(); //活动界面
  }
  private void init() {
   Button scanButton = findViewById(R.id.button_scan);
   scanButton.setOnClickListener(new OnClickListener() {
    public void onClick(View v) {
     Toast.makeText(DeviceList.this, R.string.scanning, Toast.LENGTH_LONG).show();
     doDiscovery(); //搜索蓝牙设备
    }
   });
   mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
   mNewDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
   //已配对蓝牙设备列表
   ListView pairedListView =findViewById(R.id.paired_devices);
   pairedListView.setAdapter(mPairedDevicesArrayAdapter);
   pairedListView.setOnItemClickListener(mPaireDeviceClickListener);
   //未配对蓝牙设备列表
   ListView newDevicesListView = findViewById(R.id.new_devices);
   newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
   newDevicesListView.setOnItemClickListener(mNewDeviceClickListener);
   //动态注册广播接收者
   IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
   registerReceiver(mReceiver, filter);
   filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
   registerReceiver(mReceiver, filter);
   mBtAdapter = BluetoothAdapter.getDefaultAdapter();
   Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
   if (pairedDevices.size() > 0) {
    findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
    for (BluetoothDevice device : pairedDevices) {
     mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
    }
   } else {
    String noDevices = getResources().getText(R.string.none_paired).toString();
    mPairedDevicesArrayAdapter.add(noDevices);
   }
  }
  @Override
  protected void onDestroy() {
   super.onDestroy();
   if (mBtAdapter != null) {
    mBtAdapter.cancelDiscovery();
   }
   this.unregisterReceiver(mReceiver);
  }
  private void doDiscovery() {
   findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
   if (mBtAdapter.isDiscovering()) {
    mBtAdapter.cancelDiscovery();
   }
   mBtAdapter.startDiscovery(); //开始搜索蓝牙设备并产生广播
    //startDiscovery是一个异步方法
   //找到一个设备时就发送一个BluetoothDevice.ACTION_FOUND的广播
  }
  private OnItemClickListener mPaireDeviceClickListener = new OnItemClickListener() {
   public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
    mBtAdapter.cancelDiscovery();
    String info = ((TextView) v).getText().toString();
    String address = info.substring(info.length() - 17);
    Intent intent = new Intent();
    intent.putExtra(EXTRA_DEVICE_ADDRESS, address); //Mac地址
    setResult(Activity.RESULT_OK, intent);
    finish();
   }
  };
  private OnItemClickListener mNewDeviceClickListener = new OnItemClickListener() {
   public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
    mBtAdapter.cancelDiscovery();
    Toast.makeText(DeviceList.this, "请在蓝牙设置界面手动连接设备",Toast.LENGTH_SHORT).show();
    Intent intent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
    startActivityForResult(intent,1);
   }
  };
  //回调方法:进入蓝牙配对设置界面返回后执行
  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
   super.onActivityResult(requestCode, resultCode, data);
   init(); //刷新好友列表
  }
 }

蓝牙会话的主Activity组件程序fragment.java

public class weixinFrament extends Fragment {
 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;
 public static final String DEVICE_NAME = "device_name";
 public static final String TOAST = "toast";
 private static final int REQUEST_CONNECT_DEVICE = 1; //请求连接设备
 private static final int REQUEST_ENABLE_BT = 2;
 private TextView mTitle;
 private ListView mConversationView;
 private EditText mOutEditText;
 private Button mSendButton;
 private String mConnectedDeviceName = null;
 private ArrayAdapter<String> mConversationArrayAdapter;
 private StringBuffer mOutStringBuffer;
 private BluetoothAdapter mBluetoothAdapter = null;
 private ChatService mChatService = null;

 private View view;

 public weixinFrament() {

 }

 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

  view = inflater.inflate(R.layout.tab_01, container, false);

  Toolbar toolbar = view.findViewById(R.id.toolbar);
  setHasOptionsMenu(true);

  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
   if (ContextCompat.checkSelfPermission(this.getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
   }
  }

  //创建选项菜单
  toolbar.inflateMenu(R.menu.option_menu);
  //选项菜单监听
  toolbar.setOnMenuItemClickListener(new MyMenuItemClickListener());
  mTitle = view.findViewById(R.id.title_left_text);
  mTitle.setText(R.string.app_name);
  mTitle = view.findViewById(R.id.title_right_text);
  // 得到本地蓝牙适配器
  mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  if (mBluetoothAdapter == null) {
   Toast.makeText(view.getContext(), "蓝牙不可用", Toast.LENGTH_LONG).show();
   getActivity().finish();
   return view;
  }
  if (!mBluetoothAdapter.isEnabled()) { //若当前设备蓝牙功能未开启
   Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
   startActivityForResult(enableIntent, REQUEST_ENABLE_BT); //
  } else {
   if (mChatService == null) {
    setupChat(); //创建会话
   }
  }

  return view;
 }

 @Override
 public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
  super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  if (grantResults.length > 0) {
   if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
    Toast.makeText(view.getContext(), "未授权,蓝牙搜索功能将不可用!", Toast.LENGTH_SHORT).show();
   }
  }
 }

 @Override
 public synchronized void onResume() { //synchronized:同步方法实现排队调用
  super.onResume();
  if (mChatService != null) {
   if (mChatService.getState() == ChatService.STATE_NONE) {
    mChatService.start();
   }
  }
 }

 private void setupChat() {
  mConversationArrayAdapter = new ArrayAdapter<String>(view.getContext(), R.layout.message);
  mConversationView = view.findViewById(R.id.in);
  mConversationView.setAdapter(mConversationArrayAdapter);
  mOutEditText = view.findViewById(R.id.edit_text_out);
  mOutEditText.setOnEditorActionListener(mWriteListener);
  mSendButton = view.findViewById(R.id.button_send);
  mSendButton.setOnClickListener(new View.OnClickListener() {
   public void onClick(View v) {
    TextView textview = view.findViewById(R.id.edit_text_out);
    String message = textview.getText().toString();
    sendMessage(message);
   }
  });
  //创建服务对象
  mChatService = new ChatService(view.getContext(), mHandler);
  mOutStringBuffer = new StringBuffer("");
 }

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

 private void ensureDiscoverable() { //修改本机蓝牙设备的可见性
  //打开手机蓝牙后,能被其它蓝牙设备扫描到的时间不是永久的
  if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
   Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
   //设置在300秒内可见(能被扫描)
   discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
   startActivity(discoverableIntent);
   Toast.makeText(view.getContext(), "已经设置本机蓝牙设备的可见性,对方可搜索了。", Toast.LENGTH_SHORT).show();
  }
 }

 private void sendMessage(String message) {
  if (mChatService.getState() != ChatService.STATE_CONNECTED) {
   Toast.makeText(view.getContext(), R.string.not_connected, Toast.LENGTH_SHORT).show();
   return;
  }
  if (message.length() > 0) {
   byte[] send = message.getBytes();
   mChatService.write(send);
   mOutStringBuffer.setLength(0);
   mOutEditText.setText(mOutStringBuffer);
  }
 }

 private TextView.OnEditorActionListener mWriteListener = new TextView.OnEditorActionListener() {
  @Override
  public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
   if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) {
    //软键盘里的回车也能发送消息
    String message = view.getText().toString();
    sendMessage(message);
   }
   return true;
  }
 };
 //使用Handler对象在UI主线程与子线程之间传递消息
 private final Handler mHandler = new Handler() { //消息处理
  @Override
  public void handleMessage(Message msg) {
   switch (msg.what) {
    case MESSAGE_STATE_CHANGE:
     switch (msg.arg1) {
      case ChatService.STATE_CONNECTED:
       mTitle.setText(R.string.title_connected_to);
       mTitle.append(mConnectedDeviceName);
       mConversationArrayAdapter.clear();
       break;
      case ChatService.STATE_CONNECTING:
       mTitle.setText(R.string.title_connecting);
       break;
      case ChatService.STATE_LISTEN:
      case ChatService.STATE_NONE:
       mTitle.setText(R.string.title_not_connected);
       break;
     }
     break;
    case MESSAGE_WRITE:
     byte[] writeBuf = (byte[]) msg.obj;
     String writeMessage = new String(writeBuf);
     mConversationArrayAdapter.add("我: " + writeMessage);
     break;
    case MESSAGE_READ:
     byte[] readBuf = (byte[]) msg.obj;
     String readMessage = new String(readBuf, 0, msg.arg1);
     mConversationArrayAdapter.add(mConnectedDeviceName + ": "
       + readMessage);
     break;
    case MESSAGE_DEVICE_NAME:
     mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
     Toast.makeText(getActivity().getApplicationContext(), "链接到 " + mConnectedDeviceName, Toast.LENGTH_SHORT).show();
     break;
    case MESSAGE_TOAST:
     Toast.makeText(getActivity().getApplicationContext(),
       msg.getData().getString(TOAST), Toast.LENGTH_SHORT).show();
     break;
   }
  }
 };

 //返回进入好友列表操作后的数回调方法
 public void onActivityResult(int requestCode, int resultCode, Intent data) {
  switch (requestCode) {
   case REQUEST_CONNECT_DEVICE:
    if (resultCode == Activity.RESULT_OK) {
     String address = data.getExtras().getString(DeviceList.EXTRA_DEVICE_ADDRESS);
     BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
     mChatService.connect(device);
    } else if (resultCode == Activity.RESULT_CANCELED) {
     Toast.makeText(view.getContext(), "未选择任何好友!", Toast.LENGTH_SHORT).show();
    }
    break;
   case REQUEST_ENABLE_BT:
    if (resultCode == Activity.RESULT_OK) {
     setupChat();
    } else {
     Toast.makeText(view.getContext(), R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
     getActivity().finish();
    }
  }
 }

 //内部类,选项菜单的单击事件处理
 private class MyMenuItemClickListener implements Toolbar.OnMenuItemClickListener {
  @Override
  public boolean onMenuItemClick(MenuItem item) {
   switch (item.getItemId()) {
    case R.id.scan:
     //启动DeviceList这个Activity
     Intent serverIntent = new Intent(weixinFrament.this.getActivity(), DeviceList.class);
     startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
     return true;
    case R.id.discoverable:
     ensureDiscoverable();
     return true;
    case R.id.back:
     getActivity().finish();
     System.exit(0);
     return true;
   }
   return false;
  }
 }
}

项目地址

点我进入仓库

总结

到此这篇关于Android在类微信程序中实现蓝牙聊天功能的文章就介绍到这了,更多相关android 类微信程序蓝牙聊天内容请搜索小牛知识库以前的文章或继续浏览下面的相关文章希望大家以后多多支持小牛知识库!

 类似资料:
  • 本文向大家介绍Android实现蓝牙聊天功能,包括了Android实现蓝牙聊天功能的使用技巧和注意事项,需要的朋友参考一下 蓝牙,时下最流行的智能设备传输数据的方式之一,通过手机app和智能设备进行连接,获取设备上的测量数据,我们生活中随处可见的比如蓝牙智能手环,蓝牙电子秤,蓝牙心电测量设备等等。 本篇我将紧接着上篇结尾所写,一起来看下手机之间如何通过蓝牙实现文字聊天。 先贴出上篇的一些demo;

  • 本文向大家介绍微信小程序聊天功能的示例代码,包括了微信小程序聊天功能的示例代码的使用技巧和注意事项,需要的朋友参考一下 效果 初始化滚动条高度 数据格式 wxml对话框 wxml底部输入框 css js 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。

  • 本文向大家介绍微信小程序实现即时通信聊天功能的实例代码,包括了微信小程序实现即时通信聊天功能的实例代码的使用技巧和注意事项,需要的朋友参考一下 项目背景:小程序中实现实时聊天功能 一、服务器域名配置 配置流程 配置参考URL:https://developers.weixin.qq.com/miniprogram/dev/api/api-network.html 二、nginx中配置反向代理加密w

  • 本文向大家介绍微信小程序websocket实现聊天功能,包括了微信小程序websocket实现聊天功能的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了微信小程序websocket实现聊天功能的具体代码,供大家参考,具体内容如下 效果图: chat.js chat.wxml chat.wxss github前后端都有地址:wx-chat  为大家推荐现在关注度比较高的微信小程序教程一篇

  • 本文向大家介绍微信小程序websocket实现即时聊天功能,包括了微信小程序websocket实现即时聊天功能的使用技巧和注意事项,需要的朋友参考一下 今天给大家分享一下本人做小程序使用websocket的一点小经验,希望对大家有所帮助。 使用之前肯定首先要了解一下websocket是什么,简单来讲websocket就是客户端与服务器之间专门建立的一条特殊通道,请求只需要请求一次,而且还可以从通道

  • 本文向大家介绍Android实现一对一蓝牙聊天APP,包括了Android实现一对一蓝牙聊天APP的使用技巧和注意事项,需要的朋友参考一下 学习了,三天的Android 蓝牙开发,开始是一头雾水,看着别人讲的Google官方的demo感觉很容易,所有自己也尝试写一个很简单的聊天demo.可是想的很简单,自己做起来也花了,将近一天的时间才搞定这个基本的流程设计.下面是几点心得后面再贴代码 1)写一个