Android开发——iBeacon

1.前言

      继低功耗蓝牙开发完后开发iBeacon,其实iBeacon搜索设备和ble开发都一样,这里我只介绍其具体的不同之处,

 2.开发环境

             华为p20  AndroidStudio 3.2  +  低功耗蓝牙设备

              经过测试发现有的手机搜索蓝牙设备需要开启location权限,在华为上我的手机没有开启也可以进行搜索,另外还需要动态的允许权限

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
 
      if(ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.ACCESS_FINE_LOCATION)!=PackageManager.PERMISSION_GRANTED||ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.ACCESS_COARSE_LOCATION)!=PackageManager.PERMISSION_GRANTED){
                ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION},1);
            }

3.搜索设备

           和ble一样,因为iBeacon是一个协议搭载在ble设备上,在搜寻设备的时候需要先查看自己的设备是否支持蓝牙,同时检测是否打开蓝牙,当二者都满足的时候再通过不同的方式搜索ble设备

adapter=BluetoothAdapter.getDefaultAdapter();//获取本地蓝牙设备
if(adapter!=null){
    if(!adapter.isEnabled()){  //判断是否开启了蓝牙,如何未开启执行开启操作
        Intent intent=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivity(intent);
    }
 
}else{
    //不支持蓝牙
}

获取本地的蓝牙适配器有二种方法,我以上是使用BluetoothAdapter获取默认Adapter获取到的,下面这个使用BluetoothManager再获取到,二者是一样的,当我获取到adapter之后用她获取到BluetoothLeScanner对象,将会用她来对ble设备进行扫描(这是新的扫描方式,之前通过startLeScan()方法 已被弃用)
 

BluetoothManager bluetoothManager=(BluetoothManager)getSystemService(BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter=bluetoothManager.getAdapter();
BluetoothLeScanner bluetoothLeScanner=bluetoothAdapter.getBluetoothLeScanner();
扫描将调用BluetoothLeScanner对象的startScan()方法,但是此对象需要传入一个回调对象————ScanCallback,创建此回调对她进行改写,当扫描到设备时就会调用此回调函数种的OnScanResult函数,从而获取到Device     改写ScanCallback写在下面,因为iBeacon解析的关键就在于此

搜索设备

    bluetoothLeScanner.startScan(leCallback);

4.获取iBeacon

    和传统蓝牙和低功耗蓝牙不同的是iBeacon无需连接就可以获取到iBeacon中的数据

ScanCallback leCallback=new ScanCallback() {
                @Override
                public void onScanResult(int callbackType, ScanResult result) {
                    //result.getScanRecord().getBytes()中存放的就是ibeacon中的信息,只需要对他进行解析即可获取到                   

                }
 
                @Override
                public void onBatchScanResults(List<ScanResult> results) {
                    super.onBatchScanResults(results);
                }
 
                @Override
                public void onScanFailed(int errorCode) {
                    super.onScanFailed(errorCode);
                    Log.d(TAG, "搜索失败");
                }
            };

5.iBeacon数据结构

6.解析iBeacon数据(参考其他文档)

        解析iBeacon 编写了一个类用于解析

       

public class IBeaconClass {

    static public  class iBeacon implements Serializable {
        public String beaconName;
        public int major;
        public int minor;
        public String uuid;
        public String bluetoothAddress;
        public int txPower;
        public int rssi;
        public double 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.uuid = "00000000-0000-0000-0000-000000000000";
                iBeacon.txPower = -55;
                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.uuid = "00000000-0000-0000-0000-000000000000";
                iBeacon.txPower = -55;
                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.distance = calculateAccuracy(iBeacon.txPower,iBeacon.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

        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.uuid = sb.toString();

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

        return iBeacon;
    }

    private 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
     */
    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.89976) * Math.pow(ratio, 7.7095) + 0.111;
            return accuracy;
        }
    }
}
发布了73 篇原创文章 · 获赞 14 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/daguniang123/article/details/90519223