简介:一套面向餐饮、零售等行业大屏终端的多媒体信息发布系统,包含安卓播放端与PC端配套软件,可播放视频、图片、字幕等节目并支持场景化定时编排,适合单机或局域网内直接部署使用。资源共134个文件,以Java与XML源码为主,同时包含PNG图标、TTF字体、Gradle构建脚本及少量C/JAR依赖,其中Java/XML构成播放与配置界面逻辑,PNG/TTF是界面资源与字体,Gradle负责工程构建,整体约111.62MB,结构完整便于二次开发。播放端支持多场景轮流播放、后台下载播放内容、音量设置与截图、文件数据校验等功能,并兼容avi、mkv、mp4、jpg、png、bmp等常见多媒体格式;PC端负责场景与节目单的配置下发,形成从制作到播放的闭环。目前已有5543人学习下载,非常适合需要快速搭建自有信息发布系统、深入掌握安卓大屏播放器开发,或研究场景与节目单管理逻辑的工程师参考。 做信息发布系统这活儿,最早是从一块广告屏开始的。甲方要求其实很简单:店里那块安卓屏,每天按时间段播放不同公告,总部在电脑上改内容,别让我天天拿U盘去插。后来发现这需求到处都是——银行引导屏、工厂车间看板、学校电子班牌、社区公告屏,本质都是同一个东西:一台安卓显示终端加一个 PC 管理端。我今天说的这套东西,最终整理成了“信息发布系统(安卓+PC).zip”,安卓端负责在屏幕上跑展示逻辑,PC 端负责内容下发和设备管理,两端走 HTTP 接口通信,项目不算大,但该有的模块基本都有。
这篇内容适合三类人看:第一类是刚接到信发项目、想找参考实现的开发者;第二类是想把某个现成 zip 解压后改成自己业务做二次开发的人;第三类是已经跑起来但遇到各种设备兼容性、断网、升级毛病的维护者。我下面按整个项目的实际组织方式来讲,不按教科书目录讲,方便你解压之后直接对着目录看。
1. 拆开 zip 之前:先说清这个系统要解决什么
1.1 盒子里那台安卓显示终端
安卓端在我的项目里不是普通手机 App,而是“信发终端”。普通手机 App 的核心是用户主动操作,信发终端的核心是无人值守、持续展示。开机之后最好自己跳进播放页面,不要用户手点;屏幕保持常亮,杜绝锁屏;到了一定时间自动切到夜间模板;网络断了要能自动重连;断电恢复之后还要回到原来的状态。
所以我在安卓端做了几个偏底层的模块:只出现一次的引导页、主播放页面的电源管理 WakeLock、系统广播 BOOT_COMPLETED 的自启、一个轻量级的播放调度器。播放调度器不直接依赖 Activity 的生命周期,而是自己维护一个队列,按 PC 端下发的播放单循环执行。这个设计在后续扩展多屏模板时非常省事,加一个模板就是往队列里注册一种渲染器。
一个典型工程的目录结构大概长这样:
InfoPushSystem ├── AndroidClient │ ├── app │ │ ├── src/main/java/.../player │ │ ├── src/main/java/.../network │ │ ├── src/main/java/.../service │ │ └── src/main/assets/config.properties │ └── build.gradle ├── PcManager │ ├── InfoPushManager.sln │ ├── FfmpegWorker │ └── Database └── docs我第一次拿到这类工程时,习惯先看config.properties和数据库脚本,因为通信地址和表结构最能反映系统全貌。界面代码反而是最后才看的。
1.2 PC 管理端的角色
PC 端在我这套项目里担任两个角色:一是内容管理后台,操作员登录后上传图片、视频、PDF,把它们拖到一个播放时间轴里;二是设备管理中心,能看到每台终端的在线状态、当前播放节目、磁盘占用和日志。
我用的技术栈是 C# WinForm,因为这类系统通常要求部署在 Windows 服务器或者办公电脑上,WinForm 在局域网环境下开发效率高,部署也省事。如果你不熟 C#,换成 Java Swing、Electron 甚至 PHP+Web 管理后台都可以,协议层保持一致就行。
1.3 部署形态:单机直连与公网中转
这个系统的网络部署有两种典型形态:
- 单机直连:终端和 PC 在同一个局域网,PC 管理端直接访问终端 IP,适合单个门店几十块屏的规模。
- 公网中转:终端分布在不同网络,PC 管理端部署在服务器上,终端定时轮询服务器接口拉取播放单,适合连锁门店或跨地域项目。
两种形态在我这个 zip 里都跑得通,区别只在客户端连接的 baseUrl 配置。我第一次搞的时候忽略了这一点,把接口地址写死成了局域网 IP,到了另一个项目上全是 0,后来才抽象成一个属性配置文件。
2. 安卓端最容易被低估的三个工程点
2.1 开机自启、断电重启与看门狗逻辑
信发终端很少做优雅关机,绝大多数时候是直接断电。所以你光有 BOOT_COMPLETED 自启还不够,还要处理“开机后还没收到广播就被用户 UI 抢先”和“系统有自杀式回收策略”这两类问题。
我实测下来的组合拳是这样:MainActivity 注册 BOOT_COMPLETED,同时在自己的 Application 里维护一个前台服务,服务里申请 WakeLock 并标记为 START_STICKY。START_STICKY 的意思是,系统把服务杀了之后,只要资源允许,会重新回调 onStartCommand,这样可以在 onStartCommand 里再次拉起播放页。
不少国产 ROM 还有自己的后台限制。我的做法是在首次引导时引导用户把 App 加入白名单,并把“自启动”、“关联启动”、“后台弹窗”三个开关全部打开。别嫌这一步麻烦,信发终端如果被系统杀掉,你远程想改都改不了。
2.2 显示适配、旋转锁定和后台进程保活
安卓屏的尺寸五花八门:有 1024x768 的老式横屏,有 1920x1080 的广告机,也有竖屏的电子班牌。我在布局里几乎不用固定 dp 值,而是用百分比坐标和比例布局。原因很简单:你没法跑到现场给每台机器单独调布局,只能用一条规则适配所有屏幕。
旋转锁定上,信发场景一般是固定方向。我的建议是在 Manifest 里锁死 orientation,别靠 Activity 里的 setRequestedOrientation 动态切,后者在部分 ROM 上会出现短暂黑屏。既然信息发布系统的使用场景固定,锁死就是最稳的方案。
至于保活,最实在的不是市面上那些“像素页保活”花招,而是处理好崩溃和重启。我在主播放页捕获了全局未处理异常,记录崩溃堆栈并上报到 PC 端,然后在 2 秒后自动重启页面。这样就算用户不碰终端,它也能自我恢复。
2.3 播放内核选型:图片、视频与网页混排
信发播放列表里往往同时有图片、视频、网页和滚动字幕。我试过几种方案:
- 纯 View 渲染:适合图片和字幕,但视频要接播放器。
- WebView 渲染:适合 HTML 模板和网页,但视频播放坑多。
- 混合:图片、字幕用原生 View,视频用 ExoPlayer,网页用 WebView,用一个 FrameLayout 做容器切换。
最后我选了混合方案。ExoPlayer 比 MediaPlayer 在信发场景里好用太多,错误恢复、HLS 直播流、缓存策略都能调。我的播放队列里每个节目就是一个 JSON 节点,渲染器根据 type 字段决定用哪个内核,切换节目时不用销毁整个 Activity,只替换容器里的内容。
3. PC 管理端的核心业务:素材、排期与终端状态
3.1 素材仓库和上传转码的取舍
PC 端第一个问题是素材管理。用户上传一个 2GB 的 4K 视频,终端在弱网下要拉多久?我的做法是:上传后在后端做一次转码,统一转成 H.264 编码、1080p、码率 4Mbps 以内的 MP4。这个方案极大降低了播放器的兼容压力,也避免了视频在终端上拉不起来。
不过转码服务在 WinForm 里直接集成比较重,我用的是一个独立的转码进程,监听素材目录变化,调用 FFmpeg 命令行完成转换。Windows 上直接带一个 ffmpeg.exe 即可,不引入额外框架。转码完成后,系统会写一条素材状态记录,PC 端列表里能看到“转码中 / 转码完成 / 转码失败”三种状态。
素材管理这块有个容易被忽略的点:图片素材最好也做一次统一压缩。很多运营人员会直接拖一张手机拍的原图上来,一张能到 8MB,多放几张终端加载就慢。我在上传接口里对图片做了等比压缩,单张图片最大边控制在 1920px,质量 80%,肉眼基本看不出差别,加载速度却能快出一大截。
3.2 播放计划的优先级和生效规则
信发项目里排期规则经常是业务核心。我的 PC 端播放计划设计成三张表:模板表、节目表、排期表。模板表定义页面布局,节目表塞具体素材,排期表决定“哪个节目在哪个时间段由哪些终端播放”。
优先级规则一定要定清楚。我一开始没设优先级,紧急通知发出去了,却被默认循环盖住,现场又看不到,被骂了一顿。后来给每条排期增加 priority 字段,终端取播放单时按 priority 排序再按时间段过滤,总算把问题解决干净。
| 优先级 | 场景 | 说明 |
|---|---|---|
| 10 | 临时插播 | 最高级,立刻替换当前播放内容 |
| 20 | 定时任务 | 按时间段生效,如早间公告 |
| 30 | 默认循环 | 没有任何定时任务时兜底播放 |
这个优先级模型很简单,但足够覆盖 90% 的信息发布需求。真正要花心思的是定时任务跨天的场景,比如“晚上 22:00 到次日 07:00”这种排期,过滤逻辑里要单独判断结束时间小于开始时间的情况,否则节目会在零点以后消失。
3.3 用列表页盯住所有终端的在线状态
终端状态页面看起来简单,其实最容易做烂。我建议 PC 端至少展示:设备编码、IP、最后心跳时间、在线状态、当前播放节目、存储剩余、App 版本。终端数量一多,靠人眼盯列表不现实,还要有简单的筛选和导出功能。
这里有一个细节:在线状态不能只靠心跳时间戳算,因为终端可能一直在线,但网络不通已经很久了。我在 PC 端单独起一个定时任务,每 30 秒扫描一次心跳表,把超过 60 秒没心跳的设备置为离线,同时在列表里标红,给运维一个明确的处理入口。
4. 两端协议设计:能一次调通的接口约定
4.1 REST 接口和 JSON 字段命名
两端通信我全部用 REST + JSON,字段命名统一为驼峰。接口只有五个:注册、获取播放单、上报心跳、上传日志、检查升级。不要一上来就搞一堆复杂接口,信发系统的核心诉求就是“把播放内容发给终端”。
以获取播放单为例,终端请求后返回:
{ "code": 0, "data": { "deviceId": "A10001", "timestamp": 1736300000, "playlist": [ { "id": 1001, "name": "早间公告", "type": "video", "url": "http://192.168.1.10/media/a.mp4", "duration": 0, "startTime": "08:00", "endTime": "09:30" } ] } }终端拿到之后自己算时间窗口,到点播对应素材。type 字段在前面说过,决定了渲染器类型;duration 对视频是 0,对图片是停留秒数。
设备注册接口也值得单独说明。终端第一次启动时,会读取本机 MAC 地址和设备序列号生成唯一编码,调用/register上报,PC 端把这个编码和终端名称绑定。这一步如果漏掉,后面所有状态页都是乱码,因为 PC 端不知道你上报的设备是谁。
4.2 心跳、离线补拉与时间校准
心跳接口是终端每 30 秒调一次 PC 端的,上报“我还活着、我在播什么、磁盘还剩多少”。PC 端通过心跳判断在线状态,同时响应终端是否需要切换播放单版本。
离线补拉这事我一直强调。终端可能在网络抖动时错过播放单更新,如果 PC 端一更新就主动推送,弱网环境很容易丢。我的策略是:每次心跳响应里带上当前播放单的 updateTime,终端发现和自己本地缓存的不一致,就重新拉取。这样即使中断半小时,恢复后也能自动对齐。
另外时间校准很重要。终端如果本地时间慢了,定时播放就不准。我允许 PC 端在心跳响应里下发服务器时间,终端每秒累计误差超过 30 秒就自动校正一次。校正用 SystemClock.elapsedRealtime 做基准,避免用户手动改系统时间造成的时间跳变。
4.3 回到 PC 端的日志回传
日志回传是排查问题最省事的武器。终端本地只保留最近 5 个日志文件,每个 1MB,轮转覆盖。PC 端有一个“拉日志”按钮,向指定终端下发一条指令,终端收到后把日志文件压缩上传,PC 端解压后按时间线展示。
这一点在真机调试点位时非常重要。终端分布在各个楼层,你不可能每次拿着数据线跑现场。日志只要包含崩溃栈、播放器实例状态、HTTP 请求状态码,绝大多数问题都能定位。
5. 编译、签名、上真机时踩过的坑
5.1 老设备 WebView 和 TLS 握手问题
第一坑是老设备上的 HTTPS。很多终端是低端盒子,系统 WebView 和 TLS 版本很老。PC 管理端如果上了 HTTPS,证书链稍微新一点,终端就会出现类似“SSL 握手失败”的错误,但你在新手机上完全测不出来。
我的处理方式是:PC 管理端在局域网环境默认用 HTTP,公网环境用 HTTPS,但必须在服务器配置兼容 TLS 1.2 以上,并检查证书链完整。终端侧的网络库用 OkHttp,调低连接超时时间到 5 秒,失败后走离线重试,不回抛崩溃。
5.2 权限弹窗和厂家 ROM 的“强制停止”策略
第二个坑是权限弹窗焦点。第一次打开 App,系统会弹存储权限、悬浮窗权限、电池优化白名单权限,如果这些弹窗恰好盖在播放页上面,终端就卡在授权界面。我的做法是把权限请求全部收拢到首次启动引导页,用户或现场安装工人一次性点完,之后正式进入播放页,不再触发运行时权限请求。
还有一个让我印象很深的坑:部分厂家 ROM 在用户从“最近任务”里滑动删除 App 后,会直接给 App 发强制停止信号,连前台服务一起杀掉。解决办法是在引导页教用户关闭“从最近任务移除时杀死应用”的开关,同时在服务里监听任务移除事件,被移除后 2 秒内通过 AlarmManager 重新拉起进程。代码不复杂,但缺失就是致命问题。
5.3 拿到 zip 之后的二次开发建议
如果你是从头解压这套 zip 开始做,我建议按这个顺序改:
- 先跑通编译,拿到一个能在模拟器上启动的 apk。
- 改配置中心的 baseUrl,指向你自己的 PC 端接口。
- 对照五个接口把 PC 端数据库表建好。
- 加一门业务,比如把公告里多一个“头条新闻”类型。
不要一上来就改界面。这个系统的难点不在界面复杂度,而在于两端的数据同步和异常恢复是否可靠。界面是最后一步,数据链路先通了,界面随手换。
我自己长期维护这套系统最大的感悟是:信息发布项目不怕功能多,就怕设备掉线后无法自愈。安卓端死机不可怕,可怕的是没人知道;PC 端下发遗漏也不可怕,可怕的是没有版本对比机制。如果你也想在这个基础上改,我建议优先把心跳、离线补拉和自动重启三件事做扎实,其他锦上添花的功能后面再说。
本文还有配套的精品资源,点击获取