android获取ibeacon列表的方法

 更新时间:2018年10月31日 08:32:32   作者:fulushan的技术专栏  
这篇文章主要为大家详细介绍了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
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Flutter 如何正确显示SnackBar

    Flutter 如何正确显示SnackBar

    Snackbar是Android支持库中用于显示简单消息并且提供和用户的一个简单操作的一种弹出式提醒。当使用Snackbar时,提示会出现在消息最底部,通常含有一段信息和一个可点击的按钮。本文主要介绍了Flutter 如何正确显示 SnackBar
    2021-05-05
  • Flutter实现用视频背景的登录页的示例代码

    Flutter实现用视频背景的登录页的示例代码

    这篇文章主要介绍了Flutter实现用视频背景的登录页的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • Android开发之设置开机自动启动的几种方法

    Android开发之设置开机自动启动的几种方法

    这篇文章主要介绍了Android开发之设置开机自动启动的几种方法的相关资料,这里提供三种方法帮助大家实现这样的功能,需要的朋友可以参考下
    2017-08-08
  • Android使用SQLite数据库的示例

    Android使用SQLite数据库的示例

    本篇文章主要介绍了Android使用SQLite数据库的示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • Android 消息机制问题总结

    Android 消息机制问题总结

    本文主要介绍Android 消息机制,这里整理了消息机制的详细资料,和经常出现的问题,希望能帮助大家对消息机制的理解
    2016-08-08
  • android SQLite数据库总结

    android SQLite数据库总结

    本文主要介绍了android SQLite数据库的相关知识。具有一定的参考价值,下面跟着小编一起来看下吧
    2017-01-01
  • Android自定义控件横向柱状统计图

    Android自定义控件横向柱状统计图

    这篇文章主要为大家详细介绍了Android自定义控件横向柱状统计图,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • 利用Kotlin实现破解Android版的微信小游戏--跳一跳

    利用Kotlin实现破解Android版的微信小游戏--跳一跳

    这篇文章主要给大家介绍了关于利用Kotlin实现破解Android版微信小游戏--跳一跳的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2017-12-12
  • 详解Android中的多线程断点下载

    详解Android中的多线程断点下载

    本文主要介绍了Android中多线程下载的几个步骤以及实现功能的具体代码,具有很好的参考价值,需要的朋友一起来看下吧
    2016-12-12
  • Android 开发中根据搜索内容实现TextView中的文字部分加粗

    Android 开发中根据搜索内容实现TextView中的文字部分加粗

    最近遇到一个需求,需要做一个搜索功能。搜索的内容需要加粗显示。实现方法很简单,下面通过本文给大家分享Android 开发中根据搜索内容实现TextView中的文字部分加粗样式,非常不错,需要的朋友参考下
    2017-03-03

最新评论