- 个人开发者把小程序发布到 App Store 5个步骤(保姆级教程)
用完即走,小程序已经成为连接用户与服务的重要桥梁,无论是购物、出行还是娱乐,小程序都以其便捷性和高效性赢得了用户的青睐。 那小程序是否有边界,能否拓展到 App? 微信开发者工具的最新升级,为这一问题提供了创新的解答。现在,开发者们可以轻松将已有的小程序代码构建为全功能的 App,而无需从零开始开发,这不仅节省了大量的人力和时间成本,更为小程序开发者们打开了通往 App Store 巨大流量的大门。 在这篇文章中,我们将深入探讨微信开发者工具支持小程序 App 化的五大步骤,分析其潜在价值,并通过实际案例来展示这一过程的效果。 背景:个人开发者,将小程序代码构建为 iOS App,以下为整体流程,适合 iOS 开发 / 上架零基础的同学。 [图片] 缘起 一个周末,突然奇想,我还没有搞过 App,要不搞搞玩玩😄 从 0 开始学还是很慢的,毕竟时间有限,好在了解过提示工程 [代码]《ChatGPT 进阶:提示工程入门 陈颢鹏 李子菡》[代码],问了一下助手 ChatGPT 几个常见的问题。 开发适用于 iPhone 的 App 的流程是什么 注册开发者账号 -> 下载 Xcode -> 学习 Swift -> 设计 + 编码 + 测试 -> TestFlight 内测 -> 准备上架 (准备) -> 提交审核 -> 应用上架 -> 应用更新和维护 很好,请给出可运行的应用实例,完成查询本机 IP 地址 我是一个新手,请问在 XCode 中如何运行你提供的代码 几轮对话后,大约用了 1 个小时,一个 iOS Demo 在模拟器上跑成功了,有点意思😄 不过功能有点简单,几年前用 Vue 写过一个还在跑的网站,同时我知道 ChatGPT 的编程能力,于是我丢了一个问题给他。 [代码]你是一个开发,会 Vue 、iOS 开发(使用 SwiftUI 框架 )两种语言,现在需要你根据 Vue 的代码重写为 iOS 代码,以下是 Vue 代码 [代码] [图片] 笔者是一个运维平台的产品,为了不忘记运维场景和技能,自己维护一个业务场景,开发语言:golang + Vue,部署架构:腾讯云 CLB+TKE+ 服务网格,运营系统:CLS+ 云函数 +Kafka+Doris+Flink+Hadoop+Streamsets。 结果惊奇的发现,真的可以执行,不服不行 👍 [图片] 1. 转折:把小程序代码构建为 iOS App 测试包(1 小时) 如果仅仅只是这样,那么这篇文章标题就该叫“GPT 如何将 Vue 改写为 App”。 万万没想到,过了 2 周从朋友那里获悉 微信开发者工具可以直接将小程序代码构建为 App,就像 Golang 一样,可以通过参数 [代码]GOARCH[代码] 控制构建的程序是在跑在 [代码]amd64[代码],还是 [代码]arm64[代码] CPU 架构上。 [图片] 现实就是这么巧,几年前使用 Vue 开发站点时,同时也开发了同款小程序。 有点意思,参照文档 构建你的第一个应用 花了 1 个小时,在我的 iPhone 上跑了 测试版 的 App. [图片] 此处应该给多端应用的产品和开发点个赞👍🏻 搞到这里,我其实进入了这款的第一个哎哈时刻,确实很爽,因为我不需要花心思用 GPT 来迁移 Vue 程序,直接用微信开发者工具构建为 App 即可,交互完全一致。 另外记录构建过程中遇到的两个问题 问题 1:小程序的图片在 App 中无法渲染 启用 Media SDK 即可 [图片] 问题 2:App 带有 Vconsole 入口 一开始以为在模拟器中才有,最后发现是一个配置,需要自己主动关闭。 [图片] 2. 构建正式包 谁不想在 App Store 能搜到自己的 App 呢,第二步,构建正式包。 2.1 准备苹果开发者账号 在 MacBook Air 或 iPhone 中安装 Apple Developer,然后注册苹果开发者账号 [图片] 一年 688 元会费 [图片] 正常情况下,交完会费后,第二天会收到一封欢迎加入 Apple Developer Program 的邮件,代表苹果开发者账号注册成功。 很遗憾,我注册时提示“未知错误,请再试一次” 找 Apple Developer 客服反馈,最后答复 [代码]由于一个或多个原因,您无法完成 Apple Developer Program 的注册。我们目前无法继续处理您的注册。[代码]。 好吧,估计是被风控命中了,于是找了家人的账号来注册,直接成功😄 2.2 生成 Bundle ID/ 证书 /Profile 生成 App 备案和构建正式包都需要的 Bundle ID/ 证书 /Profile。 生成 Bundle ID Bundle ID 是一个唯一的标识符,用来识别你的应用程序。它通常采用反向域名格式,例如 com.example.myapp。在开发和发布应用程序时,你需要在苹果的开发者账户中注册一个 Bundle ID,这样苹果的服务才能识别出你的应用程序。 参照 文档 生成 Bundle ID。 生成 证书 /Profile 证书(Certificates)用于建立开发者的身份,并确保应用是由已注册的开发者发布的。开发者需要从苹果开发者中心申请证书,用来对应用进行签名,这样 iOS 设备才会信任并运行这个应用程序。 配置文件(Provisioning Profiles)是一个包含证书、应用程序 ID、设备 ID 和其他信息的文件,它告诉 iOS 设备一个应用程序可以被安装和运行。配置文件将应用、开发者和设备联系起来,控制哪些设备可以安装和运行你的应用程序。 参照 文档 生成 iOS 证书和 Provisioning Profile。 [图片] 拓展资料:创建证书签名请求 问题:申请的 iPhone Distribution 证书不受信任 导入 Apple WWDRCA 证书 即可,可能原因:大致是分发的根证书没有导入你的 Mac 上。 更多资料详见 Apple PKI。 [图片] 2.3 备案(10 天 +) App 如果没有备案,在中国大陆将无法上架,这是苹果官方的说明。 中国工业和信息化部(MIIT)要求 App 必须具备有效的互联网信息服务提供者(ICP)备案号,了解更多 [图片] 其实备案比较简单,参照 App 备案 ,使用上一部分申请的 [代码]Bundle ID[代码]、证书(可查看 [代码]公钥[代码]、[代码]签名 MD5 值[代码])即可,不需要把 App 开发完,再来备案。 备案最长需要 20 个工作日,笔者用了 10 个工作日,在一个周五的下午收到了工信部发来的备案通过短信。 2.4 创建移动应用 移动应用是为了让 App 能用上微信的能力(比如分享到朋友圈或发送给朋友、微信登录 / 支付等),在移动应用中同时登记了 Bundle ID 和 Universal Links,这将会传递给下一步的多端框架,这是构建可正式包(采用苹果的分发证书)的必备条件。 先介绍一下 Universal Links。当用户使用 iPhone 手机访问你的网站,同时安装了 App 时,能在网站顶部快速跳转到 App。具体可以看下苹果官方的文档 Supporting associated domains 你需要有一个网站,未来要放 Universal Links 要用到的 [代码]apple-app-site-association[代码] 文件,不过对于我来说,这个功能好像用处不大,我更需要的是当用户用 iPhone 访问网站,引导他去 Apple Store 安装 App. 这里有一个关键信息,如果你不需要微信支付 / 微信登录 / 微信卡券的能力,不需要做开发者认证(开发者认证不能是个人主体) 访问 微信开放平台,创建移动应用,提交审核,几个小时就审核通过了。 [图片] 2.5 绑定多端框架 在 Donut 开发平台 中将 多端应用绑定上一步创建的移动应用,这样可以用到移动应用中登记的 Bundle ID 和 Universal Links,官方这么做比较合理,关键信息必须通过移动应用这关人工审核来起到一定的约束。 [图片] 绑定后,在多端应用中可以看到 Bundle ID 和 Universal Links 了。 [图片] 2.6 准备 App icon 等资料 App Icon 先用工具为你的 App 设计一个 1024px X 1024px 的图标,然后在 App Icon Generator 上生成 iPhone 所有规格的图标,之后在 [代码]project.miniapp.json[代码] 配置。 [图片] 启动图片 App 启动一般需要 2~4 秒,如果没有启动图片是白屏,用户会有点慌,不知道当前 App 是否正在启动,启动图片就是解决这个问题,同时在启动图片中传达 App 的价值主张。 我是直接用 Sketch 设计的,分辨率为 1290px x 2796px,这是兼容性最强的 6.7 寸(iPhone 15 Pro Max/15 Plus/14 Pro Max)手机的分辨率。 考虑到启动图片在不同机型上的兼容性,如果你用 Xcode 开发,苹果官方会推荐使用 Launch Screen Storyboard 隐私信息访问许可描述 小程序虽然没有用到摄像头、麦克风等权限,但多端的 SDK 中有(具体详见 Donut 官方文档 上架应用市场常见问题),所以得提前申明,不然把包通过 [代码]Transporter[代码] 上传后,会收到苹果发出的不合规邮件。 [图片] 以下是根据苹果官方打回的邮件中定义的隐私信息访问许可描述,应该是最基础的了,可以贴到你的 [代码]project.miniapp.json[代码] 文件中(用编辑器打开)。 [代码]{ "privateDescriptions": { "NSBluetoothPeripheralUsageDescription": "为了提供完整的功能,我们的应用程序需要访问蓝牙外设。这将用于与其他设备进行通信和数据交换。我们承诺保护用户隐私和数据安全。", "NSMicrophoneUsageDescription": "为了提供完整的功能,我们的应用程序需要访问麦克风。这将用于录制音频和进行语音交互。我们承诺保护用户隐私和数据安全。", "NSCalendarsUsageDescription": "为了提供完整的功能,我们的应用程序需要访问日历。这将用于提醒和日程管理。我们承诺保护用户隐私和数据安全。", "NSLocationAlwaysAndWhenInUseUsageDescription": "","NSBluetoothAlwaysUsageDescription":" 为了提供完整的功能,我们的应用程序需要始终访问蓝牙外设。这将用于与其他设备进行通信和数据交换。我们承诺保护用户隐私和数据安全。","NSPhotoLibraryUsageDescription":" 为了提供完整的功能,我们的应用程序需要始终访问相册。这将用于 IP 查询时显示 ISP 的图标。我们承诺保护用户隐私和数据安全。","NSCameraUsageDescription":" 为了提供完整的功能,我们的应用程序需要访问摄像头。这将用于录制视频。我们承诺保护用户隐私和数据安全。","NSLocationWhenInUseUsageDescription":" 为了提供完整的功能,我们的应用程序需要在使用时访问位置信息。这将用于提供定位服务和相关功能。我们承诺保护用户隐私和数据安全。" } } [代码] 2.7 构建正式版版本包 参照 打包生成 IPA 生成正式版的版本,注意使用分发证书。 [图片] 报错:file must be in miniprogram project 解决:把 mobileprovision 放在 miniprogram 目录下,因为 profile 不像 App icon 一样会自动上传到 miniprogram/ 目录下。 2.8 使用 Transporter 上传版本 参照 官方文档 上传正式版的 APK 包。 [图片] 遇到问题: Transporter,无法为 App “comxxxx.ipa” 创建临时 .itmsp 软件包。No suitable application records were found. Verify your bundle identifier ‘com.xxxx’ is correct and that you are signed into Xcode with an Apple ID that has access to the app in App Store Connect. [图片] 解决办法:去 App Store Connect 添加 App,绑定 [代码]Bundle id[代码],这样 Transporter 可以验证包在 App Store Connect 中已注册。 3. 使用 TestFlight 测试 在 App Store Connect 的 TestFlight 页面,可以选择内部、外部测试,外部测试版本需要 Apple 官方审核,把 公开链接发给朋友即可。 [图片] 在测试的同时,可以同步准备上架 App Store 的资料了。 4. 准备上架 Apple Store 审核资料 截屏 截屏是用来在 App Store 中显示你的 App 产品介绍页的,具体参照 截屏规范 [图片] 有 [代码]iPhone 15 Plus[代码] 和 [代码]iPhone 8 Plus[代码] 这两款机型就足够了,其他型号的手机能复用,分辨率应该是等比率缩放。 如果你像我一样,没有这两款手机,那用 iOS 模拟器。 Xcode -> 工具栏 Windows -> Devices and Simulators -> Create a new simulator -> Download more simulator runtimes [图片] 在微信开发者工具中运行这两款模拟器,利用模拟器自带截屏工具即可。 隐私政策 找一下常见 App 的隐私政策,在其产品介绍页中可以跳转过去。 如果你有网站就放在网站上,如果没有可以放在腾讯文档上。 [图片] 选择 App 供应的地区范围 哪些地区的用户可以下载你的 App。 [图片] 提交审核 一切准备好了后(包含备案),开启提交审核。 下午 5:35 提交审核,第二天早上 3:40 上架成功。✌🏻 [图片] 5. App Store 的数据 上架后刚好一周,看看最近一周的数据,还不错。 [图片] 这是评分数据 [图片] 6. 引流 二维码引流:草料二维码 通过草料二维码生成 App 的下载链接,放在网站上,引导用户跳转至 App。 Universal Links 参照 Apple 官网文章 Supporting associated domains 准备 Universal Links。 前面已经介绍了这个东东是干嘛的。 准备 [代码]apple-app-site-association[代码] 文件,放在网站的 [代码].well-known[代码] 目录下,完整路径为 [代码]/.well-known/apple-app-site-association[代码] 以下为示例,特别注意的是 [代码]appID[代码] 是由 [代码]团队 ID[代码] + [代码]Bundle ID[代码] 组成。 [代码]{ "applinks":{"apps":[], "details":[ { "appID":"<team_id>.<bundle_id>", "paths":["*"] } ] } } [代码] team_id 从 开发者账户 中获取 [图片] 顶部导航 当用户访问网站时,顶部引导用户跳转到 App 下载页。 等有空了搞搞。 7. 后记 小程序转 App,让个人或企业可以快速拥有 App,获取应用市场的流量,让开发者把精力放在业务逻辑上。 同时在开发小程序的过程中,发现开发者生态会散落在多个地方,比如 github,提供一些小程序模版、组件等能力,无法集中在一个地方比较方便的找到整个开发者生态的能力,和 VSCode 插件生态有点区别。 [图片] 先说 IDE 插件,比如我用 GPT4-Turbo 来写先代码或排查问题会在微信开发者工具和 Web 间跳转,操作流不太顺,如果能在微信开发者工具的插件入口中找到对应的 AI 代码助手,用起来应该很爽。 一旦平台的开放能力放出来,这些能力将源源不断的涌入到这个市场中,而不是作为平台方来集成这些能力,毕竟精力有限,同时还不一定做的最好,用插件可以让用户有更多的选择。 再说说 小程序组件,以大模型为例,目前市场有备案的大模型基座模型有好几家,在小程序开发过程中其实比较缺整体组件(UI + 背后的 API),有点像商场一样,平台方构建开放的能力,引导各个供应商提供开箱即用的能力,让用户可以快速上手,赶上这波大模型的技术趋势。 比如我自己在设计开放能力时的思考,平台专注骨架功能的开发,让开发者能参与到平台的建设中来,把生态盘活起来,最终提升大家研发运营的效率。 最后就是管理后端比较分散,比如 开放平台、donut、we 分析、云测、云托管,云开发,产品矩阵看不清,不容易知道整体的能力,缺少一个集中的控制台。 最后希望小程序越来越好 😄
01-30 - 用纯 CSS 方式实现动态切换主题风格
一、前言 UI 组件库是现代 Web 应用程序开发中不可或缺的一部分。动态主题风格切换是一个非常重要的功能,它可以允许应用程序用户在不同的场景下选择自己喜欢的主题。这样的一个特性可以增加用户体验的个性化,并提高应用程序的可用性和易用性。 微盟移动端组件库 Titian 提供了动态主题切换的能力,并且延展了主题范围。 二、背景 在以前商户店铺的品牌视觉风格往往千篇一律,同时还因为需要逐个繁琐地配置界面中元素,导致的风格错乱等问题。针对上述的痛点,本次升级在确保商户品牌风格统一的前提下,基于品牌调性提炼了具有共性的视觉特征,分别为颜色、图标、圆角。并用这些特征组合为“通用”、“潮流”、“可爱”三套风格,能够让商家随心选择,让线上店铺更贴合自身的品牌调性,提高品牌识别度,维持 C 端用户的品牌心智。 [图片] 微盟移动端组件库 Titian 的主题风格包括三个维度的风格变化: 1、主题颜色的风格切换,这里主题色可以设置任意一种色值。 2、字体图标风格的切换,组件库中的所有图标包含三种风格,具体分为通用型,超流型和可爱型。 3、所有组件的圆角的切换,组件库中所有圆角也分为三种风格,风格的分类和字体图标分类一致,通用型的圆角即为设计稿上的圆角,超流型的圆角则是所有的组件圆角都变成直角,可爱型的圆角则为在设计稿上的圆角的基础上加上8个像素。 [图片] 我们要实现三种风格的切换是互相独立的,可以互相组合搭配。另外,图标风格的切换可以是全量一起切换,也可以是部分单独切换,而且需要运行时可以动态切换。 这些风格的切换都需要内置到组件库中,只需要给业务方提供一个变量来改变整体风格。 三、需求分析 对于主题色的风格配置,由于有些组件使用的的具有百分比透明度的主题色,所以采用 RGBA 色值更加方便。对于图标风格切换,从一种风格增加到三种风格,能不能尽量的不要增加代码体积,毕竟小程序对包体积有严格的要求。 对于圆角风格,有些需要将设计稿的圆角加8像素,有些需要变成直角,而有些又需要单独处理成大圆角。 这都该如何设计呢?这么多的风格切换,如何能尽量设计少的接口来让业务方写最少的代码,不去增加业务方的记忆负担呢?另外需要在运行时进行风格的切换,我决定使用 CSS 原生变量的方式。 CSS变量的好处包括: 代码重用:可以在多个元素中使用同一个变量,避免了重复编写样式代码的问题。 简化维护:当需要修改样式时,只需要修改变量的值,而不是每个元素的样式。 动态更新:CSS 变量可以通过 JavaScript 动态修改,使得样式在运行时可以动态变化。 提高可读性:通过使用有意义的变量名,可以使样式表更易于理解和维护。 CSS 变量可以提高代码的可维护性、可读性和灵活性。 四、技术方案和实施 [图片] 4.1 主题颜色切换方案 组件库内部定义三个 CSS 变量:--theme-r、--theme-g、--theme-b,这三个 CSS 变量也是对外暴露出去修改主题颜色的关键。组件内部的全局 less 文件使用这三个变量定义主题色,所有组件使用到主题色的地方都统一使用下面的 less 变量。 @theme-r: var(--theme-r, 250); @theme-g: var(--theme-g, 44); @theme-b: var(--theme-b, 25); @brand-color: rgb(@theme-r, @theme-g, @theme-b); @brand-color-fade-10: rgba(@theme-r, @theme-g, @theme-b, 0.1); @brand-color-fade-20: rgba(@theme-r, @theme-g, @theme-b, 0.2); @brand-color-fade-30: rgba(@theme-r, @theme-g, @theme-b, 0.3); @brand-color-fade-40: rgba(@theme-r, @theme-g, @theme-b, 0.4); @brand-color-fade-50: rgba(@theme-r, @theme-g, @theme-b, 0.5); @brand-color-fade-60: rgba(@theme-r, @theme-g, @theme-b, 0.6); @brand-color-fade-70: rgba(@theme-r, @theme-g, @theme-b, 0.7); @brand-color-fade-80: rgba(@theme-r, @theme-g, @theme-b, 0.8); @brand-color-fade-90: rgba(@theme-r, @theme-g, @theme-b, 0.9); @brand-color-fade-100: rgba(@theme-r, @theme-g, @theme-b, 1); [图片] 4.2 圆角风格切换方案 三种圆角是对应三种圆角数值,默认的圆角是设计稿的圆角,怎样变成直角和大8像素的圆角呢?我采用设计圆角加上增量圆角来达到最终圆角的目的。 针对于所有增量圆角,我们定义一个css变量:--base-radius-size,另外在全局less变量中定义圆角变量,我们所有使用到圆角的地方都使用less变量;默认的增量为0。 潮流型风格需要将圆角变成直角,那么只需将增量圆角设置为一个较大负值比如-999px,那么最终也会得到一个负数圆角,因为圆角不存在负值,所以负值圆角表现就是圆角为0的直角效果。 可爱型风格需要将设计稿圆角增加8像素。那么这个增量圆角就设置为8px;而对于那些特殊需求,要单独设置成大圆角即半圆形的圆角,那么只需给一个较大的圆角即可。但是为了做区分,所以这里新增了一个css变量:--capsule-radius-size,这个是专供特殊需求圆角使用,比如button和search的圆角,他们在可爱风格下会直接变成胶囊型圆角。那么这里就把--capsule-radius-size设置为999px即可。 下图就是全局 less 变量中定义的圆角,在组件中统一使用如下圆角。目前只罗列了4px、8px、12px、16px和大圆角。如果有更多圆角,可以新增多个圆角数值。业务方在使用时,设置通用风格,只需设置--base-radius-size:0px;--capsule-radius-size:0px;这也是默认风格。设置成潮流型,只需设置--base-radius-size:-999px;--capsule-radius-size:-999px;设置成可爱型,只需设置--base-radius-size:8px;--capsule-radius-size:999px; @radius-4: calc(var(--base-radius-size, 0px) + 4px); @radius-8: calc(var(--base-radius-size, 0px) + 8px); @radius-12: calc(var(--base-radius-size, 0px) + 12px); @radius-16: calc(var(--base-radius-size, 0px) + 16px); @radius-999: calc(var(--base-radius-size, 0px) + 999px); // 圆角 (按钮button、搜索search)采用如下圆角; // 可以自适应变成胶囊型 @special-radius-4: calc(var(--capsule-radius-size, 0px) + 4px); @special-radius-8: calc(var(--capsule-radius-size, 0px) + 8px); @special-radius-12: calc(var(,--capsule-radius-size 0px) + 12px); @special-radius-16: calc(var(--capsule-radius-size, 0px) + 16px); @special-radius-999: calc(var(--capsule-radius-size, 0px) + 999px); 到这里切换圆角的功能已经实现了,但是让业务方去记忆不同的圆角值对应三种风格,比如设置可爱风需要设置--base-radius-size:8px;--capsule-radius-size:999px; 这会增加业务方的记忆负担,能不能继续优化,让设置更简单易用呢?我又探索了在 CSS 中使用布尔运算,让业务方通过传入0、1、2,组件内自动计算出需要使用的圆角值。 利用calc + var实现纯css布尔运算 [图片] 三种风格的计算逻辑 [图片] 逻辑延展,适应更多风格 [图片] 这样的方式就大大简化了业务的使用负担,只需要根据接口返回的风格类型,将对应的0、1、2通过 CSS 变量传入组件库,就可使用不同的圆角风格,计算过程完全在组件内部。后续如果要调整规则,也只需要在组件中进行全局的修改即可。 4.3 图标风格切换方案 目前常见的图标风格切换方式,主要是图标名称的切换。假如原有 50 个通用型风格的图标,现在分别新增 50 个潮流型和可爱型图标,对应不同的图标名称,换图标名就达到了换风格的目的。我的方案简单概括就是换字体,不换图标名称;由于小程序中对包体积有严格控制,所以能不增加包体积则最好; [图片] [图片] 在字体图标平台创建三套字体图标库,分别为通用型,潮流型和可爱型字体库;并分别上传对应风格的图标;按照通用型图标库为基准,修改新增字体库里的图标名称和 Unicode 编码,做到三套字体库中图标名称和 Unicode 编码一一对应相同;如下图,同一个删除图标,在三种风格的字体库中,下图标记的地方代表 Unicode 编码和图标名称,在三个字体库中要设置成一样的。将三套字体图标引入到小程序项目中,由于图标名称和 Unicode 编码一致,所以只需要引入三套字体的定义内容,具体的图标伪元素定义内容基本一致,无需新增。 [图片] 上图是设置的关键,每个图标库中需对应设置成一样的值。 五、总结 主题色可以设置任意一种色值,图标可以三种风格互相切换,圆角也可以三种风格互相切换。这三中风格又可以互相搭配。微盟移动端组件库 Titian 采用 CSS 变量方式切换风格,其中主题色风格提供三个 CSS 变量:--theme-r、--theme-g、--theme-b 对应主题色的 RGBA 色值,字体图标提供一个 CSS 变量,--icon-family 来设置图标对应的字体库的名称,圆角风格提供两个 CSS 变量:--base-radius-size 和 --capsule-radius-size 来设置圆角的增量,后续又优化为使用 --s 来计算得到增量圆角。 通过以上几个简单的 CSS 变量,微盟移动端组件库 Titian 实现了,使用纯 CSS 方式,在运行时动态切换主题风格和自由搭配三种类型风格的能力,在小程序和 H5 中是完全通用的,体验完全一致。微盟移动端组件库 Titian 动态切换主题的能力,给使用方丰富的选择性,体现品牌调性的多样化。也兼顾了商家品牌个性化需求的灵活性,圆角与图标风格可以进行脱钩单独选择风格,一键配置,全店生效。以及在已定义的部分场景中也能与全局风格脱钩 (例如价格色与标签色),既有统一的品牌风格,又不失场景化的灵活表达。贴合用户心智,维持品牌认知。在赋能品牌的同时,开发者能够探索出无限可能。 目前微盟移动端组件库 Titian 已经完全开源,期待大家共同构建组件库生态,让Titian组件库更加易用好用。
2023-09-04 - 微搭低代码产品动态更新
组件 开放自定义组件开源机制 微搭开放开源自定义组件库,本期含甘特图组件,后续将追加电子签名等。 欢迎开发者踊跃参与共建组件:https://github.com/TencentCloudBase/weda-custom-components [图片] 表格组件支持拖拽调整列宽 鼠标在表格列分隔线处长按,可拖拽调整列宽度,便于展示出更多内容,或节约横向空间。 [图片] 表格导入数据支持配置更新依据字段 数据表格组件,导入数据时,可灵活制定某字段,对已有数据进行匹配更新。 [图片] 公众号关注组件 提供小程序中关注及查看公众号的快捷入口 [图片] 循环展示提示文案下线 「循环展示」组件提示文案优化 表单组件标准化 表单组件以标准化方式实现,规范化组件做成方式,提升组件美观性,为组件后续开放性和扩展性做准备。 编辑器 编辑器批量配置属性和样式 编辑器支持同时选择多个组件,并配置样式和属性,实现批量配置组件提升效率。多选快捷键鼠标按住shift键或command/ctrl键。 [图片] 组件支持:不显示时保留组件值(hidden属性) 提供是否可见属性,该属性关闭时,组件不再展示和占位,但是属性/方法API奖依然可用,可实现:分步表单提交、特定字段隐藏提交等。 [图片] 环境变量 补充应用信息、环境信息、页面信息、设备信息、上下文信息等系统变量。包括应用运行终端、环境类型等。 [图片] 工作流 审批页面模版组件化 流程审批页面支持根据业务场景进行定制。 [图片] 区块 个人中心区块 按照常用个人中心功能范围和样式布局,提供个人中心区块,集成客服会话的能力。 [图片] 获取头像昵称区块 集成头像昵称获取,手机号获取等常用能力。 [图片]
2023-06-21 - 小程序订单中心path设置不显示?
问题:小程序后台-设置-基础设置-服务内容声明 这个标签下,没有填写订单中心path的入口。同主体下其他小程序都有如下设置入口。 [图片] 小程序为企业认证 类目:商家自营 已开通微信支付,并有过支付成功订单。
2023-03-10 - Skyline|小程序吸顶、网格、瀑布流布局都拿下~
在之前的文章中,我们知道了新 scroll-view 可以让小程序的长列表做到丝滑滚动~ 也提到了新 scroll-view 提供了很多新能力 sticky、网格布局、瀑布流布局等,这一篇,我们就来看看这些新能力是怎么使用的~ 新 scroll-view 在原来列表模式(type="list")的基础上,新增了自定义模式(type="custom") 在自定义模式下,新增了以下新组件供开发者调用 list-view:列表布局容器sticky-section / sticky-header:吸顶布局容器grid-view:网格布局容器,可实现网格布局、瀑布流布局等sticky布局sticky 布局即在应用中常见的吸顶布局,与 CSS 中的 position: sticky 实现的效果一致,当组件在屏幕范围内时,会按照正常的布局排列,当组件滚出屏幕范围时,始终会固定在屏幕顶部。 常见的使用场景有:通讯录、账单列表、菜单列表等等。 与 position: sticky 不同的是,position: sticky 很难实现列表滚动需要的交错吸顶效果,而 sticky 组件则可以帮忙开发者轻松实现交错吸顶的效果。 sticky 的使用非常简单: 将 scroll-view 切换到 custom 模式采用 sticky-section 作为 scroll-view 的子元素sticky-header 放置吸顶内容list-view 放置列表内容 {{item.name}} ... 我们来看下采用 sticky 布局做出来的通讯录效果~ [视频] sticky 布局也可以通过给 sticky-section 配置 push-pinned-header 来声明吸顶元素重叠时是否继续上推 像下图输入框和标签列表这种类型,标签列表吸顶时还是希望保留输入框吸顶。 [视频] 网格布局网格布局即将列表切割成格子,每一行的高度固定,常见的视频列表、照片列表等通常都采用网格布局。 在此之前,实现网格布局需要开发者自行实现网格切割,再嵌入到 scroll-view 中。 新 scroll-view 直接提供了 grid-view 组件供开发者使用~ 将 scroll-view 切换到 custom 模式采用 grid-view 类型为 aligned 做为直接子节点grid-view 中直接编写列表 ... 下面是使用网格布局实现的图片列表效果~ [视频] 瀑布流布局瀑布流布局与网格布局类似,不同的是瀑布流布局中每个格子的高度都可以是不一致的,所以在小程序中实现瀑布流布局就比较复杂了。 开发者需要通过计算格子高度,然后再进行瀑布流拼接,当滚动内容过多时还需要处理节点过多导致内存不足等问题。 grid-view 组件直接支持了瀑布流模式供开发者直接使用,grid-view 组件会根据子元素高度自动布局: 将 scroll-view 切换到 custom 模式采用 grid-view 类型为 masonry 做为直接子节点grid-view 中直接编写列表 ... 下面是使用瀑布流布局实现的图片列表效果~ [视频] 想要立即体验?现在通过微信开发者工具导入 代码片段,即可体验新版 scroll-view 组件能力~
2023-08-03 - 利用 GitHub Actions 实现小程序的持续集成
众所周知,微信小程序的开发需要依赖微信官方提供的开发工具(IDE),在 IDE 中完成小程序的真机预览和上传,每次都要手动操作还是比较麻烦的。对于托管在 GitHub 的项目,我们可以利用 GitHub 提供的 GitHub Actions 这一能力,实现小程序的持续集成(CI/CD)。 我们主要利用了 GitHub Action for WeChat MiniProgram 这个 Action,实现了以下自动化流程: 当 Commit 推送到 [代码]master[代码] 分支时,触发小程序预览并显示预览二维码 当有人创建了 Pull Request 时,触发小程序预览并显示预览二维码 当创建版本 Tag 并推送到 GitHub 时,触发小程序的构建和上传 更多有关小程序 GitHub Actions 的玩法,也欢迎探索和交流~ 准备工作 在使用 GitHub Action for WeChat MiniProgram 前,需要先准备好小程序代码上传密钥,这是用于小程序开发者身份鉴权的凭证。获取步骤如下: 登录微信小程序管理后台 https://mp.weixin.qq.com 登录后在左侧菜单依次找到「开发」—「开发管理」,在右侧界面找到「开发设置」Tab。向下滚动找到「小程序代码上传」模块,点击「生成」按钮。管理员使用微信扫码后,获得密钥文件并下载 关闭「IP 白名单」功能。因为执行 GitHub Actions 的机器 IP 范围我们无法获得,这里需要关闭此功能 [图片] 打开 GitHub 小程序项目的「Settings」,在左侧菜单依次找到「Secrets」—「Actions」,点击右上角按钮「New repository secret」,「Name」输入 [代码]PRIVATE_KEY[代码],「Secret」粘贴第 2 步中密钥文件的内容,点击「Add secret」保存 [图片] 至此,准备工作已完成,我们已经给项目配置了 GitHub Actions 所需的密钥。 在项目中使用 示例项目:crazyurus/recruit-miniprogram 首先在项目根目录下创建 [代码].github/workflows[代码] 文件夹,再根据我们的需求编写 YAML 文件 实现小程序预览 在 [代码]workflows[代码] 目录下新建 [代码]preview.yaml[代码]。我们需要当 Commit 推送到 [代码]master[代码] 分支时触发小程序预览。因此在 [代码]preview.yaml[代码] 中添加: [代码]name: 提交 Commit 预览小程序 on: push: branches: - master [代码] 命中该条件时,这个 YAML 就会被 GitHub Actions 执行,我们可以在项目的「Actions」中看到执行进度和结果: [图片] 接下来需要给 [代码]preview.yaml[代码] 定义具体的行为,在其中添加: [代码]jobs: preview: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - id: preview name: Compile uses: crazyurus/miniprogram-action@1.0.0 with: action_type: preview env: PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} - name: QR Code uses: peter-evans/commit-comment@v2 with: body: | Copy the following content to the address bar of the browser to open the preview QR code ``` ${{ steps.preview.outputs.preview_qrcode }} ``` [代码] 其中,[代码]jobs.preview[代码] 是 Job 的名称,[代码]runs-on[代码] 是 Job 运行环境,[代码]steps[代码] 是运行步骤。这个 Job 主要有 3 步: Checkout 项目代码 运行 [代码]crazyurus/miniprogram-action[代码] 这个 Action(即前面提到的 GitHub Action for WeChat MiniProgram),[代码]id[代码] 是 Step 的唯一标识(用于后面取 [代码]outputs[代码]),[代码]with[代码] 传递参数 [代码]action_type[代码],[代码]env[代码] 传递密钥内容。这个 Action 会对小程序进行编译,并生成预览二维码,二维码图片的 Base64 内容会通过 [代码]outputs.preview_qrcode[代码] 返回 运行 [代码]peter-evans/commit-comment[代码] 这个 Action,用来给 Commit 增加评论。我们把上一步获取到的二维码图片 Base64 评论到这个 Commit 上,在 Commit 左边即可看到一个评论图标: [图片] 点击后即可看到这条评论和二维码内容。由于 GitHub Markdown 的限制,我们暂时无法使用图片格式语法展示 Base64 图片,需要将内容复制后粘贴到浏览器地址栏即可预览。 [图片] 如果我们要实现有人创建了 Pull Request 时,触发小程序预览并显示预览二维码。只需要: 新建 [代码]pull-request.yaml[代码] 更换 [代码]on[代码] 中的触发条件,改为 [代码]pull_request[代码] 修改第 3 步中的 Action,替换为 [代码]dannyskoog/pull-request-comment[代码],用来给 Pull Request 增加评论 完整配置如下: [代码]name: 创建 Pull Request 预览小程序 on: pull_request: branches: master types: [opened, synchronize, reopened] jobs: preview: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - id: preview name: Compile uses: crazyurus/miniprogram-action@1.0.0 with: action_type: preview env: PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} - name: QR Code uses: dannyskoog/pull-request-comment@v1 with: message: | Copy the following content to the address bar of the browser to open the preview QR code ``` ${{ steps.preview.outputs.preview_qrcode }} ``` [代码] 如果需要预览时指定场景值、页面路径、页面参数等,GitHub Action for WeChat MiniProgram 也同样支持,在 [代码]with[代码] 增加参数即可。支持的参数如下: 参数 是否必填 描述 默认值 action_type [代码]false[代码] Action 类型, [代码]preview[代码] 或 [代码]upload[代码] [代码]upload[代码] project_path [代码]false[代码] 项目路径,需包含 [代码]project.config.json[代码] 文件 [代码].[代码] page_path [代码]false[代码] 预览的页面路径,例如 [代码]pages/index/index[代码] [代码]app.json[代码] 中第一个页面 page_query [代码]false[代码] 预览的页面参数,例如 [代码]a=b&c=1[代码] scene [代码]false[代码] 场景值,详细见 微信官方文档 [代码]1011[代码] version [代码]false[代码] 上传的版本号 [代码]1.0.0[代码] description [代码]false[代码] 上传的版本描述 需要注意的是,如果你的小程序代码不在项目的根目录下,则需要配置 [代码]project_path[代码] 参数指定小程序的目录([代码]project.config.json[代码] 文件所在的目录)。例如使用了 [代码]Taro[代码] 等框架,需要由框架编译后再运行,则需要指定 [代码]project_path[代码] 为编译后的目录 [代码]dist[代码],并且在 YAML 文件中的 Compile Job 前需要增加框架依赖安装和编译的步骤。YAML 如下: [代码]jobs: preview: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Install dependencies run: npm ci - name: Taro compile run: npm run build:weapp - name: Compile uses: crazyurus/miniprogram-action@1.0.0 with: action_type: preview project_path: dist env: PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} [代码] 实现小程序上传 我们使用 Git Tag 触发小程序的发布,例如执行以下命令: [代码]$ git tag 2.3.4 $ git push --tags [代码] 此时会在最新的 Commit 创建一个 [代码]2.3.4[代码] 的 Tag。我们基于这个 Commit 发布小程序的 [代码]2.3.4[代码] 版本,因此需要 GitHub Actions 触发小程序上传。 在 [代码]workflows[代码] 目录下新建 [代码]upload.yaml[代码],并添加: [代码]name: 上传小程序 on: push: tags: - "*.*.*" jobs: upload: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Upload uses: crazyurus/miniprogram-action@1.0.0 with: action_type: upload version: ${{ github.ref_name }} env: PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} [代码] 其中,[代码]github.ref_name[代码] 这里代表标签名称,我们将标签名称作为版本号传递给 Action,再由 Action 上传到微信服务端。上传后效果如下: [图片] 接下来在微信小程序管理后台提交审核即可。 给项目增加 Badge 至此小程序项目就成功接入了 GitHub Actions,我们还可以给项目 [代码]README.md[代码] 增加徽章(Badge),用于显示项目的持续集成状态。将以下图片添加到 [代码]README.md[代码] 中: [代码]![预览](https://github.com/crazyurus/recruit-miniprogram/actions/workflows/preview.yaml/badge.svg) [代码] 其中,[代码]crazyurus/recruit-miniprogram[代码] 需要替换为你的项目名称,[代码]preview.yaml[代码] 需要替换为你的 YAML 文件名。 效果如下: [图片] 更多方式可参见 GitHub 官方文档 Adding a workflow status badge 实现原理 Action 实现:crazyurus/miniprogram-action GitHub Action for WeChat MiniProgram 基于微信官方提供的 [代码]miniprogram-ci[代码] 实现了小程序的预览和上传。主要逻辑如下: 输入参数读取,使用 [代码]@actions/core[代码] 提供的 [代码]getInput[代码] 方法 使用环境变量 [代码]process.env.PRIVATE_KEY[代码] 获取密钥,[代码]process.env.GITHUB_WORKSPACE[代码] 获取小程序项目路径 读取小程序 [代码]project.config.json[代码] 文件,获取 [代码]AppID[代码]、[代码]compileType[代码]、[代码]miniprogramRoot[代码] 以及 [代码]es6[代码]、[代码]minified[代码] 等编译参数,转换后传递给 [代码]miniprogram-ci[代码] 若小程序项目存在 [代码]package.json[代码],则在预览或上传前调用 [代码]ci.packNpm[代码] 对小程序中的 NPM 依赖进行构建 根据参数 [代码]action_type[代码] 决定调用 [代码]ci.preview[代码] 还是 [代码]ci.upload[代码] 小程序预览执行完成,通过 [代码]@actions/core[代码] 提供的 [代码]setOutput[代码] 方法将二维码输出 总结 我们使用 GitHub Action for WeChat MiniProgram 实现了小程序项目的持续集成,在 Commit 或 Pull Request 时触发预览并生成二维码,在添加 Tag 时上传小程序到管理后台。 总而言之,GitHub Actions 的功能十分强大,接下来你还可以探索: 给项目增加更多的自动化流程,例如 Pull Request 被合并后也触发上传。推荐阅读阮一峰的 GitHub Actions 入门教程 了解更多用法 给项目引入更多的 GitHub Actions 让流程更强大,例如将生成的二维码通过飞书机器人发送给自己或群、基于 [代码]miniprogram-automator[代码] 实现小程序的自动化测试等。更多的 GitHub Actions 可以到 GitHub Actions 市场 获取 当现有的 GitHub Actions 无法满足项目的需求时,可以参考 GitHub Actions 开发文档 和 GitHub Action for WeChat MiniProgram 的代码自己实现一个
2022-12-07 - 「笔记」简单实现服务端动态控制原生小程序界面灰色模式开关
前言 在遇到公祭日或其它特殊日子的时候,我们需要将我们的网站、小程序变成灰色(黑白)模式,如果是在网页端比较简单,只需设置*、html最外层标签的样式设置filter: grayscale(100%)即可。但是在小程序中如果直接设置page的样式的话会导致小程序内使用flex失效,布局出现错位的情况。 如何解决错位问题?以及如何通过服务端动态控制灰色模式开关请看下文。 注:此方式无法控制非自定义导航栏颜色,如想要实现更完美的效果,请配合使用自定义导航栏。 原生小程序前端设置灰色模式: wxml <view class=“grayscale”> <view class=“content”></view> …小程序代码 </view> wxss .grayscale .content, .grayscale text, .grayscale button { -moz-filter: grayscale(100%); -ms-filter: grayscale(100%); -o-filter: grayscale(100%); filter: grayscale(100%); } 第三方UI组件/库(如:vant) .grayscale .van-goods-action, .grayscale .van-submit-bar, .grayscale .van-swipe-cell { -moz-filter: grayscale(100%); -ms-filter: grayscale(100%); -o-filter: grayscale(100%); filter: grayscale(100%); } 切忌直接设置 page { filter: grayscale(100%); } 小结:简单来说,就是把样式控制明确到具体的标签。 服务端动态控制 接下来讲我们利用小程序的数据预拉取来实现动态开关。 之所以选择使用数据预拉取来控制,是因为灰色模式并不是我们日常运营所需,如果单独封装到一个请求中去,会造成不必要的资源浪费,而且数据预拉取会在用户每次访问小程序的时候都会执行一次,所以能够保证尽可能实时获取到最新的状态,但是因为本身也是异步请求,所以无法100%保证页面加载完之前,就能够实时响应,所以返回的class并没有直接设置在全局变量globalData中,而是先存到本地存储Storage里,当我们在小程序后台关闭数据预拉取后,小程序端便不会再去请求相关接口,这样就做到了随时控制开关的效果了。 实现方式: app.js App({ onLaunch: async function (options) { // 此处用于服务端鉴权,可根据自身情况设置 wx.setBackgroundFetchToken({ token: ‘grayscale’ }) wx.onBackgroundFetchData((res) => { if(res.fetchedData && res.fetchedData.class) { wx.setStorageSync(‘class’, res.fetchedData.class); } }) }, globalData: { grayscale: wx.getStorageSync(“class”).grayscale || “” } }) 需要灰色模式的wxml <view class="{{grayscale}}"> <view class=“content”></view> …小程序代码 </view> 需要灰色模式的js const app = getApp() Page({ data: { grayscale: app.globalData.class.grayscale } }) 服务端(node.js)接收到微信推送的get请求后返回数据 ctx.body = { class: { grayscale: “grayscale” } } PS:以上方案仅供参考,当前方案在微信开发者工具中因缓存问题无法实时控制,iOS端基本上是没什么大问题,如果其它更好的方案可自行处理。
2022-12-03 - 小程序-使用typescript
为什么选择typescript?强类型语言的优势 1.错误可以更早的暴露 编码阶段可以消灭一大部分异常,不必等到运行阶段 2.强类型的代码,更能提高效率,代码更智能,编码更准确 3.使用强类型的语言重构更加牢靠,删除某个成员,或者是修改某个成员名称,会立即报出错误,然后进行相应的修改 4.减少不必要的类型判断 JavaScript 是没有类型提示的。而 TypeScript 有灵活的类型系统,可以编码期检查并且增强代码的可读性还提供了 any 类型进行缓冲。 小程序对 TS 的支持d.ts 文件对于 TypeScript 来说是很重要的东西 。它声明了对外暴露的方法和属性。而小程序官方对 TypeScript 的支持,开发所依赖的类型声明会随着官方API 发生变动时小程序本身 API 的 d.ts 文件也会自动更改,更加省力。 使用 首先更新微信开发者工具到最新版,在创建新项目时选择 TypeScript 语言。 [图片] 创建后,我们可以看到项目里带上了 typings 库,以及 TypeScript 的配置文件 tsconifg。 [图片] 事件视图的事件,对应的类型笔者在 typings 中并没有看到有 Interface 定义,可以暂时用 any,然后自己再用 as 转一下 event 携带的数据的类型。 Page&Data在 typing 中定义了 Page 对象 declare const Page: Page.PageConstructor interface PageConstructor { < D extends IAnyObject, T extends IAnyObject & PageInstance >( options: PageInstance<D, T> & T ): void } 它支持 D 和 T 两个范型。 泛型D 从下面的Page写法来看 Page({}); options 参数 就是一个 PageInstance, interface PageInstance< D extends IAnyObject = any, T extends IAnyObject = any > extends PageInstanceBaseProps< D > PageInstance 里面定义了 Page 声明周期的方法,而且继承自 PageInstanceBaseProps,并将范型 D 传入。 interface PageInstanceBaseProps<D extends IAnyObject = any> { data?: D //... } 可以看出范型 D 就是 data 的类型接口。因为 data 不是必须实现的,所以这里是可选型 ?。 泛型T T extends IAnyObject & PageInstance T 其实就是对 PageInstance 的拓展,PageInstance 是 Page 的实例接口,那么 T 就是在 Page 里面 this 的类型接口了,所以,需要在 Page 里新增的方法和属性,都在 T 里定义。 例子 一个普通页面我们可以声明两个接口,一个代表 data, 一个代表 page。 interface IIntroPage { nextButtonTap(event: any): void; isLoading: boolean; } interface IIntroData { test: string } Page<IIntroData, IIntroPage>({ isLoading: false, nextButtonTap(event: any) { this.isLoading = true; } }); 页面如果没有 data 或 不需要扩展 page,可以用 AnyObject 代替 D 或者 T 即可。 interface PageInstanceBaseProps< D extends IAnyObject = any > { data?: D setData?<K extends keyof D>( data: D | Pick<D, K> | IAnyObject, callback?: () => void ): void } // "!" : 告诉编译器,data不可能为null或者undefined 同时,由于 setData 和 data 都被声明为可选项,使用时需要加上!,[代码]this.setData!({})[代码] 和 [代码]this.data![代码]。 用上 TypeScript 之后,官方的 API 都可以直接看参数和返回值的类型,就不需要去查文档猜测类型了。
2022-05-19