android 藍牙4.0多通道

    好久沒記錄東西了,前段時間研究了一哈android4.0控制多個外設的狀況,注意,須要使用android版本4.3以上,藍牙4.0及以上。android

    我這裏使用的控制藍牙燈泡,使用android4.3的手機,手機上的藍牙是4.0.app

    記得在manifest文件中加入權限:async

    

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

    先拿到BluetoothManager和BluetoothAdapter的對象。ide

    

        // 初始化 Bluetooth adapter, 經過藍牙管理器獲得一個參考藍牙適配器(API必須在以上android4.3或以上和版本)
        final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();

        // 檢查設備上是否支持藍牙
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, R.string.error_bluetooth_not_supported,Toast.LENGTH_SHORT).show();
            finish();
            return;
        }

    看下是否開啓了藍牙,若是沒有開啓,跳轉到設置去開啓藍牙。函數

    

// 爲了確保設備上藍牙能使用, 若是當前藍牙設備沒啓用,彈出對話框向用戶要求授予權限來啓用
        if (!mBluetoothAdapter.isEnabled()) {
            if (!mBluetoothAdapter.isEnabled()) {
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
            }
        }

    調用startScan方法開始掃描,stopScan方法中止掃描,掃描到的設備都在回調函數裏。oop

    

private void scanLeDevice(final boolean enable) {
        if (enable) {
            // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    mBluetoothAdapter.stopLeScan(mLeScanCallback);
                    invalidateOptionsMenu();
                }
            }, SCAN_PERIOD);

            mScanning = true;
            mBluetoothAdapter.startLeScan(mLeScanCallback);
        } else {
            mScanning = false;
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }
        invalidateOptionsMenu();
    }

    

// Device scan callback.
    private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {

        @Override
        public void onLeScan(final BluetoothDevice device, int rssi,
                byte[] scanRecord) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mLeDeviceListAdapter.addDevice(device);
//                    mLeDeviceListAdapter.notifyDataSetChanged();
                }
            });
        }
    };

    掃描後的BluetoothDevice加入到列表中,這時列表中就會有設備,經過getName能夠獲取設備的藍牙名字,getAddress獲取設備的藍牙地址。post

    列表出來了以後,點擊某個設備進行鏈接。ui

    注意這裏的鏈接跟2.0的藍牙的鏈接不同,經過設備的connectGatt方法進行鏈接,鏈接完成後會得到一個BluetoothGatt的對象,這個對象中有鏈接的一些重要信息,切記要保存好。this

    

public boolean connect(final String address) {
        if (mBluetoothAdapter == null || address == null) {
            Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
            return false;
        }

        if (mBluetoothDeviceAddress != null
                && address.equals(mBluetoothDeviceAddress)
                && mBluetoothGatt != null) {
            Log.d(TAG,
                    "Trying to use an existing mBluetoothGatt for connection.");
            if (mBluetoothGatt.connect()) {
                return true;
            } else {
                return false;
            }
        }

        final BluetoothDevice device = mBluetoothAdapter
                .getRemoteDevice(address);
        if (device == null) {
            Log.w(TAG, "Device not found.  Unable to connect.");
            return false;
        }
        // We want to directly connect to the device, so we are setting the
        // autoConnect
        // parameter to false.
        mBluetoothGatt = device.connectGatt(this, true, mGattCallback);
        Log.d(TAG, "Trying to create a new connection.");
        mBluetoothDeviceAddress = address;
        bluetoothGatts.add(mBluetoothGatt);
        return true;
    }

     鏈接時有一個回調函數mGattCallback,這個函數中有不少設備的相關信息,好比設備的狀態啊,設備中的通道哈,一些服務啊之類的。spa

     

    // Implements callback methods for GATT events that the app cares about. For
    // example,
    // connection change and services discovered.
    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {

        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status,
                int newState) {
            System.out.println("onConnectionStateChange");
            String intentAction;
            if (status == BluetoothProfile.STATE_DISCONNECTED
                    && newState == BluetoothProfile.STATE_CONNECTED) {
                intentAction = ACTION_GATT_CONNECTED;
                Log.i(TAG, "Connected to GATT server.");
                // Attempts to discover services after successful connection.
                Log.i(TAG, "Attempting to start service discovery:"
                        + mBluetoothGatt.discoverServices());
                Log.e("shang", "鏈接成功");
                mHandler.sendEmptyMessage(MESSAGE_START_SUCCESS);
            } else if (status == BluetoothProfile.STATE_DISCONNECTED
                    && newState == BluetoothProfile.STATE_DISCONNECTED) {
                intentAction = ACTION_GATT_DISCONNECTED;
                setConnStatus(false);
                Log.e("shang", "鏈接失敗");
                Log.i(TAG, "Disconnected from GATT server.");
                mHandler.sendEmptyMessage(STATE_CONNECTFAILED);
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            System.out.println("onServicesDiscovered-----");
            if (status == BluetoothGatt.GATT_SUCCESS) {
                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
                displayGattServices(getSupportedGattServices());
                mHandler.sendEmptyMessage(MESSAGE_BLUETOOTH_INIT);
            } else {
                Log.w(TAG, "onServicesDiscovered received: " + status);
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic, int status) {
            System.out.println("onCharacteristicRead");
            if (status == BluetoothGatt.GATT_SUCCESS) {
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
            }
        }

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt,
                BluetoothGattDescriptor descriptor, int status) {

            System.out.println("onDescriptorWriteonDescriptorWrite = " + status
                    + ", descriptor =" + descriptor.getUuid().toString());
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic) {
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
            if (characteristic.getValue() != null) {

                System.out.println(characteristic.getStringValue(0));
            }
            System.out.println("--------onCharacteristicChanged-----");
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {

        }

        public void onCharacteristicWrite(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic, int status) {
            System.out.println("--------write success----- status:" + status);
        };
    };

    鏈接時會走這個方法onConnectionStateChange,傳過來的新狀態是鏈接狀態,這時在這個方法中調用一下這句:mBluetoothGatt.discoverServices(),

    mBluetoothGatt是鏈接完成時的對象,還記得吧,調用這句後,會走回調函數的onServicesDiscovered方法。在這個方法中去獲取設備的一些服務,藍牙通道,而後經過這些通道去發送數據給外設。

    查看該外設中支持的一些服務通道:

    

public List<BluetoothGattService> getSupportedGattServices() {
        if (mBluetoothGatt == null)
            return null;

        return mBluetoothGatt.getServices();
    }

    

// Demonstrates how to iterate through the supported GATT
    // Services/Characteristics.
    // In this sample, we populate the data structure that is bound to the
    // ExpandableListView
    // on the UI.
    private void displayGattServices(List<BluetoothGattService> gattServices) {
        if (gattServices == null)
            return;
        String uuid = null;
        ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<HashMap<String, String>>();
        ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData = new ArrayList<ArrayList<HashMap<String, String>>>();
        mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>();

        // Loops through available GATT Services.
        for (BluetoothGattService gattService : gattServices) {
            HashMap<String, String> currentServiceData = new HashMap<String, String>();
            uuid = gattService.getUuid().toString();
            gattServiceData.add(currentServiceData);

            ArrayList<HashMap<String, String>> gattCharacteristicGroupData = new ArrayList<HashMap<String, String>>();
            List<BluetoothGattCharacteristic> gattCharacteristics = gattService
                    .getCharacteristics();
            ArrayList<BluetoothGattCharacteristic> charas = new ArrayList<BluetoothGattCharacteristic>();

            // Loops through available Characteristics.
            for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
                charas.add(gattCharacteristic);
                HashMap<String, String> currentCharaData = new HashMap<String, String>();
                uuid = gattCharacteristic.getUuid().toString();
                gattCharacteristicGroupData.add(currentCharaData);
            }
            mGattCharacteristics.add(charas);
            gattCharacteristicData.add(gattCharacteristicGroupData);
        }
        bluetoothGattChacteristics.add(mGattCharacteristics);
    }

    而後就能夠經過Gatt這個對像,就是藍牙鏈接完成後獲取到的對象,經過這個對象設置好指定的通道向設備中寫入和讀取數據。

    寫數據:

    

public void wirteCharacteristic(BluetoothGattCharacteristic characteristic) {

        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }

        mBluetoothGatt.writeCharacteristic(characteristic);
    }

    讀數據:

/**
     * Request a read on a given {@code BluetoothGattCharacteristic}. The read
     * result is reported asynchronously through the
     * {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
     * callback.
     * 
     * @param characteristic
     *            The characteristic to read from.
     */
    public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        mBluetoothGatt.readCharacteristic(characteristic);
    }

    注意:BluetoothGattCharacteristic這個是指定的通道,藍牙服務:

BluetoothGattCharacteristic characteristic = null;
characteristic = mGattCharacteristics.get(4).get(4);

    這兩個數字就是從指定的服務中找到你要發送數據的那個服務。

  最後,若是要進行多個鏈接,每次鏈接完成後能夠將BluetoothGatt的對象放到一個list裏面,獲取到的服務也放到一個List裏面,而後發送數據的時候調用不一樣的Gatt發送不一樣的通道數據便可。

   關於藍牙4.0的BluetoothLeGatt鏈接,android Samples有一個例子,發上來吧,須要的朋友能夠下載看看。

    BluetoothLeGatt

相關文章
相關標籤/搜索