android 普通蓝牙源码解读

一:概述

上一篇博客讲了下蓝牙4.0在android中的应用,这里讲讲普通蓝牙之间如何操作。

我记得在大二的时候还做了个比较烂的游戏,当时喜欢打dota就做了个蓝牙之间对战坦克的游戏,可以去看看,确实挺烂,到现在我都没想明白两个设备之间如何保持数据实时同步的(蓝牙传输是有延迟的),我去下载了其他的蓝牙对战的游戏,别人做的很好。所以就更加郁闷了。(希望大神不吝赐教 )

蓝牙对战游戏

相对蓝牙4.0,我觉得这个普通蓝牙应该要容易许多,因为没有什么协议的,就只用两个socket中交换数据就行了。

二:源码解读

权限申明:

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

在对蓝牙进行操作之前都需要获取BluetoothAdapter

  mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

当然如果获取不到,那么就不跟你玩了。直接finish(),哼。

  if (mBluetoothAdapter == null) {
     finish();
  }

获取到了,就在判断蓝牙是否开启。如果没有开启,就请求用户是否开启。

if (!mBluetoothAdapter.isEnabled()) {
   Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
   startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
} 

然后在onActivityResult()中获取用户的操作(开启还是不想开启蓝牙),当然如果不开启蓝牙,那自然也没什么后话,finish()吧。

 if (resultCode == Activity.RESULT_OK) {
    //开启了蓝牙
    setupChat();
 } else {
   Toast.makeText(getActivity(), R.string.bt_not_enabled_leaving,Toast.LENGTH_SHORT).show();
   getActivity().finish();
 }

如果开启了蓝牙,后续就开始一些初始化工作。

这里初始化需要说点东西:
因为蓝牙需要两台设备其中一台做为服务端(server)另一台做为客户端(client),我们比如两台设备分别时A 和 B ,A如果主动去连接B ,那么A就时客户端,B自然就是服务端。可是在连接前都不知道自己该扮演什么角色。所以这个时候双方都需要开启线程进行监听。

        if (mSecureAcceptThread == null) {
            mSecureAcceptThread = new AcceptThread(true);
            mSecureAcceptThread.start();
        }
        if (mInsecureAcceptThread == null) {
            mInsecureAcceptThread = new AcceptThread(false);
            mInsecureAcceptThread.start();
        }

这里的线程是个阻塞线程()。当客户端的socket()主动连接的时候就会返回一个连接好的socket。

  socket = mmServerSocket.accept();

但是上面为什么同时开启了两个AcceptThread线程呢?
仔细一看:

  if (secure) {
       tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,MY_UUID_SECURE);
  } else {
       tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME_INSECURE, MY_UUID_INSECURE);
  }

好像一个叫安全,一个叫不安全。进去一看,其实调用的同一个方法,只是传入的参数不同而已。

public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {

if (isBluetoothEnabled() == false) {
   throw new IOException();
}

  return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
                new ParcelUuid(uuid));
}
public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {

if (isBluetoothEnabled() == false) {
    throw new IOException();
}
return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
                new ParcelUuid(uuid));
}

就是一个进行了加密验证,另一个没有进行加密验证。在使用上我没觉得有什么区别。

好了这些初始话工作做的差不多了。需要找个设备开始连接了。使用过蓝牙的都知道,已经连接过的设备不需要再重新搜索了。没有配对过的就需要重新搜索。

我们先说已经配对过的蓝牙。使用下列代码就可以获得已经配对过的蓝牙。

  // Get a set of currently paired devices
  Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
  //使用这个方式就可以遍历出来
  for (BluetoothDevice device : pairedDevices) {
       pairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
  }

好了如果其中有你想连接的蓝牙,那么就可以连接了。(连接蓝牙部分)

if (secure) {
     socket = device.createRfcommSocketToServiceRecord(MY_UUID_SECURE);
 } else {
     socket = device.createInsecureRfcommSocketToServiceRecord(MY_UUID_INSECURE);
 }

使用上面的就可以进行连接了。客户端和服务端的uuid必须时一样的,因为服务端同时有两个阻塞线程在监听,所以使用其中任何一个去连接都没什么问题。

好了,现在来讲下查找设备。查找设备肯定时一方查找,一方被查找。

先让设备设置为可以被查找。其中的300就是设置可以被查找的时间。但是如果其中时间小于0,或者大于3600将自动设置为120秒

if (mBluetoothAdapter.getScanMode() !=
     BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
     Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
     discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
     startActivity(discoverableIntent);
        }

但是我在哪里去获得他找到的设备呢(自问自答好傻=_+),在广播里啊。这个代码应该比较清楚。需要注意的是注册和注销广播哦。

 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            // When discovery finds a device
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // Get the BluetoothDevice object from the Intent
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // If it's already paired, skip it, because it's been listed already
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                    mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
                }
                // When discovery is finished, change the Activity title
            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {

                if (mNewDevicesArrayAdapter.getCount() == 0) {
                    String noDevices = getResources().getText(R.string.none_found).toString();
                    mNewDevicesArrayAdapter.add(noDevices);
                }
            }
        }
    };

找到后就开始连接吧。连接方法同上(就是用device.create…..那里)。

蓝牙连接好了,那么就要开始传数据啦。有连个socket连接之后,传数据就比较容易了。创建输入,输出流。

 tmpIn = socket.getInputStream();
 tmpOut = socket.getOutputStream();

使用输入流读取数据。

   // Read from the InputStream
   bytes = mmInStream.read(buffer);

使用输出流写数据就ok了。

  mmOutStream.write(buffer);

源码下载(copy谷歌的)

加个好友共同学习(不是公众号):

这里写图片描述

因为小弟水平有限,如果有写的有问题,希望指出。(欢迎留言)

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值