Android Service创建USB HOST通信

android usb解析(二)UsbHostManager(and6.0) 之前在Android5.1的时候我们分析过UsbDevicemanager,现在Android6.0我们不准备分析UsbDevicemanager了,因为大致原理差不多。这里准备分析下UsbHostManager。 UsbHostManager的初始化 UsbHostManager和UsbDeviceManager一样都是在UsbService中新建的。 public UsbServ 阅读详情

      之前做了一个关于Android USB通信的Case,通过Android的USB总线给Zigbee供电,和板载的Zigbee(基于Zigbee的自组网)进行通信。要使用Android的USB Host功能,首先你需要确定你的平板(手机)设备是否支持USB Host的功能,你可以从手机开发商的简介里面看到,这个功能是由CPU直接关联的,和软件没有关系,所以,你可以把你的外设模块插进去你的Android设备看看有没有反应(比如:指示灯亮),假如没有反应,那肯定是不支持的。

废话说了那么多了,进入正题。

我的案子是把USB的通信写在Service里面的,有不了解Service的,先看Service的相关内容。下面列出了Android对USB的支持。

点开USB,你可以看到Android USB支持的两种模式:

第一种就是HOST模式:Android设备为USB总线和外设供电,数据传输是双向的。

第二种是Accessory模式:即附件模式,Android作为附件,手机和电脑连接,通常是这种模式,由USB Device端向总线供电,数据传输方向是双向的。这就是为什么手机插到电脑上可以充电的原因。

我们讨论的是第一种模式——HOST。

在讨论具体代码之前,我需要先讲一下再host模式下面的调试办法,因为数据线的端口被外设使用了,那么,传统的连接数据线调试的方法已经不行了。官网给出了解决办法:

1、请把你的Android设备用数据线连接到电脑,当然,你也要把Android设备的wifi打开。

2、在windows命令行下,进入SDK platform-tools/ 目录(具体看你把SDK安装在哪个目录了),执行 adb tcpip 5555 回车。这里其实是打开了adb调试的无线端口(Android设备在电脑上的端口映射),其实后面的数字你可以随便来,只要端口没有被占用。

3、adb connect <device-ip-address>:5555键入回车,这里的device-ip-address是你Android端的IP地址。

4、最后adb usb回车,假如没有问题,现在你已经可以在eclipse上看到logcat的输出了。

其实还有个简单的办法,笔者是使用这个办法,你可以在应用商店上下一个无线ADB工具,随便哪个都可以,这类工具就是在Android端做了上面的那些工作,而且还不用连数据线,但是第三步的那个操作还是要你在windows的命令行窗口手动输入的。

通过上面的操作,你已经可以用无线下载你写的程序、调试了。

在写代码之前,我们必须在我们的manifest文件里面声明我们要使用USB Host的功能。

方法:添加权限标签


[html]  view plain copy
  1. <uses-feature  
  2.         android:name="android.hardware.usb.host"  
  3.         android:required="true" />  
  4.   
  5.     <uses-permission  
  6.         android:name="android.hardware.usb.host"  
  7.         android:required="false" />  

上面的代码,会表明本应用程序是要使用host的功能的。

除开声明外,你还要添加一个关于设备信息的xml文件,这个文件放在res目录下的xml目录下:

里面写好了我们要发现的具体设备的PID、VID,我只写了这两个,这是我在测试阶段用的一个设备的:


[html]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.   
  4.     <usb-device  
  5.         product-id="5800"  
  6.         vendor-id="1105" />  
  7.   
  8. </resources>  

里面的两个id你可以通过后面的枚举设备中打印出来。这样是方便设备一插入 ,系统就会提醒用户打开对设备进行声明的程序。

当然,你还要manifest中的某个activity下声明,你使用了这个文件,那么,一旦你打开应用,就会自动跳转到你声明的那个activity:


[html]  view plain copy
  1. <activity  
  2.             android:name="cyc.gzpl.gzplv3.WelcomeActivity"  
  3.             android:launchMode="standard"  
  4.             android:screenOrientation="landscape"  
  5.             android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >  
  6.             <intent-filter>  
  7.                 <action android:name="android.intent.action.MAIN" />  
  8.   
  9.                 <category android:name="android.intent.category.LAUNCHER" />  
  10.             </intent-filter>  
  11.             <intent-filter>  
  12.                 <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />  
  13.             </intent-filter>  
  14.   
  15.             <meta-data  
  16.                 android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"  
  17.                 android:resource="@xml/device_filter" />  


我放在了MainActivity。

建立了一个Service类:

[java]  view plain copy
  1. public class ZigbeeService extends Service {  
  2. //这里定义一些必要的变量  
  3. <span style="white-space:pre">    </span>@Override  
  4.     public void onStart(Intent intent, int startId) {  
  5.         // TODO Auto-generated method stub  
  6.         super.onStart(intent, startId); // 每次startService(intent)时都回调该方法  
  7.         System.out.println("进入service的onStart函数");  
  8.         myUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); // 获取UsbManager  
  9.           
  10.         // 枚举设备  
  11.         enumerateDevice(myUsbManager);  
  12.         // 查找设备接口  
  13.         getDeviceInterface();  
  14.         // 获取设备endpoint  
  15.         assignEndpoint(Interface2);  
  16.         // 打开conn连接通道  
  17.         openDevice(Interface2);  
  18. }  

这一段代码,基本上已经完成了和USB建立连接了。我们一个个来分析:


[java]  view plain copy
  1. myUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); // 获取UsbManager  

这条代码的作用是获取一个UsbManager的实例,通过它我们可以获取USB的状态,并且和USB设备进行通信。总的来说,它管理了USB设备。

你把你的外设插入USB接口后,紧接着就是调用美剧USB总线上的usb设备了,具体函数实现如下:


[java]  view plain copy
  1. // 枚举设备函数  
  2.     private void enumerateDevice(UsbManager mUsbManager) {  
  3.         System.out.println("开始进行枚举设备!");  
  4.         if (mUsbManager == null) {  
  5.             System.out.println("创建UsbManager失败,请重新启动应用!");  
  6.             info.setText("创建UsbManager失败,请重新启动应用!");  
  7.             return;  
  8.         } else {  
  9.             HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();  
  10.             if (!(deviceList.isEmpty())) {  
  11.                 // deviceList不为空  
  12.                 System.out.println("deviceList is not null!");  
  13.                 Iterator<UsbDevice> deviceIterator = deviceList.values()  
  14.                         .iterator();  
  15.                 while (deviceIterator.hasNext()) {  
  16.                     UsbDevice device = deviceIterator.next();  
  17.                     // 输出设备信息  
  18.                     Log.i(TAG, "DeviceInfo: " + device.getVendorId() + " , "  
  19.                             + device.getProductId());  
  20.                     System.out.println("DeviceInfo:" + device.getVendorId()  
  21.                             + " , " + device.getProductId());  
  22.                     // 保存设备VID和PID  
  23.                     VendorID = device.getVendorId();  
  24.                     ProductID = device.getProductId();  
  25.                     // 保存匹配到的设备  
  26.                     if (VendorID == 1105 && ProductID == 5800) {  
  27.                         myUsbDevice = device; // 获取USBDevice  
  28.                         System.out.println("发现待匹配设备:" + device.getVendorId()  
  29.                                 + "," + device.getProductId());  
  30.                         Context context = getApplicationContext();  
  31.                         Toast.makeText(context, "发现待匹配设备", Toast.LENGTH_SHORT)  
  32.                                 .show();  
  33.                     }  
  34.                 }  
  35.             } else {  
  36.                 info.setText("请连接USB设备至PAD!");  
  37.                 Context context = getApplicationContext();  
  38.                 Toast.makeText(context, "请连接USB设备至PAD!", Toast.LENGTH_SHORT)  
  39.                         .show();  
  40.             }  
  41.         }  
  42.     }  


通过上面的枚举函数,总线上面的设备都会被列出来,你可以选择符合你要求的设备,把它放到一个UsbDevice的实例里面。接下来还不能对USB进行直接通信。。。

接下来的工作:查找外设的usb接口,我的zigbee上面有两个接口,一个0接口,还有一个2接口,我在这里吃了很大的亏,我一直忽视了2接口,一直死在0接口那里,0接口是用来进行配置的,作为用户层,是用不到的,2接口作为数据传输口。具体情况可能是要根据你的外设的情况来定的,推荐你接口的信息都要打印出来,并且都试一下。

下面是查询接口的具体实现:


[java]  view plain copy
  1. // 寻找设备接口  
  2.     private void getDeviceInterface() {  
  3.         if (myUsbDevice != null) {  
  4.             Log.d(TAG, "interfaceCounts : " + myUsbDevice.getInterfaceCount());  
  5.             for (int i = 0; i < myUsbDevice.getInterfaceCount(); i++) {  
  6.                 UsbInterface intf = myUsbDevice.getInterface(i);  
  7.   
  8.                 if (i == 0) {  
  9.                     Interface1 = intf; // 保存设备接口  
  10.                     System.out.println("成功获得设备接口:" + Interface1.getId());  
  11.                 }  
  12.                 if (i == 1) {  
  13.                     Interface2 = intf;  
  14.                     System.out.println("成功获得设备接口:" + Interface2.getId());  
  15.                 }  
  16.             }  
  17.         } else {  
  18.             System.out.println("设备为空!");  
  19.         }  
  20.   
  21.     }  

把获取到的接口,存放在一个UsbInterface实例里面。接下来还是不能直接通信的。。。。。

接下来,我们要分配接口的端点:

[java]  view plain copy
  1. // 分配端点,IN | OUT,即输入输出;可以通过判断  
  2.     private UsbEndpoint assignEndpoint(UsbInterface mInterface) {  
  3.   
  4.         for (int i = 0; i < mInterface.getEndpointCount(); i++) {  
  5.             UsbEndpoint ep = mInterface.getEndpoint(i);  
  6.             // look for bulk endpoint  
  7.             if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {  
  8.                 if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {  
  9.                     epBulkOut = ep;  
  10.                     System.out.println("Find the BulkEndpointOut," + "index:"  
  11.                             + i + "," + "使用端点号:"  
  12.                             + epBulkOut.getEndpointNumber());  
  13.                 } else {  
  14.                     epBulkIn = ep;  
  15.                     System.out  
  16.                             .println("Find the BulkEndpointIn:" + "index:" + i  
  17.                                     + "," + "使用端点号:"  
  18.                                     + epBulkIn.getEndpointNumber());  
  19.                 }  
  20.             }  
  21.             // look for contorl endpoint  
  22.             if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_CONTROL) {  
  23.                 epControl = ep;  
  24.                 System.out.println("find the ControlEndPoint:" + "index:" + i  
  25.                         + "," + epControl.getEndpointNumber());  
  26.             }  
  27.             // look for interrupte endpoint  
  28.             if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_INT) {  
  29.                 if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {  
  30.                     epIntEndpointOut = ep;  
  31.                     System.out.println("find the InterruptEndpointOut:"  
  32.                             + "index:" + i + ","  
  33.                             + epIntEndpointOut.getEndpointNumber());  
  34.                 }  
  35.                 if (ep.getDirection() == UsbConstants.USB_DIR_IN) {  
  36.                     epIntEndpointIn = ep;  
  37.                     System.out.println("find the InterruptEndpointIn:"  
  38.                             + "index:" + i + ","  
  39.                             + epIntEndpointIn.getEndpointNumber());  
  40.                 }  
  41.             }  
  42.         }  
  43.         if (epBulkOut == null && epBulkIn == null && epControl == null  
  44.                 && epIntEndpointOut == null && epIntEndpointIn == null) {  
  45.             throw new IllegalArgumentException("not endpoint is founded!");  
  46.         }  
  47.         return epIntEndpointIn;  
  48.     }  
usb的端点不是随便分配的,有IN/OUT之分,前者是输入,后者是输出。


分配到的端点,用UsbEndpoint的实例存起来。Endpoint是用来传输数据的,但是,接下来,还是不能进行通信的。。。。。

我们要建立外设和Android设备的连接才行,也就是打开设备的连接,不然怎么通信呢?代码如下:


[java]  view plain copy
  1. // 打开设备  
  2.     public void openDevice(UsbInterface mInterface) {  
  3.         if (mInterface != null) {  
  4.             UsbDeviceConnection conn = null;  
  5.             // 在open前判断是否有连接权限;对于连接权限可以静态分配,也可以动态分配权限  
  6.             if (myUsbManager.hasPermission(myUsbDevice)) {  
  7.                 conn = myUsbManager.openDevice(myUsbDevice);  
  8.             }  
  9.   
  10.             if (conn == null) {  
  11.                 return;  
  12.             }  
  13.   
  14.             if (conn.claimInterface(mInterface, true)) {  
  15.                 myDeviceConnection = conn;  
  16.                 if (myDeviceConnection != null)// 到此你的android设备已经连上zigbee设备  
  17.                     System.out.println("open设备成功!");  
  18.                 final String mySerial = myDeviceConnection.getSerial();  
  19.                 System.out.println("设备serial number:" + mySerial);  
  20.             } else {  
  21.                 System.out.println("无法打开连接通道。");  
  22.                 conn.close();  
  23.             }  
  24.         }  
  25.     }  

打开连接后,我们会得到一个UsbDeviceConnection的实例,我们的通信都是建立在一个可用的USB的连接上。

终于可以通信了。。。。。。

下面讲一下USB传输在Android里面的几个函数。。。。。

通常有两种传输方式,一种叫控制传输,具体函数解释如下:


这个传输函数有个特点,它是用于端点0的传输,具体,我也没用过,参考文档上说,0端点是用来配置用的,所以我也没有深究。

另外一个函数bulk传输,它用于usb大流量数据的一个传输,我使用的是这个。


下面是我用这个函数实现读写USB的代码:


[java]  view plain copy
  1. // 发送数据  
  2.     private void sendMessageToPoint(byte[] buffer) {  
  3.         // bulkOut传输  
  4.         if (myDeviceConnection  
  5.                 .bulkTransfer(epBulkOut, buffer, buffer.length, 0) < 0)  
  6.             System.out.println("bulkOut返回输出为  负数");  
  7.         else {  
  8.             System.out.println("Send Message Succese!");  
  9.         }  
  10.     }  

当发送数据的时候,我们使用的是out端点。
[java]  view plain copy
  1. // 从设备接收数据bulkIn  
  2.     private byte[] receiveMessageFromPoint() {  
  3.         byte[] buffer = new byte[15];  
  4.         if (myDeviceConnection.bulkTransfer(epBulkIn, buffer, buffer.length,  
  5.                 2000) < 0)  
  6.             System.out.println("bulkIn返回输出为  负数");  
  7.         else {  
  8.             System.out.println("Receive Message Succese!"  
  9.             // + "数据返回"  
  10.             // + myDeviceConnection.bulkTransfer(epBulkIn, buffer,  
  11.             // buffer.length, 3000)  
  12.                     );  
  13.         }  
  14.         return buffer;  
  15.     }  

接收数据的时候,使用的IN端点。

上面打开设备的时候得到的UsbDeviceConnection的实例和端点分配分配的端点,将在这里被使用到。

OK!~~~

到这里,大部分的任务都完成了,剩下的工作就是写一些逻辑代码去调用bulk传输函数就可以了,这里我就不多说了。

另外,在Service是需要在manifest里面注册的,程序跑起来以后,Service是完全和程序的其他部分并行的,不影响程序的正常运行,也不会阻塞界面,实现了,后台与Zigbee的通信,这里主要讲的是usb host在Android里面的几个主要的点,关于Zigbee就没有多说了,无非就是一些看用户手册的活。

笔者了解有限,有不对的地方,请指出来,大家一起交流、探讨。。。THKS

Android NFC之仿真卡模式 NFC三种模式之仿真卡模式NFC的工作模式仿真卡模式Android仿真卡实现1.申请权限2.HostApduService实现3.注册Service4.apduservice.xml配置5.动态注册AID读卡器模式 NFC的工作模式 读卡器模式(Reader/writer mode)、仿真卡模式(Card Emulation Mode)、点对点模式(P2P mode)。 仿真卡模式 仿真卡模式就是将支持NFC的手机或其它电子设备当成借记卡、信用卡、公交卡、门禁卡等IC卡使用。基本原理是将相应IC卡中的信息( 阅读详情

相关推荐

android usb Host模式下与usb Hid 设备的通信

做android 与USB HID设备的通信有段时间了,总结一下遇到的问题和解决方法: 1,第一次遇到的问题:android 版本低不支持usb hid, 被要求做相关项目的时候,就从mUsbManager.getDeviceList开始,郁闷了一周,就是返回NULL,从google上查找所有关于android usb的资料,最后才发现,android设备是2.3的不支持android.usb

奋起追赶 1万+

USBService源码分析(一)

1、概述

Flying snow 2301

Android USB通信

1.说在前面的话 这次做了一个项目,要求android端与外接设备进行通信,用到的是otg线连接开发板。然而网上有关USB host通信的资料很少,这里我就把自己的想法以及遇到的坑说一下吧()。 2.Android Studio 配置 2.1Manifest配置

yang_jian1314的博客 9751

android usb流程

原帖地址:http://www.hzlitai.com.cn/article/ARM11/SYSTEM/Android_USB_develop_lx.html http://blog.pfan.cn/liyutai/53854.html 这是关于USB Mass Storage的架构图。   上图关系为:     StorageManager为Client,MountSe

harvey2008的专栏 951

Android USB Host通信实践:示例源码详解

USB主机模式是一种允许Android设备扮演传统计算机角色,能够连接和管理USB设备的模式。在这个模式下,Android设备可以读写外部USB设备的数据,比如打印机、键盘、外部存储等。理解这种模式对于开发者而言至关重要,因为它为应用程序提供了与硬件设备交互的全新方式。

weixin_42327217的博客 1303

电路课设-音响分频器电路设计

(一)题目简介 1.一阶分频器电路设计 假定高音和低音扬声器均等效为 16 欧姆电阻,设计如图 2 的简单分频器电 路,要求高低频分界(两个滤波器的截止频率)为 5kHz。 1) 写出高音扬声器和低音扬声器电压对于 vs 的传递函数,确定电路中电 容 C 和电感 L 的元件值;2)利用 AC 频率扫描分析求出两个扬声器电压的频率响应曲线,验证计算 结果。用包含高低频成分的电压 vs 激励进行测量验证。 3)计算并利用 EWB 仿真证明从 vs 看进去的阻抗为一常数 16 欧姆。

weixin_53507617的博客 1万+

【转】Android Service创建USB HOST通信

之前做了一个关于AndroidUSB通信的Case,通过Android的USB总线给Zigbee供电,和板载的Zigbee(基于Zigbee的自组网)进行通信。要使用Android的USB Host功能,首先你需要确定你的平板(手机)设备是否支持USB Host的功能,你可以从手机开发商的简介里面看到,这个功能是由CPU直接关联的,和软件没有关系,所以,你可以把你的外设模块插进去你的Androi...

weixin_30791095的博客 103

【WorkBuddy】WorkBuddy 智能体快速上手:从零到一的实践指南

文章摘要: 传统自动化脚本难以应对灵活多变的自然语言需求,导致逻辑复杂、维护成本高。智能体(Agent)通过理解语义意图、动态决策和松耦合组件解决了这些问题。WorkBuddy采用声明式配置,通过可视化界面定义意图、实体和对话策略,无需编码即可快速构建智能体。其核心组件包括意图分类、实体提取、对话策略、故事样本和回退机制,适用于客服支持、知识问答等高频场景。通过环境准备(Python/Node.js/Redis)和简单配置,用户可以快速搭建可运行的智能体,显著提升自动化效率。

ruiqideng的博客 1631

Android USB通信(host转串口)

公司属于北斗通信行业,项目大多都需要和各式各样的硬件设备相结合来满足项目需求,因此所涉及到的各种技术也相对比较冷门。前段时间有个项目用到了一款定制 Android 设备,其中有多个接口,包括两个 USB 接口和一个 RS232 串口,需要用到其中一个 USB 连接北斗设备实现指令互通,经过摸索现在也大致了解了 Android USB(host)通信流程后续还有另一个项目则用到了 USB(accessory)有空再写一篇。在这里记录和分享一下,有错漏或可优化之处欢迎大家留言。

无 1万+

数字IC后端面试题目汇总含解析,ICer上岸必备!

今天IC修真院为大家带来了数字IC后端的面试题目,希望大家能够用得上。

coachip的博客 2447

如何使用 SAP ABAP Development Tool 连接 SAP BTP 上的免费 ABAP 编程环境

在云端环境编写 ABAP 代码会遇到一些限制,比如你无法在云端 ABAP 编程环境进行发生在传统 SAPGUI 里的 Dynpro 和 Screen 编程。部分在 SAPGUI 里使用的 List 处理相关的关键字比如 WRITE,还有 CALL TRANSACTION 等代码,也无法在云端使用。 当然如果大家觉得上面提到的这些限制不会影响自己的 ABAP 学习,就可以继续本文的阅读,使用 ABAP Development Tool 登录云端的 ABAP 编程环境。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1517

android与usb通信,android USB通信

USB模式支持USB accessory模式和USB host模式。通过这两种模式,android支持各种各样的USB 外围设备和USB 配件(硬件需要实现android配件协议)。USB accessory模式中,外接的USB硬件设备扮演USB 主机,这种方式使不支持USB host模式的android设备有了与USB硬件交互的能力,不过android USB 配件必须遵循android acc...

weixin_42519489的博客 2480

基于YOLO系列的安全帽检测系统:从理论到实现的完整指南

安全帽检测作为计算机视觉在工业安全领域的重要应用,近年来得到了广泛关注。本文详细介绍了基于YOLOv5、YOLOv6、YOLOv7和YOLOv8的安全帽检测系统的完整实现方案,包括算法原理、数据集构建、模型训练、性能优化以及完整的UI界面设计。通过对比分析不同YOLO版本的性能差异,本文为工业安全检测系统的开发提供了全面的技术参考和实践指导。

YOLO 364

Android USB通信学习 USB Host设备通信实际应用

Android4.0之后,OTG开始普及,我们可以拓展U盘、鼠标等设备用于安卓设备。那么就需要了解USB的数据交换。 USB设备分为Host主设备和Slave从设备,我们通常理解的OTG就是安卓作为”host”:通过安卓设备作为主设备进行设备间通信。安卓中也封装好了API使我们不必研究USB协议便能进行简单设备通信。 首先 USB Host需要3.1以上的安卓版本支持,即minSdkVersi

duhanhao007的博客 1786

什么是华为OD?怎么才能通过华为OD机试?华为OD机试怎么刷题?(2024最新华为OD机试E卷更新中)

华为OD是Outsourcing Dispacth模式,是华为和外企德科联合招聘的简称。目前华为大多数是OD招聘。OD模式也是华为提出的一种新的用工形式,每年都会从OD项目挑优秀员工转为正编。所有OD和正式员工一样对待,没有差别,部门平时开会、评审等活动都是一起参加的,是同薪同酬,都是由华为的HR直接定的薪资,看的是我们技术能力。华为是大企业,能到华为上班也是有能力的,每个部门都有好多职位,是金子,在哪都会发光。

KJ.JK 11万+

【软件系统架构】系列六:系统工程

系统工程是一种跨学科方法论,用于分析、设计、集成和管理复杂系统的全生命周期。其核心特点包括系统性思维、全周期管理、跨学科协作和需求导向。主流采用V模型生命周期,涵盖需求分析、系统设计、实现、测试验证及运维退役等阶段。核心工作方法包括需求工程、系统建模、接口设计、风险管理等。系统工程与项目管理协同,分别侧重技术实现和进度资源管理。应用领域覆盖航天军工、智能制造、智慧城市等。未来将向AI融合、数字孪生、模型驱动工程等方向发展,为复杂系统开发提供系统化协作范式。

moton2017的博客 2257
上一篇: Android 热敏打印机打印二维码
下一篇: 异步JavaScript的进化
offbye
offbye 领域专家: 操作系统技术领域 领域专家: 操作系统技术领域
博客等级 码龄24年 1309粉丝 252原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值