android iBeacon开发模拟实例

这段时间微信周边摇一摇带动的ibeacon新兴市场火得一塌糊涂。

iBeacon 是苹果公司2013年9月发布的移动设备用OS(iOS7)上配备的新功能。其工作方式是,配备有 低功耗蓝牙(BLE)通信功能的设 备使用BLE技术向周围发送自己特有的ID,接收到该ID的应用软件会根据该ID采取一些行动。比如,在店铺里设置iBeacon通信模块的话,便可让iPhone和iPad上运行一资讯告知服务器,或者由服务器向顾客发送折扣券及进店积分。此外,还可以在家电发生故障或停止工作时使用iBeacon向应用软件发送资讯。

iOS这边官方已经有相关较为成熟的开发文档和封装类,但是安卓方面还没有官方的支持,只能自行开发或借助第三方sdk开发。安卓开发ibeacon是基于BLE开发的,所以大家需要先学习好安卓官方的BLE开发文档,其实iBeacon是BLE衍生版,所以iBeacon具有属性和特点BLE几乎都有,百度上的第三方包其实就是基于BLE开发的封装类。那么今天我来带大家一起来学习开发android

版的iBeacon吧:

安卓iBeacon开发前得先判断当前设备(手机)是否支持BLE功能:

        //判断手机等设备是否支持BLE,即是否可以扫描iBeacon设备
        bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();

        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
            finish();
        }

  扫描蓝牙设备,将符合IBacon特征的设备对象转成IBeacon设备对象(由IBeaconProductor类转换 ):

    // iBeacon设备扫描回调结果
    private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {

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

            final IBeacon ibeacon = IBeaconProductor.fromScanData(device, rssi, scanRecord);
            final Commodity commodity = getCommodity(ibeacon);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mLeDeviceListAdapter.addCommodity(commodity);
                    mLeDeviceListAdapter.notifyDataSetChanged();
                }
            });
        }
    };

 IBeacon生产包装类,IBeaconProductor :

/**
 * IBeacon生产包装类
 * 帮助android扫描到的蓝牙设备对象转成IBeacon对象
 *
 * @author www.icheny.cn
 * @date 2019.04.16
 */
public class IBeaconProductor {

    /**
     * 从蓝牙设备对象中解析出IBeacon对象
     *
     * @param device
     * @param rssi
     * @param scanData
     * @return
     */
    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) {
                // 这是 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 beacon = new IBeacon();
                beacon.major = 0;
                beacon.minor = 0;
                beacon.uuid = "00000000-0000-0000-0000-000000000000";
                beacon.txPower = -55;
                beacon.distance = String.format("%.2f", calculateAccuracy(beacon.txPower, rssi));
                return beacon;
            } 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 beacon = new IBeacon();
                beacon.major = 0;
                beacon.minor = 0;
                beacon.uuid = "00000000-0000-0000-0000-000000000000";
                beacon.txPower = -55;
                beacon.distance = String.format("%.2f", calculateAccuracy(beacon.txPower, rssi));
                return beacon;
            }
            startByte++;
        }

        if (patternFound == false) {
            // 这不是iBeacon
            return null;
        }

        IBeacon beacon = new IBeacon();

        beacon.major = (scanData[startByte + 20] & 0xff) * 0x100 + (scanData[startByte + 21] & 0xff);
        beacon.minor = (scanData[startByte + 22] & 0xff) * 0x100 + (scanData[startByte + 23] & 0xff);
        beacon.txPower = (int) scanData[startByte + 24];
        beacon.rssi = rssi;

        // 格式化UUID
        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));
        beacon.uuid = sb.toString();

        if (device != null) {
            beacon.address = device.getAddress();
            beacon.name = device.getName();
        }
        beacon.distance = String.format("%.2f", calculateAccuracy(beacon.txPower, rssi));
        return beacon;
    }

    /**
     * 转换十进制
     *
     * @param src
     * @return
     */
    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
     */
    private 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;
        }
    }
}

模拟从后台服务器获取商品信息:

    /**
     * 模拟根据ibeacon信息从后台取对应商品据信息
     * 这里面的uuid,major,minor 都是我这边的iBeacon设备
     * 你可以填你自己的iBeacon设备相关信息,进行iBeacon设备过滤
     *
     * @param ibeacon
     * @return
     */
    private Commodity getCommodity(IBeacon ibeacon) {
        if ("fda50693-a4e2-4fb1-afcf-c6eb07647825".equalsIgnoreCase(ibeacon.uuid) && 10001 == ibeacon.major// 这里是对照UUID,major,minor作为模拟唯一的识别id
                && 64120 == ibeacon.minor) {
            return new Commodity("1122", R.drawable.a, 288.00, "老诚一锅6-8人餐\n6-8人餐,免费wifi,美味营养,回味无穷!", ibeacon.distance);

        } else if ("fda50693-a4e2-4fb1-afcf-c6eb07647825".equalsIgnoreCase(ibeacon.uuid) && 10 == ibeacon.major
                && 7 == ibeacon.minor) {
            return new Commodity("4455", R.drawable.b, 258.00, "净味真烤羊腿套餐\n烤羊腿套餐,可使用包间", ibeacon.distance);

        } else if ("fda50693-a4e2-4fb1-afcf-c6eb07647825".equalsIgnoreCase(ibeacon.uuid)
                && 10111 == ibeacon.major && 7 == ibeacon.minor) {
            return new Commodity("7788", R.drawable.c, 258.00, "新疆纸皮核桃\n【全国免费配送】新疆纸皮核桃2袋共1000g,仅55元,享价值116元(原价值每袋68元)",
                    ibeacon.distance);
        }
        return null;
    }

OK,核心代码如上,这是模拟扫描周边iBeacon设备,过滤掉没有跟你公司合作的设备,并向用户推送这些有效设备相关是的商品信息,当然过滤规则可以自定义的,我这个过滤规则是应付教程的哈,代码很简单。下面我也会传代码供大家下载学习,注释也写得很详细。

下面是效果图:

图片[1]-android iBeacon开发模拟实例-乘月网

   下载DEMO源码 (文章,代码有小浮更新,更新时间:2016.03.29)

2019.04.16更新Android Studio的demo源码:IBeaconDemo

文笔不好,也没时间优化这篇文章,等有时间再修改细述。

© 版权声明
THE END
喜欢就支持以下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容