From 880d8e758f7dd5fddaccbece7d877ef9bb1f7ef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=86=8A=E7=86=8A=E7=86=8A=E5=AD=90=E8=B7=AF?= Date: Fri, 31 Jul 2026 13:53:13 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=BAiOS=20ATS=E9=99=90=E5=88=B6?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9B=BE=E7=89=87URL=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 引入`urlToBase64`和`getImageDisplayUrl`工具函数,以处理iOS/Mac WKWebView ATS策略下的HTTP图片加载问题。在需要时自动将HTTP图片转换为base64数据URL,同时保持HTTPS和非Apple平台不受影响。 - 更新README以添加使用示例 - 在AGENTS.md中添加新的工具文件引用。 --- AGENTS.md | 1 + README.md | 24 +++++++++++++ miniprogram/utils/image.ts | 71 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 miniprogram/utils/image.ts diff --git a/AGENTS.md b/AGENTS.md index eefe736..905cc9f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -58,6 +58,7 @@ miniprogram/ │ ├── request.ts # axios-miniprogram 封装:Token 注入、loading 管理、401 跳转 │ ├── aes.ts # AES-256-CBC 加密/解密 + URL Safe Base64 变体 │ ├── util.ts # 日期格式化(formatTime / formatDateTime) +│ ├── image.ts # 图片 URL 兼容(iOS ATS http→base64) │ └── platform.ts # 微信宿主平台信息检测(设备类别/操作系统/桌面or移动) └── miniprogram_npm/ # 微信开发者工具构建的 npm 产物(已 gitignore,不直接编辑) typings/ # 全局类型声明(IAppOption、PlatformInfoType 等)+ 微信 API 类型 diff --git a/README.md b/README.md index c89badd..e792df5 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ - 完整的 TypeScript 类型支持,提供更好的开发体验和代码提示 - 基于 axios-miniprogram 的网络请求封装,支持自动 Token 注入、统一错误处理、智能加载动画管理 - AES-256 加密解密工具,支持标准 Base64 和 URL Safe Base64 两种格式 +- 图片 URL 兼容工具,自动处理 iOS WKWebView 下 HTTP 图片无法加载的问题(ATS 限制),按需转 base64 - 集成 TDesign 组件库,提供丰富的 UI 组件 - 自定义 TabBar 实现,基于 TDesign 组件,支持自动状态同步和页面切换 - 完善的代码规范配置,支持 ESLint 和 Prettier 自动格式化 @@ -167,6 +168,29 @@ const urlSafeDecrypted = BASE64Decrypt(urlSafeEncrypted) const customEncrypted = Encrypt('hello world', 'your-key-32-bytes-long', 'your-iv-16-bytes') ``` +### 图片 URL 兼容工具(iOS ATS) + +项目提供了图片 URL 兼容工具,位于 `miniprogram/utils/image.ts`,解决微信小程序在 iOS/Mac WKWebView 下 HTTP 图片因 ATS 限制无法加载的问题。 + +**主要功能:** + +- 自动检测当前设备平台,仅在 iOS/Mac 下对 HTTP 图片触发 base64 转码 +- HTTPS 链接和非 iOS/Mac 平台直接返回原始 URL,零额外开销 +- 非完整 URL(不以 `http://` 或 `https://` 开头)会 console.warn 提示后原样返回 +- `urlToBase64` 使用 `wx.request` + `arraybuffer`,不经过 axios 拦截器 + +**使用示例:** + +```typescript +import { getImageDisplayUrl, urlToBase64 } from '../utils/image' + +// 推荐:直接获取可用于 显示的 URL(自动判断是否需要转 base64) +const displayUrl = await getImageDisplayUrl('http://example.com/photo.jpg') + +// 或手动将任意图片转为 base64 +const base64 = await urlToBase64('https://example.com/photo.jpg') +``` + ### 时间日期格式化工具 项目提供了灵活的时间日期格式化工具,位于 `miniprogram/utils/util.ts`。 diff --git a/miniprogram/utils/image.ts b/miniprogram/utils/image.ts new file mode 100644 index 0000000..45529fe --- /dev/null +++ b/miniprogram/utils/image.ts @@ -0,0 +1,71 @@ +/** + * 图片工具 — iOS ATS 兼容处理 + * + * 背景:微信小程序在 iOS WKWebView 下, 组件加载 HTTP 图片会被 ATS 拦截, + * 必须先通过 wx.request 下载为 ArrayBuffer,再转为 base64 data URL 才能正常显示。 + */ + +// ==================== 图片 URL 兼容(iOS ATS) ==================== + +/** + * 将网络图片转为 base64,用于 iOS 图片回显等场景 + * 使用 wx.request 直接请求,避免经过 axios 的 StandardResponse 拦截逻辑 + * @param url 图片完整 URL + * @returns Promise 格式的 base64 字符串 + */ +function urlToBase64(url: string): Promise { + if (!url || typeof url !== 'string') { + return Promise.reject(new Error('url 不能为空')) + } + + return new Promise((resolve, reject) => { + wx.request({ + url, + method: 'GET', + responseType: 'arraybuffer', + success: (res) => { + if (res.statusCode !== 200) { + reject(new Error(`请求失败: ${res.statusCode}`)) + return + } + const arrayBuffer = res.data as ArrayBuffer + const base64 = wx.arrayBufferToBase64(arrayBuffer) + const ext = (url.match(/\.(jpg|jpeg|png|gif|webp)/i) || ['', 'png'])[1] + resolve(`data:image/${ext};base64,${base64}`) + }, + fail: (err) => reject(err), + }) + }) +} + +/** + * 获取图片显示用的 URL,仅在 HTTP + iOS/Mac 时转为 base64 以解决 ATS 回显问题 + * - HTTPS 链接:任何平台均直接返回原始 URL + * - HTTP 链接 + iOS/Mac:转为 base64 + * - HTTP 链接 + 其他平台:直接返回原始 URL + * @param url 完整的图片 URL(必须是 http:// 或 https:// 开头) + * @returns Promise 返回可用的 url(网络链接或 base64 字符串) + */ +async function getImageDisplayUrl(url: string): Promise { + const isFullUrl = /^https?:\/\//i.test(url) + if (!isFullUrl) { + console.warn( + '[getImageDisplayUrl] 传入的不是完整 URL,请传入 http:// 或 https:// 开头的完整链接', + ) + return url + } + + const app: IAppOption = getApp() + const { clientPlatform } = app.globalData.platformInfo.software + + const isHttp = /^http:\/\//i.test(url) + const isIosOrMac = clientPlatform === 'ios' || clientPlatform === 'mac' + + if (isHttp && isIosOrMac) { + return urlToBase64(url).catch(() => url) + } + + return url +} + +export { urlToBase64, getImageDisplayUrl }