您的位置:首页 > 移动开发 > Android开发

android 普通蓝牙源码解读

2015-11-23 21:08 573 查看

一:概述

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

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

蓝牙对战游戏

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

二:源码解读

权限申明:

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


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

[code]  mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();


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

[code]  if (mBluetoothAdapter == null) {
     finish();
  }


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

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


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

[code] 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自然就是服务端。可是在连接前都不知道自己该扮演什么角色。所以这个时候双方都需要开启线程进行监听。

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


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

[code]  socket = mmServerSocket.accept();


但是上面为什么同时开启了两个AcceptThread线程呢?

仔细一看:

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


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

[code]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));
}


[code]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));
}


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

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

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

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


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

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


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

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

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

[code]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);
        }


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

[code] 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连接之后,传数据就比较容易了。创建输入,输出流。

[code] tmpIn = socket.getInputStream();
 tmpOut = socket.getOutputStream();


使用输入流读取数据。

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


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

[code]  mmOutStream.write(buffer);


源码下载(copy谷歌的)

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



因为小弟水平有限,如果有写的有问题,希望指出。(欢迎留言)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: