商米-android-使用NFC读IC卡,身份证云解和IC卡同时兼容

商米介绍地址:https://www.sunmi.com/
商米是一个提供手持PDA的一个很好的解决方案厂商,
也有其他的一些桌面设备。
其中商米提供的软件服务中,比较特别的是 身份证云解功能。

此处重点说明一下,身份证云解功能。

以往市面上的身份证读卡功能,都是找公安申请身份证读卡器硬件模块。比较贵。
商米的身份证读卡,是利用商米的NFC功能,配合身份证云解功能来实现

单独实现身份证读卡,和单独实现NFC刷IC卡,在商米提供的SDK很容易能实现
但是同时实现兼容 读IC卡和身份证,现在的商米SDK 就兼容性做的很差。
这里主要说明一下同时兼容 读IC卡和身份证,

1、引用jar包:implementation ‘com.sunmi:SunmiEID-SDK:1.3.16’

2、主界面上,初始化NFC,NfcUtils

package com.smk.travelpda.common.nfc;import android.app.Activity;
import android.content.Context;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.util.Log;
import android.widget.Toast;import com.smk.travelpda.common.util.RString;/*** luoyang*/public class NfcUtils {private static final String TAG = "NfcUtils";private static NfcAdapter mNfcAdapter;private NfcUtils(){}private static NfcUtils nfcUtils = null;private static boolean isOpen = false;/*** 获取NFC的单例* @return NfcUtils*/public static NfcUtils getInstance(){if (nfcUtils == null){synchronized (NfcUtils.class){if (nfcUtils == null){nfcUtils = new NfcUtils();}}}return nfcUtils;}private  NfcListener nfcListener;public void setNfcListener(NfcListener listener){nfcListener = listener;}/*** 在onStart中检测是否支持nfc功能* @param context 当前页面上下文*/public void onStartNfcAdapter(Context context){//设备的NfcAdapter对象mNfcAdapter = NfcAdapter.getDefaultAdapter(context);}/*** 在onResume中开启nfc功能* @param activity*/public void onResumeNfcAdapter(final Activity activity){if(mNfcAdapter==null){//判断设备是否支持NFC功能RString.showDia(activity,"提醒","设备不支持NFC功能");return;}if (!mNfcAdapter.isEnabled()){//判断设备NFC功能是否打开RString.showDia(activity,"提醒","请到系统设置中打开NFC功能!");return;}if (!isOpen) {mNfcAdapter.enableReaderMode(activity, new NfcAdapter.ReaderCallback() {@Overridepublic void onTagDiscovered(final Tag tag) {if (nfcListener != null){(activity).runOnUiThread(new Runnable() {@Overridepublic void run() {nfcListener.nfcReadHander(tag);}});}}},(NfcAdapter.FLAG_READER_NFC_A |NfcAdapter.FLAG_READER_NFC_B |NfcAdapter.FLAG_READER_NFC_F |NfcAdapter.FLAG_READER_NFC_V |NfcAdapter.FLAG_READER_NFC_BARCODE ),null);isOpen = true;}}/*** 在onPause中关闭nfc功能* @param activity*/public void onPauseNfcAdapter(Activity activity){if(mNfcAdapter!=null && mNfcAdapter.isEnabled()){if (isOpen){mNfcAdapter.disableReaderMode(activity);}isOpen = false;}}}

NFC监听组件

package com.smk.travelpda.common.nfc;import android.nfc.Tag;/*** 自定义的NFC接口*/public interface NfcListener{/*** 用于扫到nfc后的后续操作*/void nfcReadHander(Tag tag);}

设置商米SDK的回调方法

package com.smk.travelpda.common.yidcard;import android.util.Log;import com.smk.travelpda.MainActivity;
import com.smk.travelpda.common.util.RJson;
import com.sunmi.eidlibrary.EidCall;
import com.sunmi.eidlibrary.EidConstants;
import com.sunmi.eidlibrary.EidSDK;import java.util.Map;//云解身份证读卡回调方法
public class EidCardReadCall implements EidCall {private String TAG = "IdCardHander";private EidcardListener eidcardListener;private String eventType;public  EidCardReadCall(EidcardListener eidcardListener,String eventType){this.eidcardListener = eidcardListener;this.eventType = eventType;}@Overridepublic void onCallData(int code, String msg) {if(this.eventType.endsWith(EidHanderEo.EID_INIT)){initEidHanderCall(code, msg);}else if(this.eventType.endsWith(EidHanderEo.Eid_READY_NFC)){readerForNfc(code, msg);} else if (this.eventType.endsWith(EidHanderEo.GETIDCARDINFO)) {getIDCardInfo(code, msg);}}public void initEidHanderCall(int i, String s){EidHanderEo inttEo = new EidHanderEo(this.eventType);inttEo.setEventCode(i);switch (i) {case EidConstants.EID_INIT_SUCCESS:inttEo.setSucces(true);break;default:inttEo.setSucces(false);inttEo.setMsg(s);break;}eidcardListener.handEidEvent(inttEo);}public void getIDCardInfo(int i, String s) {EidHanderEo eo = new EidHanderEo(this.eventType);eo.setEventCode(i);if (i == EidConstants.DECODE_SUCCESS) {eo.setSucces(true);eo.setCardType("sfz");try{Map<String,Object> sfzMap = RJson.parseJson2Map(s);String idnum = (String)((Map<String,Object>)sfzMap.get("base_info")).get("idnum");eo.setCardId(idnum);}catch (Exception e){eo.setSucces(false);eo.setMsg("身份证解析失败,请重试");}} else {//解码失败,code 为错误吗,data为错误原因// typetext.setText("解析失敗:code:"+i);//typetext.setText("解析失敗:data:"+s);eo.setSucces(false);eo.setMsg(s);}eidcardListener.handEidEvent(eo);}public void readerForNfc(int code, String msg) {System.out.println("code:" + code + ":msg:" + msg);EidHanderEo eidHanderEo = new EidHanderEo(this.eventType);eidHanderEo.setEventCode(code);switch (code) {case  EidConstants.EID_INIT_SUCCESS:eidHanderEo.setSucces(true);break;case EidConstants.ERR_NFC_NOT_SUPPORT:// 该机器不支持NFC功能,无法使用SDKeidHanderEo.setSucces(false);eidHanderEo.setMsg("机器不支持NFC");break;case EidConstants.ERR_NETWORK_NOT_CONNECTED:eidHanderEo.setSucces(false);eidHanderEo.setMsg("网络未连接,请联网后重试");// *** 异常处理: 连接网络后,需要重新调用 startCheckCard 方法 (手动触发,非自动)***break;case EidConstants.ERR_NFC_CLOSED:eidHanderEo.setSucces(false);eidHanderEo.setMsg("NFC 未打开,打开后重试 ");//  *** 异常处理: 打开NFC后,需要重新调用 startCheckCard 方法 (手动触发,非自动)***break;case EidConstants.READ_CARD_READY://Step 3 读卡准备完成 -> 业务方可以引导用户开始进行刷卡操作eidHanderEo.setSucces(true);eidHanderEo.setMsg("SDK准备完成,请刷卡");break;case EidConstants.READ_CARD_START://Step 4 读卡中 -> 业务方可以提醒用户"读卡中,请勿移动卡片"eidHanderEo.setSucces(true);eidHanderEo.setMsg("开始读卡,请勿移动");break;case EidConstants.READ_CARD_SUCCESS://Step 5 读卡成功 -> 返回的msg为reqId,通过 reqId 业务方走云对云方案获取身份证信息//注:如不需要循环读卡,可在此处调用stopCheckCard方法eidHanderEo.setSucces(true);eidHanderEo.setMsg("读卡成功");eidHanderEo.setCardId(msg);//设置读取的身份证IDbreak;case EidConstants.READ_CARD_FAILED://*** 异常处理: 读卡失败,请重新读卡 ***eidHanderEo.setSucces(false);eidHanderEo.setMsg("读卡失败,请重试"+ msg);break;case EidConstants.ERR_ACCOUNT_EXCEPTION://*** 异常处理: 读卡失败,请重新读卡 ***eidHanderEo.setSucces(false);eidHanderEo.setMsg("该设备未开通身份证读卡权限!");break;default://*** 异常处理: 其他失败 - code为错误码,msg为详细错误原因 需要重新调用 startCheckCard 方法 (手动触发,非自动)***eidHanderEo.setSucces(false);eidHanderEo.setMsg("读卡异常,请重试code:"+code+ msg);break;}eidcardListener.handEidEvent(eidHanderEo);}}

商米SDK的监听方法

package com.smk.travelpda.common.yidcard;/*** 处理EID的事件*/
public interface EidcardListener {public void handEidEvent(EidHanderEo eidHanderEo);
}

主界面

package com.smk.travelpda;import android.content.IntentFilter;
import android.nfc.Tag;
import android.nfc.tech.IsoDep;
import android.nfc.tech.MifareClassic;
import android.nfc.tech.NfcA;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;import com.smk.travelpda.common.macinfo.MacInfoHander;
import com.smk.travelpda.common.nfc.NfcListener;
import com.smk.travelpda.common.nfc.NfcReadHander;
import com.smk.travelpda.common.nfc.NfcUtils;
import com.smk.travelpda.common.scan.ScanEventEo;
import com.smk.travelpda.common.scan.ScanListener;
import com.smk.travelpda.common.util.BusinessException;
import com.smk.travelpda.common.util.RString;
import com.smk.travelpda.common.util.VersionCheckUtil;
import com.smk.travelpda.common.yidcard.EidCardReadCall;
import com.smk.travelpda.common.yidcard.EidHanderEo;
import com.smk.travelpda.common.scan.ScanMachinReceive;
import com.smk.travelpda.common.yidcard.EidcardListener;
import com.sunmi.eidlibrary.EidCall;
import com.sunmi.eidlibrary.EidConstants;
import com.sunmi.eidlibrary.EidReader;
import com.sunmi.eidlibrary.EidSDK;/*** luoyang 2024-04-17*/
public class MainActivity extends AppCompatActivity  implements NfcListener, ScanListener, EidcardListener {public final static String APP_ID = "商米的APPID";public final static String APP_KEY = "商米的APPKEY";private   TextView datatext;//绑定的归属方,景区名称private   TextView tourname;private   TextView sntext;private TextView visionnum;private NfcUtils nfcUtils = NfcUtils.getInstance();private EidReader eid;private ScanMachinReceive myReceiver ;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);EdgeToEdge.enable(this);setContentView(R.layout.activity_main);ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);return insets;});datatext = findViewById(R.id.data);tourname = findViewById(R.id.tourname);sntext = findViewById(R.id.sntext);visionnum = findViewById(R.id.visionnum);sntext.setText("序列号:"+MacInfoHander.getSN());visionnum.setText("V1.0.0");tourname.setText("景区");//初始化NFC读卡器nfcUtils.setNfcListener(this);//商米的扫码监听initScanReceiveLislen();//初始话监听//初始化身份证读卡initCardEidSdk();}@Overrideprotected void onDestroy() {super.onDestroy();// 注销扫码接收广播unregisterReceiver(myReceiver);//注销读卡服务EidSDK.destroy();}@Overrideprotected void onStart() {super.onStart();System.out.println("onStart................................");nfcUtils.onStartNfcAdapter(this);       //初始化Nfc对象}@Overrideprotected void onResume() {super.onResume();System.out.println("onResume................................");nfcUtils.onResumeNfcAdapter(this);      //activity激活的时候开始扫描datatext.append("NFC初始化成功\n");}@Overrideprotected void onPause() {super.onPause();System.out.println("onPause................................");nfcUtils.onPauseNfcAdapter(this);       //activity切换到后台的时候停止扫描}//读NFC卡后的返回事件@Overridepublic void nfcReadHander(Tag tag) {datatext.setText("start new card");String tl[] = tag.getTechList();//POS机器,只支持2代和3代卡,身份证,其他证件不支持try {boolean isHandCard = false;for (String s:tl) {if(s.equals("android.nfc.tech.MifareClassic")){//String data = NfcReadHander.readMifareTag(tag,MifareClassic.get(tag));datatext.setText(RString.byteToString(tag.getId()));isHandCard = true;break;//旅游卡PDA 无需支持M1卡类型}else if(s.equals("android.nfc.tech.IsoDep")){String cardType = "smk";//读取IC卡String cardId = NfcReadHander.readIsoDepTag(tag, IsoDep.get(tag));System.out.println("cardId"+cardId);datatext.setText(cardId);isHandCard = true;break;}else  if(s.equals("android.nfc.tech.NfcB")){//跳转到身份证云解读取,NFCB为身份证模块,此处调用身份证云解,其他的为IC卡读取eid.nfcReadCard(tag);isHandCard = true;break;}}if(!isHandCard){throw new BusinessException("请刷IC卡或身份证");}}catch (BusinessException e){//捕获自定义异常datatext.setText(e.getMessage());}}/*** 实现扫码事件* @return*/@Overridepublic void scanEventHander(ScanEventEo eventEo) {String  eventType = eventEo.getEventType();if(eventType.equals(ScanEventEo.SCAN_START)){//typetext.setText("开始扫码");datatext.setText("开始扫码");} else if (eventType.equals(ScanEventEo.SCAN_RECEVIE)) {//typetext.setText("扫码成功");datatext.setText("");datatext.append(eventEo.isAllow()+":"+ eventEo.getQrData());} else if (eventType.equals(ScanEventEo.SCAN_END)) {datatext.setText("扫码结束");}}//实现云解身份证的事件@Overridepublic void handEidEvent(EidHanderEo eidHanderEo) {String eventType = eidHanderEo.getEventType();if(eventType.equals(EidHanderEo.EID_INIT)){//typetext.setText("init success");//init初始化监听时间if(eidHanderEo.isSucces() &&  eidHanderEo.getEventCode() == EidConstants.EID_INIT_SUCCESS){eid = EidSDK.getEidReaderForNfc(3, new EidCardReadCall(this,EidHanderEo.Eid_READY_NFC));}else {//其他都是失败的,RString.showDia(this,"身份证模块初始化失败",eidHanderEo.getMsg());}} else if (eventType.equals(EidHanderEo.Eid_READY_NFC)) {// typetext.setText("Eid_READY_NFC");//读卡的回调if(eidHanderEo.isSucces() &&  eidHanderEo.getEventCode() == EidConstants.READ_CARD_SUCCESS){datatext.setText(eidHanderEo.getCardId());//读卡成功的回调EidSDK.getIDCardInfo(eidHanderEo.getCardId(), MainActivity.APP_KEY, new EidCardReadCall(this,EidHanderEo.GETIDCARDINFO));}else if(!eidHanderEo.isSucces()){RString.showDia(this,"提醒",eidHanderEo.getMsg());}else{//有些成功,是否需要干预流程处理,不需要就不做任何事情//datatext.setText(eidHanderEo.getMsg());datatext.append("身份证模块初始化成功");}} else if (eventType.equals(EidHanderEo.GETIDCARDINFO)) {//typetext.setText("GETIDCARDINFO");//调用if(eidHanderEo.isSucces() && eidHanderEo.getEventCode() == EidConstants.DECODE_SUCCESS){//解析成功datatext.setText("");datatext.append(eidHanderEo.getCardId());}else {RString.showDia(this,"提醒",eidHanderEo.getMsg());}}}private  void initScanReceiveLislen(){myReceiver = new ScanMachinReceive(this);IntentFilter intentFilter = new IntentFilter();intentFilter.addAction(ScanEventEo.SCAN_RECEVIE); // 监听网络变化广播intentFilter.addAction(ScanEventEo.SCAN_START); // 监听网络变化广播intentFilter.addAction(ScanEventEo.SCAN_END); // 监听网络变化广播// 注册广播  只从原生获取,不从外部APP获取registerReceiver(myReceiver, intentFilter);datatext.append("扫码初始化成功\n");}private  void initCardEidSdk(){EidSDK.init(this, APP_ID, new EidCardReadCall(this,EidHanderEo.EID_INIT));// EidSDK.startCheckCard不要使用这个API}public  void visionClick(View view){//startActivity(VersionCheckUtil.check(false));}
}

这个兼容身份证和IC读卡的关键点在于,不要使用SDK里面 EidSDK.startCheckCard();

1、EidSDK.init方法,
2、在EidSDK.init的成功回调函数中,获取NFC读卡的
EidReader eid = EidSDK.getEidReaderForNfc(3, new EidCardReadCall(this,EidHanderEo.Eid_READY_NFC));
3、初始化成EidReader , 此时刷卡,在NFC读卡器检测到NFCB 的tag类型之后,再使用EidReader 去处理身份证读卡的功能 eid.nfcReadCard(tag); 此处会在第二部的回调函数中 得到读取身份证的结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/10285.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue学习JSON.stringify()将Object类型转换成String类型

Vue学习JSON.stringify&#xff08;&#xff09;将Object类型转换成String类型 一、前言1、基本用法2、复杂对象转换3、过滤器函数4、序列化函数 一、前言 JSON.stringify() 是一个 JavaScript 函数&#xff0c;用于将 JavaScript 值转换为 JSON 字符串。它接受一个 JavaScrip…

深入探索MySQL视图

前言 在数据库的世界里&#xff0c;MySQL视图作为数据抽象的一把利剑&#xff0c;为我们提供了一种灵活而高效的方式来管理和查询数据。它不仅能够简化复杂的查询逻辑&#xff0c;还能在不改动底层数据结构的前提下&#xff0c;实现数据的定制化展示与访问控制。本文旨在深入解…

【小红书采集工具】根据搜索关键词批量采集小红书笔记,含笔记正文、笔记链接、发布时间、转评赞藏等

一、背景介绍 1.1 爬取目标 熟悉我的小伙伴都了解&#xff0c;我之前开发过2款软件&#xff1a; 【GUI软件】小红书搜索结果批量采集&#xff0c;支持多个关键词同时抓取&#xff01; 【GUI软件】小红书详情数据批量采集&#xff0c;含笔记内容、转评赞藏等&#xff0c;支持…

【C++】string类的使用①(默认成员函数 || 迭代器接口begin,end,rbegin和rend)

&#x1f525;个人主页&#xff1a; Forcible Bug Maker &#x1f525;专栏&#xff1a; STL || C 目录 前言&#x1f308;关于string类&#x1f308;string类的成员函数&#x1f525;默认成员函数string类对象的构造(constructor)string类对象的析构string类对象的赋值运算符…

NPOI生成word浮动图标

1、NPOI版本2.7.0, net框架4.8 2、安装OpenXMLSDKToolV25.msi 3、先创建一个word文档&#xff0c;并设置图片为浮于文字之上 4、OpenXML显示的结果 5、实际代码如下&#xff1a; public class GenerateWordDemo {public GenerateWordDemo(){}//https://blog.fileformat.co…

js由那三部分组成

JavaScript 主要由三部分组成&#xff1a;ECMAScript、DOM&#xff08;文档对象模型&#xff09;和 BOM&#xff08;浏览器对象模型&#xff09;。 1、ECMAScript ECMAScript 是 JavaScript 的核心&#xff0c;描述了语言的基本语法&#xff08;变量、函数、条件语句、循环、…

前端笔记-day03

文章目录 01-初始CSS02-CSS引入方式03-标签选择器04-类选择器05-id选择器06-通配符选择器07-画盒子08-字体大小09-文字粗细10-字体倾斜11-行高12-行高垂直居中13-字体族14-font复合属性15-文本缩进16-文本对齐方式17-图片对齐方式18-文本修饰线19-文字颜色20-调试工具21-综合案…

Dual Aggregation Transformer for Image Super-Resolution论文总结

题目&#xff1a;Dual Aggregation Transformer&#xff08;双聚合Transformer&#xff09; for Image Super-Resolution&#xff08;图像超分辨&#xff09; 论文&#xff08;ICCV&#xff09;&#xff1a;Chen_Dual_Aggregation_Transformer_for_Image_Super-Resolution_ICCV…

IM 是什么?

在当今数字化的时代&#xff0c;即时通讯&#xff08;IM&#xff09;已经渗透到人们的日常生活和企业的工作环境中。IM技术的快速i发展为人们提供了一种高效、便捷的沟通方式&#xff0c;不仅推动了社会的信息化进程&#xff0c;也提升了企业的协同效率和竞争力。 作为企业级I…

【GD32】01-GPIO通用输入输出

GD32 闲话说在前头 这里又开一个系列啦。 原因就是之前买了立创开发板的9.9的GD32E230C8T6的板子&#xff0c;买都买了就跟着立创开发板学习一下&#xff08;属于是一次性支持了两个国产品牌了&#xff0c;立创和兆易创新&#xff09;。并且我还买了GD32F407VET6的板子&…

资金流分析下的企业供货关系强度模型

图技术 利用neo4j、networkx、dgl、python做图分析挖掘 【1】最短路径算法dijkstra 【2】基于networkx的隐性集团关系识别模型 【3】基于Neo4j的担保社群型态分析挖掘 【4】基于python求有向无环图中target到其他节点全路径 【5】有向图中任意两点的路径 【6】图基础入门 【7】…

项目管理中控制质量的工具与技术

项目管理中控制质量的工具与技术 控制质量的工具与技术包括多种方法&#xff0c;旨在确保产品或服务达到既定的质量标准。关于具体的工具格式和样式&#xff0c;以下是一些示例&#xff1a; 统计技术&#xff1a; 这是一种将质量控制要素的数据转化为实际控制手段的技术。通…

Visual Studio和Visual Studio Code适用于哪些编程语言

Visual Studio和Visual Studio Code都适用于多种编程语言&#xff0c;它们的适用编程语言如下&#xff1a; Visual Studio适用于&#xff1a; C#Visual Basic .NETF#CJavaScriptTypeScriptPythonHTML/CSSJava&#xff08;通过插件支持&#xff09; Visual Studio Code适用于…

Jtti:哪些方法可以降低美国CN2服务器的延迟?

降低美国CN2服务器的延迟可以采取多种方法&#xff0c;以下是一些常用的方法&#xff1a; 1.选择优质的网络提供商和服务商&#xff1a;选择具有高质量网络和优质服务的网络提供商和服务商是降低延迟的关键。确保您选择的网络提供商具有可靠的基础设施和优质的网络连接&#xf…

C++:关于圆形鱼眼半全景图转为等距圆柱投影图

C&#xff1a;空间坐标映射到球面坐标/全景图_如何将球体坐标映射到球面uv-CSDN博客 C&#xff1a;关于360全景图像和立方体6面全景图像的相互转换_彩色全景拆解正方体6个面-CSDN博客 之前记录了立方体和360全景之间的转换&#xff0c;这次记录下鱼眼图与360全景图之间的转换…

C++ STL的锁介绍

在 C Standard Template Library (STL) 中&#xff0c;有几个锁的实现&#xff0c;这些都位于 <mutex> 头文件。以下是一些常见的锁及其功能&#xff1a; std::mutex&#xff1a;最基本的互斥锁&#xff0c;不可递归使用。该锁提供了独占的非公平锁定能力。 std::mutex…

处理浏览器缓存问题

处理浏览器缓存问题 main.js router.onError((error) > {hasRefreshed false;console.log("异常" error.message);let ind0 error.message.indexOf(Loading chunk chunk-)let ind2 error.message.indexOf(failed.)if(ind0 ! -1 && ind2 !-1){console.…

spring-boot-starter-validation校验框架

介绍 Spring Boot Starter Validation是一个Spring Boot模块&#xff0c;用于简化应用程序中的验证功能。它包含以下依赖&#xff1a; Hibernate Validator&#xff1a;Hibernate Validator是JavaBean Validation&#xff08;JSR 380&#xff09;规范的参考实现&#xff0c;提…

信创应用软件之办公流版签

信创应用软件之办公流版签 文章目录 信创应用软件之办公流版签概述流式文件版式文件电子签章厂商金山办公永中-永中Office中标-中标普华Office福昕科技e签宝法大大 概述 办公流版签软件主要包括办公中常用到的流式软件、版式软件以及电子签章。 版式文件和流式文件都是文书类…

软件体系结构总结

文章目录 一、软件体系结构概述1.1 基本概念1.1.1 背景1.1.2 定义1.1.3 系统1.1.3.1 定义1.1.3.2 特性1.1.3.3 系统的体系结构 1.1.4 软件设计的层次性1.1.5 体系结构的类别&#xff08;类型&#xff09;1.1.6 重要性&#xff08;意义&#xff09; 1.2 模块及其设计1.2.1 定义1…