mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
3005 字
8 分钟
真·智慧校园之全自动签到系统 NYAASP

NYAASP Yet Another Auto Signing Program#

前言#

████中学使用电子班牌进行管理。早晨到校和晚自习回班都要刷卡或刷脸,如果不刷就算迟到,要扣分。 可我每天早上都会被床硬控,所以经常被扣分。 因此我编写了NYAASP,有了它,就再也不用手动刷卡了!

逆向工程#

我通过特殊手段拿到了班牌程序,反编译得到以下代码:

NOTE

注释不是我写的。对我理解它很有用。大家也要保持写注释的好习惯www

//向服务器发送用户的刷卡记录
var sendIdcardRecord = function (findinfo) {
if (isEmpty(findinfo)) return false;
var saverecord = {
card_no: findinfo.card_no,
user_name: findinfo.user_name,
record_time: findinfo.record_time,
unique_code: settings.uuid,
lesson_code: app.getArrayVal(
"lesson_code",
findinfo,
app.getDefaultVal(sessionStorage.getItem("$nowLessonCode")),
),
place_id: deviceCfg.place_id,
source: 2, //数据来源班牌设备
user_id: findinfo.user_id,
user_type: findinfo.user_type,
dept_id: findinfo.dept_id,
method: "checkonwork.idcard.saverecord",
};
request({
url: settings.apiUrl + "/rest",
method: "POST",
data: saverecord,
}).catch(function () {
//记录考勤保存失败
});
};

很好,这正是我们需要的。简要分析一下API:

签到API#

POST /rest#

参数示例说明
card_no123456789卡号
user_name李华姓名
record_time1783517738000刷卡时间戳
unique_code?UUID
lesson_code?课程ID
place_id?班级ID
source22=班牌刷卡
user_id?个人ID
dept_id?部门ID
methodcheckonwork.idcard.saverecordIdentifier

参数获取#

API地址#

点击班牌右上角设置按钮,进入设置界面,即可看到服务器地址和端口。

若地址为空,则默认为 127.0.0.1:80 ,这时只能在班牌上动手脚了。

新版本中移除了该设置按钮,此时可以暂时断开网线,进入“网络异常”界面,尝试输入默认密码 1234567890 进入设置界面。

卡号#

卡号可以通过在考勤界面刷卡得到,是一串十进制数字。

也可通过校卡UID(2字节)计算得到

Classcard 智慧班牌系统 — 完整分析文档#

本文档整合了针对 Classcard(智慧班牌/考勤终端)Android 应用的两次深度分析: A. JADX 原生层反编译分析B. www 前端源码层分析(含模拟晚习打卡)


目录#

  1. 系统概述
  2. A. JADX 原生层分析
    • A1. 应用结构总览
    • A2. 设备控制核心(DeviceControl/ConfigSettings)
    • A3. 服务框架与组件
    • A4. 网络层分析
    • A5. 原生层关键结论
  3. B. www 前端源码层分析
    • B1. 运行启动链路
    • B2. 服务器地址机制
    • B3. 刷卡打卡核心机制(完整数据流)
    • B4. 全部 API 接口清单
    • B5. 各页面职责对照表
    • B6. 关键发现与注意点
  4. C. 模拟晚习打卡分析
    • C1. 前置环境依赖
    • C2. 服务器端必需接口
    • C3. 完整 settings 数据结构
    • C4. 用户卡库数据结构
    • C5. 模拟启动流程
    • C6. 正常运维需手动输入的数据
  5. 附:代码文件清单

一、系统概述#

Classcard 是一款运行于 Android 终端(班牌、段牌、校牌、宿舍牌、门卫牌)上的智慧考勤展示应用。采用 HTML5+(DCloud / 5+ Runtime) 混合开发模式:

  • 外层:Android 原生壳 + HTML5+ Runtime(plus.* API)
  • 内层www 目录下的 HTML/JS/CSS 前端,负责界面展示与业务逻辑
  • 原生扩展deviceControlicCardread(串口读卡器)等自定义原生插件
  • 通信协议:HTTP POST JSON 到服务器 /rest 接口,method 参数区分业务

典型部署形态:每台终端对应一个教室(或门卫点),绑定后自动下载课表、座位表、用户卡库,支持学生刷卡打卡(到班、离班、早自习、午间、晚自习、进校、出校),并上报服务器统计考勤。

默认服务器地址http://hezdh.wzzd.cn/


A. JADX 原生层分析#

A1. 应用结构总览#

通过 JADX 反编译,应用为 io.dcloud.PandoraEntry(HTML5+ 标准入口)包装的混合应用。包结构包含:

  • 设备控制插件(核心自定义原生模块)
  • H5+ Runtime 框架io.dcloud 系列)
  • 网络请求模块
  • 串口读卡模块icCardread
  • 系统级操作模块(重启、关机、开屏、导航栏控制等)

A2. 设备控制核心(DeviceControl / ConfigSettings)#

关键类(推断名):ConfigSettings

负责管理 settings.json 设备配置文件,主要字段:

字段类型用途
apiUrlString服务器 API 地址
serverUrlString服务器主机
serverPortString服务器端口
domainPerfixString学校域名前缀
uuidString设备唯一标识
client_ipString设备 IP
mac_addrStringMAC 地址
mac_osString操作系统标识
resolutionString屏幕分辨率(如 1920*1080
resolutio_ratio_trueString真实分辨率
screenscaleString屏幕缩放比例
version / frame_versionString应用/框架版本
docPagecmdInt页面包命令(-1/0/1)
tmplid / tmplnameString页面模板 ID / 名称
deviceCfgObject绑定后的设备配置(含 place_id、device_name 等)

plus.deviceControl 原生插件提供的方法(推断):

  • getSettings() / setSettings() — 读写配置
  • openSettings() — 打开系统设置
  • openHomeSettings() — 切换主屏设置
  • reboot() / shutdown() — 重启 / 关机
  • statusMonitor(n) — 状态监控(n=0 停止)
  • watchdog(n) — 看门狗(代码中已注释停用)
  • identCode() — 获取设备唯一标识
  • SettingWin() — 打开终端网络设置窗口

读卡器插件 plus.icCardread

  • 通过串口读取 ID 卡/IC 卡卡号
  • 回调 receiveCardNoCallback 将卡号注入前端
  • 可配置串口路径(如 /dev/ttyS1)、波特率(如 9600)

A3. 服务框架与组件#

  • HTML5+ 标准入口io.dcloud.PandoraEntry
  • WebView 窗口管理plus.webview 管理主窗口与子窗口
  • PJAX 页面注入:通过 mui.fire / evalJS 在子页面间传递数据
  • 下载/解压plus.downloader + plus.zip 下载并解压界面包(page.zip)
  • 文件操作plus.io + plus.deviceControl 管理 _doc/ 本地目录

A4. 网络层分析#

  • 统一入口POST {apiUrl}/rest
  • 请求封装app.getJSON() / mui.ajax / request()(axios 封装)
  • 数据格式:JSON
  • 业务分发method 参数(如 checkonwork.idcard.saverecord
  • 跨域crossDomain: true
  • 重试机制:失败记录存入 $failrecordTable,定时重发

A5. 原生层关键结论#

  1. 配置持久化:核心配置存于 settings.json,通过 plus.deviceControl.getSettings() 读写。
  2. 读卡通过原生串口:读卡器卡号由原生层回调注入前端,前端再做业务处理。
  3. 看门狗已停用watchdog(0) 在代码中被注释,系统级保护弱化。
  4. 设备重启/关机:通过 device.quit() / plus.deviceControl.reboot() 实现。

B. www 前端源码层分析#

B1. 运行启动链路#

index.html (根)
├─ js/mui.min.js + js/app.js (框架 + 工具库)
├─ plus.deviceControl.getSettings() → settings (配置对象)
├─ settings.apiUrl → 服务器API地址
├─ 根据 docPagecmd 加载页面包:
│ ├─ docPagecmd=0 → _doc/page/ (本地解压页面包)
│ ├─ docPagecmd=1 → page/{tmplid}/index.html (内置页面包)
│ └─ docPagecmd=-1 → 未安装页面,跳转 program.html
├─ 内置页面包:
│ ├─ hbpzwb → 班牌座位表界面
│ ├─ duanpai → 段牌展播(带用户)界面
│ ├─ xiaopai → 校牌展播界面
│ ├─ sushe → 宿舍展播界面
│ ├─ guardplate → 门卫进出校刷卡(横屏)
│ └─ guardplatev → 门卫进出校刷卡(竖屏)
├─ page/hbpzwb/index.html (班牌主界面)
│ ├─ autoMode() 自动切换模式(按时段加载不同 module)
│ ├─ module/attence.html → 到/离班刷卡
│ ├─ module/morning.html → 早自习签到
│ ├─ module/noonday.html → 午间静校签到
│ ├─ module/evening.html → 晚自习签到
│ ├─ module/course.html → 今日课表
│ ├─ module/classtime.html → 作息时间
│ ├─ module/advertisement.html → 轮播展示
│ └─ module/classinfo.html → 班级信息
└─ 读卡事件分发:
plus.icCardread.receiveCardNoCallback(cardno)
→ DOM 事件 card.receiveCardNo
→ index.html(根) 监听 → subWebview.evalJS('inputListener("'+cardno+'")')
→ 各模块 callIdcardFun(cardno) 处理

B2. 服务器地址机制#

  • 默认回退settings.apiUrl = app.getDefaultVal(settings.apiUrl, 'http://127.0.0.1')
  • 实际配置来源setting.html / manage.html 手动输入服务器地址 + 端口,验证后写入 settings
  • 默认服务器http://hezdh.wzzd.cn/(端口 80),API 地址 = http://hezdh.wzzd.cn/rest
  • 服务器返回字段api_urldomainPerfixuuid
  • 设备信息:IP = device.deviceIp(),MAC = device.macAddr()

B3. 刷卡打卡核心机制(完整数据流)#

1. 读卡(硬件 → JS)#

  • 原生插件 plus.icCardread(串口读卡器)
  • 原生回调 → DOM 事件 card.receiveCardNo
  • index.html(根)监听 → subWebview.evalJS('inputListener("'+cardno+'")') 注入页面

2. 前端分发(page/hbpzwb/index.html)#

inputListener(cardno) 分发逻辑:

  • #frmlogin → 用户登录验证(checkIdcard)
  • #infopage → 德育/点赞
  • 否则 → callIdcardFun(cardno) → 考勤模块刷卡处理

3. 考勤页面 callIdcardFun 流程#

  1. localStorage.$cacheIdcardTable(本地卡库缓存)查找卡号
  2. 找到用户 → saveIdcardAttence(findinfo)sendIdcardRecord(findinfo) 上报
  3. layer.msg 弹窗显示:卡号 + 姓名 + 班级,成功绿图标 / 失败红图标
  4. 页面同步更新学生到班状态(绿=已签 / 红=缺勤 / 橙=迟到 / 灰=请假)

4. 上报参数(checkonwork.idcard.saverecord)#

{
method: 'checkonwork.idcard.saverecord',
unique_code: settings.uuid, // 设备唯一标识
lesson_code: $lesson_code, // 课节代码 (K0X X z/a/w/c/j)
place_id: deviceCfg.place_id, // 教室/场所ID
source: 2, // 数据来源: 2=班牌设备
user_id: findinfo.user_id, // 用户ID
user_type: findinfo.user_type, // 用户类型
dept_id: findinfo.dept_id, // 部门(班级)ID
user_name: findinfo.user_name, // 用户姓名
card_no: findinfo.card_no, // 卡号
record_time: findinfo.record_time, // 记录时间
}

5. 课节代码(lesson_code)含义#

代码含义
K000z / K0{周}z到班/早自习签到
K000w / K0{周}w离班/晚自习签到
K000j进校(门禁)
K000c出校(门禁)
K0{周}{节}{类型}某周某节课(a=午间, w=晚间, z=早间)

晚习示例:周一晚习第1节 = K01w,周二 = K02w,…周日 = K07w

B4. 全部 API 接口清单#

考勤上报核心接口(POST {apiUrl}/rest)#

Method用途来源页面
checkonwork.idcard.saverecord保存刷卡记录(核心考勤上报)所有考勤/门禁
checkonwork.idcard.cardlist获取用户卡库信息所有考勤/门禁
checkonwork.idcard.statistics获取考勤统计数据morning/noonday/evening
checkonwork.idcard.paybycard获取最近刷卡记录guardplate
classcard.classdata.attence获取到班记录attence.html
classcard.classdata.gradestudent获取班级学生列表attence.html
classcard.classdata.offclass发送离班通知attence.html.bak
classcard.classdata.schedule获取今日课表主页
studentwork.Classtypeseat.gettypeseatlist获取座位表早/中/晚
studentwork.studentleave.userleave请假验证门禁
studentwork.studentleave.guardverify门卫请假审核门禁

设备/绑定/设置接口#

Method用途来源页面
classcard.basic.checkManage管理员验证登录设置页
classcard.basic.getDeviceConfig获取设备配置定时任务
classcard.basic.bindDevice绑定设备到教室binding.html
classcard.basic.saveProgram保存页面程序设置/程序页
classcard.basic.deviceProgram获取可安装程序列表program.html
classcard.basic.getBindConfig获取绑定配置/教室列表binding.html
classcard.polling.*定时轮询任务index(根)

B5. 各页面职责对照表#

页面功能关键接口
index.html(根)启动入口,管理所有窗口
manage.html首次设备绑定/登录classcard.basic.checkManage
setting.html设置服务器地址/端口同上
binding.html绑定设备到教室classcard.basic.bindDevice
program.html选择安装页面包classcard.basic.deviceProgram
system.html系统设置中心
page/hbpzwb/index.html班牌主界面+考勤分发
module/attence.html到/离班刷卡saverecord, attence, gradestudent
module/morning.html早自习签到saverecord, statistics, gettypeseatlist
module/noonday.html午间静校签到同上
module/evening.html晚自习签到同上
guardplate/index.html门禁进校刷卡saverecord(K000j), paybycard
guardplate/goout.html门禁出校刷卡saverecord(K000c), paybycard

B6. 关键发现与注意点#

  1. www 目录文件均为明文:无 DCloud 加密,HTML/JS 全部可读。
  2. 失败重发机制sendIdcardRecord 失败后存入 $failrecordTable,每 5 秒重试。
  3. 本地卡库缓存$cacheIdcardTable 缓存用户卡号列表,刷卡先本地匹配再上报。
  4. 默认服务器地址http://hezdh.wzzd.cn/,API = http://hezdh.wzzd.cn/rest
  5. attence.html.bak:备份版含更丰富功能(离班通知 sendOffclassNotice),新版精简。
  6. 系统设置 180 秒超时system.html 无人操作自动返回($system_modetime)。
  7. 模式自动切换autoMode() 依据 $nowLessonCode(当前课节)决定加载哪个考勤模块。
  8. 设备模式 60 秒倒计时$device_modetime 归零后自动刷新本地卡库。

C. 模拟晚习打卡分析#

C1. 前置环境依赖(模拟必需)#

依赖来源说明
settings 对象localStorage.$settings含 apiUrl, uuid, deviceCfg
deviceCfg 对象settings.deviceCfg含 place_id, device_name
$nowLessonCodesessionStorage.$nowLessonCode晚习应为 K000wK0{周}w
$cacheIdcardTablelocalStorage.$cacheIdcardTable用户卡库(卡号→用户映射)
jQuery / layer / axios / mui页面引入JS 库
request 函数js/app.js(hbpzwb)axios 封装
sendIdcardRecordpage/hbpzwb/index.html刷卡记录上报
getIdcardTablepage/hbpzwb/index.html卡库刷新
app 对象js/app.js工具函数

C2. 服务器端必需接口(模拟时需可访问)#

  1. POST {apiUrl}/restcheckonwork.idcard.saverecord(保存考勤记录)
  2. POST {apiUrl}/restcheckonwork.idcard.cardlist(获取卡库)
  3. POST {apiUrl}/restcheckonwork.idcard.statistics(考勤统计)
  4. POST {apiUrl}/reststudentwork.Classtypeseat.gettypeseatlist(座位表)

C3. 完整 settings 数据结构(模拟需构造)#

// localStorage.$settings
var settings = {
"apiUrl": "http://hezdh.wzzd.cn", // 服务器API地址
"serverUrl": "hezdh.wzzd.cn", // 服务器主机
"serverPort": "80", // 端口
"domainPerfix": "", // 学校域名前缀
"uuid": "SIMULATED-UUID-001", // 设备唯一标识(伪造)
"client_ip": "192.168.1.100", // 设备IP
"mac_addr": "AA-BB-CC-DD-EE-FF", // MAC地址
"resolution": "1920*1080", // 分辨率
"screenscale": "1", // 屏幕缩放
"mac_os": "Android", // 操作系统
"version": "2.23.0616", // 应用版本
"frame_version": "1.18.1215", // 框架版本
"docPagecmd": 1, // 内置页面模式
"tmplid": "hbpzwb", // 页面模板ID
"tmplname": "班牌座位表界面",
"deviceCfg": {
"place_id": "10001", // 教室ID(伪造)
"device_name": "高三(1)班", // 设备名称
"schoolname": "某中学",
"placedata": {
"class_cfg": { "open_offclass": -1 }
},
"cardread": {
"type": "1",
"path": "/dev/ttyS1",
"baud": "9600"
}
}
};

C4. 用户卡库数据结构(模拟需构造)#

// localStorage.$cacheIdcardTable - 由 checkonwork.idcard.cardlist 返回
[
{
"user_id": "10001",
"user_name": "张三",
"user_sex": "1", // 1=男 2=女
"user_avatar": "", // 头像URL
"user_type": "2", // 2=学生
"user_type_text": "学生",
"dept_id": "2001", // 班级ID
"dept_id_text": "高三(1)班",
"card_value": ["1234567890"], // 卡号数组(可多张卡)
"extend_is_stay": "否" // 是否住校
},
{
"user_id": "10002",
"user_name": "李四",
"user_sex": "2",
"user_type": "2",
"user_type_text": "学生",
"dept_id": "2001",
"dept_id_text": "高三(1)班",
"card_value": ["0987654321"],
"extend_is_stay": "是"
}
]

C5. 模拟启动流程#

1. 打开 page/hbpzwb/index.html
2. 在控制台设置:
localStorage.setItem('$settings', JSON.stringify(settings))
localStorage.setItem('$cacheIdcardTable', JSON.stringify(cardTable))
sessionStorage.setItem('$nowLessonCode', 'K000w') // 或 K01w(周一)
3. 手动导航到 module/evening.html
4. 在控制台调用 inputListener('1234567890')
→ 走 callIdcardFun(cardno)
→ 本地卡库找到张三
→ sendIdcardRecord() → POST http://hezdh.wzzd.cn/rest
→ method=checkonwork.idcard.saverecord
→ 弹窗显示 "张三 刷卡成功"

C6. 正常运维需手动输入的数据#

步骤操作需手动输入
① 设置服务器manage.html 登录服务器地址 + 端口 + 管理员账号 + 管理员密码
② 选择学校manage.html 学校下拉选择学校(若有多个)
③ 绑定教室binding.html选择教室自定义设备名称
④ 安装页面包program.html选择界面包(如 hbpzwb 班牌座位表)

之后设备自动运行(自动下载课表/座位表/卡库,定时轮询),无需人工干预。

模拟时额外缺失数据

  • 设备 UUID(可伪造,如上例 SIMULATED-UUID-001
  • place_id(可伪造)
  • $cacheIdcardTable(需从服务器获取或手动构造)
  • $nowLessonCode(手动设置为晚习代码)

附:代码文件清单#

www 根目录#

文件说明
index.html应用启动入口,窗口/页面包管理
manage.html首次设备绑定/管理员登录
setting.html设置服务器地址/端口
binding.html绑定设备到教室
program.html选择安装页面包
system.html系统设置中心
js/app.js核心工具库(getJSON, getSettings, setSettings 等)
js/mui.min.jsMUI 框架
js/vue.min.jsVue 框架

页面包 page/#

目录说明
hbpzwb/班牌座位表界面(含 module 考勤模块)
duanpai/段牌展播(带用户)
xiaopai/校牌展播
sushe/宿舍展播
guardplate/门卫进出校刷卡(横屏)
guardplatev/门卫进出校刷卡(竖屏)

班牌考勤模块 page/hbpzwb/module/#

文件功能
attence.html到/离班刷卡
morning.html早自习签到
noonday.html午间静校签到
evening.html晚自习签到
course.html今日课表
classtime.html作息时间
advertisement.html轮播展示
classinfo.html班级信息

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

真·智慧校园之全自动签到系统 NYAASP
https://k.asxz.one/posts/nyaasp/
作者
Kuinone
发布于
2026-07-08
许可协议
CC-0

部分信息可能已经过时

目录