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中行转列方法详细讲解》SQL行转列、列转行可以帮助我们更方便地处理数据,生成需要的报表和结果集,:本文主要介绍SQLServer中行转列方法的相关资料,需要的朋友可以参考下... 目录前言一、为什么需要行转列二、行转列的基本概念三、使用PIVOT运算符进行行转列1.创建示例数据表并插入数

Android使用java实现网络连通性检查详解

《Android使用java实现网络连通性检查详解》这篇文章主要为大家详细介绍了Android使用java实现网络连通性检查的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录NetCheck.Java(可直接拷贝)使用示例(Activity/Fragment 内)权限要求

2025最新版Android Studio安装及组件配置教程(SDK、JDK、Gradle)

《2025最新版AndroidStudio安装及组件配置教程(SDK、JDK、Gradle)》:本文主要介绍2025最新版AndroidStudio安装及组件配置(SDK、JDK、Gradle... 目录原生 android 简介Android Studio必备组件一、Android Studio安装二、A

Android实现图片浏览功能的示例详解(附带源码)

《Android实现图片浏览功能的示例详解(附带源码)》在许多应用中,都需要展示图片并支持用户进行浏览,本文主要为大家介绍了如何通过Android实现图片浏览功能,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

在Android中使用WebView在线查看PDF文件的方法示例

《在Android中使用WebView在线查看PDF文件的方法示例》在Android应用开发中,有时我们需要在客户端展示PDF文件,以便用户可以阅读或交互,:本文主要介绍在Android中使用We... 目录简介:1. WebView组件介绍2. 在androidManifest.XML中添加Interne

Python 基于http.server模块实现简单http服务的代码举例

《Python基于http.server模块实现简单http服务的代码举例》Pythonhttp.server模块通过继承BaseHTTPRequestHandler处理HTTP请求,使用Threa... 目录测试环境代码实现相关介绍模块简介类及相关函数简介参考链接测试环境win11专业版python

Android协程高级用法大全

《Android协程高级用法大全》这篇文章给大家介绍Android协程高级用法大全,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友跟随小编一起学习吧... 目录1️⃣ 协程作用域(CoroutineScope)与生命周期绑定Activity/Fragment 中手

SQL Server 查询数据库及数据文件大小的方法

《SQLServer查询数据库及数据文件大小的方法》文章介绍了查询数据库大小的SQL方法及存储过程实现,涵盖当前数据库、所有数据库的总大小及文件明细,本文结合实例代码给大家介绍的非常详细,感兴趣的... 目录1. 直接使用SQL1.1 查询当前数据库大小1.2 查询所有数据库的大小1.3 查询每个数据库的详

Spring Boot 整合 SSE(Server-Sent Events)实战案例(全网最全)

《SpringBoot整合SSE(Server-SentEvents)实战案例(全网最全)》本文通过实战案例讲解SpringBoot整合SSE技术,涵盖实现原理、代码配置、异常处理及前端交互,... 目录Spring Boot 整合 SSE(Server-Sent Events)1、简述SSE与其他技术的对

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按