身份证云识别服务(即将上线)

对接调试一共分为两部分,一部分为安卓应用对接的SDK,另一部分为应用服务器与商米服务器直接的云对接API。

应用软件集成身份证识别sdk,应用软件后端服务器集成云端api(集成云端api用于保护用户身份信息,保证整个数据链路中,只有应用软件可获取身份证明文信息)

1、安卓SDK

身份证云识别的Android SDK 的集成、初始化、使用流程等。

1.1、集成

资源文件( 解压文件夹 AAR 包文件,X.X.X 表示对应的版本号) :

正式坏境:aar/SunmiEID-SDK_vX.X.X-release.aar

测试环境:aar/SunmiEID-SDK_vX.X.X-tes.aar

1.2、导入AAR包

打开项目后:File -> New -> New Module…

在新的对话框:New Module -> Import .JAR/.AAR Package -> Next

下一步:Import Module from Library -> 选择 aar 文件夹下的 SunmiEID-SDK_vX.X.X-release/tes.aar 文件 -> Finish

完成:

1.3、app 模块引用

点击-打开模块设置:

设置对话框:选择“app” -> 点击“+”号 ->  选择“Module Dependency”

显示:勾选上对应的模块(SunmiEID-SDK_vX.X.X-release/tes)-> 点击“OK”,相关SDK引用成功。

1.4、接口文档

1.4.1、初始化

推荐在Application实现SDK初始化实现:

public class IApp extends Application implements EidCall {
    @Override
    public void onCreate() {
        super.onCreate();
        try {
            EidSDK.init(this, "appid", this);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onTerminate() {
        super.onTerminate();
        EidSDK.destroy();
    }

    @Override
    public void onCallData(int code, String msg) {
        Log.d("app", "onCallData: code:" + code + ", msg:" + msg);
    }
}

1.4.2、获取 EidReader 实例

private void initEidReader() {
    Log.d("Eid", String.format("商米SDK.Ver:%s, 读卡模块Ver:%s", EidSDK.getSunmiEidSDKVersion(), EidSDK.getEidSDKVersion()));
    EidPic.init(this, fileNameBase);
    eid = EidSDK.getEidReaderForNfc(1, this);
}

1.4.3、实现 EidCall 接口

@Override
public void onCallData(int code, String msg) {
    switch (code) {
        case EidConstants.READ_CARD_START:
            mState.setText("开始读卡,请勿移动");
            Log.i(TAG, "开始读卡,请勿移动");
            break;
        case EidConstants.READ_CARD_SUCCESS:
            closeNFCReader();//电子身份证需要关闭
            Log.e("TAG", String.format(Locale.getDefault(), "正在获取身份信息(%s),请稍等.....", msg));
            mState.setText(String.format(Locale.getDefault(), "正在获取身份信息(%s),请稍等.....", msg));
            File file = new File(fileNameBase, "zp.bmp");
            if (file.exists()) {
                file.deleteOnExit();
            }
            getIDCardInfo(msg); //通过card_id请求识读卡片的信息
            break;
        case EidConstants.READ_CARD_FAILED:
            closeNFCReader();//电子身份证需要关闭
            Log.i(TAG, String.format(Locale.getDefault(), "读卡错误,请重新贴卡:%s", msg));
            mState.setText(String.format(Locale.getDefault(), "读卡错误,请重新贴卡:%s", msg));
            break;
        case EidConstants.READ_CARD_DELAY:
            Log.e("TAG", String.format(Locale.getDefault(), "延迟 %sms", msg));
            mState.setText(String.format(Locale.getDefault(), "延迟 %sms", msg));
            break;
        default:
            break;
    }
}

1.4.4、调用NFC识读卡片

识读身份证:

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    eid.nfcReadCard(intent);
 }

识读电子身份证:

@Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        try {
           Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
           try {
              isodep = IsoDep.get(tagFromIntent);
              isodep.connect();
              if (isodep.isConnected()) {
                  eid.readCard(IDCardType.ECCARD, new EidReadCardCallBack() {
                      @Override
                      public byte[] transceiveTypeB(byte[] data) {
                          return data;
                      }
                      @Override
                      public byte[] transceiveTypeA(byte[] data) {
                          byte[] outData = new byte[data.length];
                          try {
                              outData = isodep.transceive(data);
                          } catch (Exception e) {
                              e.printStackTrace();
                          }
                          return outData;
                      }
                  });
             } else {
                  closeNFCReader()
             }
        } catch (Exception e) {
             e.printStackTrace();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
 }

    private void closeNFCReader() {
        if (isodep != null) {
            try {
                isodep.close();
                isodep = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

1.5、NFC及动态授权相关

详细处理参考:ReadCardDemo.zip

1.6、详细接口说明

详细接口文档:Javadoc.zip

1.7、错误码ErrorCode

2、云对接API

身份证云识别

产品与服务介绍

1、身份证云识别

身份证件在入住、出行、金融、医疗等各个领域被广泛用于用户身份核实。传统的证件识别方式是通过专用证件阅读器验证身份证件,以确保登记信息的真实性和准确性,但存在着成本较高;体积较大,不易于携带;专用证件阅读器直接识别出来的证件信息是明文信息,在传输过程中容易被盗取或篡改,不适合直接在互联网中传输等问题。电子身份证件云识读服务可以解决以上问题,现免费向出行、入住、政务民生、金融、医疗等行业的应用机构提供。

2、什么是电子身份证件云识读服务?

在支持NFC功能的手机中,APP应用系统中通过商米提供的SDK读取二代身份证的加密数据,并发送到公安部身份证云解码中心进行解码和身份认证,然后将解码结果(身份证号码和姓名等信息)返回给应用系统,完成对用户身份信息的认证。

3、电子身份证件云识读服务支持哪些证件?

第二代居民身份证、港澳台居民居住证、外国人永久居留证、护照、eID身份电子证照。

4、电子身份证件云识读服务支持哪些终端?

支持NFC的(支持ISO14443协议的)设备:L2、L2K、V2pro、T1mini、T2mini、带NFC的刷卡器

5、电子身份证件云识读服务的套餐类型?

1、按次数购买,有效期1年

2、包年购买:为账号购买包年的套餐,一个账号下只能有一个包年套餐。用户可以选择包年的时长以及需要服务的设备名额。购买后,用户可以为包年套餐续费、增加名额和导入设备号。导入设备号后,对应设备号就拥有了有效期内无限使用身份证识别的功能。

使用指南

1、接入流程

1、注册为商米合作伙伴

2、购买身份证服务套餐

3、应用和应用服务器集成云识别sdk

4、在合作伙伴平台查看和管理服务

云打印机对接说明

5. 打印机常用ESC/POS指令集

  • LF 打印并走纸一行
内容说明
[格式]ASCII:LF
Hex:0A
Decimal:10
[描述]· 标准模式下打印缓冲区内数据并走纸一行
[注释]· 该指令将当前位置置于行首。
  • ESC ! n 选择打印模式
内容说明
[格式]ASCII:ESC ! n
Hex:1B 21 n
Decimal:27 33 n
[范围]0≤n≤255
[描述]设根据n的值设置字符打印模式
n=0字体标准大小
n=16字体倍高
n=32字体倍宽
n=48字体倍高宽
[注释]· 所有字符以底端对齐。
· 对英数字符和汉字同时有效。
[默认值]n=0
  • ESC a n 选择对齐方式
内容说明
[格式]ASCII:ESC a n
Hex:1B 61 n
Decimal:27 97 n
[范围]0≤n≤2 或 48≤n≤50
[描述]将一行数据按照指定的位置对齐如下n用以选择对齐方式:
0,48 左对齐
1,49 居中
2,50 右对齐
[注释]· 标准模式下仅在一行的开始处时,该命令才有效。
· 该命令在打印区域执行对齐。
[默认值]n=0
  • ESC p m t1 t2 打开钱箱驱动脉冲
内容说明
[格式]ASCII:ESC p m t1 t2
Hex:1B 70 m t1 t2
Decimal:27 112 m t1 t2
[范围]m = 0, 1, 48, 49
0 ≤ t1 ≤ 255
0 ≤ t2 ≤ 255
[描述]· m=0, 48 钱箱插座引脚2;m=1, 49 钱箱插座引脚5
· t1指定脉冲开启时间为[ t1 × 2 ms].
· t2指定脉冲关闭时间为[ t2 × 2 ms].
[注释]· 指定一个值(t1
  • GS V m 切刀裁纸
内容说明
[格式]ASCII:GS V m
Hex:1D 56 m
Decimal:29 86 m
[范围]m=1, 49
[描述]· 选择一种切刀裁纸操作
[注释]· 依据所装的自动裁纸器类型的不同,裁纸状态也不同。
· 仅在一行开头处理该命令时,该命令有效。
· 只有部分裁纸,没有完全裁纸。
  • GS H n 选择条码字符的打印位置
内容说明
[格式]ASCII:GS H n
Hex:1D 48 n
Decimal:29 72 n
[范围]0≤n≤3 或 48≤n≤51
[描述]打印条码时,为条码字符选择打印位置。
n指定条码字符打印位置:
0,48 不打印
1,49 在条码上方
2,50 在条码下方
3,51 在条码上方及下方
[默认值]n = 0
  • GS h n 选择条码高度
内容说明
[格式]ASCII:GS h n
Hex:1D 68 n
Decimal:29 104 n
[范围]1≤n≤255
[描述]· 设置条码的纵向高度。n设定垂直方向的点数(0.125mm/点)
[默认值]n= 162
  • GS w n 设置条形码宽度
内容说明
[格式]ASCII:GS w n
Hex:1D 77 n
Decimal:29 119 n
[范围]1≤n≤6
[描述]· 设置条形码水平尺寸
[默认值]n=3
  • GS k m n d1…dn 打印条码
内容说明
[格式]ASCII:GS k m n d1…dk
Hex:1D 6B m n d1…dk
Decima:29 107 m n d1…dk
[范围]65≤ m ≤89(d1…dn长度取决于使用的条形码系统)
[描述]· 选定条形码系统并打印。
[注释]· n用来指示条码数据的个数,打印机将其后边n字节数据作为条码数据处理。
· 如果n超出了指定范围,则打印机停止该命令的处理,并将后续数据作为普通数据处理。
· 如果条码数据d超出了规定的范围,该命令无效。
· 如果条码横向超出了打印区域,无效。
· 这条命令不管由ESC2或ESC3命令设置的行高是多少,走纸距离都与设置 的条码高度相等。
· 这条命令只有在打印缓冲区没有数据时才有效,如果打印缓冲区有数据,该命令被忽略。
· 打印条码后,将打印位置设置在行首。

m选定条形码系统如下:

m条形码系统数据长度字符个数字符范围
65UPC-A固定11≤n≤120~948≤d≤57
66UPC-E固定6≤n≤70~948≤d≤57
67JAN13(EAN13)固定12≤n≤130~948≤d≤57
68JAN8(EAN8)固定7≤n≤80~948≤d≤57
69CODE39可变1≤n≤640~9, A~Z, SP, $,
%, *, +, -, ., /
48≤d≤57, 65≤d≤90, 32,
36, 37, 43, 45, 46, 47
70Code 2 of 5 Interleaved可变2≤n≤64
(偶数)
0~948≤d≤57
71CODABAR可变1≤n0~9, A~D, a~d,
$, +, -, ., /, :
48≤d≤57, 65≤d≤68, 97≤d≤100,
36, 43, 45, 46, 47, 58,
65≤d1≤68, 97≤d1≤100,
65≤dk≤68, 97≤dk≤100
72CODE93可变1≤n≤64
73CODE128可变2≤n≤64
81Code 2 of 5 Matrix可变1≤n≤640~948≤d≤57
82Code 2 of 5 Industrial可变1≤n≤640~948≤d≤57
83Code 2 of 5 IATA可变1≤n≤640~948≤d≤57
84Code 2 of 5 Datalogic可变1≤n≤640~948≤d≤57
85CODE11可变1≤n≤640~9, –48≤d≤57,45
86CODE39 xtended可变1≤n≤64
87GS1 DataBar固定n=130~948≤d≤57
88GS1 DataBar Expanded可变
89MSI Plessey可变1≤n≤640~948≤d≤57

云打印机对接说明

6. 需要了解的其他FAQ

a) 对接流程逻辑上如何保证打印机一定能够接到订单?

答:商米云打印机有如下流程来保证:

1、打印机接入商米云MQTT服务器,该服务器采用集群架构,由商米运维团队进行维护,具有多年百万量级的商米设备接入经验打磨而成,保证了订单消息的触发和推送。

2、打印机接到订单以后,会发起HTTP订单列表请求,而且将订单限制在5条以内,有效避免了高峰时期大量订单拥挤到打印机端,从而导致丢单的问题。

3、打印机获取订单列表以后,会按列表顺序一张一张订单拉取详情进行打印,而且只有在上一张打印完毕以后,才会打印下一张订单。

4、订单打印完毕以后,打印机还会上报打印结果给服务器,让服务器实时了解订单是否已经打印完成。未上报打印完成状态的订单还可以被再次拉取打印。

5、打印中途,如果因为纸用完了,在重新装纸以后,订单会从头再打印一遍,避免了内容缺失。

6、打印中途,如果因为断电,在重新开机以后,会主动到服务器上重新拉取未打印的订单来打印。

7、打印中途,如果因为断网,只有拉取完整的订单才会打印出来,拉取一半的订单是不会打印出来的。

8、打印途中,如果因为卡纸等故障,导致打印不完整。商家可以通过按键重打最后一张订单,免去操作软件的过程。

9、如果确实由于网络因素,打印机请求多次也没有拉取到新订单数据,可以在接收到第二个新订单消息时,还是会将第一个订单拉取并打印出来。

10、打印机采用弱网切换,可以自动寻找连接顺畅的网络进行连接,网络切换时间只需20秒。

11、打印机是否断网,云指示灯会提示目前服务器是否正常连接。

12、商家怀疑网络不好时,可以通过按键自检网络状态,打印机会打印出一张检测报告,告诉你哪里出了问题。

13、打印机网络真的出现短时间无法修复问题时,还可以使用商家手机版接单,然后通过手机蓝牙向打印机发送订单,利用蓝牙将订单打印出来。

b) 打印过程缺纸,订单会不会丢失?

答:当出现打印过程缺纸时,只要重新装好纸卷,未完成的票据将会自动完整的重新打印出来;

c) 打印过程卡纸了,订单打印不完整怎么办?

答:打印机提供按键重打功能,只要双击键就可以重新打印最后一张订单;

d) 如何进行打印机wifi配网?

答:商米云打印机采用的是蓝牙配网方式,这种方式可以有效避免手机和打印机不在同一个Wifi路由器环境下的跨网段配网问题。商米已经为开发者准备了3套蓝牙配网SDK,一套是用于安卓下的配网SDK,一套是用于苹果手机的配网SDK,还有一套是用于微信小程序的配网SDK。使用这三套SDK的基础原理都是让开发者很方便的调用蓝牙进行通讯,避免各种因为通讯异常造成的重连机制开发难度。

e) 店铺WIFI网络不好导致丢单怎么办?

答:网络状态因为影响因素众多,目前还没有终极的解决方案,所以购买WIFI+GPRS版本的打印机将自动带有弱网切换功能。在平时打印机将使用WIFI联网进行通讯,如果WIFI网络通讯不稳定时,打印机就会自动切换的GPRS网络进行通讯,等待WIFI恢复正常时再切换回来,避免了因此造成的订单无法接收的问题。因为GPRS的速率受限,接单体验上没有WIFI那么快,但因为GPRS属于备用通道,保证订单不丢失才是首要考虑的。

f) 打印机网络异常了,但手机上还能收到单,怎么打印出来?

答:商米云打印机支持云、USB、蓝牙事务打印模式,允许在连接网络打印的情况下,仍然可以通过USB和BT接收来自收银机和手机的数据进行打印。所以如果手机上有订单,可以让手机蓝牙连接打印机,将票据内容通过蓝牙发送给打印机打印即可。

g) 网络异常了,如何快速查找问题点?

答:网络状态因为影响因素众多,目前还没有终极的解决方案,所以打印机带有网络自检功能,只要双击键,稍等几秒就会有一张网络自检票据打印出来,从票据中的FAIL项就可以分析网络目前处于何种故障,将故障信息提供给技术人员解决;

检测信息信息说明故障解决
Current Network目前正在业务通讯的是WIFI网络还是GPRS网络。如若未配置WIFI,请忽略此异常。如果一直处于GPRS网络,说明WIFI通路有问题,就需要检查一下打印机WIFI配置是否正确,或者路由器是否工作正常。如若未配置WIFI,请忽略此异常。
Link=>SSID:目前连接的WIFI路由器SSID名称是什么,并且连接是否正常。连接上PASS,断开中FAIL。没有SSID名称就说明打印机并没有配置WIFI,需要重新执行WIFI配网过程。如果有SSID名称,那就需要检查该SSID名称的WIFI路由器工作是否正常,或者打印机重新进行WIFI配网。
Link=>GPRS目前的GPRS通道连接是否正常。连接上PASS,断开中FAILGPRS信号差,请将设备远离金属和多层墙壁的位置后,再次尝试。另GPRS连接速度比较慢,打印机刚开机还未连接上基站也会导致测试失败,稍等几分钟再测试一遍即可。
Check=>DHCP Conflict检查网络环境中是否存在多个DHCP情况,多个DHCP或没有DHCP会导致网络连接异常。只有一个DHCP时PASS,有多个DHCP时Warn,没有DHCP为FAIL本项依赖Link测试项为PASS情况下,FAIL的故障分析才有意义,否则请忽略以下分析内容。如若Link=>SSID项未FAIL,请先确保其为Pass。
Warn表示网络中私搭的WIFI路由器导致DHCP冲突,请检查网络中是否存在多个路由器开启了DHCP模式。如果是请关闭多余的DHCP,只保留一个可以连接外网的即可。
FAIL表示网络中没有配置DHCP服务器,打印机无法获得IP地址。请检查网络中的DHCP服务器是否故障。
Check=>IP Conflict检查网络环境中是否存在IP地址重复,多个IP地址相同会导致网络通讯异常。没有重复IP时PASS,有多个重复IP时FAIL本项依赖Link测试项为PASS情况下,FAIL的故障分析才有意义,否则请忽略以下分析内容。如若Link=>SSID项未FAIL,请先确保其为Pass。
网络中的多个DHCP服务冲突或者手工给设备配置IP地址时,就会引起IP地址冲突。请关闭多余的DHCP服务,或者找到冲突的IP地址设备,修改IP地址为使用DHCP分配。
Ping=>GW检查设备与网关之间的链路,从而判断内网连接是否正常。返回值是延迟值,通过延迟值判断网络的速率是否达标,如果网关不通时FAIL本项依赖Check测试项为PASS情况下,FAIL的故障分析才有意义,否则请忽略以下分析内容。如若Check=>DHCP Confilict项FAIL,请先确保其为Pass。
网关一般都指向了WIFI路由器或者基站本身,Ping值太高或者FAIL就需要检查WIFI路由器是否工作正常,或者移动基站信号不好。
Ping=>DNS检查设备与公网根DNS之间的链路,从而判断是否已经连接上外网。返回值是延迟值,通过延迟值判断网络的速率是否达标,如果网关不通时FAIL本项依赖Ping=>GW测试项为PASS情况下,FAIL的故障分析才有意义,否则请忽略以下分析内容。如若Link=>GPRS、Ping=>GW项均为FAIL,请先确保其为Pass。
DNS根服务器是互联网上的主节点,能Ping通说明打印机已经连上了互联网。Ping值太高或者FAIL就需要检查WIFI路由器是否工作正常,或者移动基站信号不好。
Ping=>MQTT Server检查设备与MQTT服务器的链路,从而判断是否已经连接上业务服务器。返回值是延迟值,通过延迟值判断网络的速率是否达标,如果网关不通时FAIL本项依赖Ping=>GW、Ping=>DNS测试项为PASS情况下,FAIL的故障分析才有意义,否则请忽略以下分析内容。如若Link=>GPRS、Ping=>GW项均为FAIL,请先确保其为Pass。
MQTT是订单推送服务器,能Ping通说明订单推送服务器链路正常。Ping值太高或者FAIL就需要咨询设备厂商客服人员进行检查。
Ping=>HTTP Server检查设备与HTTP服务器的链路,从而判断是否已经连接上业务服务器。返回值是延迟值,通过延迟值判断网络的速率是否达标,如果网关不通时FAIL本项依赖Ping=>GW、Ping=>DNS测试项为PASS情况下,FAIL的故障分析才有意义,否则请忽略以下分析内容。如若Link=>GPRS、Ping=>GW项均为FAIL,请先确保其为Pass。
HTTP是订单内容服务器,能Ping通说明订单服务器链路正常。Ping值太高或者FAIL就需要咨询设备厂商客服人员进行检查。
MQTT=>Check Config打印机通讯主要靠MQTT,所以会自动检查服务器信息是否正确,是否可以接收来自云的订单消息。信息正确时PASS,信息错误时FAIL本项依赖Ping=>HTTP测试项为PASS情况下,FAIL的故障分析才有意义,否则请忽略以下分析内容。如若Ping=>HTTPServer项为FAIL,请先确保其为Pass。
如果接入MQTT服务器的信息出现错误,就需要咨询设备厂商客服人员进行检查。
MQTT=>Connect打印机通讯主要靠MQTT,检查MQTT目前是否连接着,是否可以接收来自云的订单消息。连接上PASS,断开中FAIL本项依赖MQTT=>MQTT config测试项为PASS情况下,FAIL的故障分析才有意义,否则请忽略以下分析内容。如若MQTT=>Check Config项为FAIL,请先确保其为Pass。
如果接入MQTT连接出现错误,就需要咨询设备厂商客服人员进行检查。
MQTT=>R&W打印机通讯主要靠MQTT,检查MQTT通讯数据是否正常,是否可以接收来自云的订单消息。可以通讯PASS,无法通讯FAIL本项依赖MQTT=>MQTT Link测试项为PASS情况下,FAIL的故障分析才有意义,否则请忽略以下分析内容。如若MQTT=>Connect项为FAIL,请先确保其为Pass。
如果接入MQTT服务器的信息出现错误,就需要咨询设备厂商客服人员进行检查。

h) 打印机自检页如何操作?

答:需要完整查看打印机硬件信息,可以通过自检页了解,只要按下键再按下键后同时松开就可以打印出来;

i) 打印出来的票据是乱码,怎么回事?

答:商米云打印机目前支持全球字库打印,所以采用UTF8编码格式,所以传输的文字都要转码成UTF8才能打印出来。采用UTF8编码后就可以实现票据内容多语种混打,满足一些行业服务特定外国人群时的双语种打印问题。

j) 播报语音内容是否可以修改?

答:商米云打印机采用TTS语音合成技术,无论你发什么文字,都可以转换成语音播报出来。也就是说只要场景需要,票据的菜品、联系方式、备注都可以按照你的想法读出来。但由于一些多音字的存在,某些特定的语句可能无法按照你的期望正确发音,所以可以将文字替换成相同发音的非多音字来播报。

k) 如何变更wifi配置?

答:设备wifi配对以后,如果需要变更接入wifi节点,只需要重新执行配网即可,不用解除授权重新绑定。

l) 云打印机和别的外卖平台是否可以同时接单?

答:外卖平台的接入数量是依据饿了么和美团的规则而定,不是由云打印机自行决定的。饿了么允许多台打印机接入相同的账号,并且同时接单打印。而美团只允许一台打印机接入一个账号,如果授权绑定了别的平台,那原有的就会被强制解除授权。

m) GPRS版本送SIM卡吗,每个月有多少流量?

答:商米云打印机是内置eSIM,不需要另外使用插卡,是直接连接到2G网络的,没有流量限制。

n) 设备通过商米助手APP绑定了,还能解绑吗?

答:可以解绑的,在商米助手中点击设备右上角的小点,其中有删除设备。删除后可以使用另一个手机重新连接绑定。已经被绑定的就无法被另一个账号绑定的。

云打印机对接说明

4. 开发对接API接口

特别声明:

为更好的保护合作伙伴的数据隐私,又能实现完整的订单打印过程,需要商米与合作伙伴共同努力一起实现。以下文档约定了云打印机通讯的两部分接口,一部分为商米云提供的API接口,提供给合作伙伴调用,以完成设备绑定相关和消息推送相关功能;一部分为合作伙伴需要开放给商米云打印机调用的API接口,以完成订单打印相关功能。

参数说明:

  1. 每个请求的参数包含两部分:公共参数和私有参数,详细请看以下对应说明。
  2. 以下每个接口只列出私有参数和返回结果,其他请看请求和公共参数说明。
  3. 返回结果皆为json格式数据。

请求公共参数说明(所有请求都必须传递的参数):

请求参数名类型说明
signstring签名,参考下面签名生成方式。注意:sign必须全部32位大写MD5
app_idstring商米提供的app_id,申请开通通道时获得
msnstring设备SN号
timestampstringUnix时间戳(秒)

返回公共参数说明:

返回参数名类型说明
codeint返回码,参见常见错误码列表
data不指定数据类型和内容详见私有返回参数data,如果有错误,返回null
msgstring结果提示信息,如果有错误返回错误信息描述

公共请求参数sign生成说明:

签名算法:MD5

签名生成方式举例(它假定所需参数如下):
app_id:sm5b9b4daef3463
storeId:SM0819
msn:NT1234DF23456
token:dhasjkdhajkdhajdkghjsakd

步骤1:以“key=value”格式,按参数名称ASCII字典顺序排序:
stringA=“app_id=sm5b9b4daef3463&msn=NT1234DF23456&storeId=SM0819&token=dhasjkdhajkdhajdkghjsakd”;

步骤2:拼接的关键app_key,假定app_key是“dd3ac24736589ae17d333e362859bf4c”,那么
stringB=“app_id=sm5b9b4daef3463&msn=NT1234DF23456&storeId=SM0819&token=dhasjkdhajkdhajdkghjsakddd3ac24736589ae17d333e362859bf4c”

步骤3:对stringB进行MD5加密得到最终签名sign,即sign=MD5(stringB)。即sign=“5759A8D552E2D54D0E8B0EBA0770BB98”

基于以上签名生成方式,其中私密参数app_id和app_Key,由商米科技统一分配。注意:签名sign必须全部32位大写MD5

常见错误码说明:

错误码说明
10000接口调用成功
20000服务不可用
20001授权失败
40001缺少所需参数
40002非法参数

此上为全局常见错误码说明,后续会继续补充。除公共错误码以外,具体业务错误码参见具体业务接口内容。

4.1 商米云API接口

基于合作伙伴数据隐私考虑,商米云不会直接获取打印数据,而是采用消息传递方式,由打印机直连合作伙伴云拉取所需数据进行打印。以下规范由商米云实现了几个基本功能接口,以完成设备绑定、订单消息通知、语音传递等相关功能。

请求URL地址(正式):https://openapi.sunmi.com

请求URL地址(调试):http://test.openapi.sunmi.com

API接口开发DEMO文档下载

1)打印机绑定接口

接口名:

  • /v1/printer/printerAdd

请求方式:

  • POST(推荐),GET

公共参数:

参数名类型说明
signstring签名,参考上面签名生成方式。注意:签名sign必须全部32位大写MD5
app_idstring商米提供的app_id
msnstring设备SN号
timestampstringUnix时间戳(秒)

私有参数:

参数名类型说明
shop_idstring合作伙伴名下的商户Id

shop_id是对名下设备进行分组管理的唯一条件,查询店铺设备状态列表时使用。若无需此功能可传””,那么店铺设备状态列表结果集将返回为空。

成功返回示例:

{
    "code": "10000",
    "data": "success",
    "msg" : ""
}

成功返回参数说明:

参数名类型说明
datastring包含成功和失败信息

失败返回示例:

{
  "code": "10000",
  "data": {
     "subCode": "60001",
     "subMessage": "",
  },
  "msg":  "string"
}

失败错误码说明:

错误码说明
60001超出时间范围请求无效
60002sn号不存在
60003不属于该渠道设备
60004绑定失败

2)打印机解绑接口

接口名:

  • /v1/printer/printerUnBind

请求方式:

  • POST(推荐),GET

公共参数:

参数名类型说明
signstring签名,参考上面签名生成方式。注意:签名sign必须全部32位大写MD5
app_idstring商米提供的app_id
msnstring设备SN号
timestampstringUnix时间戳(秒)

私有参数:

参数名类型说明
shop_idstring合作伙伴名下的商户Id

shop_id必传,否则无法将该打印机从该店铺下解绑

成功返回示例:

{
    "code": "10000",
    "data": "success",
    "msg" : ""
}

成功返回参数说明:

参数名类型说明
datastring包含成功和失败信息

失败返回示例:

{
  "code": "10000",
  "data": {
     "subCode": "60001",
     "subMessage": "",
  },
  "msg":  "string"
}

失败错误码说明:

错误码说明
60001超出时间范围请求无效
60002sn号不存在
60003不属于该渠道设备
60005解绑失败

3)查询店铺下已绑定设备状态

接口名:

  • /v1/machine/queryBindMachine

请求方式:

  • POST(推荐),GET

公共参数:

参数名类型说明
signstring签名,参考上面签名生成方式。注意:签名sign必须全部32位大写MD5
app_idstring商米提供的app_id
timestampstringUnix时间戳(秒)

私有参数:

参数名类型说明
shop_idstring合作伙伴商户Id

成功返回示例:

{
    "code": "10000",
    "data": [
        {
            "is_online": "1",
            "msn": "N302D94D40068"
        }
    ],
    "msg": ""
}

成功返回参数说明:

参数名类型说明
dataObjectmsn:设备sn号;is_online:设备是否在线 1-在线 0-不在线

失败返回示例:

{
    "code": "10000",
    "data": {
       "subCode": "60001",
       "subMessage": "",
    },
    "msg": ""
}

失败错误码说明:

错误码说明
60001超出时间范围请求无效
60002sn号不存在
60003不属于该渠道设备
60006商户Id不存在

4)有新订单消息通知

接口名:

  • /v1/printer/newOrderNotice

请求方式:

  • POST(推荐),GET

公共参数:

参数名类型说明
signstring签名,参考上面签名生成方式。注意:签名sign必须全部32位大写MD5
app_idstring商米提供的app_id
msnstring设备SN号
timestampstringUnix时间戳(秒)

私有参数:

参数名类型说明
hasOrderint1-有新的订单
orderIdint订单Id

成功返回示例:

{
    "code": "10000",
    "data": "success",
    "msg" : ""
}

成功返回参数说明:

参数名类型说明
subDatastring包含成功和失败信息

失败返回示例:

{
    "code": "10000",
    "data": {
       "subCode": "60001",
       "subMessage": "",
    },
    "msg": ""
}

失败错误码说明:

错误码说明
60001超出时间范围请求无效
60002sn号不存在
60003不属于该渠道设备

5)语音内容推送

接口名:

  • /v1/printer/pushVoice

请求方式:

  • POST(推荐),GET

公共参数:

参数名类型说明
signstring签名,参考上面签名生成方式。注意:签名sign必须全部32位大写MD5
app_idstring商米提供的app_id
msnstring设备SN号
timestampstringUnix时间戳(秒)

私有参数:

参数名类型说明
call_contentstring语音播报内容

成功返回示例:

{
    "code": "10000",
    "data": "success",
    "msg" : ""
}

成功返回参数说明:

参数名类型说明
datastring包含成功和失败信息

失败返回示例:

{
    "code": "10000",
    "data": {
       "subCode": "60001",
       "subMessage": "",
    },
    "msg": ""
}

失败错误码说明:

错误码说明
60001超出时间范围请求无效
60002sn号不存在
60003不属于该渠道设备

4.2 合作伙伴云API接口

基于合作伙伴数据隐私考虑,商米云不会直接获取打印数据,而是采用消息传递方式,由打印机直连合作伙伴云拉取所需数据进行打印。以下规范由合作伙伴云实现几个基本功能接口,以完成打印机设备获取订单数据进行打印。

请求URL地址:为了让打印机设备能够直连合作伙伴云API接口实现订单打印功能,需要事先提供可以正常调用的URL地址给到商米云。

1)获取订单列表

接口名:

  • printTicket/getPrintTicketOrderId

请求方式:

  • GET

参数:

参数名类型说明
signstring签名,参考上面签名生成方式。注意:签名sign必须全部32位大写MD5
app_idstring商米提供的app_id
msnstring设备SN号
timeStampstringUnix时间戳(秒)

返回示例(json):

{
    "code":1,
    "data":["id","id","id","id","id"],
    "msg":""
}

返回参数:

参数名说明
code1代表请求成功,-1代表请求失败
data返回数据库中五条订单id集合,若请求失败data为null
msg若请求失败,msg返回error信息,请求成功则msg为null

备注:为保证打印不漏单,订单id列表依照时间顺序每次最多返回5条订单id集合列表。打印机会将所有订单id内容依次打印完成后,再请求该接口获取需打印订单id列表,直至该接口返回为空停止。

2)获取订单详情

接口名:

  • printTicket/ getPrintTicketInfo

请求方式:

  • GET

参数:

参数名类型说明
signstring签名,参考上面签名生成方式。注意:签名sign必须全部32位大写MD5
app_idstring商米提供的app_id
msnstring设备SN号
timeStampstringUnix时间戳(秒)
orderIdstring订单id

返回示例(json):

{
    "code":1,
    "data":{
        "voice":"语音内容",
        "data":"1B21306D4B8BD5310A",//使用ESCPOS指令字体倍高宽模式打印“测试1”内容,末尾还有一个回车指令
    },
    "msg":""
}

data说明:打印内容采用十六进制格式传输,所有文本内容采用UTF8编码。在内容中可以直接使用ESC/POS指令集控制打印,以获得所需的票据排版格式。

//PHP代码示例:
$str = chr(27).chr(33).chr(48)."南国超市".chr(27).chr(33).chr(0).chr(0x0A);  //chr(27).chr(33).chr(48)是ESC/POS指令的字体效果倍高宽;chr(27).chr(33).chr(0)是ESC/POS指令的字体效果标准大小;0A是换行
$str = $str."台号:01       工号:01".chr(0x0A);
$str = $str."时间:12:45:28".chr(0x0A);
$str = $str."单号:00554789713585".chr(0x0A);
$str = $str."商品名称     单价*数量       金额".chr(0x0A);
$str = $str."--------------------------------".chr(0x0A);
$str = $str."百事利精装糖果  7.00*1      7.00".chr(0x0A);
$str = $str."旺旺雪饼        8.00*1      8.00".chr(0x0A);
$str = $str."可口可乐        2.50*1      2.50".chr(0x0A);
$str = $str."喜之朗果冻     10.00*1     10.00".chr(0x0A);
$str = $str."巧克力饼干     10.00*1     10.00".chr(0x0A);
$str = $str."--------------------------------".chr(0x0A);
$str = $str."总件数:5          总计RMB: 27.00".chr(0x0A);
$str = $str.chr(0x0A);
$str = $str.chr(27).chr(33).chr(16)."      谢谢惠顾欢迎下次光临".chr(27).chr(33).chr(0).chr(0x0A);//显示效果是字体倍高;0A是换行

$data = bin2hex(strToUtf8($str));  //$data为:1b2130e58d97e59bbde8b685e5b8821b21000ae58fb0e58fb73a303120202020202020e5b7a5e58fb73a30310ae697b6e997b43a31323a34353a32380ae58d95e58fb73a30303535343738393731333538350ae59586e59381e5908de7a7b020202020202020202020202020e58d95e4bbb72ae695b0e9878f202020202020e98791e9a29d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0ae799bee4ba8be588a9e7b2bee8a385e7b396e69e9c2020202020202020372e30302a312020202020202020372e30300ae697bae697bae99baae9a5bc2020202020202020202020202020382e30302a312020202020202020382e30300ae58fafe58fa3e58fafe4b9902020202020202020202020202020322e35302a312020202020202020322e35300ae5969ce4b98be69c97e69e9ce586bb202020202020202020202031302e30302a312020202020202031302e30300ae5b7a7e5858be58a9be9a5bce5b9b2202020202020202020202031302e30302a312020202020202031302e30300a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0ae680bbe4bbb6e695b02020342e303020202020202020202020e680bbe8aea1524d4220202020202032372e30300a0a1b2110202020202020e8b0a2e8b0a2e683a0e9a1bee6aca2e8bf8ee4b88be6aca1e58589e4b8b41b21000a

//该方法判断字符串内容是否是UTF8编码,如果是直接返回,如果不是则将字符串转换为UTF8编码
function strToUtf8($str){
    $encode = mb_detect_encoding($str, array("ASCII",'UTF-8',"GB2312","GBK",'BIG5'));
    if($encode == 'UTF-8'){
        return $str;
    }else{
        return mb_convert_encoding($str, 'UTF-8', $encode);
    }
}

返回参数:

参数名说明
code1 代表请求成功,-1代表请求失败
data返回订单内容,voice为语音播报内容,data为订单详情,若请求失败data为null
msg若请求失败,msg返回error信息,请求成功则msg为null

云打印机因为具有重打订单功能,该接口需要允许状态已经标记为打印成功的订单,仍然允许打印机根据订单ID请求订单详情,以完成重打动作。

3)更新订单状态

接口名:

  • printTicket/ updatePrintTicketStatus

请求方式:

  • GET

参数:

参数名类型说明
signstring签名,参考上面签名生成方式。注意:签名sign必须全部32位大写MD5
app_idstring商米提供的app_id
msnstring设备SN号
timeStampstringUnix时间戳(秒)
orderIdstring订单id
statusint状态 1:订单打印成功、0:订单打印失败、-1:订单json格式错误、-2:data字段内容为空

返回示例(json):

{
    "code":1,
    "data":,"success",
    "msg":""
}

返回参数:

参数名说明
code1 代表请求成功,-1代表请求失败
data成功返回“success”,失败返回“fail”
msg若请求失败,msg返回error信息,请求成功则msg为null

云打印机对接说明

3. 下载配网SDK

安卓SDK DEMO下载链接:商米云打印机配网SDK Demo
微信小程序SDK下载链接:待更新

说明:云打印机配网、云绑定过程是通过蓝牙实现的,所以需要利用手机的蓝牙来进行指令的通讯。SDK里的SunmiPrinterClient类对蓝牙配网过程进行了封装,便于APP简单开发实现打印机配对。使用该功能时必须保证蓝牙打开且允许应用获取位置权限。下面是SDK接口的使用说明,具体使用可以参考DEMO。

到手的云打印机因为没有配置过现场wifi网络,所以在开发的时候联网很不方便。所以我们提供了一个安装在安卓手机上的配网工具给合作伙伴下载使用。点击下载wifi配网工具

3.1安卓配网SDK类说明

Android配网SDK包名:BluetoothBinding.aar

1)类声明

接口名:

  • SunmiPrinterClient

接口声明:

   SunmiPrinterClient sunmiPrinterClicent = SunmiPrinterClient(Context context, IPrinterClient iPrinterClient);

传入参数:

参数名类型说明
contextContext
iPrinterClientIPrinterClient云打印机蓝牙接口的回调类

2)统一处理回调接口

配置蓝牙打印机的过程中需要通过BLE给蓝牙打印机发送消息,这里采用统一的回调处理蓝牙数据发送情况。

接口名:

  • sendDataFail

回调方法:

   public void sendDataFail(int code, String msg) {

    }

回调参数:

参数名类型说明
codeint错误信息码 0-蓝牙连接失败 1-蓝牙Notify失败
msgString错误信息

3.2安卓配网SDK接口说明

1)开始扫描打印机

接口名:

  • startScan

接口声明:

   sunmiPrinterClient.startScan();

回调方法:

    public void onPrinterFount(PrinterDevice printerDevice) {

    }

回调参数:

参数名类型说明
printerDevicePrinterDevice蓝牙打印机类 扫描到的打印机数据中只有默认的名称和蓝牙mac地址

2) 停止扫描打印机

接口没有回调,建议在当前页面销毁或者开始配置打印机前停止扫描

接口名:

  • stopScan

接口声明:

   sunmiPrinterClient.stopScan();

3) 获取蓝牙打印机SN

接口名:

  • getPrinterSn

接口声明:

   sunmiPrinterClient.getPrinterSn(btAddress);

传入参数:

参数名类型说明
btAddressString打印机的蓝牙MAC地址

回调方法:

  • 方法一:
   public void getSnRequestSuccess() {

    }

说明:该方法表示发送获取SN的命令成功,等待获取SN,该方法内可以加入超时机制

  • 方法二:
   public void onSnReceived(String sn) {

    }

回调参数:

参数名类型说明
snString打印机的sn

4)获取打印机搜索到的WIFI列表

接口名:

  • getPrinterWifiList

接口声明:

   sunmiPrinterClient.getPrinterWifiList(btAddress);

传入参数:

参数名类型说明
btAddressString打印机的蓝牙MAC地址

回调方法:

  • 方法一:
   public void routerFound(Router router) {

    }

回调参数:

参数名类型说明
routerRouter打印机搜索到的WIFI类
Router类参数说明
参数名类型说明
nameStringWIFI的名字
hasPwdbooleanWIFI是否有密码
pwdStringWIFI的密码,此时获取到的WIFI没有该数据
rssiintWIFI的信号强度范围0到4,越大信号越强
essidbyte[]WIFI的essid,配网时需要该参数
  • 方法二:
public void onGetWifiListFinish() {

    }

说明:蓝牙打印机搜索WIFI结束

  • 方法三:
public void onGetWifiListFail() {

    }

说明:蓝牙打印机搜索wifi失败

5)给打印机配置wifi

接口名:

  • setPrinterWifi

接口声明:

   sunmiPrinterClient.setPrinterWifi(btAddress, ssid, psw);

传入参数:

参数名类型说明
btAddressString打印机的蓝牙MAC地址
ssidbyte[]WIFI的essid
pwdStringWIFI的密码

回调方法:

  • 方法一:
   public void onSetWifiSuccess() {

    }

说明:打印机收到需要配置的WIFI信息,开始尝试连接WIFI,这里建议添加超时机制

  • 方法二:
   public void wifiConfigSuccess() {

    }

说明:打印机设置WIFI成功

  • 方法三:
   public void onWifiConfigFail() {

    }

说明:打印机设置WIFI失败,一般是输入的WIFI密码不正确导致

6)退出配网过程

说明:该方法只有统一的发送蓝牙信息失败的回调,该方法建议在onBackPressed方法中调用

接口名:

  • quitConfig

接口声明:

   sunmiPrinterClient.quitConfig(btAddress);

传入参数:

参数名类型说明
btAddressString打印机的蓝牙MAC地址

7)请求删除wifi 配置,并使用2G网络

说明:该方法只有统一的发送蓝牙信息失败的回调,如果打印机使用2G网络,不采用WIFI就可以调用该方法。

接口名:

  • deleteWifiInfo

接口声明:

   sunmiPrinterClient.deleteWifiInfo(btAddress);

传入参数:

参数名类型说明
btAddressString打印机的蓝牙MAC地址

8)断开和蓝牙打印机的蓝牙连接

说明:该方法需要在页面销毁的时候进行调用

接口名:

  • disconnect

接口声明:

   sunmiPrinterClient.disconnect(btAddress);

传入参数:

参数名类型说明
btAddressString打印机的蓝牙MAC地址

云打印机对接说明

2. 注册一个合作伙伴账号

  • a) 合作伙伴业务需基于商米云提供的安全保障前提下,所以要求合作伙伴需要拥有一个商米合作伙伴平台账户。

关于注册合作伙伴流程请参考:https://docs.sunmi.com/developers/registration-for-partners/

  • b) 要求打印机设备在商米公司出库时渠道一定要选择该账户下,否则打印机会因归属权问题无法进行下一步绑定业务。

云打印机对接说明

特别声明:

商米云打印机对接通道为更好的保护合作伙伴的数据隐私,又能实现完整的订单打印过程,特订立以下对接规范,并需要商米与合作伙伴双方共同努力才能实现打印通道业务。

1. 了解一下对接流程

  • ①在 https://partner.sunmi.com/ 注册一个合作伙伴平台账户,并获得账户CID关键字,用于接口API调用时使用;开通商米云打印机通道服务,并获得服务APP _ID、APP_KEY,用于接口API调用时使用;待合作伙伴接口开发上线后,还需要提供一个合作伙伴云URL给到商米云服务,用于让打印机回调合作伙伴API接口完成打印业务;
  • ②合作伙伴业务APP中,“商米配网SDK”提供了一个简单易用的蓝牙配置WIFI联网开发过程,简单调用就可以让打印机连接上云端;
  • ③SDK配网过程会自动获得打印机设备SN号,这个SN是设备的唯一标识符,利用它就可以绑定对应的商家账号完成业务通讯;
  • ④合作伙伴业务APP中,使用SN号去合作伙伴云建立设备与商家店铺的关联关系;
  • ⑤合作伙伴业务APP中,使用SN号调用商米云API绑定接口,建立设备SN与合作伙伴ID、商铺ID的关联关系;
  • ⑥合作伙伴云对接商米订单推送、声音推送等API接口,建立起消息通讯通道;
  • ⑦商米云在接收到推送消息以后,会自动向打印机下发业务消息;
  • ⑧打印机在收到触发消息以后,使用之前提供的合作伙伴云URL去回调API接口获取订单的打印内容,并打印出来;
  • ⑨打印业务对接完成以后,如果还需要进一步管理设备时,可以在合作伙伴业务APP中直接调用商米“设备管理页面”进行打印管理。更多的打印机设置内容将不断的完善,让商家可以获得更好的体验。

跳转到应用商店APP详情

注:只适用于应用市场3.5或以上版本的竖屏设备

1.在应用内通过Intent打开:

public void startActivity(){

String packageName = "要打开的App的包名";

String uri = String.format("market://woyou.market/appDetail?packageName=%s",packageName);

        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));

        intent.addCategory(Intent.CATEGORY_DEFAULT);

        PackageManager packageManager = getPackageManager();

        List activities = packageManager.queryIntentActivities(intent,

                PackageManager.MATCH_DEFAULT_ONLY);

        boolean isIntentSafe = activities.size() > 0;

        if (isIntentSafe) {

            startActivity(intent);

        }

    }

2.通过使用webview打开:

在xml中使用进入应用市场详情页

如果mWebView.setWebViewClient();设置了此函数,则不能通过a链接自动打开,只能通过拦截链接再使用Intent跳转。

mWebView.setWebViewClient(new WebViewClient(){

            @Override

            public boolean shouldOverrideUrlLoading(WebView view, String url) {

                Log.d(TAG, "shouldOverrideUrlLoading: " + url);

                Intent intent = null;

                try {

                    intent = Intent.parseUri(url,Intent.URI_INTENT_SCHEME);

                } catch (URISyntaxException e) {

                    e.printStackTrace();

                    return false;

                }

                startActivity(intent);

                return true;

            }

        });

3.在浏览器打开:

地址:market://woyou.market/appDetail?packageName=包名

注:只能在终端自带浏览器或者Chrome 浏览器打开,其他浏览器均打开不开

特殊代码说明

一、获取商米设备标识

商米建议通过获取到以下内容来判断是否商米设备:

1.设备的品牌名 brand(如:SUNMI)

    商米的品牌名统一为 SUNMI

2.设备的系统型号 model(如:V1-B18)

    系统型号组成为 产品型号+硬件特性+‘-’+软件特性

    其中以V、M、P、L开头为手持设备,以T、D、S开头为横屏设备(截至2017年12月) 

3.设备的ROM版本号(如:1.1.0)。

4.设备的ROM顺序号(如:128)。

可以下载Demo,仿照Demo在自己项目src下面新建android.os包(固定写法),将SystemProperties.java放入该包下,按以下方法获取指定的值:

获取brand的代码为:

    String brand = SystemProperties.get("ro.product.brand");

获取model的方法为:

    String model = SystemProperties.get("ro.product.model");

获取ROM版本号的代码为:

    String versionname = SystemProperties.get("ro.version.sunmi_versionname");

获取ROM顺序号的方法为:

    String versioncode = SystemProperties.get("ro.version.sunmi_versioncode");

 

二、获取设备的SN号

1.在AndroidManifest.xml中添加如下权限。

2.在需要的地方用以下代码获取商米SN号。

public static String getSN() {
        if (Build.VERSION.SDK_INT ›= Build.VERSION_CODES.O) {
            return Build.getSerial();
        } else
            return Build.SERIAL;
    }

三、隐藏及恢复底部导航栏

(注:商米新开发了Kiosk霸屏模式,APP不用做任何修改,仅通过云端设置即可实现隐藏状态栏、导航栏并无法通过手势唤出。   该功能在T2、K1设备上已实现,其他设备上线进展请联系技术支持400-902-1168(9:00-21:00)。   建议合作伙伴使用商米Kiosk霸屏模式,已获得更好的体验)

Android系统默认提供了隐藏系统的导航栏的方法,但对于Dialog的支持较差,导致全屏对话框打开时先弹出导航栏再隐藏(闪屏),SunmiOS针对此问题进行了修复(V1系统固件版本252后支持,T1系统固件版本132后支持)

1.Activity的全屏化

——安卓默认支持

public class MainActivity extends AppCompatActivity {
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        SystemUIUtils.setStickFullScreen(getWindow().getDecorView());
    }
}
public class SystemUIUtils {

    public static void setStickFullScreen(View view) {
        int systemUiVisibility = view.getSystemUiVisibility();
        int flags = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
                | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
        systemUiVisibility |= flags;
        view.setSystemUiVisibility(systemUiVisibility);
    }

}

2.Dialog的全屏化

——原生系统下 AOSP 的Bug会导致全屏对话框打开时先弹出导航栏然后再隐藏导航栏(闪屏)。

public AlertDialog create(boolean fullscreen) {
    LayoutInflater inflater = LayoutInflater.from(context);

    final AlertDialog dialog = new AlertDialog(context,
            R.style.DialogStyle);

    if(fullscreen){
        SystemUIUtils.setStickFullScreen(dialog.getWindow().getDecorView());
    }
}

3.设置隐藏后显示导航栏

3.1.全局底部上划

——上划后底部导航栏显示4s,4s后底部导航栏隐藏

3.2.切换应用至其他APP(如APP内跳转至第三方应用、第三方APP弹窗等)

——切换至其他APP是否显示底部导航栏以第三方应用要求为准,切换至自己APP时底部导航栏消失

四、避免重复申请外设权限

当APP需要通过USB关联外设来实现业务时(比如连接USB打印机打印小票),安卓要求用户手动确认设备使用权限,来保障用户信息安全,防止木马非法入侵USB设备。

1.如何避免USB设备重新插拔同一个外设时,APP反复申请该外设权限

需要用户手动确认时,勾选“默认情况下用于该USB设备”,无法通过代码绕过该安全机制

验证DEMO

2.如何避免设备重启后,已勾选“默认情况下用于该USB设备”的APP仍反复申请同一个外设的使用权限

2.1.在APP的AndroidManifest中指定某个Activity部分中,添加如下代码


                


2.2.在该目录下创建xml文档



    

其中,class的值需要和要连接的外设类型一致,外设class参照表如下


    /**
     * USB class indicating that the class is determined on a per-interface basis.
     */
    public static final int USB_CLASS_PER_INTERFACE = 0;
    /**
     * USB class for audio devices.
     */
    public static final int USB_CLASS_AUDIO = 1;
    /**
     * USB class for communication devices.
     */
    public static final int USB_CLASS_COMM = 2;
    /**
     * USB class for human interface devices (for example, mice and keyboards).
     */
    public static final int USB_CLASS_HID = 3;
    /**
     * USB class for physical devices.
     */
    public static final int USB_CLASS_PHYSICA = 5;
    /**
     * USB class for still image devices (digital cameras).
     */
    public static final int USB_CLASS_STILL_IMAGE = 6;
    /**
     * USB class for printers.
     */
    public static final int USB_CLASS_PRINTER = 7;
    /**
     * USB class for mass storage devices.
     */
    public static final int USB_CLASS_MASS_STORAGE = 8;
    /**
     * USB class for USB hubs.
     */
    public static final int USB_CLASS_HUB = 9;
    /**
     * USB class for CDC devices (communications device class).
     */
    public static final int USB_CLASS_CDC_DATA = 0x0a;
    /**
     * USB class for content smart card devices.
     */
    public static final int USB_CLASS_CSCID = 0x0b;
    /**
     * USB class for content security devices.
     */
    public static final int USB_CLASS_CONTENT_SEC = 0x0d;
    /**
     * USB class for video devices.
     */
    public static final int USB_CLASS_VIDEO = 0x0e;
    /**
     * USB class for wireless controller devices.
     */
    public static final int USB_CLASS_WIRELESS_CONTROLLER = 0xe0;
    /**
     * USB class for wireless miscellaneous devices.
     */
    public static final int USB_CLASS_MISC = 0xef;
    /**
     * Application specific USB class.
     */
    public static final int USB_CLASS_APP_SPEC = 0xfe;
    /**
     * Vendor specific USB class.
     */
    public static final int USB_CLASS_VENDOR_SPEC = 0xff;

3.如何避免前两步后设置后,业务页面会因USB设备插入而刷新

安卓原生逻辑导致用户选择“默认情况下用于该USB设备”会导致USB设备插入时打开某个指定activity。如果要避免页面刷新导致业务中断,可以增加如下代码防止页面刷新。

 

五、如何避免自己的应用数据被清除

应用数据默认是可以通过系统设置删除的,删除后应用将恢复刚安装的状态。但是可以通过配置APP来精细管理应用数据(比如按照业务分类或时间删除数据),也可以避免重要的应用数据被删除。

Screenshot-3.png
Screenshot-2.png

在程序的manifest文件的application中加上manageSpaceActivity属性,并且指定一个Activity,这个Activity就是点击管理空间之后会跳转的那个Activity了。

  

  
    
  

PS 如果要避免数据被删除,可以创建一个自动关闭的Activity。

public class ManageSpaceActivity extends Activity {  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
  
        finish();  
  
    }// onCreate  
}  

七、如何避免插入usb外设导致app界面闪烁

在APP的AndroidManifest中,添加如下代码

android:configChanges="navigation|keyboardHidden|keyboard"

八、如何避免扫描枪扫出内容与实际不一致

一般情况下,文本框输入的所有内容会提交给输入法进行转换(如拼音、联想等),有的输入法经过转换后会转义部分字词导致输入内容不一致。

除了更换系统输入法为合适的输入法外,还可以利用输入法通常不对密码框进行处理的规则,调整文本框类型为“可见密码”(inputType),并且约定好可输入规范(digits)也可以避免该问题