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

相关文章

Android使用ImageView.ScaleType实现图片的缩放与裁剪功能

《Android使用ImageView.ScaleType实现图片的缩放与裁剪功能》ImageView是最常用的控件之一,它用于展示各种类型的图片,为了能够根据需求调整图片的显示效果,Android提... 目录什么是 ImageView.ScaleType?FIT_XYFIT_STARTFIT_CENTE

Spring Boot 整合 SSE的高级实践(Server-Sent Events)

《SpringBoot整合SSE的高级实践(Server-SentEvents)》SSE(Server-SentEvents)是一种基于HTTP协议的单向通信机制,允许服务器向浏览器持续发送实... 目录1、简述2、Spring Boot 中的SSE实现2.1 添加依赖2.2 实现后端接口2.3 配置超时时

Android实现在线预览office文档的示例详解

《Android实现在线预览office文档的示例详解》在移动端展示在线Office文档(如Word、Excel、PPT)是一项常见需求,这篇文章为大家重点介绍了两种方案的实现方法,希望对大家有一定的... 目录一、项目概述二、相关技术知识三、实现思路3.1 方案一:WebView + Office Onl

Android实现两台手机屏幕共享和远程控制功能

《Android实现两台手机屏幕共享和远程控制功能》在远程协助、在线教学、技术支持等多种场景下,实时获得另一部移动设备的屏幕画面,并对其进行操作,具有极高的应用价值,本项目旨在实现两台Android手... 目录一、项目概述二、相关知识2.1 MediaProjection API2.2 Socket 网络

Android实现悬浮按钮功能

《Android实现悬浮按钮功能》在很多场景中,我们希望在应用或系统任意界面上都能看到一个小的“悬浮按钮”(FloatingButton),用来快速启动工具、展示未读信息或快捷操作,所以本文给大家介绍... 目录一、项目概述二、相关技术知识三、实现思路四、整合代码4.1 Java 代码(MainActivi

Android Mainline基础简介

《AndroidMainline基础简介》AndroidMainline是通过模块化更新Android核心组件的框架,可能提高安全性,本文给大家介绍AndroidMainline基础简介,感兴趣的朋... 目录关键要点什么是 android Mainline?Android Mainline 的工作原理关键

如何解决idea的Module:‘:app‘platform‘android-32‘not found.问题

《如何解决idea的Module:‘:app‘platform‘android-32‘notfound.问题》:本文主要介绍如何解决idea的Module:‘:app‘platform‘andr... 目录idea的Module:‘:app‘pwww.chinasem.cnlatform‘android-32

SQL server配置管理器找不到如何打开它

《SQLserver配置管理器找不到如何打开它》最近遇到了SQLserver配置管理器打不开的问题,尝试在开始菜单栏搜SQLServerManager无果,于是将自己找到的方法总结分享给大家,对SQ... 目录方法一:桌面图标进入方法二:运行窗口进入方法三:查找文件路径方法四:检查 SQL Server 安

Android实现打开本地pdf文件的两种方式

《Android实现打开本地pdf文件的两种方式》在现代应用中,PDF格式因其跨平台、稳定性好、展示内容一致等特点,在Android平台上,如何高效地打开本地PDF文件,不仅关系到用户体验,也直接影响... 目录一、项目概述二、相关知识2.1 PDF文件基本概述2.2 android 文件访问与存储权限2.

Android Studio 配置国内镜像源的实现步骤

《AndroidStudio配置国内镜像源的实现步骤》本文主要介绍了AndroidStudio配置国内镜像源的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、修改 hosts,解决 SDK 下载失败的问题二、修改 gradle 地址,解决 gradle