Giter Club home page Giter Club logo

blecore's Introduction

BleCore Android蓝牙低功耗(BLE)快速开发框架

本项目持续维护更新

  • 当前版本
  • minSdk 24
  • targetSdk 34
  • compileSdk 34

* 基于Kotlin、协程

* 基于sdk 34,最新API

* 详细的完整的容错机制

* 基于多个蓝牙库的设计**

* 强大的Notify\Indicate\Read\Write任务队列

20230613110126 20230613110146 20230614090104

demo体验

apk_address

详细用法参考demo

详细用法参考demo

详细用法参考demo

用法

    allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

    dependencies {
        implementation 'com.github.buhuiming:BleCore:latest version'
    }

添加权限

//动态申请
val LOCATION_PERMISSION = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
        arrayOf(
            //Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION,
        )
    } else {
        arrayOf(
            //Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.BLUETOOTH_SCAN,
            Manifest.permission.BLUETOOTH_ADVERTISE,
            Manifest.permission.BLUETOOTH_CONNECT,
        )
    }
  • 特别注意:如果需要用到扫描蓝牙设备的功能,需要申请精准位置权限:Manifest.permission.ACCESS_FINE_LOCATION, 否则可能会导致扫描不到设备。

  • 注意:

  • 有些设备GPS是关闭状态的话,申请定位权限之后,GPS是依然关闭状态,这里要根据GPS是否打开来跳转页面

  • BleUtil.isGpsOpen(context) 判断GPS是否打开

  • 跳转到系统GPS设置页面,GPS设置是全局的独立的,是否打开跟权限申请无关 startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))

  • 跳转到系统蓝牙设置页面 startActivity(Intent(Settings.ACTION_BLUETOOTH_SETTINGS))

初始化

val options =
        BleOptions.builder()
            .setScanServiceUuid("0000ff80-0000-1000-8000-00805f9b34fb", "0000ff90-0000-1000-8000-00805f9b34fb")
            .setScanDeviceName("midea", "BYD BLE3")
            .setScanDeviceAddress("70:86:CE:88:7A:AF", "5B:AE:65:88:59:5E", "B8:8C:29:8B:BE:07")
            .isContainScanDeviceName(true)
            .setAutoConnect(false)
            .setEnableLog(true)
            .setScanMillisTimeOut(12000)
            //这个机制是:不会因为扫描的次数导致上一次扫描到的数据被清空,也就是onScanStart和onScanComplete
            //都只会回调一次,而且扫描到的数据是所有扫描次数的总和
            .setScanRetryCountAndInterval(2, 1000)
            .setConnectMillisTimeOut(10000)
            .setConnectRetryCountAndInterval(2, 5000)
            .setOperateMillisTimeOut(6000)
            .setOperateInterval(80)
            .setMaxConnectNum(5)
            .setMtu(500)
            .setTaskQueueType(BleTaskQueueType.Operate)
            .build()
BleManager.get().init(application, options)

//或者使用默认配置
BleManager.get().init(application)

setTaskQueueType方法,有3个选项分别是:

  • BleTaskQueueType.Default 一个设备的Notify\Indicate\Read\Write\mtu操作所对应的任务共享同一个任务 队列(共享队列)(不区分特征值),rssi在rssi队列
  • BleTaskQueueType.Operate 一个设备每个操作独立一个任务队列(不区分特征值) Notify在Notify队列中,Indicate在Indicate队列中,Read在Read队列中, Write在Write队列中,mtu在共享队列,rssi在rssi队列中, 不同操作任务之间相互不影响,相同操作任务之间先进先出按序执行 例如特征值1的写操作和特征值2的写操作,在同一个任务队列当中;特征值1的写操作和特征值1的读操作, 在两个不同的任务队列当中,特征值1的读操作和特征值2的写操作,在两个不同的任务队列当中。
  • BleTaskQueueType.Independent 一个设备每个特征值下的每个操作独立一个任务队列(区分特征值) Notify\Indicate\Read\Write所对应的任务分别放入到独立的任务队列中, mtu在共享队列,rssi在rssi队列中, 且按特征值区分,不同操作任务之间相互不影响,相同操作任务之间相互不影响 例如特征值1的写操作和特征值2的写操作,在两个不同的任务队列当中;特征值1的写操作和特征值1的读操作, 在两个不同的任务队列当中,特征值1的读操作和特征值2的写操作,在两个不同的任务队列当中。

注意:BleTaskQueueType.Operate、BleTaskQueueType.Independent这两种模式下

  • 1、在Notify\Indicate\Read\Write 未完成的情况下,不要执行设置Mtu,否则会导致前者操作失败
  • 2、同时执行Notify\Indicate\Read\Write其中两个以上操作,会可能报设备忙碌失败

建议:以上模式主要也是针对操作之间的问题,强烈建议不要同时执行2个及以上操作,模式BleTaskQueueType.Default就是为 了让设备所有操作同一时间只执行一个,Rssi不受影响

扫描

注意:扫描之前先检查权限、检查GPS开关、检查蓝牙开关
扫描及过滤过程是在工作线程中进行,所以不会影响主线程的UI操作,最终每一个回调结果都会回到主线程。
开启扫描:
BleManager.get().startScan {
    onScanStart {

    }
    onLeScan { bleDevice, currentScanCount ->
        //可以根据currentScanCount是否已有清空列表数据
    }
    onLeScanDuplicateRemoval { bleDevice, currentScanCount ->
        //与onLeScan区别之处在于:同一个设备只会出现一次
    }
    onScanComplete { bleDeviceList, bleDeviceDuplicateRemovalList ->
        //扫描到的数据是所有扫描次数的总和
    }
    onScanFail {
        val msg: String = when (it) {
            is BleScanFailType.UnSupportBle -> "BleScanFailType.UnSupportBle: 设备不支持蓝牙"
            is BleScanFailType.NoBlePermission -> "BleScanFailType.NoBlePermission: 权限不足,请检查"
            is BleScanFailType.GPSDisable -> "BleScanFailType.BleDisable: 设备未打开GPS定位"
            is BleScanFailType.BleDisable -> "BleScanFailType.BleDisable: 蓝牙未打开"
            is BleScanFailType.AlReadyScanning -> "BleScanFailType.AlReadyScanning: 正在扫描"
            is BleScanFailType.ScanError -> {
                "BleScanFailType.ScanError: ${it.throwable?.message}"
            }
        }
        BleLogger.e(msg)
        Toast.makeText(application, msg, Toast.LENGTH_SHORT).show()
    }
}

停止扫描

BleManager.get().stopScan()

是否扫描中

BleManager.get().isScanning()

连接

BleManager.get().connect(device)
BleManager.get().connect(deviceAddress)
  • 在某些型号手机上,connectGatt必须在主线程才能有效,所以把连接过程放在主线程,回调也在主线程。
  • 为保证重连成功率,建议断开后间隔一段时间之后进行重连。(非常关键,因为断开后会有释放资源的等待时间,如果马上重连,会导致连接的资源会被释放掉,而产生错误)
  • v1.9.0添加字段isForeConnect,主要针对某些机型,当触发连接超时回调连接失败并释放资源之后,此时外设开启触发手机系统已连接,但BleCore资源被 释放 (bluetoothGatt是null),或BleCore和系统的连接状态不一致,而导致setMtu和Notify/Indicate都失败。

停止连接

BleManager.get().stopConnect(device)

断开连接

BleManager.get().disConnect(device)
BleManager.get().disConnect(deviceAddress)
  • 断开后,并不会马上更新状态,所以马上连接会直接返回已连接,而且扫描不出来,要等待一定时间才可以
  • BleConnectCallback中onDisConnecting、onDisConnected分别是,断开连接时触发onDisConnecting, 真正断开之后触发onDisConnected。(isActiveDisConnected = true的时候,触发onDisConnecting之后大约1秒左右 才会触发onDisConnected;isActiveDisConnected = false的时候,触发onDisConnecting之后大约5毫秒左右 才会触发onDisConnected)

是否已连接

BleManager.get().isConnected(bleDeviceAddress: String, simplySystemStatus: Boolean = true)
BleManager.get().isConnected(bleDevice: BleDevice?, simplySystemStatus: Boolean = true)
  • simplySystemStatus 为true,只根据系统的状态规则;为false,会根据sdk的状态,换句话说,只根据系统的状态返回。 此字段的意义在于:有时,sdk资源被系统回收(状态未连接),但是系统的状态是已连接。

扫描并连接,如果扫描到多个设备,则会连接第一个

BleManager.get().startScanAndConnect(bleScanCallback: BleScanCallback,
                                     bleConnectCallback: BleConnectCallback)
  • 扫描到首个符合扫描规则的设备后,便停止扫描,然后连接该设备。

获取设备的BluetoothGatt对象

BleManager.get().getBluetoothGatt(device)

设置Notify

BleManager.get().notify(bleDevice: BleDevice,
                              serviceUUID: String,
                              notifyUUID: String,
                              bleDescriptorGetType: BleDescriptorGetType = BleDescriptorGetType.Default,
                              bleIndicateCallback: BleIndicateCallback)

BleDescriptorGetType设计原则

  • 正常情况下,每个特征值下至少有一个默认描述符,并且遵循蓝牙联盟定义的UUID规则,如 [com.bhm.ble.data.Constants.UUID_CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR]便是蓝牙联盟定义的 客户端特性配置的描述符UUID,这样做是方便BLE终端在接入不同类型设备时,能够获取到正确的配置。 比如有一个APP,需要 接入A商家的智能手表和B商家的智能手表来监听用户的心跳,而如果A商家的智能手表或者B商家的智能手表 不遵循蓝牙联盟定义关于 心跳相关的UUID,则对APP来说就要分别去获取A商家的智能手表或者B商家的智能手表对应特征值的描述 符UUID,显然是不合理的。当然这个是需要硬件设备支持的,也就是说硬件设备可以自定义UUID,但需要遵循规则。
  • 在开发过程中,我们会遇到不同硬件设备定义UUID的情况,有的硬件设备通过特征值的UUID来获取描述符(用来writeDescriptor, 打开或关闭notify、indicate),而非是通过系统提供接受通知自带的UUID获取描述符。此外特征值有多个描述符时,获取其中 一个描述符来写入数据,可能会导致onCharacteristicChanged函数没有回调,我不确定是否是硬件设备需要支持修改的问题。 因此[AllDescriptor]方式则是简单粗暴的将特征值下所有的描述符都写入数据,以保证onCharacteristicChanged函数回调, 这个方法经过了一系列设备的验证可行,但不保证是完全有效的。

取消Notify

BleManager.get().stopNotify(bleDevice: BleDevice,
                              serviceUUID: String,
                              notifyUUID: String,
                              bleDescriptorGetType: BleDescriptorGetType = BleDescriptorGetType.Default)

设置Indicate

BleManager.get().indicate(bleDevice: BleDevice,
                              serviceUUID: String,
                              indicateUUID: String,
                              bleDescriptorGetType: BleDescriptorGetType = BleDescriptorGetType.Default,
                              bleIndicateCallback: BleIndicateCallback)

取消Indicate

BleManager.get().stopIndicate(bleDevice: BleDevice,
                              serviceUUID: String,
                              indicateUUID: String,
                              bleDescriptorGetType: BleDescriptorGetType = BleDescriptorGetType.Default)

读取信号值

BleManager.get().readRssi(bleDevice: BleDevice, bleRssiCallback: BleRssiCallback)
  • 获取设备的信号强度,需要在设备连接之后进行。
  • 某些设备可能无法读取Rssi,不会回调onRssiSuccess(),而会因为超时而回调onRssiFail()。

设置Mtu值

BleManager.get().setMtu(bleDevice: BleDevice, bleMtuChangedCallback: BleMtuChangedCallback) 
  • 设置MTU,需要在设备连接之后进行操作。
  • 默认每一个BLE设备都必须支持的MTU为23。
  • MTU为23,表示最多可以发送20个字节的数据。
  • 该方法的参数mtu,最小设置为23,最大设置为512。
  • 并不是每台设备都支持拓展MTU,需要通讯双方都支持才行,也就是说,需要设备硬件也支持拓展MTU该方法才会起效果。 调用该方法后,可以通过onMtuChanged(int mtu)查看最终设置完后,设备的最大传输单元被拓展到多少。如果设备不支持, 可能无论设置多少,最终的mtu还是23。
  • 建议在indicate、notify、read、write未完成的情况下,不要执行设置Mtu,否则会导致前者操作失败

设置连接的优先级

BleManager.get().setConnectionPriority(connectionPriority: Int)
  • 设置连接的优先级,一般用于高速传输大量数据的时候可以进行设置。

读特征值数据

BleManager.get().readData(bleDevice: BleDevice,
                          serviceUUID: String,
                          readUUID: String,
                          bleIndicateCallback: BleReadCallback)

写数据

 BleManager.get().writeData(bleDevice: BleDevice,
                            serviceUUID: String,
                            writeUUID: String,
                            data: ByteArray,
                            bleWriteCallback: BleWriteCallback)
 BleManager.get().writeData(bleDevice: BleDevice,
                            serviceUUID: String,
                            writeUUID: String,
                            data: SparseArray,
                            bleWriteCallback: BleWriteCallback)
  • 因为分包后每一个包,可能是包含完整的协议,所以分包由业务层处理,组件只会根据包的长度和mtu值对比后是否拦截

  • 特殊情况下:indicate\mtu\notify\read\rssi 这些操作,同一个特征值在不同地方调用(不同callback),最后面的操作 对应的回调才会触发,其他地方先前的操作对应的回调不会触发 解决方案:业务层每个特征值对应的操作维护一个单例的callback对象(假如为SingleCallback),在不同地方调用再传递callback (放入到SingleCallback中的集合CallbackList),SingleCallback 回调时循环CallbackList中的callback,这样就达到了 同一个特征值在不同地方调用,都能收到回调

  • indicate\mtu\notify\read\rssi这些操作 ,同一个特征值在不同地方调用,后面的操作会取消前面未完成的操作;write操作比较 特殊,每个写操作都会有回调,且write操作之间不会被取消。具体详情看taskId

  • 一次写操作,分包后,假如某个数据包写失败,后面的数据包不会继续写,例如一次写操作分包后有10个数据包,第7个写失败,后面第8、9、10不会再写

断开某个设备的连接 释放资源

BleManager.get().close(bleDevice: BleDevice)

断开所有连接 释放资源

BleManager.get().closeAll()

一些移除监听的函数

BleManager.get().removeBleScanCallback()
BleManager.get().removeBleConnectCallback(bleDevice: BleDevice)
BleManager.get().removeBleIndicateCallback(bleDevice: BleDevice, indicateUUID: String)
BleManager.get().removeBleNotifyCallback(bleDevice: BleDevice, notifyUUID: String)
BleManager.get().removeBleRssiCallback(bleDevice: BleDevice)
BleManager.get().removeBleMtuChangedCallback(bleDevice: BleDevice)
BleManager.get().removeBleReadCallback(bleDevice: BleDevice, readUUID: String)
BleManager.get().removeBleWriteCallback(bleDevice: BleDevice, writeUUID: String)

v1.5.0新增addBleEventCallback方法

有用户反馈,设置[connect]的bleConnectCallback、[notify]的bleNotifyCallback、
 [indicate]的bleIndicateCallback、[setMtu]的bleMtuChangedCallback之后,当其他地方需要监听这些回调时比较
不方便,所以添加addBleEventCallback来实现。addBleEventCallback与上述回调共存

v1.7.0新增系统蓝牙变化广播监听

BleManager.get().registerBluetoothStateReceiver()
BleManager.get().unRegisterBluetoothStateReceiver()

v1.8.0新增stopConnect方法停止或者取消连接

BleManager.get().stopConnect(device)

v2.0.0新增writeQueueData方法

BleManager.get().writeQueueData(),此方法支持跳过空数据包,支持写失败后重试,提高成功率。可以用于OTA升级

获取BleCore日志,使用自定义的日志框架打印日志或收集BleCore日志

通过第一步初始化时候,setEnableLog方法来决定是否使用BleCore的日志打印;
业务层,通过实现BleLogEvent接口,如下:

class MainActivity : BaseActivity(), BleLogEvent {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //添加BleCore日志监听
        BleLogManager.get().addLogListener(this)
    }

    override fun onDestroy() {
        super.onDestroy()
        //移除BleCore日志监听
        BleLogManager.get().removeLogListener(this)
    }

    /**
     * 获取BleCore库的日志,并统一使用Logger来打印日志获取其他收集功能
    */
    override fun onLog(level: BleLogLevel, tag: String, message: String?) {
        if (message.isNullOrEmpty()) {
            return
        }
       when (level) {
           is BleLogLevel.Debug ->  Logger.d(tag, message)
           is BleLogLevel.Info ->  Logger.i(tag, message)
           is BleLogLevel.Warn ->  Logger.w(tag, message)
           is BleLogLevel.Error ->  Logger.e(tag, message)
       }
    }
} 

问题锦集,但愿对你有帮助

https://blog.51cto.com/u_16213573/7811086
  • 1、少部分机型会存在断开连接(gatt.disconnect)后,连接状态仍未刷新,导致其他机型连接不上外设。 参考

其他

  • 1、关闭系统蓝牙,没有触发onConnectionStateChange 解决方案: 1、操作前判断蓝牙状态, 2、系统蓝牙变化广播监听 BleManager.get().registerBluetoothStateReceiver(getBluetoothCallback()) BleManager.get().unRegisterBluetoothStateReceiver()

考虑把Collections.synchronizedList换成其他不会导致死锁的集合

License

Copyright (c) 2023 Bekie

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

blecore's People

Contributors

buhuiming avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

blecore's Issues

连接慢的问题

同一个手机,同一个蓝牙设备,用fastble和本库连接,测试多次均发现连接、读写。通知全流程都会慢5~6s,还有优化的空间吗

oppo reno11 setScanServiceUuid后搜索不到指定的设备,去掉setScanServiceUuid后就可以搜到,其他手机正常

问题描述(出现的环境,demo是否存在)【必填】
存在
设备蓝牙是开着的,在demo代码中添加了.setScanServiceUuid("00001801-0000-1000-8000-00805f9b34fb"),其他手机都是正常能搜索到这个设备,但是目前发现oppo reno11搜索不到设备,如果我把setScanServiceUuid去掉,就又可以搜索到

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

isForceConnect的作用和解释没明白

我可不可以理解无论是isForceConnect 还是AutoConnect还是无法在蓝牙断开后进行自动重连,
我在测试的时候连接成功后,设备蓝牙断电后,间隔2S后马上开启,DEMO不会进行重连处理,
还是需要自己去在监听地方处理重连逻辑

关于接收大量数据的问题

作者你好,在使用过程中接收大量数据时会出现数据错乱的问题

1698811566756

在接收大数据时,onCharacteristicChanged接收的某包数据会延时发出,导致后续组帧错误

可以设置特征的writeType吗?

我有一个特征,他可以是 WRITE_TYPE_DEFAULT 的 也可以是WRITE_TYPE_NO_RESPONSE
(也就是有响应和无响应)但是在demo app上面显示,他是write类型的,默认是有响应的写入。
我找了很久没找到可以设置Write类型的,目前只能通过有响应的方式来写入,这样速度很慢。
可以设置特征的writeType为 WRITE_TYPE_NO_RESPONSE 吗?

大佬有设备会报这个错:在BleDeviced的Parcelable闪退

aused by: java.lang.RuntimeException: Parcel android.os.Parcel@ff2c20f: Unmarshalling unknown type code 7209071 at offset 304
at android.os.Parcel.readValue(Parcel.java:2763)
at android.os.Parcel.readArrayMapInternal(Parcel.java:3053)
at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:288)
at android.os.BaseBundle.unparcel(BaseBundle.java:232)
at android.os.Bundle.getParcelable(Bundle.java:940)
at android.content.Intent.getParcelableExtra(Intent.java:7542)
at com.bhm.demo.ui.DetailOperateActivity.initData(DetailOperateActivity.kt:62)
at com.bhm.demo.BaseActivity.onCreate(BaseActivity.kt:75)
at android.app.Activity.performCreate(Activity.java:7317)
at android.app.Activity.performCreate(Activity.java:7308)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1272)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3128)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3299) 
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:114) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:74) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1988) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:242) 
at android.app.ActivityThread.main(ActivityThread.java:7240) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:502) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:906) 

小米手机接收不到数据,华为和pixel手机能接收到

问题描述(出现的环境,demo是否存在)【必填】

我们有个蓝牙接口,需要先发送1个数据,表示偏移量,然后读取数据(这个数据量比较大,后台准备数据会花几秒钟时间),看log小米手机会直接读出空,华为和pixel手机能正常读取到,demo也存在

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

下面是小米手机log

2024-07-29 18:18:38.648 21365-21365 DetailViewModel         com.bhm.ble                          I  #######----> data is: 31 
2024-07-29 18:18:38.652 21365-21365 BleTaskQueue            com.bhm.ble                          D  #######----> (共享队列) 当前任务数量:0, 添加任务:com.bhm.ble.control.BleTask@3bf851b
2024-07-29 18:18:38.758 21365-21440 BleTaskQueue            com.bhm.ble                          I  #######----> (共享队列) 开始执行任务:com.bhm.ble.control.BleTask@3bf851b
2024-07-29 18:18:38.759 21365-21440 BleWriteRequest         com.bhm.ble                          I  #######----> 1005:00003a00-0000-1000-8000-00805f9b34fb(1722248318649)(1) - > 开始写第1包数据
2024-07-29 18:18:38.766 21365-21386 BleWriteRequest         com.bhm.ble                          I  #######----> 1005:00003a00-0000-1000-8000-00805f9b34fb(1722248318649)(1) -> 第1包数据写成功:31 
2024-07-29 18:18:38.767 21365-21386 BleTaskQueue            com.bhm.ble                          E  #######----> (共享队列) 移除正在执行的任务:com.bhm.ble.control.BleTask@3bf851b
2024-07-29 18:18:38.768 21365-21440 BleLogger               com.bhm.ble                          I  #######----> (共享队列) 任务完成,未超时:com.bhm.ble.control.BleTask@3bf851b
2024-07-29 18:18:38.769 21365-21437 BleTaskQueue            com.bhm.ble                          D  #######----> (共享队列) 任务:com.bhm.ble.control.BleTask@3bf851b结束完毕,剩下0个任务
2024-07-29 18:18:38.770 21365-21437 BleTaskQueue            com.bhm.ble                          I  #######----> (共享队列) 所有任务执行完毕
2024-07-29 18:18:38.811 21365-21365 ScrollerOp...ionManager com.bhm.ble                          D  registerConfigChangedListener
2024-07-29 18:18:46.625 21365-21365 BleTaskQueue            com.bhm.ble                          D  #######----> (共享队列) 当前任务数量:0, 添加任务:com.bhm.ble.control.BleTask@4d79dfc
2024-07-29 18:18:46.730 21365-21437 BleTaskQueue            com.bhm.ble                          I  #######----> (共享队列) 开始执行任务:com.bhm.ble.control.BleTask@4d79dfc
2024-07-29 18:18:49.823 21365-21386 BleTaskQueue            com.bhm.ble                          E  #######----> (共享队列) 移除正在执行的任务:com.bhm.ble.control.BleTask@4d79dfc
2024-07-29 18:18:49.824 21365-21437 BleLogger               com.bhm.ble                          I  #######----> (共享队列) 任务完成,未超时:com.bhm.ble.control.BleTask@4d79dfc
2024-07-29 18:18:49.825 21365-21440 BleTaskQueue            com.bhm.ble                          D  #######----> (共享队列) 任务:com.bhm.ble.control.BleTask@4d79dfc结束完毕,剩下0个任务
2024-07-29 18:18:49.825 21365-21386 BleReadRequest          com.bhm.ble                          D  #######----> 00003a00-0000-1000-8000-00805f9b34fb -> 读特征值数据成功:
2024-07-29 18:18:49.826 21365-21440 BleTaskQueue            com.bhm.ble                          I  #######----> (共享队列) 所有任务执行完毕
2024-07-29 18:18:49.860 21365-21365 ScrollerOp...ionManager com.bhm.ble                          D  registerConfigChangedListener

下面是pixel手机log:

2024-07-29 18:22:49.548 24833-24833 DetailViewModel         com.bhm.ble                          I  #######----> data is: 31 
2024-07-29 18:22:49.550 24833-24833 BleTaskQueue            com.bhm.ble                          D  #######----> (共享队列) 当前任务数量:0, 添加任务:com.bhm.ble.control.BleTask@6d3796
2024-07-29 18:22:49.655 24833-24895 BleTaskQueue            com.bhm.ble                          I  #######----> (共享队列) 开始执行任务:com.bhm.ble.control.BleTask@6d3796
2024-07-29 18:22:49.657 24833-24895 BleWriteRequest         com.bhm.ble                          I  #######----> 1005:00003a00-0000-1000-8000-00805f9b34fb(1722248569548)(1) - > 开始写第1包数据
2024-07-29 18:22:49.668 24833-24911 BleWriteRequest         com.bhm.ble                          I  #######----> 1005:00003a00-0000-1000-8000-00805f9b34fb(1722248569548)(1) -> 第1包数据写成功:31 
2024-07-29 18:22:49.673 24833-24911 BleTaskQueue            com.bhm.ble                          E  #######----> (共享队列) 移除正在执行的任务:com.bhm.ble.control.BleTask@6d3796
2024-07-29 18:22:49.673 24833-24895 BleLogger               com.bhm.ble                          I  #######----> (共享队列) 任务完成,未超时:com.bhm.ble.control.BleTask@6d3796
2024-07-29 18:22:49.675 24833-24895 BleTaskQueue            com.bhm.ble                          D  #######----> (共享队列) 任务:com.bhm.ble.control.BleTask@6d3796结束完毕,剩下0个任务
2024-07-29 18:22:49.676 24833-24895 BleTaskQueue            com.bhm.ble                          I  #######----> (共享队列) 所有任务执行完毕
2024-07-29 18:22:51.648 24833-24833 BleTaskQueue            com.bhm.ble                          D  #######----> (共享队列) 当前任务数量:0, 添加任务:com.bhm.ble.control.BleTask@6a905b3
2024-07-29 18:22:51.754 24833-24895 BleTaskQueue            com.bhm.ble                          I  #######----> (共享队列) 开始执行任务:com.bhm.ble.control.BleTask@6a905b3
2024-07-29 18:22:54.842 24833-24848 BleTaskQueue            com.bhm.ble                          E  #######----> (共享队列) 移除正在执行的任务:com.bhm.ble.control.BleTask@6a905b3
2024-07-29 18:22:54.844 24833-24895 BleLogger               com.bhm.ble                          I  #######----> (共享队列) 任务完成,未超时:com.bhm.ble.control.BleTask@6a905b3
2024-07-29 18:22:54.844 24833-24907 BleTaskQueue            com.bhm.ble                          D  #######----> (共享队列) 任务:com.bhm.ble.control.BleTask@6a905b3结束完毕,剩下0个任务
2024-07-29 18:22:54.844 24833-24907 BleTaskQueue            com.bhm.ble                          I  #######----> (共享队列) 所有任务执行完毕
2024-07-29 18:22:54.858 24833-24848 BleReadRequest          com.bhm.ble                          D  #######----> 00003a00-0000-1000-8000-00805f9b34fb -> 读特征值数据成功:7b 22 73 73 69 64 22 3a 22 4c 44 43 2d 6d 61 6e 61 67 65 72 2d 61 70 22 2c 22 6b 65 79 22 3a 22 22 2c 22 65 6e 63 72 79 70 74 69 6f 6e 22 3a 22 70 73 6b 32 22 2c 22 73 69 67 6e 61 6c 4c 65 76 65 6c 22 3a 22 2d 35 35 22 2c 22 63 6f 6e 6e 65 63 74 65 64 22 3a 66 61 6c 73 65 7d 2c 7b 22 73 73 69 64 22 3a 22 4c 44 43 2d 6f 66 66 69 63 65 2d 74 65 73 74 31 22 2c 22 6b 65 79 22 3a 22 22 

怀疑是否是因为read timeout,但是log看又没有超时,很奇怪,我这边几个小米手机都会出现

大佬,读特征值数据失败,超时 是什么原因呢?

image
2024-01-11 19:21:58.949 16315-16433 BleLogger com.bhm.ble E #######----> 49535343-6daa-4d02-abf6-19569aca69fe -> 读特征值数据失败,超时
2024-01-11 19:28:25.190 16947-17033 BleLogger com.bhm.ble E #######----> 00002a00-0000-1000-8000-00805f9b34fb -> 读特征值数据失败,超时
2024-01-11 19:28:42.712 16947-17031 BleLogger com.bhm.ble E #######----> 00002a01-0000-1000-8000-00805f9b34fb -> 读特征值数据失败,超时
2024-01-11 19:29:23.954 16947-17031 BleLogger com.bhm.ble E #######----> 49535343-aca3-481c-91ec-d85e28a60318 -> 读特征值数据失败,超时

请教问题

你好, 我对蓝牙这块开发不是很懂,我想问一下app是否能同时连接两个或多个设备, 比如血糖仪设备, 同时连接两个以上

报错 One or more classes has class file version >= 56 which is not officially supported.

Execution failed for task ':app:mergeExtDexDebug'.

Could not resolve all files for configuration ':app:debugRuntimeClasspath'.
Failed to transform BleCore-1.5.3.aar (com.github.buhuiming:BleCore:1.5.3) to match attributes {artifactType=android-dex, asm-transformed-variant=NONE, dexing-enable-desugaring=true, dexing-is-debuggable=true, dexing-min-sdk=24, org.gradle.category=library, org.gradle.dependency.bundling=external, org.gradle.libraryelements=aar, org.gradle.status=release, org.gradle.usage=java-runtime}.
> Execution failed for DexingNoClasspathTransform: /Users/johnvi/.gradle/caches/transforms-3/05df512089c51dbd2ced0e2d27d3c06d/transformed/jetified-BleCore-1.5.3-runtime.jar.
> Error while dexing.

One or more classes has class file version >= 56 which is not officially supported.
com.android.tools.r8.internal.nc: Sealed classes are not supported as program classes

autoconnect

要使用autoconnect是否需要先和裝置配對
以及 非主動斷開自動連接的非主動 是建立在什麼樣的情況

关于短时间内写入大量数据ANR的问题

ANR in com.bhm.ble (com.bhm.ble/com.bhm.demo.ui.DetailOperateActivity)
                                                                                                    PID: 32329
                                                                                                    Reason: Input dispatching timed out (5b0d78d com.bhm.ble/com.bhm.demo.ui.DetailOperateActivity (server) is not responding. Waited 5002ms for MotionEvent)
                                                                                                    Parent: com.bhm.ble/com.bhm.demo.ui.DetailOperateActivity
                                                                                                    Frozen: false
                                                                                                    Load: 0.0 / 0.0 / 0.0
                                                                                                    ----- Output from /proc/pressure/memory -----
                                                                                                    some avg10=0.00 avg60=0.00 avg300=0.00 total=3050098580
                                                                                                    full avg10=0.00 avg60=0.00 avg300=0.00 total=1236302433
                                                                                                    ----- End output from /proc/pressure/memory -----
                                                                                                    
                                                                                                    CPU usage from 0ms to 6611ms later (2023-09-18 18:18:29.225 to 2023-09-18 18:18:35.836):
                                                                                                      30% 1382/system_server: 13% user + 16% kernel / faults: 10811 minor
                                                                                                      4.2% 1550/media.codec: 2.9% user + 1.3% kernel / faults: 32066 minor
                                                                                                      5.9% 1128/surfaceflinger: 3.6% user + 2.2% kernel / faults: 988 minor
                                                                                                      5.1% 17486/adbd: 0.6% user + 4.5% kernel / faults: 10 minor
                                                                                                      4.5% 11643/com.jhyan.yan:widgetProvider: 1% user + 3.4% kernel / faults: 142 minor
                                                                                                      4% 1037/[email protected]: 2.2% user + 1.8% kernel / faults: 352 minor
                                                                                                      3.3% 669/kworker/u24:7-memlat_wq: 0% user + 3.3% kernel
                                                                                                      3.1% 3539/com.android.phone: 1.9% user + 1.2% kernel / faults: 1223 minor
                                                                                                      2.7% 626/logd: 0.3% user + 2.4% kernel
                                                                                                      2.2% 668/kworker/u24:6-events_unbound: 0% user + 2.2% kernel
                                                                                                      0.3% 1490/media.extractor: 0.1% user + 0.1% kernel / faults: 3681 minor
                                                                                                      2.2% 12235/com.sohu.inputmethod.sogouoem: 1.6% user + 0.6% kernel / faults: 1162 minor
                                                                                                      2.2% 32213/com.android.systemui: 1.9% user + 0.3% kernel / faults: 110 minor
                                                                                                      2.1% 664/kworker/u24:1+memlat_wq: 0% user + 2.1% kernel
                                                                                                      2.1% 24292/kworker/u24:2-events_unbound: 0% user + 2.1% kernel
                                                                                                      2.1% 26537/kworker/u25:3-fsverity_read_queue: 0% user + 2.1% kernel
                                                                                                      0% 1014/[email protected]_64: 0% user + 0% kernel / faults: 30 minor
                                                                                                      1.8% 32329/com.bhm.ble: 1.2% user + 0.6% kernel / faults: 1727 minor
                                                                                                      0.2% 25222/com.android.bluetooth: 0% user + 0.2% kernel / faults: 261 minor
                                                                                                      1% 17645/process-tracker: 0.1% user + 0.9% kernel
                                                                                                      0.9% 11/rcu_preempt: 0% user + 0.9% kernel
                                                                                                      0.9% 470/usbtemp_kthread: 0% user + 0.9% kernel
                                                                                                      0% 5572/com.qualcomm.qti.workloadclassifier: 0% user + 0% kernel / faults: 395 minor
                                                                                                      0.9% 21604/process-tracker: 0% user + 0.9% kernel / faults: 2 minor
                                                                                                      0% 722/tombstoned: 0% user + 0% kernel
                                                                                                      0.7% 4896/irq/52-90b6300.: 0% user + 0.7% kernel
                                                                                                      0.7% 17711/com.quark.browser:channel: 0.6% user + 0.1% kernel / faults: 391 minor
                                                                                                      0.7% 24889/kworker/u25:1-dwc_wq: 0% user + 0.7% kernel
                                                                                                      0.6% 293/kgsl_worker_thr: 0% user + 0.6% kernel
                                                                                                      0.6% 983/qrtr_rx: 0% user + 0.6% kernel
                                                                                                      0.6% 1050/vendor.qti.hardware.display.composer-service: 0% user + 0.6% kernel / faults: 251 minor
                                                                                                      0.6% 17638/logcat: 0.1% user + 0.4% kernel
                                                                                                      0.6% 19844/kworker/u24:3-events_unbound: 0% user + 0.6% kernel
                                                                                                      0.6% 21601/logcat: 0.1% user + 0.4% kernel
                                                                                                      0.6% 31866/logcat: 0.1% user + 0.4% kernel
                                                                                                      0.4% 14/rcuop/0: 0% user + 0.4% kernel
                                                                                                      0.4% 37/rcuop/2: 0% user + 0.4% kernel
                                                                                                      0% 862/zygote64: 0% user + 0% kernel / faults: 22 minor
                                                                                                      0.4% 2084/com.taobao.taobao:channel: 0.3% user + 0.1% kernel / faults: 1 minor
                                                                                                      0.4% 4584/com.tencent.mm: 0.1% user + 0.3% kernel / faults: 19 minor
                                                                                                      0.4% 4898/irq/53-90cd000.: 0% user + 0.4% kernel
                                                                                                      0.4% 17459/com.quark.browser:push: 0.3% user + 0.1% kernel / faults: 93 minor
                                                                                                      0% 1/init: 0% user + 0% kernel
                                                                                                      0% 12/rcu_sched: 0% user + 0% kernel
                                                                                                      0.3% 73/rcuop/6: 0% user + 0.3% kernel
                                                                                                      0% 863/zygote: 0% user + 0% kernel / faults: 12 minor
                                                                                                      0% 1010/android.hardware.audio.service: 0% user + 0% kernel / faults: 78 minor
                                                                                                      0.3% 1043/[email protected]: 0.1% user + 0.1% kernel / faults: 30 minor
                                                                                                      0.3% 1049/vendor.qti.hardware.display.allocator-service: 0.1% user + 0.1% kernel / faults: 264 minor
                                                                                                      0.3% 1123/audioserver: 0.1% user + 0.1% kernel / faults: 72 minor
                                                                                                      0% 1473/cameraserver: 0% user + 0% kernel / faults: 58 minor
                                                                                                      0% 1501/mediaserver: 0% user + 0% kernel / faults: 76 minor
viewBinding.btnSend.setOnClickListener {
            if (ViewUtil.isInvalidClick(it)) {
                return@setOnClickListener
            }
            val content = viewBinding.etContent.text.toString()
            if (content.isEmpty()) {
                Toast.makeText(applicationContext, "请输入数据", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }
            if (currentSendNode == null) {
                Toast.makeText(applicationContext, "请选择特征值写操作", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }
            currentSendNode?.let { node ->
                lifecycleScope.launch {
                    withContext(Dispatchers.IO){
                        repeat(1000) {
                            viewModel.writeData(
                                getBleDevice(),
                                node,
                                content
                            )
                        }
                    }
                }
            }
        }

如果复现不出来,可以尝试点击界面中的其他按钮

onCharacteristicChanged接收到的data数据被截断

image

如图,一条完整的蓝牙返回数据格式:ff 30 33 36 31 00 00 00 00 00 fe,但实际在收到的数据中会出现各种的数据被截断,我不知道是少设置参数导致还是什么原因?蓝牙返回发每次发送数据是一条完整的数据格式,收到就会各种各样的数据,还存在部分数据丢失问题。

大佬,请问如何提升发送固件文件的速度?

情况说明:蓝牙固件文件文件大小有1.5M左右,设置Mtu为512,读取固件文件以hex发送给设备。间隔1000ms给writeData传ByteArray的长度为2048的数据给设备。我看日志,您做了分包,每次startWriteJob的差不多100ms,这样发送完要10分钟,请问如何修改才能更快?

关于扫描蓝牙权限问题

想请教下扫描蓝牙权限 的问题 扫描蓝牙是否一定要开精确位置权限 用户选择了大致位置是否就无法扫描到蓝牙设备 TargetSDK 为33 测试机为Android 14 的三星 因为蓝牙权限被很多用户投诉

公司的设备,华为手机无法read,显示超时

问题描述(出现的环境,demo是否存在)【必填】
直接跑的demo,连公司设备,connect,notify没问题,read,就超时;
https://github.com/wandersnail/easyble-x 这个sdk,链接公司设备后,read没有问题,你可以参考一下read部分代码;

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】
看文档了,用的是demo;

issue 列表中是否有人曾提过类似的问题【必答】
无;

是否已经搜索过了 issue 列表但还未能解决的【必答】
yes;

1713495711267

1713497011467

支持多连接嘛?

您好~
我想问下这个库支持多连接嘛?我 看了下库代码好像没发现,请问这个在需求计划表之内了吗?
看到大佬这个库用上了 kotlin 以及 jetpack 套件很是惊喜!!! 感谢作者的努力~

通过mac 构造bledevice

大佬 我保存了 mac 列表 ,循环连设备是通过 mac连的, 通过mac 连接 gatt 服务获取为空了

关于分包

是否可以增加一个包发送前的hook来处理每一个包的数据结构?
参数可以是发送的包整id和第几个分包
这样更方便实现分包协议

数据频繁交互时出现卡死

作者你好:
在使用过程中,实现一秒查询一次数据,返回数据量2000个字节左右,如果长时间进行数据交互会偶发性出现蓝牙Notifiy无法收到数据的情况,但是发送数据时没有问题的,当这个时候断开蓝牙连接会出现ANR报错。

数据发送问题

大佬遇到一个问题:
发送一段数据,日志线上发送成功,数据也是完整,但是接收设备收到的只是一部分,这是什么原因?
mtu设置为512

这是我发送的日志:
2023-08-04 11:16:41.237 30773-30773 FrViewModel com.bhm.ble I #######----> data is: 73 73 69 64 3a 61 61 73 73 64 64 66 67 71 77 65 65 72 74 79 69 6f 6f 6f 69 75 79 74 72 72 72 64
2023-08-04 11:16:41.238 30773-30773 FrViewModel com.bhm.ble I #######----> 509==mtu==512
2023-08-04 11:16:41.243 30773-30773 BleTaskQueue com.bhm.ble I #######----> (共享队列) 当前任务数量:0, 添加任务:com.bhm.ble.control.BleTask@5fa37d3
2023-08-04 11:16:41.350 30773-31045 BleTaskQueue com.bhm.ble I #######----> (共享队列) 开始执行任务:com.bhm.ble.control.BleTask@5fa37d3
2023-08-04 11:16:41.350 30773-31045 BleWriteRequest com.bhm.ble I #######----> 1005:16962447-c623-61ba-d94b-4d1e43535349(1691119001238)(1) - > 开始写第1包数据
2023-08-04 11:16:41.358 30773-30799 BleWriteRequest com.bhm.ble D #######----> 1005:16962447-c623-61ba-d94b-4d1e43535349(1691119001238)(1) -> 第1包数据写成功:73 73 69 64 3a 61 61 73 73 64 64 66 67 71 77 65 65 72 74 79 69 6f 6f 6f 69 75 79 74 72 72 72 64

但是设备端收到只有:ssid:aassddfg
用其他工具发送,设备接收数据是完整正常的

多连接问题

请问多连接的通知回调怎么处理呢,回调函数里面有没device,只有数据。

调用`startScanAndConnect`时当扫描不到任何设备会发生崩溃

java.lang.NullPointerException
                                                                      	at com.bhm.ble.request.base.BleRequestImp$startScanAndConnect$1.invokeSuspend(BleRequestImp.kt:168)
                                                                      	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                                                                      	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
                                                                      	at android.os.Handler.handleCallback(Handler.java:942)
                                                                      	at android.os.Handler.dispatchMessage(Handler.java:99)
                                                                      	at android.os.Looper.loopOnce(Looper.java:210)
                                                                      	at android.os.Looper.loop(Looper.java:299)
                                                                      	at android.app.ActivityThread.main(ActivityThread.java:8261)
                                                                      	at java.lang.reflect.Method.invoke(Native Method)
                                                                      	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:559)
                                                                      	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:954)
                                                                      	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@bdbbac5, Dispatchers.Main]

Android 14兼容性问题

Google piexl 7a 设备,Android14系统
设置MTU=23 设备可以正常接收到 拦截抓取的日志也是正常 设置大于23的数字就不行,
默认读取到设备的MTU是247 设置成247之后,写入是成功,
返回的是true 但是设备那边用串口抓包抓到的数据都是空格换行了,
我们需要用BLE发送几kb 的数据 导致无法正常接收,发送几个字节的数据,
一共15包数据,每一包数据写入的都是成功 是否完成也是成功 其他Android设备 Android 10 Android11 Android 12 Android13 都没有出现这个问题
设备可以正常接收到,想请教下大佬,能否帮忙调试一下 多谢

Screenshot_20231014_181757

minSdk问题

因为项目的minSdk=21,框架的minSdk=24,编译不通过,能否把框架的minSdk设为21?
谢谢!

请严格按照 issue 模板来提问题,否则一律不受理

问题描述(出现的环境,demo是否存在)【必填】

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

版权声明

/*

  • Copyright (c) 2022-2032 buhuiming
  • 不能修改和删除上面的版权声明
  • 此代码属于buhuiming编写,在未经允许的情况下不得传播复制
    */
    大佬,我能用你这个库,接入项目里面使用吗

特征值notify没收到onCharacteristicChanged回调(同样操作fastble可以)

问题描述(出现的环境,demo是否存在)
公司的设备两个特征值,一个用来写,一个用来notiffy,本框架写了之后notify的那个特征值收不到change的回调,fastble可以

bleCore
fastble1
fastble2

框架文档是否提及了该问题【必答】 否

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

Notify fail

华为手机,使用测试APP notify提示SetCharacteristicNotificationFail,用fastBle notify成功,不知道为啥!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.