蓝牙的使用

安卓上的蓝牙 一种是传统蓝牙 搜索 连接 通信 感觉耗时有点长 支持低版本的安卓系统 
还有一种是 低功耗蓝牙 基于安卓4.3系统 应该就是根据ios系统的ibeacon蓝牙改过来的 在不需要蓝牙通信的情况下 感觉还是速度挺快的 缺点就是因为是依据ios系统 所以安卓系统的api不是很多 苹果上可以一次直接获取满足条件的所有蓝牙设备 并且可以获取信号量级 距离等大概数据 而安卓系统则只能获得基本数据 信号量级 距离需要转换 并且没有特定周期 个人测试安卓系统蓝牙搜索是随机的 如果同时搜索多个设备 虽然每个用时都很少 可能几毫秒 但是所有都一次搜索完成的周期还不是确定

首先 要有2个蓝牙权限 
<uses-permissionandroid:name="android.permission.BLUETOOTH"/>
<uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN"/>

有几个蓝牙的基本参数 major minor proxomityUUid 设备的编号 bludtoothAddress 蓝牙的地址 txPower 在计算用要用到
rssi 信号强度 distance 根据强度计算出的距离 受信号自身波动和环境相应较大 可以对信号做均值处理


放一个ibeacon的类



public class iBeaconClass {

    static public class iBeacon {
        public String name;
        public int major;
        public int minor;
        public String proximityUuid;
        public String bluetoothAddress;
        public int txPower;
        public int rssi;
        public String distance;
      


    public static iBeacon fromScanData(BluetoothDevice device, int rssi, byte[] scanData) {

        int startByte = 2;
        boolean patternFound = false;
        while (startByte <= 5) {
            if (((int) scanData[startByte + 2] & 0xff) == 0x02 &&
                    ((int) scanData[startByte + 3] & 0xff) == 0x15) {
                // yes!  This is an iBeacon
                patternFound = true;
                break;
            } else if (((int) scanData[startByte] & 0xff) == 0x2d &&
                    ((int) scanData[startByte + 1] & 0xff) == 0x24 &&
                    ((int) scanData[startByte + 2] & 0xff) == 0xbf &&
                    ((int) scanData[startByte + 3] & 0xff) == 0x16) {
                iBeacon iBeacon = new iBeacon();
                iBeacon.major = 0;
                iBeacon.minor = 0;
                iBeacon.filter = 0;
                iBeacon.proximityUuid = "00000000-0000-0000-0000-000000000000";
                iBeacon.txPower = -55;
                iBeacon.distance = String.format("%.2f", calculateDistance(iBeacon.txPower, rssi));
                return iBeacon;
            } else if (((int) scanData[startByte] & 0xff) == 0xad &&
                    ((int) scanData[startByte + 1] & 0xff) == 0x77 &&
                    ((int) scanData[startByte + 2] & 0xff) == 0x00 &&
                    ((int) scanData[startByte + 3] & 0xff) == 0xc6) {

                iBeacon iBeacon = new iBeacon();
                iBeacon.major = 0;
                iBeacon.minor = 0;
                iBeacon.filter = 0;
                iBeacon.proximityUuid = "00000000-0000-0000-0000-000000000000";
                iBeacon.txPower = -55;
                iBeacon.distance = String.format("%.2f", calculateDistance(iBeacon.txPower, rssi));
                return iBeacon;
            }
            startByte++;
        }


        if (patternFound == false) {
            // This is not an iBeacon
            return null;
        }

        iBeacon iBeacon = new iBeacon();

        iBeacon.major = (scanData[startByte + 20] & 0xff) * 0x100 + (scanData[startByte + 21] & 0xff);
        iBeacon.minor = (scanData[startByte + 22] & 0xff) * 0x100 + (scanData[startByte + 23] & 0xff);
        iBeacon.txPower = (int) scanData[startByte + 24]; // this one is signed
        iBeacon.rssi = rssi;
        iBeacon.filter = 0;
        iBeacon.distance = String.format("%.2f", calculateDistance(iBeacon.txPower, rssi));
        // AirLocate:
        // 02 01 1a 1a ff 4c 00 02 15  # Apple's fixed iBeacon advertising prefix
        // e2 c5 6d b5 df fb 48 d2 b0 60 d0 f5 a7 10 96 e0 # iBeacon profile uuid
        // 00 00 # major
        // 00 00 # minor
        // c5 # The 2's complement of the calibrated Tx Power

        // Estimote:
        // 02 01 1a 11 07 2d 24 bf 16
        // 394b31ba3f486415ab376e5c0f09457374696d6f7465426561636f6e00000000000000000000000000000000000000000000000000

        try {
            byte[] proximityUuidBytes = new byte[16];
            System.arraycopy(scanData, startByte + 4, proximityUuidBytes, 0, 16);
            String hexString = bytesToHexString(proximityUuidBytes);
            StringBuilder sb = new StringBuilder();
            sb.append(hexString.substring(0, 8));
            sb.append("-");
            sb.append(hexString.substring(8, 12));
            sb.append("-");
            sb.append(hexString.substring(12, 16));
            sb.append("-");
            sb.append(hexString.substring(16, 20));
            sb.append("-");
            sb.append(hexString.substring(20, 32));
            iBeacon.proximityUuid = sb.toString();
        } catch (Exception e) {
            e.printStackTrace();

        }
        if (device != null) {
            iBeacon.bluetoothAddress = device.getAddress();
            iBeacon.name = device.getName();
        }

        return iBeacon;
    }


    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 估算用户设备到ibeacon的距离
     *
     * @param txPower
     * @param rssi
     * @return
     */
    protected static double calculateAccuracy(int txPower, double rssi) {
        if (rssi == 0) {
            return -1.0; // if we cannot determine accuracy, return -1.
        }

        double ratio = rssi * 1.0 / txPower;
        if (ratio < 1.0) {
            return Math.pow(ratio, 10);
        } else {
            double accuracy = (0.89976) * Math.pow(ratio, 7.7095) + 0.111;
            return accuracy;
        }
    }


    // 使用这个测量距离
    public static double calculateDistance(int txPower, int rssi) {
        // 信号值得绝对值.
        int absRssi = Math.abs(rssi);
        // txPower 一米值. 暂时使用经验值 59 .需要替换成自己的真实值.
        txPower = 59;
        double power = (absRssi - txPower) / (10 * 2.0);
        return Math.pow(10, power);
    }

//    public static double calculateAccuracy(int txPower, double rssi) {
//        if (rssi == 0) {
//            return -1.0; // if we cannot determine accuracy, return -1.
//        }
//        double ratio = rssi * 1.0 / txPower;
//        if (ratio < 1.0) {
//            return Math.pow(ratio, 10);
//        } else {
//            double accuracy = (0.42093) * Math.pow(ratio, 6.9476) + 0.54992;
//            return accuracy;
//        }
//    }

}


网上有很多计算距离的方法 随便找了一个 这个类可以根据安卓的蓝牙参数转换出我们需要的参数


在activity中

@Override
protected void onCreate(Bundle savedInstanceState) {
BluetoothManager bluetoothManager =
        (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();

startleScan();
}
private BluetoothAdapter.LeScanCallback mLeScanCallback =
        new BluetoothAdapter.LeScanCallback() {
            @Override
            public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
                Log.d("device", device.getAddress());
                
                iBeaconClass.iBeacon ibeacon = iBeaconClass.fromScanData(device, rssi, scanRecord);
                

            }
        };


private void startleScan() {
    mBluetoothAdapter.startLeScan(mLeScanCallback);
   
}

private void stop() {
       
                mBluetoothAdapter.stopLeScan(mLeScanCallback);

    }

系统自带的蓝牙搜索 大概几毫秒收到一个信号 但是发送信号设备的发送周期 多个设备同时发送 接收就是随机的 不像ios系统周期一秒返回全部的蓝牙设备信号强度 这个要自己处理下 网上的第三方 也可以用
compile 'org.altbeacon:android-beacon-library:2+'

其实根原生的差不多 也是确定周期 然后按周期返回信号强度 但是周期内也不能保证每个设备都接收到
有个问题就是蓝牙的搜索要在系统授权定位权限以后才能搜到数据 要不然是收不到数据的 而且要手机带蓝牙模块安卓系统4.3才开始支持ibecaon 
所以先处理权限 在处理是否支持蓝牙
private void checkPermissions() {
    BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (!bluetoothAdapter.isEnabled()) {//如果adapter为空说明 没有蓝牙模块ø
        dialog(); //提示开启蓝牙开关
        return;
    } else {
        beaconManager = BeaconManager.getInstanceForApplication(this);
        beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout(IBEACON_FORMAT));
        beaconManager.bind(this);
    }

    String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION}; //如果没有定位权限 蓝牙什么也搜不到
    List<String> permissionDeniedList = new ArrayList<>();
    for (String permission : permissions) {
        int permissionCheck = ContextCompat.checkSelfPermission(this, permission);
        if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
            beaconManager = BeaconManager.getInstanceForApplication(this);
            beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout(IBEACON_FORMAT));
            beaconManager.bind(this);
        } else {
            permissionDeniedList.add(permission);

        }
    }
    if (!permissionDeniedList.isEmpty()) {
        String[] deniedPermissions = permissionDeniedList.toArray(new String[permissionDeniedList.size()]);
        ActivityCompat.requestPermissions(this, deniedPermissions, REQUEST_CODE_PERMISSION_LOCATION);
    }
}

private void dialog() {
    Log.d("boolean", "" + mBluetoothAdapter.isEnabled());
    if (!mBluetoothAdapter.isEnabled()) {
        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBtIntent, 10);
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 10) {
        if (resultCode == RESULT_OK) {
            beaconManager = BeaconManager.getInstanceForApplication(this);
            beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout(IBEACON_FORMAT));
            beaconManager.bind(this);
        } else {
            Toast.makeText(this, "请开启蓝牙", Toast.LENGTH_LONG).show();
        }
    }
}


















你可能感兴趣的:(蓝牙)