Android 开发中 iBeacon的使用

iBeacon的工作原理是基于Bluetooth Low Energy(BLE)低功耗蓝牙传输技术,iBeacon基站不断向四周发送蓝牙信号,当智能设备进入设定区域时,就能够收到信号。只要满足iBeacon技术标准的都可以使用,所以Android也能够支持iBeacon。Google在Android4.3中支持BLE技术

定位一直是非常关键的功能。通过iBeacon基站的部署能够实现室内导航,同时通过蓝牙推送信息,iBeacon在商场零售或者一些公共服务领域如体育馆、博物馆能提供非常棒的体验。尤其是蓝牙不错传输距离、低功耗、以及信号加密使得iBeacon在移动支付领域也非常有前景。总之,iBeacon的潜力似乎是无穷大,也受到了越来越多的关注。

要了解iBeacon是如何工作首先我们要了解BLE。BLE(也称为Bluetooth Smart)最早追溯到Nokia于2006年提出的Wibree,后来融合进了蓝牙标准,成为Bluetooth4.0的一部分。目前我们经常能看到3种蓝牙设备:

  • Bluetooth:只支持传统模式的蓝牙设备
  • Bluetooth Smart Ready:支持传统和低功耗两种模式设备
  • Bluetooth Smart:只支持低功耗蓝牙设备

BLE与传统的蓝牙相比最大的优势是功耗降低90%,同时传输距离增大(超过100米)、安全和稳定性提高(支持AES加密和CRC验证)。iBeacon同时有一些自己的特点:

  • 无需配对,一般蓝牙设备印象中都需要配对工作。iBeacon无需配对,因为它是采用蓝牙的广播频道传送信号。
  • 程序可以后台唤醒,iBeacon的信息推送需要App支持。但是我们接收iBeacon信号无需打开App,只要保证安装了,同时手机蓝牙打开。

iBeacon是如何工作呢?实际上iBeacon基站通过蓝牙的广播频道不断向外发送位置信息,发送频率越快越耗电。也就是说iBeacon并不推送消息,而只是用于定位,推送消息的功能必须由App来完成。苹果定义了iBeacon 其中32位广播的数据格式。

  • UUID:厂商识别号

    
    
  • Major:相当于群组号,同一个组里Beacon有相同的Major
  • Minor:相当于识别群组里单个的Beacon
  • TX Power:用于测量设备离Beacon的距离

UUID+Major+Minor就构成了一个Beacon的识别号,有点类似于网络中的IP地址。TX Power用于测距,iBeacon目前只定义了大概的3个粗略级别:

  • 非常近(Immediate): 大概10厘米内
  • 近(Near):1米内
  • 远(Far):1米外

这里主要是对其用法做一个介绍:

首先是获取BluetoothAdapter对象:

final BluetoothManager bluetoothManager =
                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();
        mBluetoothAdapter.startLeScan(mLeScanCallback);

然后就是它的回调,在这里对搜索到的iBeacon设备距手机的距离做了一个排序

private BluetoothAdapter.LeScanCallback mLeScanCallback =
            new BluetoothAdapter.LeScanCallback() {

        @Override
        public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
        	final iBeacon ibeacon = iBeaconClass.fromScanData(device,rssi,scanRecord);
        	addDevice(ibeacon);
        	Collections.sort(mLeDevices, new Comparator<iBeacon>() {
    			@Override
    			public int compare(iBeacon h1, iBeacon h2) {
    				return h2.rssi - h1.rssi;
    			}
    		});
        }
    };

最后把搜索到的数据添加到集合中去

private ArrayList<iBeacon> mLeDevices = new ArrayList<iBeacon>();
    private void addDevice(iBeacon device) { //更新beacon信息
		if(device==null) {
			Log.d("DeviceScanActivity ", "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);
				break;
			}
		}
		mLeDevices.add(device);

	}

我们在iBbeaconClass类中对其进行数据的解析处理,参考:https://github.com/AltBeacon/android-beacon-library

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 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.proximityUuid = "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.proximityUuid = "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;

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

        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();
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-27 08:22:37

Android 开发中 iBeacon的使用的相关文章

Android 开发中的日常积累

欢迎Star,Fork https://github.com/lizhangqu/CoreLink 里面记录了开发过程中有用的东西,欢迎补充,不定时更新. Android 性能优化 Android内存优化之OOM Android最佳性能实践(1):合理管理内存 Android最佳性能实践(2):分析内存的使用情况 Android最佳性能实践(3):高性能编码优化 Android最佳性能实践(4):布局优化技巧 Android 加固与反编译 Apktool dex2jar DecompileApk

android开发中碰到的三个小问题

Android开发中注意到的几个问题 1.  关于actionbar 初始化配置actionbar,getactionbar经常为null,原因是因为在源码或者布局文件中设置了全屏显示的缘故,不设置全屏显示就不会有问题. 2.  关于textview Textview默认是没有焦点的,因此不可能有点击事件,也无法直接实现背景的selector.通过设置android:clickable = true;就可以了,这一点与Button有很大的不同 3.  关于sourcinsight中的php代码.

android开发中监听器的三种实现方法(OnClickListener)

Android开发中监听器的实现有三种方法,对于初学者来说,能够很好地理解这三种方法,将能更好地增进自己对android中监听器的理解. 一.什么是监听器. 监听器是一个存在于View类下的接口,一般以On******Llistener命名,实现该接口需要复写相应的on****(View v)方法(如onClick(View v)). 二.监听器的三种实现方法 (以OnClickListener为例) 方法一:在Activity中定义一个内部类继承监听器接口(这里是OnClickListener

android开发中,两个按下手机实体返回键,两个Activity反复来回跳转的问题

android开发中,对于用intent实现跳转的Ativity,有时候按下手机的返回键时,两个Activity之间会多次相互跳转,始终退出不了程序的情况.这是由于从Activity  A跳转到Activity  B时,A被压入Activity栈中:当从B返回时,默认又重新创建了一个Activity A对象,这样一来就有了多个Activity A对象.所以造成了无法退出情况. 解决办法是:在AndroidManifest.xml文件中找到Activity A项,在其属性中加入  android:

Android开发中常用的ListView列表的优化方式ViewHolder

在Android开发中难免会遇到大量的数据加载到ListView中进行显示, 然后其中最重要的数据传递桥梁Adapter适配器是常用的,随着市场的需 求变化ListView'条目中的内容是越来越多这就需要程序员来自定义适配器, 而关键的就是适配器的优化问题,适配器没有优化好往往就会造成OOM (内存溢出)或者是滑动卡顿之类的问题,接下来我就给大家介绍一种常 用的Adapter优化方法 1 /** 2 * list View的适配器 3 */ 4 class Adapter extends Bas

Builder模式详解及其在Android开发中的应用

一.引言 在Android开发中,采用Builder模式的代码随处可见,比如说Android系统对话框AlertDialog的使用或者是Android中的通知栏(Notification)的使用,又比如说在一些常用的第三方库中也随处可见其踪迹,比如说一些常用的网络请求库如OkHttp或者是retrofit,又或者是图片加载库Glide中也不缺乏它的应用. 为什么Builder模式在Android或是Java开发中这么火呢?因为它相较于构造函数或者是Get/Set方法,它的灵活性和封装性上都比较有

android权限--android开发中的权限及含义(上)

android权限--android开发中的权限及含义(上) android.permission.EXPAND_STATUS_BAR 允许一个程序扩展收缩在状态栏,android开发网提示应该是一个类似Windows Mobile中的托盘程序 android.permission.FACTORY_TEST 作为一个工厂测试程序,运行在root用户 android.permission.FLASHLIGHT 访问闪光灯,android开发网提示HTC Dream不包含闪光灯 android.pe

Android学习笔记_78_ Android开发中使用软引用和弱引用防止内存溢出

在<Effective Java 2nd Edition>中,第6条"消除过期的对象引用"提到,虽然Java有 垃圾回收机制,但是只要是自己管理的内存,就应该警惕内存泄露的问题,例如的对象池.缓存中的过期对象都有可能引发内存泄露的问题.书中还提到可以用 WeakHashMap来作为缓存的容器可以有效解决这一问题.之前也确实遇到过类似问题,但是没有接触过"弱引用"相关的问题,于是查阅了一些资料. <Java 理论与实践: 用弱引用堵住内存泄漏>

Android开发中使用七牛云存储进行图片上传下载

Android开发中的图片存储本来就是比较耗时耗地的事情,而使用第三方的七牛云,便可以很好的解决这些后顾之忧,最近我也是在学习七牛的SDK,将使用过程在这记录下来,方便以后使用. 先说一下七牛云的存储原理,上面这幅图片是官方给出的原理图,表述当然比较清晰了.可以看出,要进行图片上传的话可以分为五大步: 1. 客户端用户登录到APP的账号系统里面: 2. 客户端上传文件之前,需要向业务服务器申请七牛的上传凭证,这个凭证由业务服务器使用七牛提供的服务端SDK生成: 3. 客户端使用七牛提供的客户端S