Android as Bluetooth Low Energy Peripheral (GATT server).

2024-01-18 23:08

本文主要是介绍Android as Bluetooth Low Energy Peripheral (GATT server).,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转载目的是以后查看,不然到时候找不到


转载原文

http://blog.csdn.net/u013606170/article/details/46038283#comments


I demonstrate how to write a simple BLE peripheral application in Android here. I am bad in Android development, The UI would be very ugly, but the code work:

  Currently(5/25/2015), the code could be running in Nexus 6 or Nexus 9 only based on my test. The other phones or tablets DO NOT support to be a BLE peripheral.  So, if you really interested in the issue of Android as BLE Peripheral , please open your wallet or swipe your card, to buy a GOOGLE official device, thank you.


 To add a characteristic as notification is little bit complicated, In here I just add read and write characteristics. 
  About the notification, I put code in the last part of this post.

You should add 

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

The 2 lines in your AndroidManifest.xml, like this :


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.gaiger.simplebleperipheral"android:versionCode="1"android:versionName="1.0" ><uses-sdkandroid:minSdkVersion="21"android:targetSdkVersion="21" /><uses-permission android:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />    <applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid:name=".MainActivity"android:label="@string/app_name" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

The kernal code are below , note the AdvertiseCallback is callback of BluetoothLeAdvertiser ::startAdvertising, and BluetoothGattServerCallback is callback function of ALL BluetoothGattCharacteristic.


BLEPeripheral.java: (that is what you want) 


package com.gaiger.simplebleperipheral;import java.util.List;
import java.util.UUID;import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.util.Log;public class BLEPeripheral{public interface ConnectionCallback {void onConnectionStateChange(BluetoothDevice device, int newState);}BluetoothManager mManager;BluetoothAdapter mAdapter;BluetoothLeAdvertiser  mLeAdvertiser;AdvertiseSettings.Builder settingBuilder;AdvertiseData.Builder advBuilder;        BluetoothGattServer  mGattServer;  ConnectionCallback mConnectionCallback;public interface WriteCallback {void onWrite(byte[] data);}WriteCallback mWriteCallback;public static boolean isEnableBluetooth(){return BluetoothAdapter.getDefaultAdapter().isEnabled();}public int init(Context context){if(null == mManager){mManager = (BluetoothManager)context.getSystemService(Context.BLUETOOTH_SERVICE);if(null == mManager)return -1;if(false == context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE))return -2;          }      if(null == mAdapter){mAdapter = mManager.getAdapter();if(false == mAdapter.isMultipleAdvertisementSupported())return -3; }if(null == settingBuilder){settingBuilder = new AdvertiseSettings.Builder();settingBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY);settingBuilder.setConnectable(true);   settingBuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);  } if(null == advBuilder){advBuilder = new AdvertiseData.Builder();                                         mAdapter.setName("SimplePeripheral");        advBuilder.setIncludeDeviceName(true);}if(null == mGattServer){mGattServer = mManager.openGattServer(context, mGattServerCallback);if(null == mGattServer)return -4;        addDeviceInfoService();              }return 0;}public void setConnectionCallback(ConnectionCallback callback){mConnectionCallback = callback;}public void close(){if(null != mLeAdvertiser)stopAdvertise();if(null != mGattServer)mGattServer.close();mGattServer = null;if(null != advBuilder)advBuilder = null;if(null != settingBuilder)settingBuilder = null;if(null != mAdapter)mAdapter = null;if(null != mManager)mManager = null;   }public static String getAddress(){return BluetoothAdapter.getDefaultAdapter().getAddress();}private AdvertiseCallback mAdvCallback = new AdvertiseCallback() {@Overridepublic void onStartFailure(int errorCode){Log.d("advertise","onStartFailure");}@Overridepublic void onStartSuccess(AdvertiseSettings settingsInEffect){Log.d("advertise","onStartSuccess");};};private final BluetoothGattServerCallback mGattServerCallback = new BluetoothGattServerCallback(){@Overridepublic void onConnectionStateChange(BluetoothDevice device, int status, int newState){Log.d("GattServer", "Our gatt server connection state changed, new state ");Log.d("GattServer", Integer.toString(newState));      if(null != mConnectionCallback && BluetoothGatt.GATT_SUCCESS == status)mConnectionCallback.onConnectionStateChange(device, newState);super.onConnectionStateChange(device, status, newState);}@Overridepublic void onServiceAdded(int status, BluetoothGattService service) {Log.d("GattServer", "Our gatt server service was added.");super.onServiceAdded(status, service);}@Overridepublic void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {Log.d("GattServer", "Our gatt characteristic was read.");super.onCharacteristicReadRequest(device, requestId, offset, characteristic);mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());}@Overridepublic void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {Log.d("GattServer", "We have received a write request for one of our hosted characteristics");//Log.d("GattServer", "data = "+ value.toString()); super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);if(null != mWriteCallback)mWriteCallback.onWrite(value);}@Overridepublic void onNotificationSent(BluetoothDevice device, int status){Log.d("GattServer", "onNotificationSent");          super.onNotificationSent(device, status);                  }@Overridepublic void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {Log.d("GattServer", "Our gatt server descriptor was read.");super.onDescriptorReadRequest(device, requestId, offset, descriptor);}@Overridepublic void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {Log.d("GattServer", "Our gatt server descriptor was written.");super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);}@Overridepublic void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {Log.d("GattServer", "Our gatt server on execute write.");super.onExecuteWrite(device, requestId, execute);}};private void addDeviceInfoService(){  if(null == mGattServer)return;  final String SERVICE_DEVICE_INFORMATION = "0000180a-0000-1000-8000-00805f9b34fb";final String SOFTWARE_REVISION_STRING = "00002A28-0000-1000-8000-00805f9b34fb";BluetoothGattService previousService =mGattServer.getService( UUID.fromString(SERVICE_DEVICE_INFORMATION));if(null != previousService)        mGattServer.removeService(previousService);BluetoothGattCharacteristic softwareVerCharacteristic = new BluetoothGattCharacteristic(UUID.fromString(SOFTWARE_REVISION_STRING), BluetoothGattCharacteristic.PROPERTY_READ,BluetoothGattCharacteristic.PERMISSION_READ);BluetoothGattService deviceInfoService = new BluetoothGattService(UUID.fromString(SERVICE_DEVICE_INFORMATION), BluetoothGattService.SERVICE_TYPE_PRIMARY);softwareVerCharacteristic.setValue(new String("0.0.0").getBytes());deviceInfoService.addCharacteristic(softwareVerCharacteristic);mGattServer.addService(deviceInfoService);}public void setService(String read1Data, String read2Data, WriteCallbackwriteCallBack){  if(null == mGattServer)return ;stopAdvertise();final String  SERVICE_A = "0000fff0-0000-1000-8000-00805f9b34fb";final String  CHAR_READ1 = "0000fff1-0000-1000-8000-00805f9b34fb";final String  CHAR_READ2 = "0000fff2-0000-1000-8000-00805f9b34fb";final String  CHAR_WRITE = "0000fff3-0000-1000-8000-00805f9b34fb";       final String  CHAR_NOTIFY = "0000fff4-0000-1000-8000-00805f9b34fb";       BluetoothGattService previousService =mGattServer.getService( UUID.fromString(SERVICE_A));if(null != previousService)        mGattServer.removeService(previousService);BluetoothGattCharacteristic read1Characteristic = new BluetoothGattCharacteristic(UUID.fromString(CHAR_READ1), BluetoothGattCharacteristic.PROPERTY_READ,BluetoothGattCharacteristic.PERMISSION_READ);                 BluetoothGattCharacteristic read2Characteristic = new BluetoothGattCharacteristic(UUID.fromString(CHAR_READ2), BluetoothGattCharacteristic.PROPERTY_READ,BluetoothGattCharacteristic.PERMISSION_READ);BluetoothGattCharacteristic writeCharacteristic = new BluetoothGattCharacteristic(UUID.fromString(CHAR_WRITE), BluetoothGattCharacteristic.PROPERTY_WRITE,BluetoothGattCharacteristic.PERMISSION_WRITE);read1Characteristic.setValue(read1Data.getBytes());read2Characteristic.setValue(read2Data.getBytes());mWriteCallback = writeCallBack;BluetoothGattService AService = new BluetoothGattService(UUID.fromString(SERVICE_A), BluetoothGattService.SERVICE_TYPE_PRIMARY);AService.addCharacteristic(read1Characteristic);AService.addCharacteristic(read2Characteristic);AService.addCharacteristic(writeCharacteristic); final BluetoothGattCharacteristic notifyCharacteristic = new BluetoothGattCharacteristic(UUID.fromString(CHAR_NOTIFY), BluetoothGattCharacteristic.PROPERTY_NOTIFY,BluetoothGattCharacteristic.PERMISSION_READ);notifyCharacteristic.setValue(new String("0"));AService.addCharacteristic(notifyCharacteristic);  final Handler handler = new Handler();Thread thread = new Thread() {int i = 0;         @Overridepublic void run() {             while(true) {try {sleep(1500);} catch (InterruptedException e) {}handler.post(this);List<BluetoothDevice> connectedDevices = mManager.getConnectedDevices(BluetoothProfile.GATT);if(null != connectedDevices){notifyCharacteristic.setValue(String.valueOf(i).getBytes());if(0 != connectedDevices.size())mGattServer.notifyCharacteristicChanged(connectedDevices.get(0),notifyCharacteristic, false);}                       i++;}               }};thread.start();mGattServer.addService(AService);}public void startAdvertise(String scanRespenseName){  mAdapter.setName(scanRespenseName);        advBuilder.setIncludeDeviceName(true);startAdvertise();}public void startAdvertise(){if(null == mAdapter)return;if (null == mLeAdvertiser) mLeAdvertiser = mAdapter.getBluetoothLeAdvertiser();if(null == mLeAdvertiser)return;mLeAdvertiser.startAdvertising(settingBuilder.build(), advBuilder.build(), mAdvCallback);         }public void stopAdvertise(){if(null != mLeAdvertiser)mLeAdvertiser.stopAdvertising(mAdvCallback);mLeAdvertiser = null;  }}


There is a callback interface WriteCallback to hold tthe data which the BLE has written.

MainActivity.java : (UI part)


package com.gaiger.simplebleperipheral;import java.io.UnsupportedEncodingException;import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;public class MainActivity extends Activity {private BLEPeripheral blePeri; private CheckBox  adverstiseCheckBox;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);adverstiseCheckBox = (CheckBox) findViewById(R.id.advertise_checkBox);blePeri = new BLEPeripheral();                        adverstiseCheckBox.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if(true == adverstiseCheckBox.isChecked()){              TextView textView;textView = (TextView)findViewById(R.id.status_textView);textView.setText("advertising");              blePeri.setService(new String("GAIGER"),new String("AndroidBLE"),mWrittenCallback);    blePeri.startAdvertise();}else{TextView textView;textView = (TextView)findViewById(R.id.status_text);textView.setText("disable");blePeri.stopAdvertise();              }}});adverstiseCheckBox.setEnabled(false);if(false == BLEPeripheral.isEnableBluetooth()){Intent intentBtEnabled = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); // The REQUEST_ENABLE_BT constant passed to startActivityForResult() is a locally defined integer (which must be greater than 0), that the system passes back to you in your onActivityResult() // implementation as the requestCode parameter. int REQUEST_ENABLE_BT = 1;startActivityForResult(intentBtEnabled, REQUEST_ENABLE_BT);Toast.makeText(this, "Please enable bluetooth and execute the application agagin.",Toast.LENGTH_LONG).show();}          }byte[]  writtenByte;BLEPeripheral.WriteCallback mWrittenCallback = new BLEPeripheral.WriteCallback(){@Overridepublic        void onWrite(byte[] data){writtenByte = data.clone();Thread timer = new Thread(){public void run() {runOnUiThread(new Runnable() {@Overridepublic void run() {TextView textView;textView = (TextView)findViewById(R.id.written_textView);try {textView.setText(new String(writtenByte, "UTF-8"));} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}}});}};timer.start();}            };Runnable mCleanTextRunnable = new Runnable() {public void run() {TextView textView;textView = (TextView)findViewById(R.id.connected_textView);textView.setText("no connection");             }};Handler mConnectTextHandler = new Handler() {  @Override                  public void handleMessage(Message msg) {  super.handleMessage(msg);String data = (String)msg.obj;  switch (msg.what) {case 0:data += new String(" disconnected");this.postDelayed(mCleanTextRunnable, 3000);break;case 2: data += new String(" connected");                                                          break;                  default:  break;  }TextView textView;textView = (TextView)findViewById(R.id.connected_textView);textView.setText(data);              }  }; @Overridepublic void onResume(){super.onResume();int sts;sts = blePeri.init(this);//        blePeri.mConnectionCallback = new BLEPeripheral.ConnectionCallback (){
//         @Override
//      public void onConnectionStateChange(BluetoothDevice device, int newState){
//       Log.d("main","onConnectionStateChange");
//      }
//        };
//       blePeri.setConnectionCallback( new BLEPeripheral.ConnectionCallback (){@Overridepublic void onConnectionStateChange(BluetoothDevice device, int newState){           Message msg = new Message();    msg.what = newState;                      msg.obj = new String( device.getName() +" "+ device.getAddress() );mConnectTextHandler.sendMessage(msg);                                       }});if(0  > sts){if(-1 == sts)Toast.makeText(this, "this device is without bluetooth module",Toast.LENGTH_LONG).show();if(-2 == sts)Toast.makeText(this, "this device do not support Bluetooth low energy", Toast.LENGTH_LONG).show();if(-3 == sts)Toast.makeText(this, "this device do not support to be a BLE peripheral, " +"please buy nexus 6 or 9 then try again", Toast.LENGTH_LONG).show();finish();}   TextView textView;textView = (TextView)findViewById(R.id.mac_textView);textView.setText(BLEPeripheral.getAddress());adverstiseCheckBox.setEnabled(true);            }@Overrideprotected void onStop() {super.onStop();      }@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// Handle action bar item clicks here. The action bar will// automatically handle clicks on the Home/Up button, so long// as you specify a parent activity in AndroidManifest.xml.int id = item.getItemId();if (id == R.id.action_settings) {return true;}return super.onOptionsItemSelected(item);}
}

activity_main.xml: (layout, very ugly)


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.awind.presentsenseperipheral.MainActivity" ><TextViewandroid:id="@+id/mac_textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignTop="@+id/status_text"android:layout_marginLeft="18dp"android:layout_toRightOf="@+id/status_text"android:text="00:11:22:AA:BB:CC"android:textAppearance="?android:attr/textAppearanceLarge" /><CheckBoxandroid:id="@+id/advertise_checkBox"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_below="@+id/mac_text"android:layout_marginLeft="34dp"android:layout_marginTop="41dp"android:text="Advertise" /><TextViewandroid:id="@+id/status_textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignLeft="@+id/advertise_checkBox"android:layout_alignParentTop="true"android:layout_marginTop="124dp"android:text="Disable"android:textAppearance="?android:attr/textAppearanceMedium" /><TextViewandroid:id="@+id/connected_textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignLeft="@+id/mac_text"android:layout_centerVertical="true"android:text="no connection"android:textAppearance="?android:attr/textAppearanceLarge" /><TextViewandroid:id="@+id/written_textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignLeft="@+id/mac_text"android:layout_alignParentBottom="true"android:text="WrittenText"android:textAppearance="?android:attr/textAppearanceLarge" /></RelativeLayout>


    I do not like to write too much explanation in here, One said: if you could implement, you understand it; if you could not, you know about nothing of it .

    Notice the part of notifyCharacteristic ,I create a thread, which updates value and send a signal to BluetoothGattServer, to inform the BLE central the value has changed.

  There is a bug in written text update: once WriteCallback::onWrite been called, the runOnUiThread for updating  R.id.written_textView should be executed once. But in my code, the update would not work. That is very minior for the purpose of demonstration BLE on Android, So, please ignore it.

这篇关于Android as Bluetooth Low Energy Peripheral (GATT server).的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/620552

相关文章

SQL server数据库如何下载和安装

《SQLserver数据库如何下载和安装》本文指导如何下载安装SQLServer2022评估版及SSMS工具,涵盖安装配置、连接字符串设置、C#连接数据库方法和安全注意事项,如混合验证、参数化查... 目录第一步:打开官网下载对应文件第二步:程序安装配置第三部:安装工具SQL Server Manageme

C#连接SQL server数据库命令的基本步骤

《C#连接SQLserver数据库命令的基本步骤》文章讲解了连接SQLServer数据库的步骤,包括引入命名空间、构建连接字符串、使用SqlConnection和SqlCommand执行SQL操作,... 目录建议配合使用:如何下载和安装SQL server数据库-CSDN博客1. 引入必要的命名空间2.

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

Android ClassLoader加载机制详解

《AndroidClassLoader加载机制详解》Android的ClassLoader负责加载.dex文件,基于双亲委派模型,支持热修复和插件化,需注意类冲突、内存泄漏和兼容性问题,本文给大家介... 目录一、ClassLoader概述1.1 类加载的基本概念1.2 android与Java Class

SQL Server配置管理器无法打开的四种解决方法

《SQLServer配置管理器无法打开的四种解决方法》本文总结了SQLServer配置管理器无法打开的四种解决方法,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录方法一:桌面图标进入方法二:运行窗口进入检查版本号对照表php方法三:查找文件路径方法四:检查 S

Android DataBinding 与 MVVM使用详解

《AndroidDataBinding与MVVM使用详解》本文介绍AndroidDataBinding库,其通过绑定UI组件与数据源实现自动更新,支持双向绑定和逻辑运算,减少模板代码,结合MV... 目录一、DataBinding 核心概念二、配置与基础使用1. 启用 DataBinding 2. 基础布局

Android ViewBinding使用流程

《AndroidViewBinding使用流程》AndroidViewBinding是Jetpack组件,替代findViewById,提供类型安全、空安全和编译时检查,代码简洁且性能优化,相比Da... 目录一、核心概念二、ViewBinding优点三、使用流程1. 启用 ViewBinding (模块级

SQL Server修改数据库名及物理数据文件名操作步骤

《SQLServer修改数据库名及物理数据文件名操作步骤》在SQLServer中重命名数据库是一个常见的操作,但需要确保用户具有足够的权限来执行此操作,:本文主要介绍SQLServer修改数据... 目录一、背景介绍二、操作步骤2.1 设置为单用户模式(断开连接)2.2 修改数据库名称2.3 查找逻辑文件名

SQL Server数据库死锁处理超详细攻略

《SQLServer数据库死锁处理超详细攻略》SQLServer作为主流数据库管理系统,在高并发场景下可能面临死锁问题,影响系统性能和稳定性,这篇文章主要给大家介绍了关于SQLServer数据库死... 目录一、引言二、查询 Sqlserver 中造成死锁的 SPID三、用内置函数查询执行信息1. sp_w

Linux中修改Apache HTTP Server(httpd)默认端口的完整指南

《Linux中修改ApacheHTTPServer(httpd)默认端口的完整指南》ApacheHTTPServer(简称httpd)是Linux系统中最常用的Web服务器之一,本文将详细介绍如何... 目录一、修改 httpd 默认端口的步骤1. 查找 httpd 配置文件路径2. 编辑配置文件3. 保存