简介:基于Uniapp开发的壁纸小程序源码,支持微信与抖音双端运行,面向小程序开发者、独立创业者和运营人员,解决从零搭建壁纸应用时前端展示、用户交互、图片分类管理与接口对接等核心问题。rar压缩包内共709个文件、约1.72MB,以281个js逻辑文件、119个vue页面组件、82个php后端接口为主,另含40个json配置、31个wxml、29个wxss及20个scss样式文件,工程结构完整,可直接对照学习双端小程序前后端协作方式。目前已有158人学习/下载,适合希望快速上手Uniapp跨端开发、或需要一套可运行源码作参考的初中级开发者。包内包含完整代码、png/gif等图片素材、使用说明html和静态样式库,目录布局清晰,便于单独抽取页面或接口复用;在此基础上可继续完善个性化推荐、用户上传与安全防护等模块,借助微信社交生态和抖音流量入口,降低双端产品上线与试错成本。
1. 从 .rar 到双端上架:这套壁纸小程序源码到底在解决什么问题
你从某个下载站拉回一个几十 MB 的 .rar,解压后看到 pages、static、manifest.json、uni.scss 这些目录,就知道这是一个 Uniapp 工程。壁纸小程序这个品类在微信和抖音上都很适合跑:内容消费属性强、图片即内容、分享裂变路径短,而且后端可以只做静态资源托管,开发成本压在客户端。用 Uniapp 写一套代码同时输出微信小程序和抖音小程序,是这类项目最常见的落地姿势。源码包的标题里写“双端”,意味着代码里一定做了平台判断或条件编译,而不是两套代码各写一遍。这篇文章不评价那份 rar 的质量,只讲清楚当你拿到这样一份代码、或者打算自己搭一个同款工程时,从工程结构、双端差异、核心功能到打包上架,每一步该怎么做、参数怎么设、坑在哪里。适合接过外包、自己跑副业,或者刚入门小程序想找一个完整练手项目的开发者。
2. 双端能力差异与 Uniapp 的适配边界:先看清微信和抖音哪里不一样
2.1 微信与抖音开放能力对比:核心 API 能平替,边界在账号体系
做双端小程序,第一件事是问清楚:微信有的能力,抖音是不是都有?直接看对照表比猜靠谱。
| 能力 | 微信小程序 | 抖音小程序 | Uniapp 封装 |
|---|---|---|---|
| 登录 | wx.login / wx.getUserProfile | tt.login / tt.getUserInfo | uni.login / uni.getUserProfile |
| 保存图片 | wx.saveImageToPhotosAlbum | tt.saveImageToPhotosAlbum | uni.saveImageToPhotosAlbum |
| 分享 | open-type="share" / wx.shareAppMessage | open-type="share" / tt.shareAppMessage | uni.share 或按钮 open-type |
| 支付 | wx.requestPayment | tt.requestPayment | uni.requestPayment |
| 网络请求 | wx.request | tt.request | uni.request |
| 用户隐私协议 | wx.requirePrivacyAuthorize | tt 各版本策略不同 | 自行封装 |
壁纸小程序用到的主力 API 基本都是平替关系,uni.*这一层能屏蔽掉大部分差异。真正需要动脑子的是授权逻辑:抖音端的tt.getUserInfo和微信端的wx.getUserProfile在返回值结构、触发时机上都不同。后面第 5 章单独讲。
提示:不要指望
uni.*封装的 API 在两端行为完全一致。头像昵称的返回格式、保存相册前的授权弹窗顺序,这些细节封装不了,必须条件编译。
2.2 条件编译:一套代码两套行为的落点
Uniapp 的条件编译写在注释里,编译器在打包时才会识别。微信端用#ifdef MP-WEIXIN,抖音端用#ifdef MP-TOUTIAO,#ifndef表示“非某平台时执行”。常见做法是:能共用逻辑就共用,只在平台特有 API 或 UI 差异处写条件编译。
// 保存壁纸到相册 function saveWallpaper(filePath) { // #ifdef MP-WEIXIN uni.saveImageToPhotosAlbum({ filePath: filePath, success: () => uni.showToast({ title: '已保存' }), fail: (err) => handleAuthFail(err) }); // #endif // #ifdef MP-TOUTIAO tt.saveImageToPhotosAlbum({ filePath: filePath, success: () => tt.showToast({ title: '已保存' }), fail: (err) => handleAuthFail(err) }); // #endif }这段代码的逻辑是:微信端走uni.saveImageToPhotosAlbum,抖音端直接调tt.saveImageToPhotosAlbum——因为抖音端对uni.*实现的兼容性有时滞后,直接调底层 API 反而更稳。handleAuthFail是统一的授权失败处理,稍后在授权章节展开。
条件编译也适用于模板和样式,不只是 JS。微信端独有组件比如open-data,抖音端没有,就应该包在#ifdef里。反过来,抖音的侧滑返回手势相关配置,只在 MP-TOUTIAO 下生效。
2.3 为什么是这个方案,而不是原生双写
原生双写意味着两套代码、两个开发语言、两个提审节奏、两个运维入口,壁纸类小程序的内容和 UI 迭代很快,双写成本会吃掉大部分收益。Uniapp 的短板在复杂原生能力——比如涉及 AR、高性能 Canvas 或深度定制的原生插件时,封装层会成为阻碍。但壁纸类应用需要的 Image 组件、下载、分享、Canvas 生成图片,Uniapp 的成熟度足够兜底。
从这个角度看,源码包用 Uniapp 是合理取舍:下载站这种交付场景里,成交率最高的是“代码能编译、双端能跑、核心功能完整”的工程,而不是某个平台性能最优的实现。
3. manifest.json 与工程配置:双端打包前必须确认的参数
3.1 manifest.json 里三个必改项
拿到源码先别急着跑,打开根目录的manifest.json,这几乎是所有双端项目“本地能跑、一上传就废”的源头。三个必改项如下:
| 配置项 | 位置 | 说明 |
|---|---|---|
| 小程序 AppID | mp-weixin.appid | 微信公众平台里申请,测试号也可先在开发者工具里跑 |
| 抖音小程序 AppID | mp-toutiao.appid | 抖音开放平台创建小程序后获得 |
| 基础库最低版本 | mp-weixin.libVersion / mp-toutiao.minVersion | 设太低兼容好但代码受限,设太高低版本用户打不开 |
{ "mp-weixin": { "appid": "wx1234567890abcdef", "setting": { "urlCheck": false }, "usingComponents": true }, "mp-toutiao": { "appid": "tt1234567890abcdef", "setting": { "urlCheck": false } } }urlCheck: false在开发者工具里等效于勾选“不校验合法域名”,本地联调时必须有,否则请求会被拦截。注意这只是开发态配置,真机预览和提审时依然要求线上域名备案且加入白名单。
3.2 请求域名白名单的差异:微信要配,抖音也要配
微信端的合法域名在微信公众平台“开发管理-服务器域名”里配置,抖音端在抖音开放平台“开发-服务器域名”里配置。壁纸类的图片资源通常来自 CDN,图片域名和接口域名都要加。
我一般会在工程里封装一层request.js,统一管理 baseURL,这个文件不用写条件编译,因为两端都会请求同一个后端。
// utils/request.js const BASE_URL = 'https://api.example.com'; // 换成自己的接口域名 export function request(path, method = 'GET', data = {}) { return new Promise((resolve, reject) => { uni.request({ url: BASE_URL + path, method: method, data: data, timeout: 10000, success: (res) => { if (res.statusCode === 200) { resolve(res.data); } else { uni.showToast({ title: '请求失败', icon: 'none' }); reject(res); } }, fail: (err) => reject(err) }); }); }timeout: 10000是给慢网络兜底,避免用户看着转圈。壁纸接口的数据量不小,响应超过 10 秒的直接提示失败,比无限等待体验好。
3.3 本地联调:把接口跑通再碰页面
接口是本地起的 Node 服务时,有两个选择:微信开发者工具勾选“不校验合法域名”,或者用代理工具把 URL 重写。抖音开发者工具同样有“开发-不校验合法域名”的开关,但抖音的版本更新频繁,有时设置入口位置会变,找不到的话直接看设置里有没有 request 相关的开关。
提示:改完 manifest.json 之后必须重新编译,HBuilderX 不会自动热更新 manifest 里的原生配置。改 AppID、最低基础库版本这类配置后,没有重新编译导致的报错特别隐蔽。
4. 壁纸核心功能落地:瀑布流、详情页与双端保存到相册
4.1 瀑布流布局:用两列还是多列,性能差距在哪
壁纸小程序的首页基本都是瀑布流。实现方案常见的三种:view多列布局、CSS columns、uni-grid。壁纸场景我推荐view两列或三列,左侧和右侧各一个数组。原因是 CSS columns 在图片加载时会出现内容错位,uni-grid是九宫格语义,不适合不等高瀑布流。
<view class="waterfall"> <view class="column" v-for="(column, index) in columns" :key="index"> <view class="card" v-for="item in column" :key="item.id" @click="preview(item)"> <image :src="item.cover" mode="widthFix" lazy-load="true" /> <text class="title">{{ item.title }}</text> </view> </view> </view>let left = [], right = []; this.list.forEach((item, index) => { if (index % 2 === 0) { left.push(item); } else { right.push(item); } }); this.columns = [left, right];mode="widthFix"会等比例缩放图片宽度到 100%,高度自适应,这是壁纸瀑布流最常用的模式。lazy-load是图片懒加载,滚动时才发起加载请求。列表很长时,必须用v-for加key,否则小程序端的 diff 会出现错乱。
数据切分逻辑:按索引奇偶轮流分给两列,简单且稳定。更精细的做法是按图片加载后的实际高度动态分配,但在小程序里测量图片高度代价很大,壁纸图片宽高比通常固定,奇偶分列的效果足够。
4.2 图片详情与预览:没有后端时先跑静态数据
解压源码后如果接口不可用,第一步是 mock 数据,让页面先跑通。壁纸数据结构最简单的是把图片 URL、标题、宽高比、分类 ID 放在一个数组里:
// mock/data.js export const wallpaperList = [ { id: 1, title: '极简山峰', url: 'https://example.com/wallpaper/1.jpg', ratio: 1.78 }, { id: 2, title: '暗夜森林', url: 'https://example.com/wallpaper/2.jpg', ratio: 1.5 } ];点击卡片进入预览页,或者直接调用uni.previewImage,两种交互都可以。预览页适合做“设为壁纸”和“分享”的按钮,列表页直接 preview 则交互更轻。源码包里常见的是两者结合:点击进入详情,详情里再用uni.previewImage支持手势放大和左右滑动。
function previewImage(current, urls) { uni.previewImage({ current: current, urls: urls }); }current是当前图片的 URL,urls是同一分类下的全部大图 URL。用户左滑右滑时,小程序端会按数组下标切换,不需要自己维护滑动状态。
4.3 保存到相册:授权弹窗、失败拦截、永久拒绝闭环
保存相册是壁纸应用的转化核心。用户点“保存图片”时良性流程是:有授权直接保存,无授权弹授权框,用户拒绝后引导去设置页打开。注意微信和抖音在“拒绝后再次触发”的行为不同,但代码要处理同一个状态机。
function saveWallpaper(filePath) { uni.saveImageToPhotosAlbum({ filePath: filePath, success: () => uni.showToast({ title: '已保存到相册' }), fail: (err) => { if (err.errMsg && err.errMsg.includes('auth deny')) { uni.showModal({ title: '需要权限', content: '请在设置中打开相册权限', confirmText: '去设置', success: (res) => { if (res.confirm) { uni.openSetting(); } } }); } else { uni.showToast({ title: '保存失败', icon: 'none' }); } } }); }逻辑说明:saveImageToPhotosAlbum失败的原因常见两种:用户拒绝授权,或网络下载临时文件失败。判断errMsg里包含auth deny时弹窗引导去uni.openSetting()打开权限。注意auth deny这个字符串在两端返回值里不一定完全一致,微信常见格式是saveImageToPhotosAlbum:fail auth deny,抖音的格式类似,但更稳妥的写法是同时判断err.errMsg.indexOf('auth') !== -1加saveImageToPhotosAlbum。授权被永久拒绝后,uni.openSetting弹的是系统设置页,用户手动打开后回到小程序,能继续保存。
保存之前还需要下载图片到本地临时路径。uni.downloadFile拿到的临时路径传给saveImageToPhotosAlbum,而详情页大图 URL 来自 CDN,直接保存远程 URL 是行不通的。这个细节是壁纸小程序最常见的报错:fail url is not valid。
function downloadAndSave(url) { uni.downloadFile({ url: url, success: (res) => { if (res.statusCode === 200) { saveWallpaper(res.tempFilePath); } else { uni.showToast({ title: '下载失败', icon: 'none' }); } } }); }tempFilePath是下载后的本地临时路径,保存完成前操作系统可能清理临时文件。需要快速连续保存时,考虑先复制到本地持久路径再保存,但这个需求在壁纸场景里出现频率不高,一次性保存一张是主路径。
5. 双端差异化适配:抖音端的授权、分享与微信端的不同玩法
5.1 抖音端用户信息获取:getUserInfo 和 getUserProfile 各有各的规则
壁纸类应用不做社交关系链,登录需求往往是“标记收藏、同步设置”,这种场景不需要强制授权。微信端从 2022 年 10 月起wx.getUserProfile不再返回真实头像昵称,返回的是“微信用户”加灰色默认头像。抖音端则不同,部分版本中tt.getUserProfile仍然能返回完整资料,但也经常有调整。
不依赖头像昵称时,用户信息展示用 localStorage 缓存一份默认昵称就行。必须拿头像的场景,微信端推荐先用<button open-type="chooseAvatar">让用户主动选头像,昵称用 input 输入,这个流程是微信官方推荐的“头像昵称填写能力”;抖音端则看版本用tt.getUserInfo或者<button open-type="getUserInfo">。
<!-- 微信端头像昵称填写 --> <!-- #ifdef MP-WEIXIN --> <button class="avatar-wrapper" open-type="chooseAvatar" @chooseavatar="onChooseAvatar"> <image :src="avatarUrl" /> </button> <input type="nickname" placeholder="请输入昵称" v-model="nickname" /> <!-- #endif -->open-type="chooseAvatar"和type="nickname"是微信专门设计的替代方案。不要在微信端再用uni.getUserProfile去拉头像,拿到的已经是被脱敏的数据。抖音端保持自己那套逻辑,两边通过条件编译隔离。
5.2 分享:微信玩裂变,抖音玩路径
壁纸小程序最有效的增长方式是“用户看到一张好看的图,分享给朋友”。微信端分享卡片在onShareAppMessage里配置,抖音端同理但字段有差异。
// #ifdef MP-WEIXIN onShareAppMessage() { return { title: '这张壁纸太好看了', path: '/pages/detail/detail?id=' + this.currentId, imageUrl: this.currentImage }; } // #endif // #ifdef MP-TOUTIAO tt.shareAppMessage({ title: '这张壁纸太好看了', desc: '来自壁纸小程序', path: '/pages/detail/detail?id=' + this.currentId, imageUrl: this.currentImage }); // #endif微信端的onShareAppMessage是页面生命周期方法,分享按钮只需要<button open-type="share">;抖音端则要调用tt.shareAppMessage显式触发。imageUrl建议直接用当前壁纸的缩略图 URL,好友看到卡片时加载更快,分享转化率明显高于默认截图。朋友圈分享在微信端只能走onShareTimeline,不支持自定义路径之外的参数,打开只会进首页,这个限制要接受。
5.3 给壁纸小程序加一点“DIY”留存:从爆款珠了个珠想到的
热词里“珠了个珠 diy 小程序”能火,核心是“用户自己参与生成内容”。壁纸类小程序同样可以借鉴:用户选底图、调滤镜、加文字,生成一张自己的专属壁纸,然后保存和分享。生成逻辑用 Canvas 绘制,微信端和抖音端的 Canvas 接口在小程序环境下差异比较大,建议走uni.createCanvasContext的兼容层,只绘制简单文字和图案时不至于踩性能坑。
<canvas canvas-id="poster" style="width: 300px; height: 500px;" />const ctx = uni.createCanvasContext('poster'); ctx.setFillStyle('#ffffff'); ctx.fillRect(0, 0, 300, 500); ctx.drawImage('../../static/bg.png', 0, 0, 300, 500); ctx.setFillStyle('#000000'); ctx.setFontSize(20); ctx.fillText('自定义内容', 40, 460); ctx.draw(false, () => { uni.canvasToTempFilePath({ canvasId: 'poster', success: (res) => downloadAndSave(res.tempFilePath) }); });注意步骤:先ctx.draw完成绘制,再在回调里调用canvasToTempFilePath导出图片。若导出得到空白图,大概率是 draw 回调里拿路径的时序问题,把它写清楚能少废不少时间。
6. 从本地到线上:微信抖音双端打包上架与其间的 3 个硬坑
6.1 双端打包的完整步骤
微信端:HBuilderX 菜单栏“运行 -> 运行到小程序模拟器 -> 微信开发者工具”,首次会要求填 AppID。微信开发者工具里做真机预览的话,需要项目配置勾选“不校验合法域名”。正式发布要在“上传”里提交代码,然后在微信公众平台提交审核。
抖音端:HBuilderX 里“运行 -> 运行到小程序模拟器 -> 抖音开发者工具”。抖音开发者工具的 AppID 在 manifest 里填好,否则报错invalid appid。同样在开发者工具里完成预览和上传,去抖音开放平台提审。
提审需要的物料包括:小程序的简介、类目(壁纸通常选“图片/摄影”或“工具”)、隐私保护指引(声明收集的信息类型)。2024 年以来微信和抖音都加强了隐私协议合规检查,小程序里有任何授权弹窗,都要在后台声明对应隐私接口。壁纸App常见的隐私问题就是相册权限,开发时填写的“收集你的相册(仅写入)权限使用说明”要写清楚“用于保存你选择的壁纸到相册”,不能写“用于完善用户体验”这类模糊话术。
6.2 域名和备案是双端上架后面最常被打回的原因
微信端打回常见理由是“接口请求失败”或“图片无法访问”:后台配置的 request 合法域名过期、CDN 图片域名没有加入 downloadFile 合法域名。抖音端审核逻辑类似,打回信息里会标明具体请求失败的 URL,排查方向一致:域名必须 HTTPS、必须有 ICP 备案、证书链完整,且域名备案主体和开发者主体尽量一致。
6.3 压缩包里的代码不一定是最终版
.rar和“源码包”这两个关键词意味着你拿到的可能是老版本。老工程里最危险的是wx.getUserInfo直接调用——这个接口在微信端已经无法弹出授权窗口;其次是 manifest 里指向某个已失效的 AppID。拿到任何这套源码包,第一件事不是改功能,而是把双端基础库版本抬到最新稳定版,全局搜索getUserInfo、getSystemInfoSync这类过期 API,看代码里哪些被标记为 deprecated。用uni.getSystemInfoSync()获取设备信息时,老代码里经常有windowWidth被算法依赖,新基础库改了部分字段返回值,抽查一遍详情页布局再发版。
最后是内容侧:壁纸类小程序的审核风险点集中在图片版权上,接图库 API 的话确认分发授权,不要直接抓第三方 4K 壁纸站的图片热链,除了审核和法律问题,防盗链也会让线上图片大片失效。
本文还有配套的精品资源,点击获取