聊一聊微信小程序包内容
本文是对上次公众号发文《微信小程序逆向源码深度揭秘》 的扩展,着重探究小程序包的主要内容构成。
# 先有鸡还是先有蛋?谈谈小程序包的产生与消亡
任何事物都是有生命周期的,小程序包也不例外,为了方便理解,我们暂且叫它【小程序包的生命周期】。其实本没有这个概念,只是为了本文的理解才引入了这么一个概念。 这里大致归纳为以下几个阶段。
- 产生:苦逼的程序猿们接到领导的需求,火速开发小程序,最后在微信开发者工具中点击【上传】按钮完成小程序包的打包上传,至此一个体验版小程序包(需要后台手动设置版本为体验版)就此在微信的服务器上诞生了。
- 传播:提交审核通过之后小程序包会被分发到CDN网络,供用户下载。
- 使用:用户通过某种渠道打开小程序就会把小程序包下载到本地进行解压使用。
- 归宿:用户们玩腻了在微信主页顶端下拉菜单中长按小程序并拖进垃圾桶。。(最终归于尘土 ಥ_ಥ)
这里需要注意的是:同一小程序分开发版、体验版、正式版,几个包都是独立,互相隔离的,并且缓存(优先加载)在本地。普通用户看到的只是正式版。
# 用户初次打开小程序时发生了什么?
在小程序启动时,微信会为小程序展示一个固定的启动界面,界面内包含小程序的图标、名称和加载提示图标。 微信会做以下工作:
- 下载小程序代码包
- 加载小程序代码包
- 初始化小程序首页
# 包文件结构介绍与打包规则
关于文件结构这里不再赘述(不是本文关注重点) 这里简要提一下微信小程序包的文件格式,注意是『微信』哦。
格式: 文件头+文件名+文件内容起始地址及长度
注意:
- 微信小程序包文件头信息是以
0xbe
开头,所以如果你拿了抖音的小程序包来解是没用的 - 文件内容都是明文存放的,这是我们能够顺利解包的前提
接着我们回过来来看看解包后文件的主要构成,这里还是拿开源中国的小程序开刀吧??。
为了辅助理解,我们先修改源码中的 wuWxapkg.js
文件,L34(34行)后面追加下面的代码
console.log(`No.${i+1}:`, info.name);
然后执行以下命令得到日志
node wuWxapkg.js -o osc.wxapkg
执行命令后可以在命令行看到包内文件名列表
通过观察文件名列表我们可以看出: 包内主要包含 ①静态资源->static/**、图片、svg...... ②app-config.json ③app-service.js ④page-frame.html ⑤页面html文件->pages/**.html、其它组件或者页面的html
关键文件作用整理如下:
文件名 |
作用 |
---|---|
app-config.json |
小程序完整的配置,包含我们通过app.json里的所有配置,综合了默认配置 |
app-service.js |
各页面的JS代码 |
page-frame.html |
小程序视图(渲染页面)的模板文件,所有的页面都使用此加载渲染,且所有的WXML都拆解为JS实现打包到这里 |
**.html |
其它页面的html |
主包一般都是2M左右大小,也有特别的会达到4M+
未列进来的文件:
文件名 |
作用 |
---|---|
WAService.js |
逻辑层基础库文件,提供逻辑层基础能力 |
WAWebview.js |
视图层基础库文件,提供视图层基础能力 |
WAConsole.js |
控制台基础库 |
解出来之后如果得到包含这几个文件的内容,就说明解的不是主包。
我们顺带看看微信开发者工具源码中的 pageframe.html 在mac系统下可以通过『微信开发者工具』上右键菜单点击显示包内容来找到这个模板文件,文件路径:
/Applications/wechatwebdevtools.app/Contents/Resources/package.nw/html
部分内容一览:
<!-- -->
部分即是模板字符串,会在执行过程中被动态替换
# 得出的一些结论
- 基础库是内置在微信客户端的,在用户本地会有缓存,打开小程序时如果本地存在缓存则优先加载,所以如果在开发模式下开启了调试模式没有关闭则打开正式版也会出现绿底白字的『console』悬浮按钮。
- 微信小程序包的文件头是以 oxbe 开头,所以如果不是则认为不是微信家的小程序包
- page-frame.html 是小程序运行时模板文件,所有视图层页面内容的加载都是基于这个模板html文件(从微信开发者工具源码也可以略知一二)进行模板字符串替换
- 所有的业务逻辑代码都是打包到 app-service.js 文件
注:以上内容仅是博主学习了相关资料结合个人理解整理所得,不免会有疏漏的地方,如有更好的发现,欢迎交流。
# 参考资料
- python 序列化数据:pickle与json ,dumps与loads
- golang继承,和多态
- python 利用random生成验证码与MD5码加密过程
- Java内部类的继承
- Java继承类中static成员函数的重写
- Search for a range寻找上下界-Leetcode
- Basic Calculator 基本计算器-Leetcode
- python yield函数深入浅出理解
- 十分钟搞定 Tensorflow 服务
- datapump跨平台升级迁移的总结 (r8笔记第77天)
- Java中isAssignableFrom()方法与instanceof()方法用法
- 与Ajax同样重要的jQuery(1)
- Java中Class类详解、用法及泛化
- python 函数编程的位置参数、默认参数、关键字参数以及函数的递归
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- GitHub修改昵称和用户名(图解详细教程)
- Python飞机大战小游戏_完整源码免费分享
- Linux求助命令
- Linux关机命令及步骤
- Java实现二叉树层次遍历:从上往下打印出二叉树的每个节点,同层节点从左至右打印。
- Django 用户认证系统使用总结
- 前端综合面试题(9道)
- 用SQL查询Oracle数据库名和实例名
- Hadoop历史服务器配置详细步骤
- MySQL常见关键字优先级
- Linux进程管理命令及状态详解
- sqoop把hive数据导入mysql出现中文乱码
- Flink实现WordCount(实操详细步骤)
- 在客户端创建要素图层 (FeatureLayer)
- 11.深入k8s:kubelet工作原理及其初始化源码分析