Zebra 打印机 Android 端驱动接口开发及调用案例
文章目录
- Zebra 打印机 Android 端驱动接口开发及调用
- GitHub 源码
- 开发步骤
- 环境配置
- Zebra SDK 资源下载
- Android 开发环境搭建
- 新建Android项目
- 新建 Android Library
- 导入 Zebra 驱动包
- Android Library 权限配置
- ZPL II 语法在线测试
- 主体功能开发
- 打包 arr 文件
- 调用 arr 接口
- 附加:APP 打包成 APK 文件
Zebra 打印机 Android 端驱动接口开发及调用
Android 设备驱动 Zebra ZQ520 移动式打印机打印条码信息案例
GitHub 源码
- 点击跳转
开发步骤
环境配置
- 硬件环境
- Zebra ZQ520 移动打印机 1 台
- Android 设备 1 台
- 打印纸(50mm * 40mm)
- 软件环境
- Android Studio 3.2
- gradle:3.2.0
- Android Studio 3.2
Zebra SDK 资源下载
方法1:官网下载(需要各种注册信息)
由于我是 windows 系统,所以点击 windows Installer,下载完成后,在 windows 系统中直接双击安装,安装完成后在目录:\link_os_sdk\android\v2.14.5198\lib 目录下可以找到所需要的 jar 包。方法2:CSDN 资源下载(会需要少量积分)
方法3:百度网盘下载(链接:https://pan.baidu.com/s/1tVg6lW52SSeh3j6kW7ih8Q 提取码: qfc8 )
Android 开发环境搭建
正常来讲,如果是开发完整的 app 引用,则直接引入上一步中的 jar 包就可以调用 Zebra 的驱动接口了。
但是由于业务需求,我这边只负责开发一个处理拆分数据、生成ZPL命令、驱动列印功能的接口。
其他同事负责开发 Android 客户端并调用我提供的接口
所以,本案例采用的开发模式是:
- 开发 Android Library ,打包成 arr 文件;
- 新建空 App 应用,调用打包的 arr 接口测试。
- 测试成功后,将测试案例与 arr 接口发送给调用者使用。
新建Android项目
输入项目名称、包名,选择项目目录。
选择支持的驱动环境。选择 Phone,最低 Android 4.0
创建一个空模板,方便后续测试。
Activity 的 name 和 layout name,默认即可,点击 finish
新建完成后, Gradle 会自动同步,此时需要保持网络畅通(需要一段时间,耐心等待即可。如果没有网络,需要保证 gradle 的离线版本支持)
如果遇到如下错误:
Unable to resolve dependency for ‘:app@debug/compileClasspath’: Could not find any version that matches com.android.support:appcompat-v7:29.+.
Open File
Show Details
这是因为没有找到符合正则验证: com.android.support:appcompat-v7:29.+. 版本的文件
解决方案:
简单暴力:放宽该包的正则验证规则。
步骤:
- 点击报错信息中的 Open File 超链接打开对应的 build gradle 文件;
- 找到 com.android.support:appcompat-v7:29.+ 这一行;
- 删除 29. 几个字符,保存
- 点击上方的 “try agine”,或者 “File --> Sync Project With Gradle Files” 重新同步 gradle 文件
至此,一个空的 Android 项目就新建完成了。
新建 Android Library
- 在项目文件上右键,或者 File --> new module
- 选择 Android Library
- 输入 library name,选择 minmum SDK 版本(建议和 Android 项目相同),点击 finish。
如果遇到如下错误:
Unable to resolve dependency for ‘:app@debug/compileClasspath’: Could not find any version that matches com.android.support:appcompat-v7:29.+.
Open File
Show Details
解决方案和上面相同(注意Library有自己对应的 build.gradle 文件,建议 点击报错信息中 open file 超链接跳转)
导入 Zebra 驱动包
- 点击左上角资源总览视图中的 Android 部分,切换为 project 显示方式
- 引入 Zebra 驱动文件到 Android Library 模块的 libs 目录下(第一步中下载的 jar 包)
- 选中所有 jar 包,右键,Add as Library,选择 add to module 为 刚才新建的 Android Library
Add 成功后,在 Android Library 对应的 build.gradle 文件下,会自动生成如下一段代码:
dependencies {...implementation files('libs/commons-io-2.2.jar')implementation files('libs/commons-net-3.1.jar')implementation files('libs/commons-validator-1.4.0.jar')implementation files('libs/httpcore-4.3.1.jar')implementation files('libs/httpmime-4.3.2.jar')implementation files('libs/jackson-annotations-2.2.3.jar')implementation files('libs/jackson-core-2.2.3.jar')implementation files('libs/jackson-databind-2.2.3.jar')implementation files('libs/opencsv-2.2.jar')implementation files('libs/snmp6_1.jar')implementation files('libs/ZSDK_ANDROID_API.jar')
}
如果上一步中右键没有找到 “Add as Library” 选项,也可以直接手动在对应的 build.gradle 文件中添加如上代码(注意路径)
Android Library 权限配置
由于本案例采用 BlueTooth 连接,所以,需要配置 BlueTooth 赋予蓝牙的访问权限。
在 Android Library 模块(zebraprinter)下依次展开 src --> main --> AndroidMainfest.xml 文件。加入如下两行代码:
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
如果需要其他需求,也可以在这里继续配置权限(如:后续可能需要获取主机mac地址,所以我再加入WIFI_STATE权限)
ZPL II 语法在线测试
推荐一个在线测试 ZPL II 的网站。点击跳转
在这里,你可以在线编写 ZPL 代码,并随时点击 redraw 按钮预览结果,非常方便!
主体功能开发
本案例的主体需求为:收到一份信息,将该信息进行拆分,打印出两份信息。
Android Library 的代码基本结构如下:
其中:
- Entity 包中存放了两个实体:
- ResultObj:返回信息实体类。包含一个 boolean 类型的执行状态,和一个 String 类型的执行信息
- ZeroSymbolBill:存储案例中收到与拆分的信息。为了方便操作。
- Utils 包中存放了一个工具类:
- Utils:工具类。包含一个生成唯一码 GUID 的静态方法。
- ZebraPrinter 包中存放了打印机相关代码
- ZQ520 Printer:存放了调用 ZQ520 打印机的主体代码
具体代码如下:
package com.amborsecdmeng.demo.entity;/*** Result Object*/
public class ResultObj {/*** 状态*/private boolean status;/*** 信息*/private String message;public ResultObj() {this.status = false;}public ResultObj(boolean status) {this.status = status;}public ResultObj(boolean status, String message) {this.status = status;this.message = message;}public boolean isStatus() {return status;}public void setStatus(boolean status) {this.status = status;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}
}
package com.amborsecdmeng.demo.entity;/*** Model of ZeroSymbolBill** Example:** W,NEW00182631190729C0001,P2a-J60102,2T459M000-000-G5,20190729,WmL-J76036,2200,PCS,VCN00182631190729C0001* W,NEW00182631190729C0002,P2a-J60102,2T459M000-000-G5,20190729,WmL-J76036,5000,PCS,VCN00182631190729C0001*/
public class ZeroSymbolBill {/*** 类型:W*/private String type;/*** 料号:2T459M000-000-G5*/private String pn;/*** 数量:7200*/private Integer qty;/*** 拆分:5000*/private Integer splitQty;/*** 单位:PCS*/private String unit;/*** 旧 GUID:VCN00182631190729C0001*/private String oldGuid;/*** 新 GUID:NEW00182631190729C0001*/private String newGuid;/*** 日期:20190729*/private String date;/*** 预留字段 1:P2a-J60102*/private String var1;/*** 预留字段 2:WmL-J76036*/private String var2;/*** Constructor without params*/public ZeroSymbolBill() {}/*** Constructor with all params** @param type* @param newGuid* @param var1* @param pn* @param date* @param var2* @param qty* @param unit* @param oldGuid* @param splitQty*/public ZeroSymbolBill(String type, String newGuid, String var1, String pn, String date, String var2, Integer qty, String unit, String oldGuid, Integer splitQty) {this.type = type;this.newGuid = newGuid;this.var1 = var1;this.pn = pn;this.date = date;this.var2 = var2;this.qty = qty;this.unit = unit;this.oldGuid = oldGuid;this.splitQty = splitQty;}/*** Getter & Setter*/public String getType() {return type;}public void setType(String type) {this.type = type;}public String getPn() {return pn;}public void setPn(String pn) {this.pn = pn;}public Integer getQty() {return qty;}public void setQty(Integer qty) {this.qty = qty;}public Integer getSplitQty() {return splitQty;}public void setSplitQty(Integer splitQty) {this.splitQty = splitQty;}public String getUnit() {return unit;}public void setUnit(String unit) {this.unit = unit;}public String getOldGuid() {return oldGuid;}public void setOldGuid(String oldGuid) {this.oldGuid = oldGuid;}public String getNewGuid() {return newGuid;}public void setNewGuid(String newGuid) {this.newGuid = newGuid;}public String getDate() {return date;}public void setDate(String date) {this.date = date;}public String getVar1() {return var1;}public void setVar1(String var1) {this.var1 = var1;}public String getVar2() {return var2;}public void setVar2(String var2) {this.var2 = var2;}
}
package com.amborsecdmeng.demo.utils;import java.util.UUID;public class Utils {public static String GUID() {UUID uuid = UUID.randomUUID();String str = uuid.toString();String uuidStr = str.replace("-", "");return uuidStr;}
}
package com.amborsecdmeng.demo.zerbraprinter;import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.net.wifi.WifiManager;import com.amborsecdmeng.demo.entity.ResultObj;
import com.amborsecdmeng.demo.entity.ZeroSymbolBill;
import com.amborsecdmeng.demo.utils.Utils;
import com.zebra.sdk.comm.BluetoothConnection;
import com.zebra.sdk.comm.Connection;
import com.zebra.sdk.comm.ConnectionException;
import com.zebra.sdk.comm.TcpConnection;
import com.zebra.sdk.printer.PrinterLanguage;
import com.zebra.sdk.printer.PrinterStatus;
import com.zebra.sdk.printer.ZebraPrinter;
import com.zebra.sdk.printer.ZebraPrinterFactory;
import com.zebra.sdk.printer.ZebraPrinterLinkOs;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Set;/*** ZQ520 Printer*/
public class ZQ520Printer {private Context context;public ZQ520Printer(Context context) {this.context = context;}private Connection connection = null;private boolean isConnByBluetooth = true;private String bluetoothMacAddress = "";// Test Machine mac address: AC:3F:A4:E4:D6:3Fprivate String tcpAddress = "127.0.0.1";private Integer tcpPortNumber = 0;private String printerStatusMsg = "";/*** ZeroSymbolBill Printer** @param codeMsg BQ code message.* Example:* W,NEW00182631190729C0001,P2a-J60102,2T459M000-000-G5,20190729,WmL-J76036,2000,PCS,VCN00182631190729C0001* @param splitQty split quantity* @return*/public ResultObj zeroSymbolBill(String codeMsg, Integer splitQty) {String[] codeMsgArr = codeMsg.split(",");ArrayList<ZeroSymbolBill> zsbs = new ArrayList<>();/* BQ code message before split. include split quantity */ZeroSymbolBill zsb = new ZeroSymbolBill();try {zsb.setType(codeMsgArr[0].trim()); // type.zsb.setNewGuid(codeMsgArr[1].trim()); // current guid. -- after split. It will become the old guidzsb.setVar1(codeMsgArr[2].trim()); //zsb.setPn(codeMsgArr[3].trim()); // p/nzsb.setDate(codeMsgArr[4].trim()); // datezsb.setVar2(codeMsgArr[5].trim()); //zsb.setQty(Integer.valueOf(codeMsgArr[6].trim())); // quantityzsb.setUnit(codeMsgArr[7].trim()); // unitzsb.setSplitQty(splitQty);} catch (NumberFormatException e) {return new ResultObj(false, "Exc-03: "+e.getMessage());}if (zsb.getSplitQty() >= zsb.getQty())return new ResultObj(false, "the split quantity must be less than quantity");/* BQ code message after split. return an arrayList */zsbs.add(new ZeroSymbolBill(zsb.getType(),Utils.GUID(), // set new guid for BQ code after splitzsb.getVar1(),zsb.getPn(),zsb.getDate(),zsb.getVar2(),zsb.getSplitQty(),// first split. quantity = split quantityzsb.getUnit(),zsb.getNewGuid(), // become the old guid after split0));zsbs.add(new ZeroSymbolBill(zsb.getType(),Utils.GUID(), // set new guid for BQ code after splitzsb.getVar1(),zsb.getPn(),zsb.getDate(),zsb.getVar2(),zsb.getQty() - zsb.getSplitQty(),// second split. quantity = quantity - split quantityzsb.getUnit(),zsb.getNewGuid(), // become the old guid after split0));/* BQ code split completion */if (isConnByBluetooth) {/* get first bonded mac address */bluetoothMacAddress = findBluetoothMacAddress().get(0);connection = new BluetoothConnection(bluetoothMacAddress);} else {try {connection = new TcpConnection(tcpAddress, tcpPortNumber);} catch (NumberFormatException e) {return new ResultObj(false, "Exc-01: Tcp connection open failed");}}try {connection.open();ZebraPrinter printer = ZebraPrinterFactory.getInstance(connection);ZebraPrinterLinkOs linkOsPrinter = ZebraPrinterFactory.createLinkOsPrinter(printer);PrinterStatus printerStatus = (linkOsPrinter != null) ? linkOsPrinter.getCurrentStatus() : printer.getCurrentStatus();if (printerStatus.isReadyToPrint) {return sendToPrint(printer, zsbs);} else if (printerStatus.isHeadOpen)printerStatusMsg = "Err-01: Head Open! \n Please close Printer Head to print. ";else if (printerStatus.isHeadCold)printerStatusMsg = "Err-02: Head Cold! \n Please try again. ";else if (printerStatus.isHeadTooHot)printerStatusMsg = "Err-03: Head too hot! \n Please do it later. ";else if (printerStatus.isPaperOut)printerStatusMsg = "Err-04: Media Out! \n Please load Media to Print. ";else if (printerStatus.isPartialFormatInProgress)printerStatusMsg = "Err-05: Head Open! \n Please try again later. ";else if (printerStatus.isPaused)printerStatusMsg = "Err-06: Printer Paused. ";else if (printerStatus.isReceiveBufferFull)printerStatusMsg = "Err-07: Buffer full! \n Please do it later. ";else if (printerStatus.isRibbonOut)printerStatusMsg = "Err-08: Ribbon Out! \n Please retry after adjustment. ";connection.close();return new ResultObj("".equals(printerStatusMsg), printerStatusMsg);} catch (Exception e) {return new ResultObj(false, "Exc-02: " + e.getMessage());} finally {}}private ResultObj sendToPrint(ZebraPrinter printer, ArrayList<ZeroSymbolBill> zsbs) {String filename = "TEMP.LBL";try {File file = context.getFileStreamPath(filename);if (!file.exists())file.createNewFile();createZPLFile(printer, filename, zsbs);printer.sendFileContents(file.getAbsolutePath());return new ResultObj(true, "filepath: " + file.getAbsolutePath());} catch (IOException e) {return new ResultObj(false, e.getMessage());} catch (ConnectionException e) {return new ResultObj(false, e.getMessage());}}private void createZPLFile(ZebraPrinter printer, String filename, ArrayList<ZeroSymbolBill> zsbs) throws IOException {FileOutputStream os = context.openFileOutput(filename, Context.MODE_PRIVATE);byte[] zplByte = null;PrinterLanguage printerLanguage = printer.getPrinterControlLanguage();if (printerLanguage == printerLanguage.ZPL) {StringBuilder sb = new StringBuilder();for (ZeroSymbolBill zsb : zsbs) {sb.append(buildZPLTemplate(zsb));}zplByte = sb.toString().getBytes();}os.write(zplByte);os.flush();os.close();}private String buildZPLTemplate(ZeroSymbolBill zsb) {final String formName = "Zero Symbol Bill";zsb.setNewGuid(Utils.GUID());StringBuilder sb = new StringBuilder();sb.append("^XA\n").append("^LL320\n").append("^PW400\n").append("^LH0,0\n").append("^CI26\n").append("^SEE:GB18030.DAT\n").append("^FO48,20^AEN,10,10^FD" + formName + "^FS\n")//Zero Symbol Bill.append("^FO24,62^AEN,10,10^FDP/N:^FS\n")//P/N.append("^FO54,102^AEN,10,10^FD" + zsb.getPn() + "^FS\n")//2T459M000-000-G5.append("^FO24,142^AEN,10,10^FDQTY:^FS\n")//QTY.append("^FO54,182^AEN,10,10^FD" + zsb.getQty() + " PCS^FS\n")//200000.append("^FO24,222^AEN,10,10^FDDATE:^FS\n")//DATE.append("^FO54,264^AEN,10,10^FD" + zsb.getDate() + "^FS\n")//20191107.append("^FO280,172^BQN,2,2^FD\n").append(" " + zsb.getType()+ "," + zsb.getNewGuid()+ "," + zsb.getVar1()+ "," + zsb.getPn()+ "," + zsb.getDate()+ "," + zsb.getVar2() + "," + zsb.getQty() + ",PCS," + zsb.getOldGuid() + "^FS\n").append("^XZ");return sb.toString();}/*** find bluetooth mac address list** @return*/private ArrayList<String> findBluetoothMacAddress() {ArrayList<String> macAddressList = new ArrayList<>();BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();for (BluetoothDevice device : devices)macAddressList.add(device.getAddress());return macAddressList;}/*** get Local Mac Address** @return*/private String getLocalMacAddress(){WifiManager wifi = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);return wifi.getConnectionInfo().getMacAddress();}
}
打包 arr 文件
arr 文件和 jar 文件类似都可以理解为一个类库文件。不同的是,arr 文件包含了class以及res资源文件,而 jar 文件只包含了 class 文件。
至于这两种文件详细的异同,请自行查阅资料,本文不做详细介绍。
在 Android Studio 代码界面最右侧 “gradle” 选项,选中开始创建的 Android Library 目录,依次展开:Tasks --> build --> assemble。 双击执行。
打包 arr 文件。(输出在 /build/outputs/arr 目录下)
其中,zebraprinter-release.aar 文件就是打包好的发布版本(才发现,模块名字中我将 zebra 误写成 zerbra 了)
调用 arr 接口
以上,arr 接口开发以及打包已经完成,按理来说,这里只需要将 arr 文件打包发送 Android 客户端的开发人员即可。
但是,我们这里先自行测试一下。
将 arr 文件 copy 到 项目 app 模块(最开始创建的 Android 应用空模板)的 libs 目录下并重命名(记得切换到 project 显示,否则不显示 libs 包)。
修改 build.gradle 配置文件(如不修改,在使用时 Android Studio 也会提示修改,建议手动修改)
在 app 模块的 build.gradle 文件中的 dependencies 代码块中,加入如下代码:implementation files('libs/zebraprinter.aar')
在 app 模块的 activity_main.xml 界面设计文件中,增加一个按钮用于测试。
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><Buttonandroid:id="@+id/btnPrintTest"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="67dp"android:text="PrintTest"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /></android.support.constraint.ConstraintLayout>
在 app 模块的 MainActivity 文件中为 printtest 按钮增加点击监听事件,调用 arr 接口中的 zeroSymbolBill 方法发送打印命令
package com.foxconn.mac1.zebraprintdemo;import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.Toast;import com.foxconn.mac1.zebraprinter.Entity.ResultObj; import com.foxconn.mac1.zebraprinter.ZebraPrinter.ZQ520Printer;public class MainActivity extends AppCompatActivity {protected Button btnPrint;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btnPrint = this.findViewById(R.id.btnPrintTest);btnPrint.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View view){printTest();}});}public void printTest(){try {/* Example for Test */String BQcode = "W,VCN00182631190729C0001,P2a-J60102,2T459M000-000-G5,20190729,WmL-J76036,7200,PCS";Integer split = 2000;ZQ520Printer zq520Printer = new ZQ520Printer(this);ResultObj resultObj = zq520Printer.zeroSymbolBill(BQcode, split);if (resultObj.isStatus()){Toast.makeText(MainActivity.this, "print test success", Toast.LENGTH_SHORT).show();}else{Toast.makeText(MainActivity.this, resultObj.getMessage(), Toast.LENGTH_SHORT).show();}/* Example end */} catch (Exception e) {e.printStackTrace();Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();}} }
至此,代码开发及测试已经完成。
附加:APP 打包成 APK 文件
选中 app 模块,依次选择 Build --> Generate Signed Bundle / APK
选择打包类型。
选择 Android APP Bundle 会生成 aab 格式文件;
选择 APK 会生成 apk 格式文件;
aab 格式与 apk 格式的区别:参考文章
配置 app 开发证书信息
Android 开发证书生成指南:参考文章
选择最终生成 apk 文件的目录
打包成功
打包完成,Copy 到 Android 客户端即可安装测试。
Zebra 打印机 Android 端驱动接口开发及调用案例相关推荐
- Android实现注册登录头像上传等功能常规开发(Android端,服务器端开发实例)
Android实现注册登录头像上传等功能常规开发(Android端,服务器端开发实例) 标签: 注册登录Android开发servlet 2017-04-18 20:34 454人阅读 评论(1) ...
- Android项目驱动式开发教程 第2版,《Android项目驱动式开发教程》第一章开发入门.ppt...
<Android项目驱动式开发教程>第一章开发入门 1.4 项目框架分析 4 android:versionName="1.0" > 5 8 第9行代码andro ...
- android滴滴打车代码,Android 端滴滴打车接口的开发
前两天做了一个对Android端'滴滴打车'的接口开发吧! 今天来做个简单的流程, 滴滴会提供这样一个接口, http://webapp.diditaxi.com.cn/? maptype=wgs&a ...
- Android 端滴滴打车接口的开发
前两天做了一个对Android端'滴滴打车'的接口开发吧! 今天来做个简单的流程, 滴滴会提供这样一个接口, http://webapp.diditaxi.com.cn/? maptype=wgs&a ...
- 【Android 逆向】Android 进程注入工具开发 ( 远程调用 | x86 架构的返回值获取 | arm 架构远程调用 )
文章目录 前言 一.x86 架构的返回值获取 二.ARM 架构远程调用 前言 在之前的博客 [Android 逆向]Android 进程注入工具开发 ( 注入代码分析 | 获取 远程 目标进程 中的 ...
- 【Android 逆向】Android 进程注入工具开发 ( 远程调用总结 | 远程调用注意事项 )
文章目录 一.远程调用总结 二.远程调用注意事项 一.远程调用总结 在之前的博客 [Android 逆向]Android 进程注入工具开发 ( 调试进程中寄存器的作用 | 通过 EIP 寄存器控制程序 ...
- android 服务器201,Android端i-jetty服务器开发(八)
http://blog.csdn.net/kongxx/article/details/7237034 Jetty实战之 嵌入式Jetty运行web app 1. 运行标准的war文件 1.1 首先找 ...
- java 红包接口开发_java调用微信现金红包接口的心得与体会总结
这几天看了下之前写的有关微信支付的博客,看的人还是挺多的,看了下留言不知道是因为博客写的不够细还是什么情况,大多都找我要源码,我觉得吧程序员还是需要有这么一个思考的过程,因此没直接给源码,俗话说&qu ...
- Android端海康监控视频调用-实例
一. 开发环境 1. 操作系统:windows7(X64) 2. 开发工具:eclipse adt Build: v22.2.1-833290 JDK7 android SDK 3. 客户端设备版本: ...
最新文章
- c#项目转JAVA,第5个月,基本完成
- java将两个区间范围合并_Java如何将若干时间区间进行合并的方法步骤
- SQL Server数据库原理
- java ee会话_Java EE会话技术Cookie和Session
- mysql将表的某一列全部置空NULL。
- [NOI2015]寿司晚宴——状压dp
- pd17虚拟机启动器生成方法
- 麦子学院python百度云_麦子学院python
- 【Win10】【亲手解决】华硕笔记本重装系统遇到的各种问题【包括重启会自动修复】
- 【阿里云镜像】更新阿里巴巴开源镜像站镜像——Ubuntu镜像
- linux离线安装nettools,CentOS最小安装之安装net-tools并配置网络
- Aegisub彩虹字特效代码
- 路由器不同网段虚拟服务器设置,局域网中不同网段互访?静态路由表必须要学会设置...
- 无需代码,1秒搞定QQ和微信多开!
- MoverScore: Text Generation Evaluating with Contextualized Embeddings and Earth Mover Distance
- wms、wmts和wfs的区别
- 高防服务器好,还是游戏盾好?
- 第一个只出现一次的字符
- python协程和网易云歌单
- 室内定位UWB技术在工业场景的潜力几何?