写在前面:
作为一个程序员,各种苦逼啊,作为一个Android程序员,苦逼死了。
Android手机可以使用WIFI、蓝牙和数据网络进行网络通信,那作为Android程序员,就必须得会这些了。如果不会,都不好意思给别人说你是21世纪的屌丝程序员。
通过WIFI和数据网络通信的Socket编程(基于IP的TCP、UDP、HTTP通信 )相信大家都是驾轻就熟了。而现阶段,随着物联网的发展和蓝牙的BLE低功耗方案的成熟,BLE设备应用越来越广泛,尤其是智能穿戴设备。
那么BLE编程是和怎么回事呢?到底难不难呢?网上已经很多关于BLE的文章了,有些写的很好,有些真的没有什么毛用,完全是官方的Demo。
由于项目需要,最近一直在研究BLE编程,现在做好了,就做一下总结,与大家分享,能力有限,大牛莫笑!


一、什么是BLE
蓝牙低能耗(BLE)技术是低成本、短距离、可互操作的鲁棒性无线技术,工作在免许可的2.4GHz ISM射频频段。它从一开始就设计为超低功耗(ULP)无线技术。它利用许多智能手段最大限度地降低功耗。蓝牙低能耗技术采用可变连接时间间隔,这个间隔根据具体应用可以设置为几毫秒到几秒不等。另外,因为BLE技术采用非常快速的连接方式,因此平时可以处于“非连接”状态(节省能源),此时链路两端相互间只是知晓对方,只有在必要时才开启链路,然后在尽可能短的时间内关闭链路。
其实就是蓝牙的一种新技术而已,特点就是低功耗,连接速度快,但是只能传输小数据。


二、一些关于BLE的概念
Generic Attribute Profile (GATT)
通过BLE连接,读写属性类小数据的Profile通用规范。现在所有的BLE应用Profile都是基于GATT的。
 
Attribute Protocol (ATT)
GATT是基于ATT Protocol的。ATT针对BLE设备做了专门的优化,具体就是在传输过程中使用尽量少的数据。每个属性都有一个唯一的UUID,属性将以characteristics and services的形式传输。


Characteristic
Characteristic可以理解为一个数据类型,它包括一个value和0至多个对次value的描述(Descriptor)。


Descriptor
对Characteristic的描述,例如范围、计量单位等。


Service
Characteristic的集合。例如一个service叫做“Heart Rate Monitor”,它可能包含多个Characteristics,其中可能包含一个叫做“heart rate measurement"的Characteristic。


请记住:一个BLE设备可以有多个Service,一个Service可以有多个Chracteristic,一个Chracteristic有一个Value和多个Descriptor,一个Descriptor包含一个Value。


三、关于BLE的一个API

BluetoothGatt 

 继承BluetoothProfile,通过BluetoothGatt可以连接设备(connect),发现服务(discoverServices),并把相应地属性返回到BluetoothGattCallback  

   

 BluetoothGattCharacteristic 

 相当于一个数据类型,它包括一个value和0~n个value的描述(BluetoothGattDescriptor) 

   

 BluetoothGattDescriptor 

 描述符,对Characteristic的描述,包括范围、计量单位等 

   

 BluetoothGattService 

 服务,Characteristic的集合。 

   

 BluetoothProfile 

  一个通用的规范,按照这个规范来收发数据。 

   

 BluetoothManager 

 通过BluetoothManager来获取BluetoothAdapter 

 BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); 



 BluetoothAdapter 

 一个Android系统只有一个BluetoothAdapter ,通过BluetoothManager 获取 

 BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter(); 



 BluetoothGattCallback 

 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。 

   

 gatt.discoverServices() 

 BluetoothDevice



四、开始上代码
代码主要实现功能:首先进入BLEActivity,然后即可扫描BLE设备,选择你想要连接的BLE设备,点击,程序会开启BLEService,BLEService将开始与设备建立GATT连接,并根据UUID或取相应的Service和相应的Chracteristic然后就可以进行数据读写了。
本程序,我留出了三个接口函数(均在BLEService中)
一个是self(),用于获得BLEService的实例
一个是writeToBle(byte[]),可以通过此方法接口向BLE设备写数据
一个是readFromBle(),通过此函数从BLE设备读取数据

AndroidManifest.xml 

 <?xml version="1.0" encoding="utf-8"?> 

 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 

     package="com.study.blestudy" 

     android:versionCode="1" 

     android:versionName="1.0" > 



     <uses-sdk 

         android:minSdkVersion="8" 

         android:targetSdkVersion="21" /> 



     <!-- 添加蓝牙权限 --> 

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

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

     <!-- 添加BLE特征 --> 

     <uses-feature 

         android:name="android.hardware.bluetooth_le" 

         android:required="false" /> 



     <application 

         android:allowBackup="true" 

         android:icon="@drawable/ic_launcher" 

         android:label="@string/app_name" 

         android:theme="@style/AppTheme" > 

         <activity 

             android:name=".BLEActivity" 

             android:label="@string/app_name" > 

             <intent-filter> 

                 <action android:name="android.intent.action.MAIN" /> 



                 <category android:name="android.intent.category.LAUNCHER" /> 

             </intent-filter> 

         </activity> 

         <!-- BLE服务 --> 

         <service android:name=".BLEService" /> 

     </application> 



 </manifest> 



 BLEActivity.java 

 package com.study.blestudy; 



 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.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; 



 @SuppressLint("NewApi") 

 public class BLEActivity extends Activity { 

private static Context mContext;// 上下文 

private static final String TAG = BLEActivity.class.getSimpleName();// 标志 



private SharedPreferences sp = null; 



private BluetoothAdapter mBluetoothAdapter = null;// 本地蓝牙设备 



private Handler mHandler = null;// 用于postDelay 

private boolean mScanning = false;// 循环标志位 



private static final long SCAN_PERIOD = 10000;// 扫描10s 

private static final int REQUEST_ENABLE_BT = 1;// 请求码 



private ListView mListView = null; 

private BLEAdapter mAdapter = null; 



@Override 

protected void onCreate(Bundle savedInstanceState) { 

// TODO Auto-generated method stub 

super.onCreate(savedInstanceState); 

setContentView(R.layout.activity_ble); 

if (!checkBluetooth()) { 

finish(); 

} 

init(); 

} 



@Override 

protected void onResume() { 

// TODO Auto-generated method stub 

super.onResume(); 

// 为了确保设备上蓝牙能使用, 如果当前蓝牙设备没启用,弹出对话框向用户要求授予权限来启用 

if (!mBluetoothAdapter.isEnabled()) { 

if (!mBluetoothAdapter.isEnabled()) { 

Intent enableBtIntent = new Intent( 

BluetoothAdapter.ACTION_REQUEST_ENABLE); 

startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); 

} 

} 

mAdapter = new BLEAdapter(mContext); 

mListView.setAdapter(mAdapter); 

if (mBluetoothAdapter.isEnabled()) { 

scanLeDevice(true); 

} 

} 



@Override 

protected void onPause() { 

super.onPause(); 

scanLeDevice(false); 

mAdapter.clear(); 

} 



@Override 

protected void onDestroy() { 

// TODO Auto-generated method stub 

super.onDestroy(); 

suiside(); 

} 



@Override 

protected void onActivityResult(int requestCode, int resultCode, Intent data) { 

// TODO Auto-generated method stub 

if (requestCode == REQUEST_ENABLE_BT 

&& resultCode == Activity.RESULT_CANCELED) { 

finish(); 

return; 

} 

super.onActivityResult(requestCode, resultCode, data); 

} 



@Override 

public 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.actionbar_indeterminate_progress); 

} 

return true; 

} 



@Override 

public 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() { 

// 判断是否支持BLE 

if (!getPackageManager().hasSystemFeature( 

PackageManager.FEATURE_BLUETOOTH_LE)) { 

toast("ble not supported"); 

return false; 

} 



// 初始化BluetoothAdapter 

final 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.lv_device_ble); 

mListView.setOnItemClickListener(mItemClickListener); 

} 



/** 

* 列表单击事件 

*/ 

private OnItemClickListener mItemClickListener = new OnItemClickListener() { 



@Override 

public void onItemClick(AdapterView<?> arg0, View arg1, int position, 

long arg3) { 

// TODO Auto-generated method stub 

/** 

* 跳转到BLEService 传递一个参数 一个地址 并把名字和地址保存起来 

*/ 

BluetoothDevice mDevice = mAdapter.getDevice(position); 

toast(mDevice.getAddress()); 

saveDeviceAddress(mDevice.getAddress()); 

startTheService(); 

finish(); 

} 

}; 



/** 

* 启动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设备 

*  

* @param enable 

*/ 

private void scanLeDevice(final boolean enable) { 

if (enable) { 

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

} 



/** 

* BLE扫描回调函数,设备保存在remoteDevice里面 

*/ 

private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { 



@Override 

public void onLeScan(final BluetoothDevice device, int rssi, 

byte[] scanRecord) { 

// TODO Auto-generated method stub 

runOnUiThread(new Runnable() { 

@Override 

public void run() { 

mAdapter.addDevice(device); 

mAdapter.notifyDataSetChanged(); 

} 

}); 

} 

}; 



/** 

* 自杀 

*/ 

private void suiside() { 

scanLeDevice(false); 

sp = null; 

} 

 } 



BLEAdapter.java 

 package com.study.blestudy; 



 import java.util.ArrayList; 



 import android.annotation.SuppressLint; 

 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; 



 /** 

  * @date 2015-07-22 

  * @detail 设备列表适配器 

  * @author Leo 

  *  

  */ 

 @SuppressLint("InflateParams") 

 public class BLEAdapter extends BaseAdapter { 

private ArrayList<BluetoothDevice> mLeDevices; 

private LayoutInflater mInflater; 



public BLEAdapter(Context context) { 

mLeDevices = new ArrayList<BluetoothDevice>(); 

mInflater = LayoutInflater.from(context); 

} 



@Override 

public int getCount() { 

// TODO Auto-generated method stub 

return mLeDevices.size(); 

} 



@Override 

public Object getItem(int arg0) { 

// TODO Auto-generated method stub 

if (mLeDevices.size() <= arg0) { 

return null; 

} 

return mLeDevices.get(arg0); 

} 



@Override 

public long getItemId(int arg0) { 

// TODO Auto-generated method stub 

return arg0; 

} 



@Override 

public View getView(int position, View view, ViewGroup arg2) { 

// TODO Auto-generated method stub 

ViewHolder 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); 

else 

viewHolder.deviceName.setText("unknown name"); 



return view; 

} 



/** 

* 列表显示控件类 

*  

* @author Leo 

*  

*/ 

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.study.blestudy; 



 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.Toast; 



 /** 

  * @date 2015-07-22 

  * @detail BLE连接通信 

  * @author Leo 

  *  

  */ 

 @SuppressLint("NewApi") 

 public class BLEService extends Service { 

private static byte[] testData = { 1, 2, 3 }; 



private static Context mContext;// 上下文 

private static final String TAG = BLEService.class.getSimpleName();// TAG 



private 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;// 已连接 



@Override 

public IBinder onBind(Intent arg0) { 

// TODO Auto-generated method stub 

return null; 

} 



@Override 

public void onCreate() { 

// TODO Auto-generated method stub 

super.onCreate(); 

init(); 

} 



@Override 

public void onDestroy() { 

// TODO Auto-generated method stub 

super.onDestroy(); 

suiside(); 

} 



@Override 

public int onStartCommand(Intent intent, int flags, int startId) { 

// TODO Auto-generated method stub 

// 如果地址不为空就尝试连接 如果为空就跳到BLEActivity让用户去选择BLE设备 

if (mBluetoothDeviceAddress != null) { 

if (connect(mBluetoothDeviceAddress)) { 

} else { 

} 

} else { 

Intent bleIntent = new Intent(); 

bleIntent.setClass(mContext, BLEActivity.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); 

mBluetoothDeviceAddress = address; 

mConnectionState = STATE_CONNECTING; 

return true; 

} 



/** 

* 斷開GATT連接 

*/ 

private void disconnect() { 

if (mBluetoothAdapter == null || mBluetoothGatt == null) { 

return; 

} 

mBluetoothGatt.disconnect(); 

} 



/** 

* GATT通信回調函數 

*/ 

@SuppressLint("NewApi") 

private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { 



@Override 

public void onCharacteristicChanged(BluetoothGatt gatt, 

BluetoothGattCharacteristic characteristic) { 

// TODO Auto-generated method stub 

// super.onCharacteristicChanged(gatt, characteristic); 

System.out.println("我收到的:" + new String(characteristic.getValue())); 

} 



@Override 

public void onCharacteristicRead(BluetoothGatt gatt, 

BluetoothGattCharacteristic characteristic, int status) { 

// TODO Auto-generated method stub 

super.onCharacteristicRead(gatt, characteristic, status); 

} 



@Override 

public void onCharacteristicWrite(BluetoothGatt gatt, 

BluetoothGattCharacteristic characteristic, int status) { 

// TODO Auto-generated method stub 

super.onCharacteristicWrite(gatt, characteristic, status); 

} 



@Override 

public 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"); 

} 

} 



@Override 

public void onDescriptorRead(BluetoothGatt gatt, 

BluetoothGattDescriptor descriptor, int status) { 

// TODO Auto-generated method stub 

super.onDescriptorRead(gatt, descriptor, status); 

} 



@Override 

public void onDescriptorWrite(BluetoothGatt gatt, 

BluetoothGattDescriptor descriptor, int status) { 

// TODO Auto-generated method stub 

super.onDescriptorWrite(gatt, descriptor, status); 

} 



@Override 

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

// TODO Auto-generated method stub 

super.onReadRemoteRssi(gatt, rssi, status); 

} 



@Override 

public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { 

// TODO Auto-generated method stub 

super.onReliableWriteCompleted(gatt, status); 

} 



@Override 

public 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); 

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) { 

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) { 



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; 



if (mBluetoothAdapter == null || mBluetoothGatt == null) { 

return null; 

} 



boolean isSuccess = mBluetoothGatt.readCharacteristic(mCharacteristic); 

if (isSuccess) { 

value = mCharacteristic.getValue(); 

} 



return value; 

} 

 }




五、小结
BLE编程,最重要的不是代码,而是理解其工作模式和编程步骤。工作模式呢,其实就是中心设备和外围设备,其次就是他的GATT/ATT通信。
编程步骤呢:
步骤:
1、开始准备(包括:添加权限,判断支持,打开蓝牙)
2、扫描设备(扫描BLE设备)
3、建立连接(能过地址,并建立GATT连接)
4、列举服务(列举BLE设备开启了哪些服务,并找出相关特征)
5、开始通信(读写数据,通知等)
6、关闭连接