先写一个Ble服务  AdvertiserService  代码如下


/*** Created by lxy on 2022/04/26.*/public class AdvertiserService extends Service {
//    private  RecvDelegate delegate;private static final String TAG="AdvertiserService";String CHANNEL_ONE_ID = "com.shanling.com";
//    private static final int FOREGROUND_NOTIFICATION_ID=1;public static  BluetoothDevice mDevice;private static final String NOTIF_ID = "com.shanling.bleService";    //这里的id里面输入自己的项目的包的路径private static final String NOTIF_NAME = "Channel_One";public static boolean running=false;public static final String ADVERTISENG_FILED="com.shanLing.Lxy.advertising_failed";public static final String ADVERTISING_FAILED_EXTRA_CODE="failureCode";
//    public static final int ADVERTISING_TIMED_OUT=6;private BluetoothLeAdvertiser mBluetoothLeAdvertiser;private AdvertiseCallback mAdertiseCallback;
//    private Handler mHandler;
//    private Runnable timeoutRunnable;
//    private long TIMEOUT= TimeUnit.MILLISECONDS.convert(10,TimeUnit.MINUTES);public static BluetoothGattServer mBluetoothGattServer;BluetoothManager mBluetoothManager;public static BluetoothGattCharacteristic characteristicNotif;private static UUID UUID_SERVER = UUID.fromString("0000d33c-0000-1000-8000-00805f9b34fb");private static UUID UUID_DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");private static UUID UUID_CHARNOTIF = UUID.fromString("0000D351-0000-1000-8000-00805f9b34fb");
//    private static UUID UUID_CHARREAD = UUID.fromString("0000D352-0000-1000-8000-00805f9b34fb");private static UUID UUID_CHARWRITE = UUID.fromString("0000D353-0000-1000-8000-00805f9b34fb");//D33C服务的UUIDpublic static final ParcelUuid Service_UUID=ParcelUuid.fromString("0000d33c-0000-1000-8000-00805f9b34fb");private byte[] rData;private  int len = 0;@Overridepublic void onCreate(){running=true;initialize();startAdvertising();setTimeout();super.onCreate();}@Overridepublic void onDestroy(){stopAdvertising();running=false;
//        mHandler.removeCallbacks(timeoutRunnable);
//        stopForeground(true);
//防止在系统蓝牙切换后无法启动D33C的服务特征 从而无法进行Ble交互mBluetoothGattServer = null;rData = null;len = 0;super.onDestroy();}@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}private void initialize(){if(mBluetoothLeAdvertiser==null){mBluetoothManager=(BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);if(mBluetoothManager!=null){BluetoothAdapter bluetoothAdapter=mBluetoothManager.getAdapter();if(bluetoothAdapter!=null){mBluetoothLeAdvertiser=bluetoothAdapter.getBluetoothLeAdvertiser();}else{Toast.makeText(this,"设备不支持蓝牙广播",Toast.LENGTH_SHORT).show();}}else{Toast.makeText(this,"不支持蓝牙",Toast.LENGTH_SHORT).show();}}}private void setTimeout(){//服务开启后不设定时间关闭
//        mHandler=new Handler();
//        timeoutRunnable=new Runnable(){
//            @Override
//            public void run(){
//                Log.d(TAG,"广播服务已经运行"+TIMEOUT+"秒,停止停止广播");
//                sendFailureIntent(ADVERTISING_TIMED_OUT);
//                stopSelf();
//            }
//        };
//        mHandler.postDelayed(timeoutRunnable,TIMEOUT);}private void startAdvertising(){
//        goForeground();
//        Log.d(TAG,"服务开始广播");if(mAdertiseCallback==null){AdvertiseSettings settings=buildAdvertiseSettings();AdvertiseData data = buildAdvertiseData();AdvertiseData aa = buildScanResponseData();mAdertiseCallback=new SampleAdvertiseCallback();if(mBluetoothLeAdvertiser!=null){
//这种方式发送可以广播62个字节
//还有个方式发送广播包 ,不添加扫描响应包参数,最多只能发送31个字节       mBluetoothLeAdvertiser.startAdvertising(settings,data,aa,mAdertiseCallback);}}}private void stopAdvertising(){
//        Log.d(TAG,"服务停止广播");if(mBluetoothLeAdvertiser!=null){if (mDevice!=null){SynclinkLogic.getInstance().getChatService().sendDataToClient(new byte[0],SynclinkConstants.SL_LOGOUT_RESP);SystemClock.sleep(20);//休眠20毫秒}mBluetoothLeAdvertiser.stopAdvertising(mAdertiseCallback);
//            startAdvertising();//开始广播
//            mAdertiseCallback=null; //lxy 这个必须要屏蔽 否则会出现多个读写特征 屏蔽的话 就只有一个}}/*创建广播包数据*/private AdvertiseData buildAdvertiseData(){AdvertiseData.Builder dataBuilder=new AdvertiseData.Builder();dataBuilder.addServiceUuid(Service_UUID);//服务ID D33C
//        dataBuilder.setIncludeTxPowerLevel(true); //是否广播信号强度return dataBuilder.build();}/*扫描响应包数据*/private AdvertiseData buildScanResponseData(){AdvertiseData.Builder mScanResponseData = new AdvertiseData.Builder().setIncludeDeviceName(true);//是否显示设备名称String aa= NetUtils.getBluetoothAddress();String bb = aa.replace(":", "");byte[] mm = stringToBytes(bb);if (mm!=null && mm.length == 6){byte[] a = new byte[2];byte[] b = new byte[4];System.arraycopy(mm,0,a,0, 2);int c  = ((a[0] & 0xFF) << 8)+ (a[1]& 0xfff);System.arraycopy(mm,2,b,0, 4);mScanResponseData.addManufacturerData(c,b);  //添加厂商信息}return mScanResponseData.build();}private AdvertiseSettings buildAdvertiseSettings(){AdvertiseSettings.Builder settingsBuilder=new AdvertiseSettings.Builder();settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER);settingsBuilder.setTimeout(0);return settingsBuilder.build();}private class SampleAdvertiseCallback extends AdvertiseCallback{@Overridepublic void onStartFailure(int errorCode){super.onStartFailure(errorCode);
//            Log.d(TAG,"广播失败");sendFailureIntent(errorCode);stopSelf();}@Overridepublic void onStartSuccess(AdvertiseSettings settingsInEffect){super.onStartSuccess(settingsInEffect);
//            Log.d(TAG,"服务端的广播成功开启");
//            Log.d(TAG,"BLE服务的广播启动成功后:TxPowerLv="+settingsInEffect.getTxPowerLevel()+";mode="+settingsInEffect.getMode()+";timeout="+settingsInEffect.getTimeout());initServices(getContext());//该方法是添加一个服务,在此处调用即将服务广播出去}}private void sendFailureIntent(int errorCode){Intent failureIntent=new Intent();failureIntent.setAction(ADVERTISENG_FILED);failureIntent.putExtra(ADVERTISING_FAILED_EXTRA_CODE,errorCode);sendBroadcast(failureIntent);}//添加一个服务,该服务有一个读特征、该特征有一个描述;一个写特征。//用BluetoothGattServer添加服务,并实现该类的回调接口private void initServices(Context context){if (mBluetoothGattServer!=null){//防止出现多个服务和特征return;}mBluetoothGattServer = mBluetoothManager.openGattServer(context,bluetoothGattServerCallback);BluetoothGattService service=new BluetoothGattService(UUID_SERVER,BluetoothGattService.SERVICE_TYPE_PRIMARY);
//        characteristicRead=new BluetoothGattCharacteristic(UUID_CHARREAD,BluetoothGattCharacteristic.PROPERTY_READ,BluetoothGattCharacteristic.PERMISSION_READ);
//        BluetoothGattDescriptor descriptor=new BluetoothGattDescriptor(UUID_DESCRIPTOR,BluetoothGattCharacteristic.PERMISSION_WRITE);
//        characteristicRead.addDescriptor(descriptor);
//        service.addCharacteristic(characteristicRead);BluetoothGattCharacteristic characteristicWrite = new BluetoothGattCharacteristic(UUID_CHARWRITE,BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE,BluetoothGattCharacteristic.PERMISSION_WRITE);service.addCharacteristic(characteristicWrite);characteristicNotif = new BluetoothGattCharacteristic(UUID_CHARNOTIF,BluetoothGattCharacteristic.PROPERTY_NOTIFY,BluetoothGattCharacteristic.PROPERTY_NOTIFY);BluetoothGattDescriptor descriptor=new BluetoothGattDescriptor(UUID_DESCRIPTOR,BluetoothGattCharacteristic.PROPERTY_NOTIFY);characteristicNotif.addDescriptor(descriptor);service.addCharacteristic(characteristicNotif);mBluetoothGattServer.addService(service);
//        Log.d(TAG,"初始化服务成功:initServices ok");}//服务事件的回调private BluetoothGattServerCallback bluetoothGattServerCallback=new BluetoothGattServerCallback() {//1、首先是连接状态的回调@Overridepublic void onConnectionStateChange(BluetoothDevice device, int status, int newState) {super.onConnectionStateChange(device, status, newState);if (newState == 2) {mDevice = device;
//                Log.e(TAG, "连接状态成功  "+ "status=" + status + "newstate=" + newState);} else {mDevice = null;SynclinkLogic.getInstance().setSyncLinkServerConnection(false);
//                Log.e(TAG, "连接状态失败  "+ "status=" + status + "newstate=" + newState);}}//        @Override
//        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
//            super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
//            Log.e(TAG,"客户端有读的请求,安卓系统回调该onCharacteristicReadRequest()方法");
//
//            mBluetoothGattServer.sendResponse(device,requestId, BluetoothGatt.GATT_SUCCESS,offset,characteristic.getValue());
//        }//接受具体字节,当有特征被写入时,回调该方法,写入的数据为参数中的value@Overridepublic void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
//            Log.e(TAG,"客户端有写入Id="+requestId+"写入的字节长度Length="+value.length);/*** 该方法必须调用 否则会半分钟断开连接* 特征被读取,在该回调方法中回复客户端响应成功*/mBluetoothGattServer.sendResponse(device,requestId,BluetoothGatt.GATT_SUCCESS,offset,value);//处理响应内容 value:客户端发送过来的数据onResponseToClient(value,device,requestId,characteristic);
//            if (running) { //连接成功后关闭关闭
//                if(mBluetoothLeAdvertiser!=null){
//                    mBluetoothLeAdvertiser.stopAdvertising(mAdertiseCallback);
//                }
//            }}//特征被读取。当回复相应成功后,客户端胡读取然后触发本方法@Overridepublic void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {super.onDescriptorReadRequest(device, requestId, offset, descriptor);
//            Log.e(TAG, "onDescriptorReadRequest: "+"特征被读取。当回复相应成功后,客户端胡读取然后触发本方法" );mBluetoothGattServer.sendResponse(device,requestId,BluetoothGatt.GATT_SUCCESS,offset,null);}//2、其次,当有描述请求被写入时,回调该方法,@Overridepublic void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
//            Log.e(TAG, "onDescriptorWriteRequest: "+"其次,当有描述请求被写入时,回调该方法,");mBluetoothGattServer.sendResponse(device,requestId,BluetoothGatt.GATT_SUCCESS,offset,value);}//通知@Overridepublic void onNotificationSent(BluetoothDevice device, int status) {super.onNotificationSent(device, status);
//            Log.e(TAG, "onNotificationSent: 通知  状态status = "+status );}@Overridepublic void onServiceAdded(int status,BluetoothGattService service){super.onServiceAdded(status,service);
//            Log.e(TAG,"添加服务成功,安卓系统回调该onServiceAdded()方法");}};//4.处理相应内容,requestBytes是客户端发送过来的数据private void onResponseToClient(byte[] data,BluetoothDevice device,int requestId,BluetoothGattCharacteristic characteristic){
//        //在服务端接受数据
//        if (SynclinkLogic.getInstance()!=null &&SynclinkLogic.getInstance().getChatService()!=null )              //SynclinkLogic.getInstance().getChatService().parseDataForIOS(data);if (SynclinkLogic.getInstance()!=null &&SynclinkLogic.getInstance().getChatService()!=null ){if (rData!=null && rData.length>= 12){System.arraycopy(data,0, rData, 180, data.length);SynclinkLogic.getInstance().getChatService().parseDataForIOS(rData);rData = null;len = 0;}else {if (data.length>=12){byte[] lenBytes = new byte[]{data[8], data[9], data[10], data[11]};len = ConvertUtils.bytes2Int(lenBytes, lenBytes.length);rData = new byte[len+12];  //12  168System.arraycopy(data, 0, rData, 0, data.length);}if (len<=168 && len>=0) {SynclinkLogic.getInstance().getChatService().parseDataForIOS(rData);rData = null;len = 0;}}}}public Context getContext(){return this;}/*** String转byte[]* @return byte[]*/public static byte[] stringToBytes(String src) {int m=0,n=0;int l=src.length()/2;System.out.println(l);byte[] ret = new byte[l];for (int i = 0; i < l; i++){m=i*2+1;n=m+1;int aa = Integer.decode("0x" + src.substring(i*2, m) + src.substring(m,n));ret[i] = (byte) aa;}return ret;}

App只关心D33C服务,在D33C服务下存在 无回应写(D353) 和 通知(D351) 两个特征

创建完后再Manifest注册服务

        <serviceandroid:name=".Synclink.AdvertiserService"android:enabled="true"android:exported="false" />

注册完在需要用到的地方注册服务回调(回调可以省略不写,但是广播出错时,可是添加服务回调,查看错误信息)

//by lxyprivate BroadcastReceiver advertisingFailureReceiver;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);baseSetContentView(R.layout.sync_link_activity);ButterKnife.bind(this);init();advertisingFailureReceiver=new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {int errorCode=intent.getIntExtra(AdvertiserService.ADVERTISING_FAILED_EXTRA_CODE,-1);setSyncLinkServer(false);String errorMessage="广告启动失败类型:";switch (errorCode){case AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED:errorMessage+=" 已经开始";break;case AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE:errorMessage+=" 数据包太长";break;case AdvertiseCallback.ADVERTISE_FAILED_FEATURE_UNSUPPORTED:errorMessage+=" 设备不支持广告";break;case AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR:errorMessage+=" 整形错误";break;case AdvertiseCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS:errorMessage+=" 太多广告";break;
//                    case AdvertiserService.ADVERTISING_TIMED_OUT:
//                        errorMessage+=" 广告超时";
//                        break;default:errorMessage+=" 未知错误";}Log.e("TAG", "onReceive: "+errorMessage );
//                Toast.makeText(SynclinkActivity.this,errorMessage,Toast.LENGTH_SHORT).show();}};}

在onResume和onPause中进行注册和取消注册

    //by lxy add@Overrideprotected void onResume() {super.onResume();IntentFilter failureFilter=new IntentFilter(AdvertiserService.ADVERTISENG_FILED);registerReceiver(advertisingFailureReceiver,failureFilter);}@Overridepublic void onPause(){super.onPause();unregisterReceiver(advertisingFailureReceiver);}

创建单例  声明属性  并实现/关闭Ble服务

private Intent bleServiceIntent;

实例化该属性

bleServiceIntent = new Intent(mContext,AdvertiserService.class);

开启/关闭Ble服务

        //by lxy  停止ble服务if (AdvertiserService.running) {mContext.stopService(bleServiceIntent);}
            //开启Ble服务if (!AdvertiserService.running)mContext.startService(bleServiceIntent);

到此功能完成

服务开启后可通过iPhone上的LightBlue App查看ble设备(没有LightBlue可在App Store下载)。通过LightBlue也可查看发出的广播包以及服务特征,如图:其中UUID为AA15的为该手机自身携带的特征。D33C为我们自定义的特征

该功能是去年完成 ,转载请说明出处。

Android App创建Ble服务相关推荐

  1. Android App 连接ble蓝牙模块并进行通讯

    Android App 连接ble蓝牙模块并进行通讯 对于蓝牙的基础知识我在这里就不赘述了,直接来干货,讲解连接ble蓝牙模块并进行通讯,通讯使用广播模式,结尾附上一个项目的demo.精彩内容即将开始 ...

  2. 如何给Android应用创建本地服务

    Android系统给应用提供了两种类型的服务:启动型本地服务和绑定型本地服务,这两种服务的详细信息请参考"Android Service开发指南" Android Service开 ...

  3. Android App 与 蓝牙服务 通信变更

    首先,让我们来回顾下 Google官方 在 Android 5.0 引入的媒体应用框架:Android MediaSession框架简析. 然后,由于支持 蓝牙音乐 的音乐类App,也是基于 Medi ...

  4. Android APP 提高进程服务优先级 常驻内存 服务杀不死

    首先明确,国内定制的系统(小米,华为,OPPO等)都实现了 无论自启或提升进程优先级的策略都能被杀死,而对于用户量大的APP(如微信)和系统级别APP 系统有做白名单;抛开那些定制系统,还是有很多原生 ...

  5. 无法在PC上找到,android app 创建的文件 问题.

    2019独角兽企业重金招聘Python工程师标准>>> 不用reboot就可以让数据出现的方法. As anyone who worked with android applicat ...

  6. STM32与BLE蓝牙通信 Android APP配置(二)

    事务的难度远远低于对事物的恐惧 0.前言 在 Android BLE蓝牙配置全流程(一) 附APP源码 中已经完成了前期的准备工作,在这里我们得到了需要连接的蓝牙设备的名字和地址,需要完成蓝牙设备的连 ...

  7. 低功耗蓝牙(BLE)在 Android APP 中的应用

    低功耗蓝牙(BLE)在 Android APP 中的应用 前言 最近公司接了一个新项目,用户可以把自己的乐器跟Phone或Pad连接起来,当弹奏乐器的时候,会把演奏情况同步反馈到设备上,方便用户练习, ...

  8. Android服务二 创建绑定服务

    若对AIDL感兴趣,请参考跨进程通信二 AIDL 绑定服务 Ibinder实现绑定服务 功能:主要为了实现组件与服务的交互,在绑定的组件可以调用服务端的功能函数 package service;imp ...

  9. Android服务一 创建启动服务

    若要学习创建绑定服务,请查看下篇Android服务二 创建绑定服务 启动服务 基于Service package service;import android.app.Service; import ...

最新文章

  1. awk取文本列_awk命令结构/内置变量/获取文本某行或某列
  2. Scheduler(Spring)
  3. Flask实战2问答平台-发布问答界面完成
  4. 有一个OEM制造商代理做HP笔记本电脑(Laptop),后来该制造商得到了更多的品牌笔记本电脑的订单Acer,Lenovo,Dell,该OEM商发现,如果一次同时做很多个牌子的本本,有些不利于管理。利
  5. potplayer 皮肤_如何美化背部皮肤?
  6. 采用动态解析设置***
  7. 程序设计与算法----递归之放苹果问题
  8. 使用jsoncpp解析生成json
  9. 深入浅出JMS(三)--ActiveMQ简单的HelloWorld实例
  10. exchange2010查询用户邮箱配额、设置用户邮箱配置的方法
  11. android 组件消失了,Android 12 2.2 开发者预览版发布:修复桌面小组件消失等问题...
  12. html增删改查按钮控件,HTML DOM节点的增删改查
  13. SDN(软件定义网络)详解
  14. matlab 固态 机械_固态硬盘无法识别或数据删除还能恢复数据吗?
  15. 【js与jquery】产品详情页面常用的js特效
  16. vue生命周期是什么?
  17. libxml2的参考手册
  18. flying-saucer-pdf预览及下载
  19. win10照片应用打不开的解决方法
  20. 时间序列之holt-winters(三次指数平滑)

热门文章

  1. 详解Android系统耗电
  2. 超越 Nginx!号称下一代 Web 服务器,用起来够优雅!
  3. 游戏陪玩源码的那些关键环节,利用了什么技术手段?
  4. 在js中如何使用jquery的属性选择器
  5. 在线压缩视频的方法,一键压缩视频文件
  6. 三好先生--2021年定个小目标
  7. 广东2021年高考成绩查询被屏蔽,广东省教育考试院:2021年广东高考查分入口、查分系统...
  8. 网易严选APP工程架构演进
  9. 在DNS服务器上动态注册失败,DNS 注册的动态更新延迟 - Windows Server | Microsoft Docs...
  10. 一般纳米材料是指尺度为_纳米材料与纳米结构21个题目+完整答案