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修改数据库名及物理数据文件名操作步骤》在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. 保存

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

Windows Server 2025 搭建NPS-Radius服务器的步骤

《WindowsServer2025搭建NPS-Radius服务器的步骤》本文主要介绍了通过微软的NPS角色实现一个Radius服务器,身份验证和证书使用微软ADCS、ADDS,具有一定的参考价... 目录简介示意图什么是 802.1X?核心作用802.1X的组成角色工作流程简述802.1X常见应用802.

SQL Server身份验证模式步骤和示例代码

《SQLServer身份验证模式步骤和示例代码》SQLServer是一个广泛使用的关系数据库管理系统,通常使用两种身份验证模式:Windows身份验证和SQLServer身份验证,本文将详细介绍身份... 目录身份验证方式的概念更改身份验证方式的步骤方法一:使用SQL Server Management S

Spring AI 实现 STDIO和SSE MCP Server的过程详解

《SpringAI实现STDIO和SSEMCPServer的过程详解》STDIO方式是基于进程间通信,MCPClient和MCPServer运行在同一主机,主要用于本地集成、命令行工具等场景... 目录Spring AI 实现 STDIO和SSE MCP Server1.新建Spring Boot项目2.a

SQL Server中的PIVOT与UNPIVOT用法具体示例详解

《SQLServer中的PIVOT与UNPIVOT用法具体示例详解》这篇文章主要给大家介绍了关于SQLServer中的PIVOT与UNPIVOT用法的具体示例,SQLServer中PIVOT和U... 目录引言一、PIVOT:将行转换为列核心作用语法结构实战示例二、UNPIVOT:将列编程转换为行核心作用语

Android NDK版本迭代与FFmpeg交叉编译完全指南

《AndroidNDK版本迭代与FFmpeg交叉编译完全指南》在Android开发中,使用NDK进行原生代码开发是一项常见需求,特别是当我们需要集成FFmpeg这样的多媒体处理库时,本文将深入分析A... 目录一、android NDK版本迭代分界线二、FFmpeg交叉编译关键注意事项三、完整编译脚本示例四

Android与iOS设备MAC地址生成原理及Java实现详解

《Android与iOS设备MAC地址生成原理及Java实现详解》在无线网络通信中,MAC(MediaAccessControl)地址是设备的唯一网络标识符,本文主要介绍了Android与iOS设备M... 目录引言1. MAC地址基础1.1 MAC地址的组成1.2 MAC地址的分类2. android与I