ARTICLE · 1134541
把网页装进手机:安卓安装包打包全流程
我手上有个纯本地的单文件网页,一个 .html 双击就开,数据全躺在浏览器本地存储里,不传任何服务器。写到第九期的时候发现一个问题:电脑端用得很顺手,一到手机上就三个难受——桌面没有图标打不开、导出文件在浏览器里默默消失、往后台一切,数据还认得,可入口没了。
办法其实就一条:给它套个安卓壳。整份网页原样塞进 App 的 assets 里,外面只包一层全屏 WebView,再补上网页自己做不到、但系统能做的两件事(跳外链、导出落盘)。业务代码一行不用写。
全程零联网、零外链、零权限,装完的 App 断网照样能开。下面这一套我完整走了一遍,每一步的图都是当时的真实画面。
一、备齐工具链:就三样东西
不装 Android Studio,不用图形界面,全部命令行搞定。你要的四样:JDK 17、Android SDK(platform 34 + build-tools 34)、Gradle 8.7、一个自签名证书。都放在 D:\wbtools 这么一个纯英文目录里——别图省事丢在 C 盘带中文的路径下,Gradle 会给你脸色看。
JDK 一定选 17,21 版本跟这套 AGP 8.1.1 不搭。坑:sdkmanager 的命令行工具必须解压到 cmdline-tools/latest/ 这一层,直接解压到 cmdline-tools 根目录会报 "sdkmanager not found"。

图 1:工具链目录,JDK、SDK、Gradle 三件套平铺在一个目录里
SDK 装两个包就够了,别全下载,几百兆:
sdkmanager "platforms;android-34" "build-tools;34.0.0" sdkmanager --licenses # 逐条 y,不然后面构建卡住

图 2:SDK 安装过程,两个包足矣
二、造一个自签名证书,再做个图标
自己给自己签,30 年有效,够用到你换手机:
keytool -genkeypair -v ^ -keystore signing.jks -alias personaldesk ^ -keyalg RSA -keysize 2048 -validity 10950
密码记牢,以后每次升级都要用它,改了就装不成「同一个 App」,旧数据也认不回来了。

图 3:keytool 生成证书,一路回车加 y
图标这块,画一张 512×512 的底图,脚本帮你铺成 8 份:mdpi / hdpi / xhdpi / xxhdpi / xxxhdpi 五档圆角图标,外加安卓 8 之后必须的 adaptive icon(前景 + 背景两层)。

图 4:res 目录 8 个图标一次生成
三、整个 App 的核心,就一个 WebView
工程长这样,干净到不像话:

图 5:工程结构,加号后面那行最要紧
assets/index.html —— 整份网页原样丢进去,一个字节都不用改。所以你在电脑上改网页,重新打包就行,之前所有断言和功能全都在。
MainActivity 里真正管用的就这几行:
web.getSettings().setJavaScriptEnabled(true); web.getSettings().setDomStorageEnabled(true); // 这行不开,数据全丢 web.getSettings().setBuiltInZoomControls(false); web.loadUrl("file:///android_asset/index.html");

图 6:MainActivity 上半段——搭一个全屏 WebView
第二件要紧事是导出。网页里点「导出 CSV」,在手机浏览器上会直接闪没;这里改成用 JS 把内容取成文本丢给 Java,Java 用 MediaStore 写进系统「文件/下载」,再 toast 一句报出文件名。Android 10 起这么写不用申请任何存储权限。

图 7:MainActivity 下半段——导出直接落进下载目录
四、权限和配置:干净得像什么都没写
清单文件里一个 uses-permission 都不写。安装的时候系统会显示「该应用无权限」,越干净越放心——里面有学生信息、记账、账号密码,绝不许它碰任何东西。

图 8:AndroidManifest,多行权限声明都没有
签名配置这里有个最关键的决定:v1 + v2 双签,一个都不能少。只签 v2 的话,部分鸿蒙机型直接装不上,报「解析包失败」。多写一行 v1SigningEnabled 的账,比事后 Debug 三天划算。

图 9:build.gradle,双签配置
再写一个 build.bat,把「拷网页 → 打包 → 覆盖」串成一条命令。以后网页改完了,双击它,十秒钟出包:

图 10:build.bat,三行搞定全流程
五、出包
第一次跑会下载一堆依赖,慢是正常的;第二次起有缓存,几秒就完:

图 11:gradle assembleRelease,BUILD SUCCESSFUL
产物 72.8 KB,一个还能跑的 App 其实就这么点体积:

图 12:产出的 apk 文件
六、别急着装,先验一遍
签名这一步有个假警报必须提前说:apksigner 会大大方方打印 v1 scheme: false,看着像漏签,其实只是它这轮只验到 v2。别信它一个字,立刻用 jarsigner 复验一遍——jar verified. 出来了就说明 v1 在。

图 13:apksigner + jarsigner 双重验签,aapt2 看包名和权限
解包看一眼里面装了什么,顺便确认网页确实是原样进去的:

图 14:解包条目,assets/index.html 与源文件逐字节一致
七、装上手机之后

图 15:手机端首页,底部是固定二级导航
点「工作」切到工作组,学期条才冒出来——首页、生活、数据三个组不显示学期选择,省地方:

图 16:手机端工作视图,学期条 + 底部导航
往下滑到底,底部导航不会盖住最后一行内容,这是靠主区域留了对应的内边距换来的:

图 17:滚到底部,内容不被遮挡
电脑上打开是左侧两级导航,右手边才是内容区:

图 18:电脑端左侧两级导航
八、踩过的坑,一条条列清楚
1. setDomStorageEnabled 必须开。不开就存不住,用户以为存了,一退全没。 2. v1 + v2 双签。只签 v2 的鸿蒙机型装不上。 3. screenOrientation 只能写小写nosensor,写成 NOSENSOR 直接编译失败。 4. 屏幕方向、图标别留白边、别画三条线当图标,系统会自我裁剪成一团糊。 5. 导出用 MediaStore,Android 10 以上不用申请存储权限;toast 记得跑在主线程,不然闪退。 6. apksigner 报 v1 false 是假警报,jarsigner 复验才作数。 7. 后台提醒(生日、待办)依赖 App 活着,鸿蒙会冻结后台,得把 App 加进「受保护应用」。
写在最后
这套东西最省事的地方在于:网页一行代码都没为 App 改过。你在电脑上怎么调、怎么测、怎么备份 JSON,装在手机里照样是那一份。反过来也成立——手机端发现的问题,改完网页重打一个包就行,不需要动任何原生代码。
给学校老师、给办公室同事装的时候,同样一个 apk,安卓和鸿蒙都能直接装上,覆盖安装不丢数据。
需要安卓或者鸿蒙系统安装包的,请后台留言666。