您的位置:首页 > 移动开发 > Android开发

浅谈BLE

2015-08-03 14:14 465 查看
最近刚开始接触Android,Android编程对于一个学过C++的人来说,入门挺容易的;但想要做一名合格的Android开发工程师还有很长的路要走。当然这里仅限于我C++也不是学的很好,也只能说是个入门级别,大牛除外,大牛级别的人学什么编程语言都很快。
   说说BLE的特性吧。蓝牙4.0最重要的特性是省电,极低的运行和待机功耗可以使一粒纽扣电池连续工作数年之久。可以用于计步器、心律监视器、智能仪表、传感器物联网等众多领域。BLE通信由三部分Service、Characteristic、Descriptor构成,这三部分都由UUID作为唯一标示符。一个蓝牙4.0的终端可以包含多个Service,一个Service可以包含多个Characteristic,一个Characteristic包含一个Value和多个Descriptor,一个Descriptor包含一个Value。接下来说说gatt回调函数9个要实现的方法。
private BluetoothGattCallback GattCallback = new BluetoothGattCallback() {
// 这里有9个要实现的方法,看情况要实现那些,用到那些就实现那些
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState){};
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status){};
};
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
BluetoothGatt gatt = device.connectGatt(this, false, mGattCallback);
:notification对应onCharacteristicChanged;

gatt.setCharacteristicNotification(characteristic, true);
:readCharacteristic对应onCharacteristicRead;

gatt.readCharacteristic(characteristic);
: writeCharacteristic对应onCharacteristicWrite;

gatt.wirteCharacteristic(mCurrentcharacteristic);
:连接蓝牙或者断开蓝牙 对应 onConnectionStateChange;

:readDescriptor对应onDescriptorRead;

:writeDescriptor对应onDescriptorWrite;

gatt.writeDescriptor(descriptor);
:readRemoteRssi对应onReadRemoteRssi;

gatt.readRemoteRssi()
:executeReliableWrite对应onReliableWriteCompleted;
:discoverServices对应onServicesDiscovered。
代码实现:
实现步骤:1、开启蓝牙
2、扫描蓝牙
3、与外设建立gatt连接
4、枚举服务以及对应的UUID号
5、断开连接
具体代码:
   MainActivity.java
package com.example.ble;import android.annotation.SuppressLint;import android.app.Activity;import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothDevice;import android.bluetooth.BluetoothManager;import android.content.Context;import android.content.Intent;import android.content.SharedPreferences;import android.content.SharedPreferences.Editor;import android.content.pm.PackageManager;import android.os.Bundle;import android.os.Handler;import android.util.Log;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.ListView;import android.widget.Toast;/*** @date 2015-07-31* @describe* @author lai**/@SuppressLint("NewApi")public class MainActivity extends Activity {private static Context mContext;// 上下文private static final String TAG = MainActivity.class.getSimpleName();// 标志private SharedPreferences sp = null;private BluetoothAdapter mBluetoothAdapter = null;// 本地蓝牙设备private Handler mHandler = null;// 用于postDelayprivate boolean mScanning = false;// 循环标志位private static final long SCAN_PERIOD = 10000;// 扫描10sprivate static final int REQUEST_ENABLE_BT = 1;// 请求码private ListView mListView = null;private TestAdapter mAdapter = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.main);if (!checkBluetooth()) {finish();}init();}@Overrideprotected void onResume() {// TODO Auto-generated method stubsuper.onResume();System.out.println("2");// 为了确保设备上蓝牙能使用, 如果当前蓝牙设备没启用,弹出对话框向用户要求授予权限来启用if (!mBluetoothAdapter.isEnabled()) {if (!mBluetoothAdapter.isEnabled()) {Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);}}mAdapter = new TestAdapter(mContext);mListView.setAdapter(mAdapter);if (mBluetoothAdapter.isEnabled()) {scanLeDevice(true);}}@Overrideprotected void onPause() {super.onPause();scanLeDevice(false);mAdapter.clear();System.out.println("4");}@Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();suiside();}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {// TODO Auto-generated method stubif (requestCode == REQUEST_ENABLE_BT&& resultCode == Activity.RESULT_CANCELED) {finish();return;}super.onActivityResult(requestCode, resultCode, data);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.main, menu);if (!mScanning) {menu.findItem(R.id.menu_stop).setVisible(false);menu.findItem(R.id.menu_scan).setVisible(true);menu.findItem(R.id.menu_refresh).setActionView(null);} else {menu.findItem(R.id.menu_stop).setVisible(true);menu.findItem(R.id.menu_scan).setVisible(false);menu.findItem(R.id.menu_refresh).setActionView(R.layout.menurefresh);}return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()) {case R.id.menu_scan:mAdapter.clear();scanLeDevice(true);break;case R.id.menu_stop:scanLeDevice(false);break;}return true;}/*** 判断是否支持蓝牙和BLE** @return*/private boolean checkBluetooth() {// 判断是否支持BLEif (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {toast("ble not supported");return false;}// 初始化BluetoothAdapterfinal BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);mBluetoothAdapter = bluetoothManager.getAdapter();// 检查设备上是否支持蓝牙不支 持就退出程序if (mBluetoothAdapter == null) {toast("bluetooth not supported");return false;}return true;}/*** 初始化数据*/private void init() {mContext = this;mHandler = new Handler();sp = getSharedPreferences(Constant.SP_NAME, Context.MODE_PRIVATE);mListView = (ListView) findViewById(R.id.list_view);mListView.setOnItemClickListener(mItemClickListener);System.out.println("1");}/*** 列表单击事件*/private OnItemClickListener mItemClickListener = new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> arg0, View arg1, int position,long arg3) {// TODO Auto-generated method stub/*** 跳转到BLEService 传递一个参数 一个地址 并把名字和地址保存起来*/System.out.println("3");BluetoothDevice mDevice = mAdapter.getDevice(position);toast(mDevice.getAddress());saveDeviceAddress(mDevice.getAddress());startTheService();}};/*** 启动BLE通信服务*/private void startTheService() {Intent service = new Intent();service.setClass(mContext, BLEService.class);startService(service);}/*** 把地址保存起来 以便服务可以使用** @param address*/private void saveDeviceAddress(String address) {Editor editor = sp.edit();editor.putString(Constant.KEY_DEVICE_ADDRESS, address);editor.commit();}/*** 吐丝** @param text*/private void toast(String text) {Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();}/*** 扫描BLE设备*100c6* @param enable*/private void scanLeDevice(final boolean enable) {if (enable) {mHandler.postDelayed(new Runnable() {@Overridepublic void run() {mScanning = false;mBluetoothAdapter.stopLeScan(mLeScanCallback);invalidateOptionsMenu();}}, SCAN_PERIOD);mScanning = true;mBluetoothAdapter.startLeScan(mLeScanCallback);} else {mScanning = false;mBluetoothAdapter.stopLeScan(mLeScanCallback);}invalidateOptionsMenu();}/*** BLE扫描回调函数,设备保存在remoteDevice里面*/private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {@Overridepublic void onLeScan(final BluetoothDevice device, int rssi,byte[] scanRecord) {// TODO Auto-generated method stubrunOnUiThread(new Runnable() {@Overridepublic void run() {mAdapter.addDevice(device);mAdapter.notifyDataSetChanged();}});}};/*** 自杀*/private void suiside() {scanLeDevice(false);sp = null;}}
 
TestAdapter.java
package com.example.ble;import java.util.ArrayList;import android.bluetooth.BluetoothDevice;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;public class TestAdapter extends BaseAdapter {private ArrayList<BluetoothDevice> mLeDevices;private LayoutInflater mInflater;public TestAdapter(Context context) {mLeDevices = new ArrayList<BluetoothDevice>();mInflater = LayoutInflater.from(context);}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn mLeDevices.size();}@Overridepublic Object getItem(int arg0) {// TODO Auto-generated method stubif (mLeDevices.size() <= arg0) {return null;}return mLeDevices.get(arg0);}@Overridepublic long getItemId(int arg0) {// TODO Auto-generated method stubreturn arg0;}@Overridepublic View getView(int position, View view, ViewGroup arg2) {// TODO Auto-generated method stubViewHolder viewHolder;if (null == view) {viewHolder = new ViewHolder();view = mInflater.inflate(R.layout.item_ble, null);viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);view.setTag(viewHolder);} else {viewHolder = (ViewHolder) view.getTag();}BluetoothDevice device = mLeDevices.get(position);final String deviceName = device.getName();if (deviceName != null && deviceName.length() > 0)viewHolder.deviceName.setText(deviceName);elseviewHolder.deviceName.setText("unknown name");return view;}private class ViewHolder {public TextView deviceName;}/*** 设置数据源* * @param mDevices*/public void setData(ArrayList<BluetoothDevice> mDevices) {this.mLeDevices = mDevices;}/*** 添加设备* * @param mDevice*/public void addDevice(BluetoothDevice mDevice) {if (!mLeDevices.contains(mDevice)) {mLeDevices.add(mDevice);}}/*** 得到设备* * @param position* @return*/public BluetoothDevice getDevice(int position) {if (mLeDevices.size() <= position) {return null;}return mLeDevices.get(position);}/*** 清空设备*/public void clear() {mLeDevices.clear();}}
BLEService.java
package com.example.ble;import java.util.List;import android.annotation.SuppressLint;import android.app.Service;import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothDevice;import android.bluetooth.BluetoothGatt;import android.bluetooth.BluetoothGattCallback;import android.bluetooth.BluetoothGattCharacteristic;import android.bluetooth.BluetoothGattDescriptor;import android.bluetooth.BluetoothGattService;import android.bluetooth.BluetoothManager;import android.bluetooth.BluetoothProfile;import android.content.Context;import android.content.Intent;import android.content.SharedPreferences;import android.os.IBinder;import android.util.Log;import android.widget.ArrayAdapter;import android.widget.ListView;import android.widget.Toast;public class BLEService extends Service {private static byte[] testData = { 1, 2, 3 };private static Context mContext;// 上下文private static final String TAG = BLEService.class.getSimpleName();// TAGprivate BluetoothManager mBluetoothManager = null;// 蓝牙管理器private BluetoothAdapter mBluetoothAdapter = null;// 本地设备private String mBluetoothDeviceAddress = null;// 远程设备地址private BluetoothGatt mBluetoothGatt = null;// GATT通信private BluetoothGattCharacteristic mCharacteristic = null;// 可读写可通知的private SharedPreferences sp = null;private static final boolean AUTO_CONNECT = true;// 是否自动连接private static final boolean NOTIFICATION_ENABLED = true;private int mConnectionState = STATE_DISCONNECTED;// 连接状态private static final int STATE_DISCONNECTED = 0;// 断开连接private static final int STATE_CONNECTING = 1;// 连接中private static final int STATE_CONNECTED = 2;// 已连接@Overridepublic IBinder onBind(Intent arg0) {// TODO Auto-generated method stubreturn null;}@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();init();}@Overridepublic void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();suiside();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// TODO Auto-generated method stub// 如果地址不为空就尝试连接 如果为空就跳到BLEActivity让用户去选择BLE设备if (mBluetoothDeviceAddress != null) {if (connect(mBluetoothDeviceAddress)) {System.out.println("mBluetoothDeviceAddress");} else {}} else {Intent bleIntent = new Intent();bleIntent.setClass(mContext, MainActivity.class);bleIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(bleIntent);}// return super.onStartCommand(intent, flags, startId);return Service.START_STICKY;}/*** 各种初始化信息*/private void init() {mContext = this;if (!initBluetooth()) {stopSelf();}sp = getSharedPreferences(Constant.SP_NAME, Context.MODE_PRIVATE);mBluetoothDeviceAddress = sp.getString(Constant.KEY_DEVICE_ADDRESS,null);}private void toast(String text) {Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();}/*** 初始化BluetoothManager和BluetoothAdapter* * @return*/private boolean initBluetooth() {if (mBluetoothManager == null) {mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);if (mBluetoothManager == null) {return false;}}mBluetoothAdapter = mBluetoothManager.getAdapter();if (mBluetoothAdapter == null) {return false;}return true;}/*** 自殺*/private void suiside() {disconnect();close();try {if (mBluetoothAdapter != null) {mBluetoothAdapter.disable();mBluetoothAdapter = null;mBluetoothManager = null;sp = null;}} catch (Exception e) {toast("关闭蓝牙失败,请手动关闭");}}/*** 关闭通信*/private void close() {if (mBluetoothGatt == null) {return;}mBluetoothGatt.close();mBluetoothGatt = null;}/*** 建立通信連接* * @param address* @return*/private boolean connect(final String address) {if (mBluetoothAdapter == null || address == null) {return false;}if (mBluetoothDeviceAddress != null&& address.equals(mBluetoothDeviceAddress)&& mBluetoothGatt != null) {if (mBluetoothGatt.connect()) {mConnectionState = STATE_CONNECTING;return true;} else {return false;}}final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);if (device == null) {return false;}mBluetoothGatt = device.connectGatt(this, AUTO_CONNECT, mGattCallback);System.out.println("mBluetoothGatt");mBluetoothDeviceAddress = address;mConnectionState = STATE_CONNECTING;return true;}/*** 斷開GATT連接*/private void disconnect() {System.out.println("e");if (mBluetoothAdapter == null || mBluetoothGatt == null) {return;}mBluetoothGatt.disconnect();}/*** GATT通信回調函數*/@SuppressLint("NewApi")private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {@Overridepublic void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic) {// TODO Auto-generated method stub// super.onCharacteristicChanged(gatt, characteristic);System.out.println("我收到的:" + new String(characteristic.getValue()));}@Overridepublic void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {// TODO Auto-generated method stubsuper.onCharacteristicRead(gatt, characteristic, status);}@Overridepublic void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {// TODO Auto-generated method stubsuper.onCharacteristicWrite(gatt, characteristic, status);}@Overridepublic void onConnectionStateChange(BluetoothGatt gatt, int status,int newState) {// TODO Auto-generated method stub// super.onConnectionStateChange(gatt, status, newState);if (newState == BluetoothProfile.STATE_CONNECTED) {if (mBluetoothGatt != null)mBluetoothGatt.discoverServices();mConnectionState = STATE_CONNECTED;System.out.println("state connected");} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {// connect(mBluetoothDeviceAddress);mConnectionState = STATE_DISCONNECTED;System.out.println("state disconnected");}}@Overridepublic void onDescriptorRead(BluetoothGatt gatt,BluetoothGattDescriptor descriptor, int status) {// TODO Auto-generated method stubsuper.onDescriptorRead(gatt, descriptor, status);}@Overridepublic void onDescriptorWrite(BluetoothGatt gatt,BluetoothGattDescriptor descriptor, int status) {// TODO Auto-generated method stubsuper.onDescriptorWrite(gatt, descriptor, status);}@Overridepublic void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {// TODO Auto-generated method stubsuper.onReadRemoteRssi(gatt, rssi, status);}@Overridepublic void onReliableWriteCompleted(BluetoothGatt gatt, int status) {// TODO Auto-generated method stubsuper.onReliableWriteCompleted(gatt, status);}@Overridepublic void onServicesDiscovered(BluetoothGatt gatt, int status) {// TODO Auto-generated method stub
// super.onServicesDiscovered(gatt, status);if (status == BluetoothGatt.GATT_SUCCESS) {if (mBluetoothGatt != null) {BluetoothGattService mGattService = mBluetoothGatt.getService(SampleGattAttributes.UUID_SERVICE);System.out.println("0");mCharacteristic = mGattService.getCharacteristic(SampleGattAttributes.UUID_CHARACTERISTIC);List<BluetoothGattDescriptor> mDescriptors = mCharacteristic.getDescriptors();for (BluetoothGattDescriptor mDescriptor : mDescriptors) {System.out.println(mDescriptor.getUuid().toString());}setCharacteristicNotification(mCharacteristic,NOTIFICATION_ENABLED);wirteToBLE(testData);System.out.println(new String(readFromBLE()));wirteToBLE(testData);System.out.println(new String(readFromBLE()));}}}};/*** 设置后可以使用通知 设备给手机发送通知时可触发onCharacteristicChanged()* * @param characteristic* @param enabled*/private void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {if (mBluetoothAdapter == null || mBluetoothGatt == null) {System.out.println("setCharacteristicNotification");return;}mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);BluetoothGattDescriptor descriptor = characteristic.getDescriptor(SampleGattAttributes.UUID_DESCRIPTOR);if (descriptor != null) {descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);mBluetoothGatt.writeDescriptor(descriptor);}}/*** 获取此实例* * @return*/public static BLEService self() {if (mContext != null)return (BLEService) mContext;return null;}/*** 通信接口 通过此函数即可向BLE设备写入数据* * @param value* @return*/public boolean wirteToBLE(byte[] value) {System.out.println("f");if (mBluetoothAdapter == null || mBluetoothGatt == null) {Log.w(TAG, "BluetoothAdapter not initialized");return false;}mCharacteristic.setValue(value);boolean isSuccess = mBluetoothGatt.writeCharacteristic(mCharacteristic);return isSuccess;}/*** 通信接口 从BLE设备读数据* * @return*/public byte[] readFromBLE() {byte[] value = null;System.out.println("g");if (mBluetoothAdapter == null || mBluetoothGatt == null) {return null;}boolean isSuccess = mBluetoothGatt.readCharacteristic(mCharacteristic);if (isSuccess) {value = mCharacteristic.getValue();}return value;}            //-----Characteristics的字段信息-----//    }
item_ble.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   android:layout_width="fill_parent"   android:layout_height="fill_parent"   android:orientation="vertical" ><TextView     android:id="@+id/device_name"     android:layout_width="fill_parent"     android:layout_height="wrap_content"     android:text="yuuyy88"      android:textSize="22sp"/></LinearLayout>
main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"   android:layout_width="fill_parent"   android:layout_height="fill_parent"   android:orientation="vertical" >   <ListView     android:id="@+id/list_view"     android:layout_width="match_parent"     android:layout_height="match_parent" >   </ListView> /FrameLayout>
meumrefresh.xml
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_height="wrap_content"    android:layout_width="56dp"    android:minWidth="56dp">      <ProgressBar android:layout_width="32dp"      android:layout_height="32dp"      android:layout_gravity="center"      style="?indeterminateProgressStyle" /> </FrameLayout> 
main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"   xmlns:app="http://schemas.android.com/apk/res-auto"   xmlns:tools="http://schemas.android.com/tools"   tools:context="com.example.ble.MainActivity" >     <item android:id="@+id/menu_scan"      android:title="扫描"      android:layout_width="fill_parent"       android:layout_height="fill_parent"      />       <item android:id="@+id/menu_stop"      android:title="扫描停止"      android:layout_width="fill_parent"       android:layout_height="fill_parent"      />        <item android:id="@+id/menu_refresh"      android:title="刷新扫描"      android:layout_width="fill_parent"       android:layout_height="fill_parent"      />   </menu>至此大部分代码已完成,还有部分定义常量的代码自行添加。还有请自行枚举出服务的UUID号然后添加到对应的代码中,否则程序会有问题。
本文的思想方法来自于http://blog.csdn.net/zhaicaixiansheng/article/details/47070187;代码也主要来自于这篇博客;本文只是将他未贴出的部分代码完善而已。还请体谅作为一位新手的不易。

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android BLE