android iBeacon开发模拟实例

原创 cheny  2016-03-24 13:01  阅读 80 次 评论 0 条
摘要:

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

这段时间微信周边摇一摇带动的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();
        }
    // 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);
            final Commodity commodity = getCommodity(ibeacon);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mLeDeviceListAdapter.addCommodity(commodity);
                    mLeDeviceListAdapter.notifyDataSetChanged();
                }
            });
        }
    };
    /**
     * 模拟根据ibeacon信息从后台取对应商品据信息
     * 这里面的uuid,major,minor 都是我这边的iBeacon设备。你可以填你自己的iBeacon设备相关信息,进行iBeacon设备过滤
     * @param ibeacon
     * @return
     */
    private Commodity getCommodity(iBeacon ibeacon) {
        if ("fda50693-a4e2-4fb1-afcf-c6eb07647825".equalsIgnoreCase(ibeacon.proximityUuid) && 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.proximityUuid) && 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.proximityUuid)
                && 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;
    }


下面是是iBeaconClass 是基于网上其他大神小浮修改优化的

public class iBeaconClass {
    /**
     * iBeacon静态内部实体类
     * 
     * @author cheny
     *
     */
    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 String distance;
    }

    /**
     * 解析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 iBeacon = new iBeacon();
                iBeacon.major = 0;
                iBeacon.minor = 0;
                iBeacon.proximityUuid = "00000000-0000-0000-0000-000000000000";
                iBeacon.txPower = -55;
                iBeacon.distance = String.format("%.2f", calculateAccuracy(iBeacon.txPower, rssi));
                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;
                iBeacon.distance = String.format("%.2f", calculateAccuracy(iBeacon.txPower, rssi));
                return iBeacon;
            }
            startByte++;
        }

        if (patternFound == false) {
            // 这不是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];
        iBeacon.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));
        iBeacon.proximityUuid = sb.toString();

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

    /**
     * 转换十进制
     * 
     * @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
     */
    protected 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;
        }
    }
}

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

 

下面是效果图:

android iBeacon开发模拟实例 Android 第1张

 

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

 

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

 

 

本文地址:https://www.icheny.cn/android-ibeacon%e5%bc%80%e5%8f%91%e6%a8%a1%e6%8b%9f%e5%ae%9e%e4%be%8b/
关注我们:加我微信:扫描二维码乘月网的微信号,微信号:ausboyue
版权声明:本文为原创文章,版权归 cheny 所有,欢迎分享本文,转载请保留出处!
PREVIOUS:已经是最后一篇了

发表评论


表情