1,概述

1.1 HID协议

HID协议: Hunman Interface Device Profile人机交互设备协议

使用场景:支持人机交互设备之间的控制

市场产品:蓝牙键盘,蓝牙鼠标,蓝牙游戏手柄等。

1.2 代码路径

客户端: frameworks\base\core\java\android\bluetooth

服务端: packages\apps\Bluetooth\src\com\android\bluetooth\ hid

HidDevService.java                 hid协议的服务端

开发流程和健康设备类似,但是稍微麻烦

2,接口

接口如下

3,开发步骤

在官方文档中有一个建立通信的流程:

1、调用getProfileProxy(Context,BluetoothProfile.ServiceListener, int)来获取代理对象的连接。

2、创建BluetoothHidDeviceAppSdpSettings, BluetoothHidDeviceAppQosSettings对象,创建BluetoothHidDeviceCallback回调,调用registerApp方法注册

3、将手机与设备配对,并且进行连接。

4、实现BluetoothHidDeviceCallback的7个回调方法

5、调用sendReport方法分别实现蓝牙鼠标,蓝牙键盘等。

3.1 获取客户端代理对象

一般在oncreate方法中,直接调用getProfileProxy方法,这个没什么好说的。

BluetoothAdapter.getDefaultAdapter().getProfileProxy(getApplicationContext(), mProfileServiceListener,BluetoothProfile. HID_DEVICE);

private BluetoothProfile.ServiceListener mProfileServiceListener = new BluetoothProfile.ServiceListener() {@Overridepublic void onServiceDisconnected(int profile) {if (profile == BluetoothProfile.HEALTH){mBluetoothHealth = null;}}@SuppressLint("NewApi")@Overridepublic void onServiceConnected(int profile, BluetoothProfile proxy) {if (profile == BluetoothProfile.HEALTH) {mHidDevice = (BluetoothHidDevice) proxy;// 获取代理对象之后就进行注册...}}};

一般经过这个步骤,客户端的BluetoothHidDevice对象已经和服务端的HidDevService对象绑定了。

3.2 注册registerApp

BluetoothHidDeviceAppSdpSettings sdp = new BluetoothHidDeviceAppSdpSettings(HidConsts.NAME, HidConsts.DESCRIPTION, HidConsts.PROVIDER,BluetoothHidDevice.SUBCLASS1_COMBO, HidConsts.DESCRIPTOR);
BluetoothHidDeviceAppQosSettings inQos = new BluetoothHidDeviceAppQosSettings(BluetoothHidDeviceAppQosSettings.SERVICE_GUARANTEED, 200, 2, 200,10000 /* 10 ms */, 10000 /* 10 ms */);
BluetoothHidDeviceAppQosSettings outQos = new BluetoothHidDeviceAppQosSettings(BluetoothHidDeviceAppQosSettings.SERVICE_GUARANTEED, 900, 9, 900,10000 /* 10 ms */, 10000 /* 10 ms */);
boolean result = mHidDevice.registerApp(sdp, inQos, outQos, mCallback);

HidConsts类的定义如下:

public class HidConsts {public final static String NAME = "HID Device Testapp";public final static String DESCRIPTION = "";public final static String PROVIDER = "Codeaurora";/* @formatter:off */public final static byte[] DESCRIPTOR = {(byte) 0x05, (byte) 0x01,                    // USAGE_PAGE (Generic Desktop)(byte) 0x09, (byte) 0x02,                    // USAGE (Mouse)(byte) 0xa1, (byte) 0x01,                    // COLLECTION (Application)(byte) 0x09, (byte) 0x01,                    //   USAGE (Pointer)(byte) 0xa1, (byte) 0x00,                    //   COLLECTION (Physical)(byte) 0x85, (byte) 0x02,                    //     REPORT_ID (2)(byte) 0x05, (byte) 0x09,                    //     USAGE_PAGE (Button)(byte) 0x19, (byte) 0x01,                    //     USAGE_MINIMUM (Button 1)(byte) 0x29, (byte) 0x03,                    //     USAGE_MAXIMUM (Button 3)(byte) 0x15, (byte) 0x00,                    //     LOGICAL_MINIMUM (0)(byte) 0x25, (byte) 0x01,                    //     LOGICAL_MAXIMUM (1)(byte) 0x95, (byte) 0x03,                    //     REPORT_COUNT (3)(byte) 0x75, (byte) 0x01,                    //     REPORT_SIZE (1)(byte) 0x81, (byte) 0x02,                    //     INPUT (Data,Var,Abs)(byte) 0x95, (byte) 0x01,                    //     REPORT_COUNT (1)(byte) 0x75, (byte) 0x05,                    //     REPORT_SIZE (5)(byte) 0x81, (byte) 0x03,                    //     INPUT (Cnst,Var,Abs)(byte) 0x05, (byte) 0x01,                    //     USAGE_PAGE (Generic Desktop)(byte) 0x09, (byte) 0x30,                    //     USAGE (X)(byte) 0x09, (byte) 0x31,                    //     USAGE (Y)(byte) 0x15, (byte) 0x81,                    //     LOGICAL_MINIMUM (-127)(byte) 0x25, (byte) 0x7f,                    //     LOGICAL_MAXIMUM (127)(byte) 0x75, (byte) 0x08,                    //     REPORT_SIZE (8)(byte) 0x95, (byte) 0x02,                    //     REPORT_COUNT (2)(byte) 0x81, (byte) 0x06,                    //     INPUT (Data,Var,Rel)(byte) 0x09, (byte) 0x38,                    //     USAGE (Wheel)(byte) 0x15, (byte) 0x81,                    //     LOGICAL_MINIMUM (-127)(byte) 0x25, (byte) 0x7f,                    //     LOGICAL_MAXIMUM (127)(byte) 0x75, (byte) 0x08,                    //     REPORT_SIZE (8)(byte) 0x95, (byte) 0x01,                    //     REPORT_COUNT (1)(byte) 0x81, (byte) 0x06,                    //     INPUT (Data,Var,Rel)(byte) 0xc0,                                 //   END_COLLECTION(byte) 0xc0,                                 // END_COLLECTION// battery strength(byte) 0x05, (byte) 0x0c,(byte) 0x09, (byte) 0x01,(byte) 0xa1, (byte) 0x01,(byte) 0x85, (byte) 0x20,                    //   REPORT_ID (32)(byte) 0x05, (byte) 0x01,(byte) 0x09, (byte) 0x06,(byte) 0xa1, (byte) 0x02,(byte) 0x05, (byte) 0x06,                    // USAGE_PAGE (Generic Device Controls)(byte) 0x09, (byte) 0x20,                    // USAGE (Battery Strength)(byte) 0x15, (byte) 0x00,                    // LOGICAL_MINIMUM (0)(byte) 0x26, (byte) 0xff, (byte) 0x00,      // LOGICAL_MAXIMUM (100)(byte) 0x75, (byte) 0x08,                    // REPORT_SIZE (8)(byte) 0x95, (byte) 0x01,                    // REPORT_COUNT (1)(byte) 0x81, (byte) 0x02,                    // INPUT (Data,Var,Abs)(byte) 0xc0,(byte) 0xc0,(byte) 0x05, (byte) 0x01,                    // USAGE_PAGE (Generic Desktop)(byte) 0x09, (byte) 0x06,                    // USAGE (Keyboard)(byte) 0xa1, (byte) 0x01,                    // COLLECTION (Application)(byte) 0x85, (byte) 0x01,                    //   REPORT_ID (1)(byte) 0x05, (byte) 0x07,                    //   USAGE_PAGE (Keyboard)(byte) 0x19, (byte) 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)(byte) 0x29, (byte) 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)(byte) 0x15, (byte) 0x00,                    //   LOGICAL_MINIMUM (0)(byte) 0x25, (byte) 0x01,                    //   LOGICAL_MAXIMUM (1)(byte) 0x75, (byte) 0x01,                    //   REPORT_SIZE (1)(byte) 0x95, (byte) 0x08,                    //   REPORT_COUNT (8)(byte) 0x81, (byte) 0x02,                    //   INPUT (Data,Var,Abs)(byte) 0x05, (byte) 0x0c,                    //   USAGE_PAGE (Consumer Devices)(byte) 0x15, (byte) 0x00,                    //   LOGICAL_MINIMUM (0)(byte) 0x25, (byte) 0x01,                    //   LOGICAL_MAXIMUM (1)(byte) 0x95, (byte) 0x07,                    //   REPORT_COUNT (7)(byte) 0x75, (byte) 0x01,                    //   REPORT_SIZE (1)(byte) 0x09, (byte) 0xb6,                    //   USAGE (Scan Previous Track)(byte) 0x09, (byte) 0xb5,                    //   USAGE (Scan Next Track)(byte) 0x09, (byte) 0xb7,                    //   USAGE (Stop)(byte) 0x09, (byte) 0xcd,                    //   USAGE (Play/Pause)(byte) 0x09, (byte) 0xe2,                    //   USAGE (Mute)(byte) 0x09, (byte) 0xe9,                    //   USAGE (Volume Up)(byte) 0x09, (byte) 0xea,                    //   USAGE (Volume Down)(byte) 0x81, (byte) 0x02,                    //   INPUT (Data,Var,Abs)(byte) 0x95, (byte) 0x01,                    //   REPORT_COUNT (1)(byte) 0x75, (byte) 0x01,                    //   REPORT_SIZE (1)(byte) 0x81, (byte) 0x03,                    //   INPUT (Constant,Var,Abs)(byte) 0x05, (byte) 0x07,                    //   USAGE_PAGE (Keyboard)(byte) 0x95, (byte) 0x05,                    //   REPORT_COUNT (5)(byte) 0x75, (byte) 0x01,                    //   REPORT_SIZE (1)(byte) 0x85, (byte) 0x01,                    //   REPORT_ID (1)(byte) 0x05, (byte) 0x08,                    //   USAGE_PAGE (LEDs)(byte) 0x19, (byte) 0x01,                    //   USAGE_MINIMUM (Num Lock)(byte) 0x29, (byte) 0x05,                    //   USAGE_MAXIMUM (Kana)(byte) 0x91, (byte) 0x02,                    //   OUTPUT (Data,Var,Abs)(byte) 0x95, (byte) 0x01,                    //   REPORT_COUNT (1)(byte) 0x75, (byte) 0x03,                    //   REPORT_SIZE (3)(byte) 0x91, (byte) 0x03,                    //   OUTPUT (Cnst,Var,Abs)(byte) 0x95, (byte) 0x06,                    //   REPORT_COUNT (6)(byte) 0x75, (byte) 0x08,                    //   REPORT_SIZE (8)

连接很简单,直接调用connect方法就可以了。

public void connect() {if (mHidDevice == null) return;mHidDevice.connect();
}

3.4 BluetoothHidDeviceCallback

BluetoothHidDeviceCallback这个抽象类有7个回调方法,

private byte[] mBuffer = new byte[1];
private final BluetoothHidDeviceCallback mCallback = new BluetoothHidDeviceCallback() {@Overridepublic void onAppStatusChanged(BluetoothDevice pluggedDevice,BluetoothHidDeviceAppConfiguration config, boolean registered) {// 一般在registerApp和unregisterApp方法之后回调    // registered 表示是否注册上      }@Overridepublic void onConnectionStateChanged(BluetoothDevice device, int state) {// device 远程蓝牙设备  state连接状态mBuffer = (byte) 63mHidDevice.sendReport(32, mBuffer);  // 不知道为啥子这样写?}// 其他5个方法就可以不管了。@Overridepublic void onIntrData(byte reportId, byte[] data) {Log.v(TAG, "intr data: reportId=" + reportId + " data=" + Arrays.toString(data));}@Overridepublic void onSetProtocol(byte protocol) {Log.d(TAG, "protocol set to " + protocol);}@Overridepublic void onVirtualCableUnplug() {}@Overridepublic void onGetReport(byte type, byte id, int bufferSize) {}@Overridepublic void onSetReport(byte type, byte id, byte[] data) {}};

BluetoothHidDeviceCallback7个方法都是C/C++等通过JNI机制的回调。

4,蓝牙鼠标

4.1 蓝牙鼠标滑动

实现鼠标在整个界面前后左右上下滑动

mTouchpad = view.findViewById(R.id.touchpad);mTouchpad.setOnTouchListener(new OnTouchListener() {private int mPrevX; private int mPrevY; @Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:mPrevX = (int) (event.getX() * mSpeed);mPrevY = (int) (event.getY() * mSpeed);break;case MotionEvent.ACTION_MOVE:int x = (int) (event.getX() * mSpeed);int y = (int) (event.getY() * mSpeed);mouseMove((byte) (x – mPrevX), (byte) (y - mPrevY)); mPrevX = x;mPrevY = y;break;}return true;}});
private int mSpeed = 3;

mSpeed的值控制鼠标移动的速度。

private byte[] mBuffer = new byte[4];
byte id = 2;
public synchronized void move(byte dx, byte dy) {// leave buttons state unchangedmBuffer[1] = dx;mBuffer[2] = dy;mHidDevice.sendReport(id, mBuffer);}

4.2 蓝牙鼠标点击

将鼠标滑动到目标后,点击按钮可以选中目标。

button.setOnTouchListener(new OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {int which = 0;switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mouseButtonDown(which);break;case MotionEvent.ACTION_UP:mouseButtonUp(which);break;}return false;}});

Which的值有三种,分别是0,1,2 之间好像没什么差别。

public synchronized void buttonDown(int which) {mBuffer[0] |= (1 << which);mBuffer[1] = 0;mBuffer[2] = 0;mHidDevice.sendReport(id, mBuffer);}public synchronized void buttonUp(int which) {mBuffer[0] &= ~(1 << which);mBuffer[1] = 0;mBuffer[2] = 0; mHidDevice.sendReport(id, mBuffer);}

4.3 蓝牙鼠标翻页

比如在手机中,有时候界面不止一页,这样就需要翻页来显示了。

private int mScrollSpeed = 3;   // 控制翻页的速度mScrollZone.setOnTouchListener(new OnTouchListener() {private int mPrevY;@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mPrevY = (int) (event.getY() * mScrollSpeed);break;case MotionEvent.ACTION_MOVE:int y = (int) (event.getY() * mScrollSpeed);mouseScroll((byte) (mPrevY - y));mPrevY = y;break;}return true;}});public synchronized void scroll(byte delta) {mBuffer[3] = delta;mHidDevice.sendReport(id, mBuffer);mBuffer[3] = 0x00;}

5,蓝牙键盘

市面上的键盘类型较多,实现了3种蓝牙键盘,

                                           标准键盘

lable以及对应keyCode如下:

<Keyboard><Layout><Key keyLabel="Esc" keyCode="0x29"/><Key keyLabel="F1" keyCode="0x3A"/><Key keyLabel="F2" keyCode="0x3B"/><Key keyLabel="F3" keyCode="0x3C"/><Key keyLabel="F4" keyCode="0x3D"/><Key keyLabel="F5" keyCode="0x3E"/><Key keyLabel="F6" keyCode="0x3F"/><Key keyLabel="F7" keyCode="0x40"/><Key keyLabel="F8" keyCode="0x41"/><Key keyLabel="F9" keyCode="0x42"/><Key keyLabel="F10" keyCode="0x43"/><Key keyLabel="F11" keyCode="0x44"/><Key keyLabel="F12" keyCode="0x45"/><Key keyLabel="Del" keyCode="0x4C"/></Layout><Layout><Key keyLabel="'" shiftLabel="~" keyCode="0x35"/><Key keyLabel="1" shiftLabel="!" keyCode="0x1E"/><Key keyLabel="2" shiftLabel="\@" keyCode="0x1F"/><Key keyLabel="3" shiftLabel="\#" keyCode="0x20"/><Key keyLabel="4" shiftLabel="$" keyCode="0x21"/><Key keyLabel="5" shiftLabel="%" keyCode="0x22"/><Key keyLabel="6" shiftLabel="^" keyCode="0x23"/><Key keyLabel="7" shiftLabel="&" keyCode="0x24"/><Key keyLabel="8" shiftLabel="*" keyCode="0x25"/><Key keyLabel="9" shiftLabel="(" keyCode="0x26"/><Key keyLabel="0" shiftLabel=")" keyCode="0x27"/><Key keyLabel="-" shiftLabel="_" keyCode="0x2D"/><Key keyLabel="=" shiftLabel="+" keyCode="0x2E"/><Key keyLabel="Backspace ←" keyCode="0x2A" weight="1.5"/></Layout><Layout><Key keyLabel="Tab ↹" keyCode="0x2B" weight="1.5"/><Key keyLabel="Q" keyCode="0x14"/><Key keyLabel="W" keyCode="0x1A"/><Key keyLabel="E" keyCode="0x08"/><Key keyLabel="R" keyCode="0x15"/><Key keyLabel="T" keyCode="0x17"/><Key keyLabel="Y" keyCode="0x1C"/><Key keyLabel="U" keyCode="0x18"/><Key keyLabel="I" keyCode="0x0C"/><Key keyLabel="O" keyCode="0x12"/><Key keyLabel="P" keyCode="0x13"/><Key keyLabel="[" keyCode="0x2F" shiftLabel="{"/><Key keyLabel="]" keyCode="0x30" shiftLabel="}"/><Key keyLabel="\\" keyCode="0x31" shiftLabel="|"/></Layout><Layout><Key keyLabel="Caps Lock" keyCode="0x39" weight="1.5"/><Key keyLabel="A" keyCode="0x04"/><Key keyLabel="S" keyCode="0x16"/><Key keyLabel="D" keyCode="0x07"/><Key keyLabel="F" keyCode="0x09"/><Key keyLabel="G" keyCode="0x0A"/><Key keyLabel="H" keyCode="0x0B"/><Key keyLabel="J" keyCode="0x0D"/><Key keyLabel="K" keyCode="0x0E"/><Key keyLabel="L" keyCode="0x0F"/><Key keyLabel=";" keyCode="0x33" shiftLabel=":"/><Key keyLabel="'" keyCode="0x34" shiftLabel="""/><Key keyLabel="Enter ↵" keyCode="0x28" weight="3.0"/></Layout><Layout><Key keyLabel="Shift ⇧" keyCode="0xE1" keyFunc="Shift" weight="1.5"/><Key keyLabel="Z" keyCode="0x1D"/><Key keyLabel="X" keyCode="0x1B"/><Key keyLabel="C" keyCode="0x06"/><Key keyLabel="V" keyCode="0x19"/><Key keyLabel="B" keyCode="0x05"/><Key keyLabel="N" keyCode="0x11"/><Key keyLabel="M" keyCode="0x10"/><Key keyLabel="," keyCode="0x36" shiftLabel="<"/><Key keyLabel="." keyCode="0x37" shiftLabel=">"/><Key keyLabel="/" keyCode="0x38" shiftLabel="\?"/><Key keyLabel="Shift ⇧" keyCode="0xE5" keyFunc="Shift" weight="1.5"/></Layout><Layout><Key keyLabel="Ctrl" keyCode="0xE0" weight="1.5"/><Key keyLabel="Win" keyCode="0xE3"/><Key keyLabel="Alt" keyCode="0xE2"/><Key keyLabel=" " keyCode="0x2C" weight="10.0"/><Key keyLabel="Alt Gr" keyCode="0xE6"/><Key keyLabel="Win" keyCode="0xE7"/><Key keyLabel="Menu" keyCode="0x76"/><Key keyLabel="Ctrl" keyCode="0xE4" weight="1.5"/></Layout>
</Keyboard>

左边是导航键盘  右边是数字键盘

导航键盘的lable以及对应keyCode如下:

<Keyboard><Layout><Key keyLabel="Vol Down ⇩" keyCode="0x86"/><Key keyLabel="Mute" keyCode="0x84"/><Key keyLabel="Vol Up ⇧" keyCode="0x85"/></Layout><Layout><Key keyLabel="Print Screen" keyCode="0x46"/><Key keyLabel="Scroll Lock" keyCode="0x47"/><Key keyLabel="Pause" keyCode="0x48"/></Layout><Layout><Key keyLabel="Insert" keyCode="0x49"/><Key keyLabel="Home" keyCode="0x4A"/><Key keyLabel="Page Up" keyCode="0x4B"/></Layout><Layout><Key keyLabel="Delete" keyCode="0x4C"/><Key keyLabel="End" keyCode="0x4D"/><Key keyLabel="Page Down" keyCode="0x4E"/></Layout><Layout><Key visible="false"/><Key keyLabel="↑" keyCode="0x52"/><Key visible="false"/></Layout><Layout><Key keyLabel="←" keyCode="0x50"/><Key keyLabel="↓" keyCode="0x51"/><Key keyLabel="→" keyCode="0x4F"/></Layout>
</Keyboard>

数字键盘的lable以及对应keyCode如下:

<Keyboard><Layout><Key keyLabel="Prev\n⇦" keyCode="0x80"/><Key keyLabel="Next\n⇨" keyCode="0x81"/><Key keyLabel="Stop" keyCode="0x82"/><Key keyLabel="Play\nPause" keyCode="0x83"/><Key visible="false"/></Layout><Layout><Key keyLabel="Num\nLock" keyCode="0x53"/><Key keyLabel="/" keyCode="0x54"/><Key keyLabel="*" keyCode="0x55"/><Key keyLabel="-" keyCode="0x56"/></Layout><Layout><Key keyLabel="7\nHome" keyCode="0x5F"/><Key keyLabel="8 ↑" keyCode="0x60"/><Key keyLabel="9\nPgUp" keyCode="0x61"/><Key keyLabel="+" keyCode="0x57"/></Layout><Layout><Key keyLabel="4\n←" keyCode="0x5C"/><Key keyLabel="5" keyCode="0x5D"/><Key keyLabel="6\n→" keyCode="0x5E"/><Key visible="false"/></Layout><Layout><Key keyLabel="1\nEnd" keyCode="0x59"/><Key keyLabel="2 ↓" keyCode="0x5A"/><Key keyLabel="3\nPgDn" keyCode="0x5B"/><Key visible="false"/></Layout><Layout><Key keyLabel="0\nIns" keyCode="0x62" weight="2.0"/><Key keyLabel=".\nDel" keyCode="0x63"/><Key keyLabel="Enter" keyCode="0x58"/></Layout>
</Keyboard>

按键事件都是一样的,主要就是keyCode不同,

@Overridepublic void onKeyUp(byte keyCode) {keyboardKeyUp(keyCode);}@Overridepublic void onKeyDown(byte keyCode) {keyboardKeyDown(keyCode);}private final static byte MODIFIER_BASE = (byte) 0xe0;private final static byte MODIFIER_COUNT = 8; /* left ctrl -> right gui */private byte[] mBuffer = new byte[8];byte id = 1;
public synchronized void keyDown(byte key) {if (key >= MODIFIER_BASE && key <= MODIFIER_BASE + MODIFIER_COUNT) {mBuffer[0] |= (1 << (key - MODIFIER_BASE));} else if ((key & 0x80) != 0) {mBuffer[1] |= (1 << (key & 0x07));} else {for (int i = 2; i < 8; i++) {if (mBuffer[i] == 0x00) {mBuffer[i] = key;break;}}}mHidDevice.sendReport(id, mBuffer);}public synchronized void keyUp(byte key) {if (key >= MODIFIER_BASE && key <= MODIFIER_BASE + MODIFIER_COUNT) {mBuffer[0] &= ~(1 << (key - MODIFIER_BASE));} else if ((key & 0x80) != 0) {mBuffer[1] &= ~(1 << (key & 0x07));} else {for (int i = 2; i < 8; i++) {if (mBuffer[i] == key) {mBuffer[i] = 0x00;break;}}}mHidDevice.sendReport(id, mBuffer);}

这样就可以了,很简单吧。

6,源码解析

客户端的BluetoothHidDevice和服务端的HidDevService都比较简单,很直接,完全没有拐弯抹角的地方, sendReport方法从客户端到服务端的过程如下,

回调的7个方法流程如下,以onAppStatusChanged回调为例,

7,小节

问题:1,回调的几个方法以及2个类还未弄清楚其作用。

2,客户端的BluetoothInputDevice以及客户端的HidService和HID协议的文件在一个文件夹下,那么这2个类的作用是什么呢?如何使用。

蓝牙hid协议源码解析相关推荐

  1. 蓝牙map协议源码解析

    MAP协议 使用场景:智能车载中同步短信,彩信等信息 1 协议概述 协议代码路径: frameworks\opt\bluetooth\src\android\bluetooth\client\ map ...

  2. 蓝牙avrcp协议源码分析

    原址:http://blog.csdn.net/u012439416/article/details/54348147 1,概述 1.1 avrcp协议 全称: Audio / Video Remot ...

  3. 蓝牙a2dp协议源码分析

    1,a2dp协议 1.1 a2dp协议 全称:Advanced Audio Distribution Profile 蓝牙音频传输协议 使用场景:主要是通过蓝牙将声音从一个设备传输到另一个设备. 市场 ...

  4. 代币标准--ERC1155协议源码解析

    ERC1155多代币标准 ERC1155结合了ERC20和ERC721的能力,这是一个标准接口,支持开发同质化的.半同质化的.非同质化的代币和其他配置的通用智能合约. IERC1155接口 // SP ...

  5. 代币标准--ERC721协议源码解析

    IERC165接口定义 interface IERC165 {function supportsInterface(bytes4 interfaceId) external view returns ...

  6. Dubbo源码解析-Dubbo服务消费者_Dubbo协议(一)

    前言: 在介绍完Dubbo 本地模式(Injvm协议)下的服务提供与消费后,上文我们又介绍了Dubbo远程模式(dubbo协议)下的服务暴露过程,本质上就是通过Netty将dubbo协议端口暴露出去, ...

  7. Thrift源码解析(二)序列化协议

    概述 对于一个RPC框架,定义好网络数据的序列化协议是最基本的工作,thrift的序列化协议主要包含如下几种: TBinaryProtocol TCompactProtocol TJSONProtoc ...

  8. 谷歌BERT预训练源码解析(二):模型构建

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_39470744/arti ...

  9. 彻底理解OkHttp - OkHttp 源码解析及OkHttp的设计思想

    OkHttp 现在统治了Android的网络请求领域,最常用的框架是:Retrofit+okhttp.OkHttp的实现原理和设计思想是必须要了解的,读懂和理解流行的框架也是程序员进阶的必经之路,代码 ...

最新文章

  1. 【C#】Gif文件生成
  2. 大满贯!清华学生超算团队获得国际大学生超级计算机竞赛(SC18)总冠军(附现场视频)...
  3. 追查连接mysql的客户端
  4. 下单问题分析及解决方式
  5. 今天起,踏踏实实做技术
  6. 基于.NetCore3.1搭建项目系列 —— 使用Swagger导出文档 (番外篇)
  7. vector父类类型可以存放子类吗_拼夕夕三轮面经:被问到反射和泛型的bug,你踏空了吗?...
  8. dylib java_使用单声道可执行文件捆绑.dylib文件
  9. c#截取两个指定字符串中间的字符串
  10. 使用一个DataContext,还是多个?
  11. 简明firewalld不断的更新中....
  12. 智慧交通信息服务平台产品解决方案
  13. html中加入点击事件,html中的点击事件
  14. 计算机在开机时会进行自检遇到,电脑开机自检卡住了怎么办
  15. 小成开发日记----物联网项目LoveTv实现web网页传输数据到单片机-表白女朋友(技术栈涉及web前端,php后端,c/c++ socket,嵌入式前后端)
  16. 计算机网络自顶向下-套接字编程作业
  17. cocos creator 显示截图并保存图片到手机
  18. 点,线,面,透视(手绘课)
  19. 【Elastic Search权威指南 读书小记3】ES之数据操作
  20. 华为机试—介绍、剖析、建议

热门文章

  1. SV环境搭建基础知识整合①
  2. 中国医学计算机成级别像杂志,中国医学计算机成像杂志
  3. 关于论文格式要求及字体大小
  4. win 10 slmgr.vbs -xpr 无法运行,被豆麦笔记打开解决方法
  5. 【MT7620】MT7620 WiFi驱动增加无线终端连接实时协商速率功能
  6. sed: -e expression #1, char 0: no previous regular expression
  7. 总谐波失真80_总谐波失真
  8. centos内核升级的两种方法
  9. HTML中视频默认显示自定义图片
  10. android应用 数量,谷歌Android应用数量超40万 免费应用占总数2/3