Android-BLE蓝牙开发学习记录

Android开发并非我擅长,最近刚好又做回蓝牙业务了,iOS搞完了看了下Android的,似乎区别不大,唯一比iOS多了一个descriptor,那就顺便把Android蓝牙也搞搞吧,本文仅做学习记录完成过程以及中途遇到的坑。代码是否规范不重要哈!

1.申请权限

首先在第一步我就遇到了坑,Android蓝牙开发需要申请地理位置权限,位置权限是敏感权限,高版本Android需要动态申请,最开始我只在AndroidManifest添加了权限申请,结果就是不管用旧的API还是最新的API扫描,都不走扫描结果回调!注意避坑!!!
AndroidManifest中申请以下权限

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

    <uses-feature android:name="android.hardware.location.gps" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

然后在代码中动态申请,这里写一个requestPermission方法申请

 private void requestPermission() {
        //动态申请
        if (Build.VERSION.SDK_INT < 23) {
            return;
        }
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
        }
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
        }
    }

2.初始化蓝牙

  private void initBluetooth() {
        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = mBluetoothManager.getAdapter();
        mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
        if (mBluetoothAdapter == null) {
            Log.d(TAG, "蓝牙不支持");
        } else {
            int status = mBluetoothAdapter.getState();
            if (status == BluetoothAdapter.STATE_OFF) {
                mBluetoothAdapter.enable();
            }else {
                Log.d(TAG, "蓝牙可用");
            }
        }
    }

3.开始扫描

扫描的方式可以用BluetoothAdapter.startLeScan扫描,但谷歌已经不建议用该方法扫描了,那就用最新的BluetoothLeScanner的方式扫描吧,在需要扫描的地方添加下面的代码,扫描可以根据服务UUID扫描固定一类蓝牙设备,也可以不过滤扫描所有设备,我这里根据服务UUID过滤(Android除了UUID过滤扫描,还有其他的,比如name等,没仔细研究,iOS过滤条件目前就只有UUID)

        List<ScanFilter> bleScanFilters = new ArrayList<>();
        bleScanFilters.add(new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString("你的蓝牙设备UUID")).build());
        ScanSettings scanSetting = new ScanSettings.Builder().setScanMode(SCAN_MODE_LOW_LATENCY).setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES).setMatchMode(ScanSettings.MATCH_MODE_STICKY).build();
        mBluetoothLeScanner.startScan(bleScanFilters, scanSetting, callback);
        Log.d(TAG, "开始扫描");

4.扫描回调并连接

因为我是根据UUID只扫描一类设备,为了省电扫描到后我直接停止扫描,然后连接第一个扫描到的设备

final ScanCallback stopCallback = new ScanCallback() {
    };

final ScanCallback callback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);
            Log.d(TAG, "扫描到设备");
            BluetoothDevice btDevice = result.getDevice();
            mBluetoothLeScanner.stopScan(stopCallback);
            btDevice.connectGatt(MainActivity.this,true, connectCallBack);
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            super.onBatchScanResults(results);
            Log.d(TAG, "onBatchScanResults");
        }

        @Override
        public void onScanFailed(int errorCode) {
            super.onScanFailed(errorCode);
            Log.d(TAG, "扫描出错");
        }
    };

5.连接回调,发现服务,发现特征值,监听蓝牙发过来的数据,发送数据

    final  BluetoothGattCallback connectCallBack = new BluetoothGattCallback(){
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            if (newState == BluetoothProfile.STATE_CONNECTED){
                Log.d(TAG, "连接成功");
                gatt.discoverServices();
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            Log.d(TAG, "发现服务");
            BluetoothGattService service = gatt.getService(UUID.fromString("蓝牙设备服务uuid"));
            if (service != null){
                Log.d(TAG, "有服务");
                BluetoothGattCharacteristic notyChara = service.getCharacteristic(UUID.fromString("蓝牙设备可监听征值uuid"));
                if (notyChara != null){
                    Log.d(TAG, "有特征值");
                    boolean success = gatt.setCharacteristicNotification(notyChara,true);
                    Log.i("监听结果: "+success);
                    BluetoothGattDescriptor descriptor = notyChara.getDescriptor(UUID.fromString("蓝牙设备描述uuid"));
                    if (descriptor != null){
                        descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
                        gatt.writeDescriptor(descriptor);
                    }
                }
                //发送数据
                BluetoothGattCharacteristic writeChar = service.getCharacteristic(UUID.fromString("蓝牙设备可写特征值的UUID"));
                writeChar.setValue(TAG.getBytes());
                gatt.writeCharacteristic(writeChar);
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            Log.d(TAG, "收到数据");
        }
    };

值得一提的是,为了省电,在不需要监听数据后需要设置停止监听,也可以用readCharacteristic读取单条数据

gatt.setCharacteristicNotification(chara,false);
descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);

在不需要蓝牙后应该调用gatt的disconnect方法断开设备,因为有最大连接数限制,还需要调用gatt的close方法释放当前连接个数计数。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,601评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,367评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,249评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,539评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,967评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,929评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,098评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,825评论 0 207
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,609评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,796评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,282评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,603评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,277评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,159评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,959评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,079评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,874评论 2 277

推荐阅读更多精彩内容