android获取ibeacon列表

android获取ibeacon列表

最近公司有需要做ibeacon需求。

因为涉及扫码的时间。特意写一个service实现获取列表 可以根据扫描时间扫描出ibeacon列表
包含 uuid,设备名称,单位(米),电量等。
请根据自己的项目进行改造代码。

核心代码如下:



/**
 *
 * <ibeaon服务>
 *
 * @author fulushan
 * @date 创建时间:2018年4月5日 下午11:34:04
 */
public class IbeaconService extends Service {

    private static  final  String TAG = IbeaconService.class.getName();

    ArrayList<IBeaconClass.iBeacon> mLeDevices;

    private boolean mScanning;
    private final static int DATA_COMPLETE = 0;
    private final static int DATA_FAIL = 1;

    /**搜索BLE终端*/
    private BluetoothAdapter mBluetoothAdapter;

    // Stops scanning after 10 seconds.
    private static  long SCAN_PERIOD = 10000;

    ResponseResult responseResult = new ResponseResult();
    public class IbeaconBinder extends Binder{
        public ResponseResult getResponseResult(){
            return responseResult;
        }
    }

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }


    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        if (intent != null) {
            SCAN_PERIOD = intent.getIntExtra("time",10)*1000;
            mLeDevices = new ArrayList<>();
            //开启一个新的线程,如果使用Service,会导致ANR问题,Service本身也会阻塞
            new Thread(new IbeaconRunnable()).start();
        }

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopUpdateService();
        scanLeDevice(false);
    }



    class IbeaconRunnable implements Runnable {
        Message message = handler.obtainMessage();

        public void run() {

            try {
                //获取蓝牙数据
                //开始判断
                // Use this check to determine whether BLE is supported on the device.  Then you can
                // selectively disable BLE-related features.
                if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
                    message.what = DATA_FAIL;
                    responseResult.setStatus(BlueToothEnum.BLU_SERVICE_UNAVAI.getCode());
                    responseResult.setMsg(BlueToothEnum.BLU_SERVICE_UNAVAI.getMsg());
                    message.obj = responseResult;
                    handler.sendMessage(message);
                    return;
                }


                if(Build.VERSION.SDK_INT<JELLY_BEAN_MR2){
                    responseResult.setStatus(BlueToothEnum.BLU_SERVICE_UNAVAI.getCode());
                    responseResult.setMsg(BlueToothEnum.BLU_SERVICE_UNAVAI.getMsg());
                    message.obj = responseResult;
                    handler.sendMessage(message);
                    return;
                }
                // Initializes a Bluetooth adapter.  For API level 18 and above, get a reference to
                // BluetoothAdapter through BluetoothManager.
                final BluetoothManager bluetoothManager =
                        (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                    mBluetoothAdapter = bluetoothManager.getAdapter();
                }

                if(!mBluetoothAdapter.isEnabled()){
                    responseResult.setStatus(BlueToothEnum.BLU_SERVICE_UNAVAI.getCode());
                    responseResult.setMsg(BlueToothEnum.BLU_SERVICE_UNAVAI.getMsg());
                    message.obj = responseResult;
                    handler.sendMessage(message);
                    return;
                }

                // Checks if Bluetooth is supported on the device.
                if (mBluetoothAdapter == null) {
                    responseResult.setStatus(BlueToothEnum.BLU_SERVICE_UNAVAI.getCode());
                    responseResult.setMsg(BlueToothEnum.BLU_SERVICE_UNAVAI.getMsg());
                    message.obj = responseResult;
                    handler.sendMessage(message);
                    return;
                }
                //开启蓝牙
                mBluetoothAdapter.enable();

                scanLeDevice(true);


            } catch (Exception ex) {
                ex.printStackTrace();
                message.what = DATA_FAIL;
                //下载失败
                handler.sendMessage(message);

            }
        }
    }


    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
    private void scanLeDevice(final boolean enable) {
        if (enable) {
            // Stops scanning after a pre-defined scan period.
            handler.postDelayed(new Runnable() {
                @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
                @Override
                public void run() {
                    LogUtil.e(TAG,"scanLeDeviceStop");
                    mScanning = false;
                    mBluetoothAdapter.stopLeScan(mLeScanCallback);


                    Message message = handler.obtainMessage();
                    message.what = DATA_COMPLETE;
                    responseResult.setStatus(BlueToothEnum.SUCCESS.getCode());
                    responseResult.setMsg(BlueToothEnum.SUCCESS.getMsg());
                    responseResult.setData(mLeDevices);
                    message.obj = responseResult;
                    //数据数据完毕 更新数据列表
                    handler.sendMessage(message);


                }
            }, SCAN_PERIOD);

            mScanning = true;
            mBluetoothAdapter.startLeScan(mLeScanCallback);
        } else {
            mScanning = false;
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }
    }
    public void addDevice(IBeaconClass.iBeacon device) {
        if(device==null)
            return;

        for(int i=0;i<mLeDevices.size();i++){
            String btAddress = mLeDevices.get(i).bluetoothAddress;
            if(btAddress.equals(device.bluetoothAddress)){
                mLeDevices.add(i+1, device);
                mLeDevices.remove(i);
                return;
            }
        }
        mLeDevices.add(device);

    }
    // Device scan callback.
    private BluetoothAdapter.LeScanCallback mLeScanCallback =
            new BluetoothAdapter.LeScanCallback() {

                @Override
                public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {

                    final IBeaconClass.iBeacon ibeacon = IBeaconClass.fromScanData(device,rssi,scanRecord);
                     LogUtil.e(TAG,"onLeScan");
                      addDevice(ibeacon);
                     if(!mScanning){
                         LogUtil.e(TAG,"!mScanning");

                     }
                }
            };



    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case DATA_COMPLETE:
                    EventBus.getDefault().post(new BlueTeethEvent(responseResult));
                    //停止服务
                    stopUpdateService();

                    break;
                case DATA_FAIL:
                    responseResult.setStatus(BlueToothEnum.OTHER_ERROR.getCode());
                    responseResult.setMsg(BlueToothEnum.OTHER_ERROR.getMsg());

                    EventBus.getDefault().post(new BlueTeethEvent(responseResult));
                    stopUpdateService();
                    break;
                default:
                    // stopService(updateIntent);
                    // stopService(updateIntent);
                    // stopService(new Intent(UpdateService.this,UpdateService.class));
                    break;
            }
        }
    };

    private void stopUpdateService() {
        Intent updateIntent = new Intent(getBaseContext(),IbeaconService.class);
        updateIntent.setAction(ServiceHelper.IBEACON_SERVICE);
        updateIntent.setPackage(getBaseContext().getPackageName());//这里你需要设置你应用的包名
        stopService(updateIntent);
    }

}

调用方式:

    /**
     * 开启蓝牙服务UpdateService
     */
    public static void startIbeacon(Context context,int time) {
        Intent intent = new Intent(context,IbeaconService.class);
        intent.putExtra("time", time);//扫描ibeacon时间
        intent.setAction(IBEACON_SERVICE);
        intent.setPackage(context.getPackageName());//这里你需要设置你应用的包名
        context.startService(intent);
    }

其中IBeacon类

/**
 * 代码改自https://github.com/RadiusNetworks/android-ibeacon-service/blob/master/src/main/java/com/radiusnetworks/ibeacon/IBeacon.java
 * @author gvzhang
 *
 */
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;
        }
    }
}

缺少的类请自己补全。请根据自己的项目进行改造代码。

{
    "msg": "获取数据成功",
    "data": [{
            "uuid": "11111",
            "beaconName": "设备A",
            "distance": 0.56
        },
        {
            "uuid": "2222",
            "beaconName": "设备B",
            "distance": 1.56
        }
    ],
    "status": 100
}

猜你喜欢

转载自blog.csdn.net/fulushan/article/details/80227649