关闭

android蓝牙ble4.0开发

标签: android蓝牙ble4.0
1539人阅读 评论(0) 收藏 举报
分类:

1、权限配置

AndroidManifest.xml里配置,android:required="true"表示apk只有在具有bluetooth_le属性的系统里运行。

    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

2、判断是否支持蓝牙

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

3、打开和关闭蓝牙

先获取蓝牙适配器:

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

        // Checks if Bluetooth is supported on the device.
        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);
            }
        }

public void onActivityResult(int requestCode, int resultCode, Intent data){  
       if(requestCode == REQUEST_ENABLE_BT){  
              if(requestCode == RESULT_OK){  
                   //蓝牙已经开启   
              }  
       }  
}

// 也可以用enable()方法来开启,无需询问用户(无声息的开启蓝牙设备),这时就需要用到android.permission.BLUETOOTH_ADMIN权限。  
        // mBluetoothAdapter.enable();  //打开蓝牙 
        // mBluetoothAdapter.disable();//关闭蓝牙 

注意,如果用静默的方式打开蓝牙,不能马上开始扫描,这样会失败,因为打开蓝牙要一两秒时间。

4、搜索蓝牙

            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);
        }
在4.3之前的api是通过注册广播来处理搜索时发生的一些事件,使用startDiscovery()这个函数搜索,而支持ble的新的api中,是通过回调的方式来处理的,mLeScanCallback就是一个接口对象。

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

device代表蓝牙设备,rssi是信号强度,scanRecord是广播数据,一些项目要求广播匹配蓝牙设备才能被发现,就是根据把产品ID写到广播里来判别。如下:

4.3以下的通过广播方式来搜索,如下:

// 设置广播信息过滤    
IntentFilter intentFilter = new IntentFilter();   
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);   
intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);   
intentFilter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);   
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);   
// 注册广播接收器,接收并处理搜索结果    
context.registerReceiver(receiver, intentFilter);   
// 寻找蓝牙设备,android会将查找到的设备以广播形式发出去    
adapter.startDiscovery();  
private BroadcastReceiver receiver = new BroadcastReceiver() {   
   @Override   
  public void onReceive(Context context, Intent intent) {   
       String action = intent.getAction();   
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {   
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);   
            System.out.println(device.getName());   
       }   
   }   
}

另外,还可以配置本机蓝牙是否可见,被对方搜索到:

//使本机蓝牙在300秒内可被搜索  
private void ensureDiscoverable() {  
        if (mBluetoothAdapter.getScanMode() !=   BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {  
            Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);  
            discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);  
            startActivity(discoverableIntent);  
        }  
} 
还有查找以前配对过的设备:

		Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
		if (pairedDevices.size() > 0) {
			for (BluetoothDevice device : pairedDevices) {
				//device.getName() +" "+ device.getAddress());
			}
		} else {
			mPairedDevicesArrayAdapter.add("没有找到已匹对的设备");
		}

5、蓝牙连接

两个设备通过BLE通信,首先需要建立GATT连接。这里我们讲的是Android设备作为client端,连接GATT Server。
连接GATT Server,你需要调用BluetoothDevice的connectGatt()方法。此函数带三个参数:Context、autoConnect(boolean)和BluetoothGattCallback对象。调用示例:
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
函数成功,返回BluetoothGatt对象,它是GATT profile的封装。通过这个对象,我们就能进行GATT Client端的相关操作。BluetoothGattCallback用于传递一些连接状态及结果。
 
BluetoothGatt常规用到的几个操作示例:
connect() :连接远程设备。
discoverServices() : 搜索连接设备所支持的service。
disconnect():断开与远程设备的GATT连接。
close():关闭GATT Client端。
readCharacteristic(characteristic) :读取指定的characteristic。
setCharacteristicNotification(characteristic, enabled) :设置当指定characteristic值变化时,发出通知。
getServices() :获取远程设备所支持的services。

google的demo里,连接蓝牙,首先绑定一个服务:

		Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
		bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

// Code to manage Service lifecycle.
	private final ServiceConnection mServiceConnection = new ServiceConnection() {

		@Override
		public void onServiceConnected(ComponentName componentName,
				IBinder service) {
			mBluetoothLeService = ((BluetoothLeService.LocalBinder) service)
					.getService();
			if (!mBluetoothLeService.initialize()) {
				Log.e(TAG, "Unable to initialize Bluetooth");
				finish();
			}
			// Automatically connects to the device upon successful start-up
			// initialization.
			mBluetoothLeService.connect(mDeviceAddress);
		}

		@Override
		public void onServiceDisconnected(ComponentName componentName) {
			mBluetoothLeService = null;
		}
	};


initialize()初始化函数里,主要是获得mBluetoothManager和mBluetoothAdapter:

 /**
     * Initializes a reference to the local Bluetooth adapter.
     *
     * @return Return true if the initialization is successful.
     */
    public boolean initialize() {
        // For API level 18 and above, get a reference to BluetoothAdapter through
        // BluetoothManager.
        if (mBluetoothManager == null) {
            mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
            if (mBluetoothManager == null) {
                Log.e(TAG, "Unable to initialize BluetoothManager.");
                return false;
            }
        }

        mBluetoothAdapter = mBluetoothManager.getAdapter();
        if (mBluetoothAdapter == null) {
            Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
            return false;
        }

        return true;
    }
     连接函数mBluetoothLeService.connect里,先用getRemoteDevice获取BluetoothDevice,然后调用connectGatt函数连接,连接成功返回BluetoothGatt。

 /* Connects to the GATT server hosted on the Bluetooth LE device.
     *
     * @param address The device address of the destination device.
     *
     * @return Return true if the connection is initiated successfully. The connection result
     *         is reported asynchronously through the
     *         {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
     *         callback.
     */
    public boolean connect(final String address) {
        if (mBluetoothAdapter == null || address == null) {
            Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
            return false;
        }

        // Previously connected device.  Try to reconnect.
        if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
                && mBluetoothGatt != null) {
            Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
            if (mBluetoothGatt.connect()) {
                mConnectionState = STATE_CONNECTING;
                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, false, mGattCallback);
        Log.d(TAG, "Trying to create a new connection.");
        mBluetoothDeviceAddress = address;
        mConnectionState = STATE_CONNECTING;
        System.out.println("device.getBondState=="+device.getBondState());
        return true;
    }
这里的mGattCallback是蓝牙连接和通讯读写和收到通知时的回调函数。
 //蓝牙数据返回
    // 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) {
            String intentAction;
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                intentAction = ACTION_GATT_CONNECTED;
                mConnectionState = STATE_CONNECTED;
                broadcastUpdate(intentAction);
                Log.i(TAG, "Connected to GATT server.");
                // Attempts to discover services after successful connection.
                Log.i(TAG, "Attempting to start service discovery:" +
                        mBluetoothGatt.discoverServices());

            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                intentAction = ACTION_GATT_DISCONNECTED;
                mConnectionState = STATE_DISCONNECTED;
                Log.i(TAG, "Disconnected from GATT server.");
                broadcastUpdate(intentAction);
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
            } else {
                Log.w(TAG, "onServicesDiscovered received: " + status);
                System.out.println("onServicesDiscovered received: " + status);
            }
        } 
        
        public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic,int status) {
        	 Log.e(TAG, "onCharacteristicRead");
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Log.e(TAG,"onCharRead "+gatt.getDevice().getName()
                        +" read "
                        +characteristic.getUuid().toString()
                        +" -> "
                        +UMDataProcessUtil.bytesToHexString(characteristic.getValue()));
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
                
            }
        }
        /**
         * 返回数据。
         */
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic characteristic) {
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
            //数据
            Log.i("onCharacteristicChanged", "返回读出的值");
            Log.e("notify data:", UMDataProcessUtil.bytesToHexString(characteristic.getValue()));

        }
        
    };


6、蓝牙通讯

BLE分为三部分Service、Characteristic、Descriptor,这三部分都由UUID作为唯一标示符。一个蓝牙4.0的终端可以包含多个Service,一个Service可以包含多个Characteristic,一个Characteristic包含一个Value和多个Descriptor,一个Descriptor包含一个Value
我们一般需要操作的是Characteristic,需要先获取Service,然后可以进行读、写和打开通知操作。
    public static final UUID SERVIE_UUID = UUID.fromString("0000FE95-0000-1000-8000-00805f9b34fb");
     BluetoothGattService linkLossService = mBluetoothGatt.getService(SERVIE_UUID);

1)、Characteristic读操作
    public static final UUID LIGHT_UUID = UUID.fromString("00001006-0000-1000-8000-00805F9B34FB");
public void readLlsAlertLevel(){
		BluetoothGattService linkLossService = mBluetoothGatt.getService(SERVIE_UUID);
		if (linkLossService == null) {
			showMessage("readLlsAlertLevel, link loss Alert service not found!");
			return;
		}
		BluetoothGattCharacteristic alertLevel = linkLossService.getCharacteristic(STATE_UUID);
		if(mBluetoothGatt.readCharacteristic(alertLevel)) {
			 Log.e("test","ble read success");
		} else {
			 Log.e("test","ble read fail");
		}
		
    }
蓝牙读操作对应上面mGattCallback的函数是onCharacteristicRead,执行完读之后可以在onCharacteristicRead里收到读的数据。

2)Characteristic写操作
    public void writeLlsAlertLevel(int iAlertLevel, byte[] bb) {

		BluetoothGattService linkLossService = mBluetoothGatt.getService(SERVIE_UUID);
		if (linkLossService == null) {
			showMessage("writeLlsAlertLevel,link loss Alert service not found!");
			return;
		}
		
		BluetoothGattCharacteristic alertLevel = null;
		alertLevel = linkLossService.getCharacteristic(KEY_UUID);
		if (alertLevel == null) {
			showMessage("writeLlsAlertLevel,link loss Alert Level charateristic not found!");
			return;
		}

		int storedLevel = alertLevel.getWriteType();
		Log.d(TAG, "storedLevel() - storedLevel=" + storedLevel);

		alertLevel.setValue(bb);
		Log.e("发送的指令", "bb" + bb[0]);

		alertLevel.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
		boolean status = mBluetoothGatt.writeCharacteristic(alertLevel);
		Log.d(TAG, "writeLlsAlertLevel() - status=" + status);
	}
蓝牙写操作对应上面mGattCallback的函数是onCharacteristicWrite,但是我们一般没有必要监视这个,直接从返回的status判断是否写成功就行了。

3)Characteristic打开\关闭notify
如果我们要长期监视蓝牙设备的状态变化,一般需要用到notify功能。
    public boolean enableStateNotification(boolean enable){
    	
		BluetoothGattService linkLossService = mBluetoothGatt.getService(SERVIE_UUID);
		if (linkLossService == null) {
			showMessage("enableStateNotification, link loss Alert service not found!");
			return false;
		}
		BluetoothGattCharacteristic characteristic = linkLossService.getCharacteristic(STATE_UUID);
	    int charaProp = characteristic.getProperties();
    	if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) <= 0)
    	{
    		showMessage("getProperties wrong!Not PROPERTY_NOTIFY !");
    		return false;
    	}
    	return setCharacteristicNotification(characteristic,enable);
    }


 public static String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";
 /**
     * Enables or disables notification on a give characteristic.
     * @param characteristic Characteristic to act on.
     * @param enabled If true, enable notification.  False otherwise.
     */
    public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
                                              boolean enabled) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return false;
        }
        boolean result =mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
        if(!result){
         <span style="white-space:pre">	</span>Log.e(TAG, "setCharacteristicNotification fail!!!!!!!!!!!");
        <span style="white-space:pre">	</span>return false;
        }


        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
                UUID.fromString(UMGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        return  mBluetoothGatt.writeDescriptor(descriptor);
       
    }

蓝牙notify操作对应上面mGattCallback的函数是onCharacteristicChanged,打开之后,可以在这个函数里监视notify的数据变化。









1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:17727次
    • 积分:260
    • 等级:
    • 排名:千里之外
    • 原创:6篇
    • 转载:12篇
    • 译文:0篇
    • 评论:1条
    最新评论