HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

如何混用Navigation和router实现路由导航

问题现象
如何实现Navigation和router的混用?

背景知识
router:提供通过不同的url访问不同的页面,包括跳转到应用内的指定页面、同应用内的某个页面替换当前页面、返回上一页面或指定的页面等。
Navigation:用于实现Navigation页面(NavDestination)间的跳转,支持在不同Navigation页面间传递参数,提供灵活的跳转栈操作,从而更便捷地实现对不同页面的访问和复用。Navigation是路由导航的根视图容器,一般作为页面(@Entry)的根容器。
解决方案
对于router跳转到的页面需要使用Navigation作为根容器,才能在这个页面跳转到下个NavDestination页面。这是因为router跳转的是page页面,而NavDestination是Navigation的子组件,二者层次不同。以下为Navigation和router混用的三种常见场景。

场景一
Navigation页面与router页面间的跳转,如:入口页面->NavPageOne->RouterPageOne->NavPageTwo。该混用场景常见于“全局导航 局部导航”的页面设计,例如首页到隐私模块页面等。

使用router跳转到RouterPageOne,RouterPageOne使用Navigation作为根容器跳转到NavPageTwo,这里RouterPageOne的Navigation和第一个Navigation相互独立,都有各自的路由栈,互不影响。开发者需参考系统路由表配置Navigation路由,配置说明附在本文末尾。

入口页面代码如下:需在resources/base/profile/main_pages.json配置,参考pages标签。

https://pastebin.com/T0qjEdhR
https://pastebin.com/9j2xhYmA
https://pastebin.com/y3qDY8zJ
https://pastebin.com/ACGMG4Ja
https://pastebin.com/hMkaAgnr
https://pastebin.com/DKCau8pY
https://pastebin.com/KMR7ahzA
https://pastebin.com/tJvRKc4N
https://pastebin.com/NVEwG9uZ
https://pastebin.com/EPxLpA6i
https://pastebin.com/FK8MaSeV
https://pastebin.com/CytN6Qcs
https://pastebin.com/q7ugna3X
https://pastebin.com/EjiwDGkT
https://pastebin.com/nsPUWMri
https://pastebin.com/SbiDFTm9
https://pastebin.com/mNrgbF0F
https://pastebin.com/x6eZ1ygU
https://pastebin.com/PBL5tVYf
https://pastebin.com/jX1mX3T0
https://pastebin.com/WXYZUzhC
https://pastebin.com/UDyfqTN0
https://pastebin.com/wXk3dYJG
https://pastebin.com/dSzW4S5n
https://pastebin.com/iud6XZSS
https://pastebin.com/scHYNFMf
https://pastebin.com/AeHxaU7w
https://pastebin.com/H7Au1Apz
https://pastebin.com/DRCNjV3v
https://pastebin.com/7gv7ubWE
https://pastebin.com/SZdUViky
https://pastebin.com/cp63TTTg
https://pastebin.com/fzCVAvCF
https://pastebin.com/jJ4Tgfcm
https://pastebin.com/gKUBHbAx
https://pastebin.com/SHxpbQus
https://pastebin.com/PUgXw4SZ
https://pastebin.com/kQudDe6v
https://pastebin.com/Q8kzX5QG
https://pastebin.com/gJTuU53X
https://pastebin.com/tgUM3kmm
https://pastebin.com/XSzcmndG
https://pastebin.com/STYGr8HQ
https://pastebin.com/Cke4tPN7
https://pastebin.com/G9vGA4VD
https://pastebin.com/9Qdn0wFX
https://pastebin.com/fNK8TZBi
https://pastebin.com/BaX3LH8U
https://pastebin.com/ZZQcNB1N
https://pastebin.com/X9RbKjBw
https://pastebin.com/KAJYpJte
https://pastebin.com/vnKJfsX4
https://pastebin.com/Kd1Xm439
https://pastebin.com/VEBbiMGW
https://pastebin.com/asWsvVUg
https://pastebin.com/bADNrv39
https://pastebin.com/dbE231R1
https://pastebin.com/urCZ7b7n
https://pastebin.com/rJUkQLTy
https://pastebin.com/0WJW2iZm
https://pastebin.com/MYR6YbuM
https://pastebin.com/FvqPxU7T
https://pastebin.com/RHgL2GWD
https://pastebin.com/zfUdLzmn
https://pastebin.com/3RiMytue
https://pastebin.com/8Q0gji6p
https://pastebin.com/bURMaJ6s
https://pastebin.com/vSEEbx6q
https://pastebin.com/sxF2ewtt
https://pastebin.com/qS8u7xGj
https://pastebin.com/Pi4zhEac
https://pastebin.com/3BWfDUkr
https://pastebin.com/Mfvfq5a1
https://pastebin.com/8GucH56m
https://pastebin.com/3g8rK644
https://pastebin.com/86tms6GZ
https://pastebin.com/6PeE5NJ9
https://pastebin.com/zQZMR3uQ
https://pastebin.com/ZzKRebtY
https://pastebin.com/RXSvMK0S
https://pastebin.com/EJkW2AzU
https://pastebin.com/HV1WwkJr
https://pastebin.com/3bj7RrVR
https://pastebin.com/5CgX4SEE
https://pastebin.com/z8MPVtnX
https://pastebin.com/UX0Am16Z
https://pastebin.com/SNgYcfe9
https://pastebin.com/5qiLcbAd
https://pastebin.com/XZcpNxKU
https://pastebin.com/g1eR9CPP
https://pastebin.com/uJeVWMAd
https://pastebin.com/gRjHa4ex
https://pastebin.com/EBarihNi
https://pastebin.com/sMg2cGSe
https://pastebin.com/Z8MPPgLr
https://pastebin.com/LyUNjkvn
https://pastebin.com/S3eeuU8M
https://pastebin.com/e1bYnW5j
https://pastebin.com/QYdf4Mv9
https://pastebin.com/mQJQHVzW
https://pastebin.com/andd0da6
https://pastebin.com/PeTHqrxq
https://pastebin.com/P6gk0Tj9
https://pastebin.com/QQ2dxGdL
https://pastebin.com/E2ibKkNu
https://pastebin.com/YC0sK7jB
https://pastebin.com/1EYYscyi
https://pastebin.com/FRXXxWwg
https://pastebin.com/ZXXi9xM1
https://pastebin.com/0izhXiFJ
https://pastebin.com/3sPJWA9h
https://pastebin.com/C9s6zMRc
https://pastebin.com/92djJXhJ
https://pastebin.com/rxLq7fK7
https://pastebin.com/1jjxq2y7
https://pastebin.com/RQuravmU
https://pastebin.com/0HC8tnCM
https://pastebin.com/qV828LM2
https://pastebin.com/KsTnZQKK
https://pastebin.com/0DGQvkf5
https://pastebin.com/ZpSpZ1ad
https://pastebin.com/RyCxRXXc
https://pastebin.com/FNT47tiG
https://pastebin.com/M9kRCjFZ
https://pastebin.com/5FYBqVba
https://pastebin.com/tc3AxKPP
https://pastebin.com/cmEzD2cm
https://pastebin.com/G8epzgNn
https://pastebin.com/DvkkCE48
https://pastebin.com/qQn5nr1T
https://pastebin.com/LdRyg3fJ
https://pastebin.com/bhMmk2QE
https://pastebin.com/Ezp4M2mU
https://pastebin.com/pgc1FurG
https://pastebin.com/Ct29GCzi
https://pastebin.com/X2SibK2k
https://pastebin.com/cPyP1sGv
https://pastebin.com/BpRi9nQ3
https://pastebin.com/PuEQk2D5
https://pastebin.com/LqQtd4xC
https://pastebin.com/0m9SGErQ
https://pastebin.com/2TjekbUJ
https://pastebin.com/LCfheMsR
https://pastebin.com/KBGaUPqA
https://pastebin.com/adQ498ic
https://pastebin.com/0wuucsZ0
https://pastebin.com/5p9vtftU
https://pastebin.com/NBdsXhQi
https://pastebin.com/N1rgsNYD
https://pastebin.com/pNyDCENQ
https://pastebin.com/9cDP15GL
https://pastebin.com/F2a621ab
https://pastebin.com/aJ9PzUyf
https://pastebin.com/P5UjJuY1
https://pastebin.com/Sn9J5rLr
https://pastebin.com/3rQRmumG
https://pastebin.com/QNSSbDRg
https://pastebin.com/csLrWKhY
https://pastebin.com/Ceg1c07i
https://pastebin.com/hwKtUzVf
https://pastebin.com/WzAyiC5N
https://pastebin.com/qDteic1q
https://pastebin.com/tfYq4WsV
https://pastebin.com/bRqVufy3
https://pastebin.com/93ex9FyT
https://pastebin.com/stpFZB0f
https://pastebin.com/GAm5Qri7
https://pastebin.com/a5xG0wd1
https://pastebin.com/2J1Hiqvm
https://pastebin.com/gh7CZTcv
https://pastebin.com/XLdTknfz
https://pastebin.com/CUjaXXKR
https://pastebin.com/RHVccDjS
https://pastebin.com/Fyc2a9PC
https://pastebin.com/Y7QzDaEQ
https://pastebin.com/30AHcs66
https://pastebin.com/76dUwnrz
https://pastebin.com/Eefce3y4
https://pastebin.com/rgUGwQR4
https://pastebin.com/b1wjhncJ
https://pastebin.com/ReNE2D36
https://pastebin.com/vyJXbMcD
https://pastebin.com/vYKvCKch
https://pastebin.com/XfHEyEgJ
https://pastebin.com/v8zRpCdK
https://pastebin.com/fFVAe7NL
https://pastebin.com/USryqJTr
https://pastebin.com/yAc9niyy
https://pastebin.com/nkJB8XRC
https://pastebin.com/PSqZGpwq
https://pastebin.com/ZD0VWb9t
https://pastebin.com/5YsLCMSB
https://pastebin.com/yXkvdiH1
https://pastebin.com/4YzAMWHC
https://pastebin.com/QaVh0Srp
https://pastebin.com/d9Yjsr9D
https://pastebin.com/4rKTisyH
https://pastebin.com/jGe97xbT
https://pastebin.com/KCFPzysq
https://pastebin.com/JXVdBeaz

继续阅读 »

问题现象
如何实现Navigation和router的混用?

背景知识
router:提供通过不同的url访问不同的页面,包括跳转到应用内的指定页面、同应用内的某个页面替换当前页面、返回上一页面或指定的页面等。
Navigation:用于实现Navigation页面(NavDestination)间的跳转,支持在不同Navigation页面间传递参数,提供灵活的跳转栈操作,从而更便捷地实现对不同页面的访问和复用。Navigation是路由导航的根视图容器,一般作为页面(@Entry)的根容器。
解决方案
对于router跳转到的页面需要使用Navigation作为根容器,才能在这个页面跳转到下个NavDestination页面。这是因为router跳转的是page页面,而NavDestination是Navigation的子组件,二者层次不同。以下为Navigation和router混用的三种常见场景。

场景一
Navigation页面与router页面间的跳转,如:入口页面->NavPageOne->RouterPageOne->NavPageTwo。该混用场景常见于“全局导航 局部导航”的页面设计,例如首页到隐私模块页面等。

使用router跳转到RouterPageOne,RouterPageOne使用Navigation作为根容器跳转到NavPageTwo,这里RouterPageOne的Navigation和第一个Navigation相互独立,都有各自的路由栈,互不影响。开发者需参考系统路由表配置Navigation路由,配置说明附在本文末尾。

入口页面代码如下:需在resources/base/profile/main_pages.json配置,参考pages标签。

https://pastebin.com/T0qjEdhR
https://pastebin.com/9j2xhYmA
https://pastebin.com/y3qDY8zJ
https://pastebin.com/ACGMG4Ja
https://pastebin.com/hMkaAgnr
https://pastebin.com/DKCau8pY
https://pastebin.com/KMR7ahzA
https://pastebin.com/tJvRKc4N
https://pastebin.com/NVEwG9uZ
https://pastebin.com/EPxLpA6i
https://pastebin.com/FK8MaSeV
https://pastebin.com/CytN6Qcs
https://pastebin.com/q7ugna3X
https://pastebin.com/EjiwDGkT
https://pastebin.com/nsPUWMri
https://pastebin.com/SbiDFTm9
https://pastebin.com/mNrgbF0F
https://pastebin.com/x6eZ1ygU
https://pastebin.com/PBL5tVYf
https://pastebin.com/jX1mX3T0
https://pastebin.com/WXYZUzhC
https://pastebin.com/UDyfqTN0
https://pastebin.com/wXk3dYJG
https://pastebin.com/dSzW4S5n
https://pastebin.com/iud6XZSS
https://pastebin.com/scHYNFMf
https://pastebin.com/AeHxaU7w
https://pastebin.com/H7Au1Apz
https://pastebin.com/DRCNjV3v
https://pastebin.com/7gv7ubWE
https://pastebin.com/SZdUViky
https://pastebin.com/cp63TTTg
https://pastebin.com/fzCVAvCF
https://pastebin.com/jJ4Tgfcm
https://pastebin.com/gKUBHbAx
https://pastebin.com/SHxpbQus
https://pastebin.com/PUgXw4SZ
https://pastebin.com/kQudDe6v
https://pastebin.com/Q8kzX5QG
https://pastebin.com/gJTuU53X
https://pastebin.com/tgUM3kmm
https://pastebin.com/XSzcmndG
https://pastebin.com/STYGr8HQ
https://pastebin.com/Cke4tPN7
https://pastebin.com/G9vGA4VD
https://pastebin.com/9Qdn0wFX
https://pastebin.com/fNK8TZBi
https://pastebin.com/BaX3LH8U
https://pastebin.com/ZZQcNB1N
https://pastebin.com/X9RbKjBw
https://pastebin.com/KAJYpJte
https://pastebin.com/vnKJfsX4
https://pastebin.com/Kd1Xm439
https://pastebin.com/VEBbiMGW
https://pastebin.com/asWsvVUg
https://pastebin.com/bADNrv39
https://pastebin.com/dbE231R1
https://pastebin.com/urCZ7b7n
https://pastebin.com/rJUkQLTy
https://pastebin.com/0WJW2iZm
https://pastebin.com/MYR6YbuM
https://pastebin.com/FvqPxU7T
https://pastebin.com/RHgL2GWD
https://pastebin.com/zfUdLzmn
https://pastebin.com/3RiMytue
https://pastebin.com/8Q0gji6p
https://pastebin.com/bURMaJ6s
https://pastebin.com/vSEEbx6q
https://pastebin.com/sxF2ewtt
https://pastebin.com/qS8u7xGj
https://pastebin.com/Pi4zhEac
https://pastebin.com/3BWfDUkr
https://pastebin.com/Mfvfq5a1
https://pastebin.com/8GucH56m
https://pastebin.com/3g8rK644
https://pastebin.com/86tms6GZ
https://pastebin.com/6PeE5NJ9
https://pastebin.com/zQZMR3uQ
https://pastebin.com/ZzKRebtY
https://pastebin.com/RXSvMK0S
https://pastebin.com/EJkW2AzU
https://pastebin.com/HV1WwkJr
https://pastebin.com/3bj7RrVR
https://pastebin.com/5CgX4SEE
https://pastebin.com/z8MPVtnX
https://pastebin.com/UX0Am16Z
https://pastebin.com/SNgYcfe9
https://pastebin.com/5qiLcbAd
https://pastebin.com/XZcpNxKU
https://pastebin.com/g1eR9CPP
https://pastebin.com/uJeVWMAd
https://pastebin.com/gRjHa4ex
https://pastebin.com/EBarihNi
https://pastebin.com/sMg2cGSe
https://pastebin.com/Z8MPPgLr
https://pastebin.com/LyUNjkvn
https://pastebin.com/S3eeuU8M
https://pastebin.com/e1bYnW5j
https://pastebin.com/QYdf4Mv9
https://pastebin.com/mQJQHVzW
https://pastebin.com/andd0da6
https://pastebin.com/PeTHqrxq
https://pastebin.com/P6gk0Tj9
https://pastebin.com/QQ2dxGdL
https://pastebin.com/E2ibKkNu
https://pastebin.com/YC0sK7jB
https://pastebin.com/1EYYscyi
https://pastebin.com/FRXXxWwg
https://pastebin.com/ZXXi9xM1
https://pastebin.com/0izhXiFJ
https://pastebin.com/3sPJWA9h
https://pastebin.com/C9s6zMRc
https://pastebin.com/92djJXhJ
https://pastebin.com/rxLq7fK7
https://pastebin.com/1jjxq2y7
https://pastebin.com/RQuravmU
https://pastebin.com/0HC8tnCM
https://pastebin.com/qV828LM2
https://pastebin.com/KsTnZQKK
https://pastebin.com/0DGQvkf5
https://pastebin.com/ZpSpZ1ad
https://pastebin.com/RyCxRXXc
https://pastebin.com/FNT47tiG
https://pastebin.com/M9kRCjFZ
https://pastebin.com/5FYBqVba
https://pastebin.com/tc3AxKPP
https://pastebin.com/cmEzD2cm
https://pastebin.com/G8epzgNn
https://pastebin.com/DvkkCE48
https://pastebin.com/qQn5nr1T
https://pastebin.com/LdRyg3fJ
https://pastebin.com/bhMmk2QE
https://pastebin.com/Ezp4M2mU
https://pastebin.com/pgc1FurG
https://pastebin.com/Ct29GCzi
https://pastebin.com/X2SibK2k
https://pastebin.com/cPyP1sGv
https://pastebin.com/BpRi9nQ3
https://pastebin.com/PuEQk2D5
https://pastebin.com/LqQtd4xC
https://pastebin.com/0m9SGErQ
https://pastebin.com/2TjekbUJ
https://pastebin.com/LCfheMsR
https://pastebin.com/KBGaUPqA
https://pastebin.com/adQ498ic
https://pastebin.com/0wuucsZ0
https://pastebin.com/5p9vtftU
https://pastebin.com/NBdsXhQi
https://pastebin.com/N1rgsNYD
https://pastebin.com/pNyDCENQ
https://pastebin.com/9cDP15GL
https://pastebin.com/F2a621ab
https://pastebin.com/aJ9PzUyf
https://pastebin.com/P5UjJuY1
https://pastebin.com/Sn9J5rLr
https://pastebin.com/3rQRmumG
https://pastebin.com/QNSSbDRg
https://pastebin.com/csLrWKhY
https://pastebin.com/Ceg1c07i
https://pastebin.com/hwKtUzVf
https://pastebin.com/WzAyiC5N
https://pastebin.com/qDteic1q
https://pastebin.com/tfYq4WsV
https://pastebin.com/bRqVufy3
https://pastebin.com/93ex9FyT
https://pastebin.com/stpFZB0f
https://pastebin.com/GAm5Qri7
https://pastebin.com/a5xG0wd1
https://pastebin.com/2J1Hiqvm
https://pastebin.com/gh7CZTcv
https://pastebin.com/XLdTknfz
https://pastebin.com/CUjaXXKR
https://pastebin.com/RHVccDjS
https://pastebin.com/Fyc2a9PC
https://pastebin.com/Y7QzDaEQ
https://pastebin.com/30AHcs66
https://pastebin.com/76dUwnrz
https://pastebin.com/Eefce3y4
https://pastebin.com/rgUGwQR4
https://pastebin.com/b1wjhncJ
https://pastebin.com/ReNE2D36
https://pastebin.com/vyJXbMcD
https://pastebin.com/vYKvCKch
https://pastebin.com/XfHEyEgJ
https://pastebin.com/v8zRpCdK
https://pastebin.com/fFVAe7NL
https://pastebin.com/USryqJTr
https://pastebin.com/yAc9niyy
https://pastebin.com/nkJB8XRC
https://pastebin.com/PSqZGpwq
https://pastebin.com/ZD0VWb9t
https://pastebin.com/5YsLCMSB
https://pastebin.com/yXkvdiH1
https://pastebin.com/4YzAMWHC
https://pastebin.com/QaVh0Srp
https://pastebin.com/d9Yjsr9D
https://pastebin.com/4rKTisyH
https://pastebin.com/jGe97xbT
https://pastebin.com/KCFPzysq
https://pastebin.com/JXVdBeaz

收起阅读 »

云打包次数限制,除了账号次数限制,还有电脑限制 吃相也太难看了

云端打包发布常见问题

吃相也太难看了!
账号次数限制 ok 我承认我今天打包次数很多 但是 测试插件兼容性就是有问题要一直测啊
特意注册了一个新账号测试插件功能
结果又说本电脑打包太多次了,那就一开始就提示本电脑打包太多次了啊
测试插件有问题就是要调试很多次啊
我也不是恶意的浪费资源
真的很生气 操作半天还是不行
就是让花钱打包 一开始就说清楚啊

继续阅读 »

吃相也太难看了!
账号次数限制 ok 我承认我今天打包次数很多 但是 测试插件兼容性就是有问题要一直测啊
特意注册了一个新账号测试插件功能
结果又说本电脑打包太多次了,那就一开始就提示本电脑打包太多次了啊
测试插件有问题就是要调试很多次啊
我也不是恶意的浪费资源
真的很生气 操作半天还是不行
就是让花钱打包 一开始就说清楚啊

收起阅读 »

Uni-App iOS 上架全流程|Windows(Win7/10/11)免 Mac 制作 P12 证书 + 描述文件 + IPA 上传完整教程

ipa Appstore上传 iOS打包 Apple证书 iOS证书

前言
做 Uni-App 开发的团队大多以 Windows 电脑为主,传统 iOS 上架必须依赖 Mac 电脑,通过钥匙串生成 CSR、制作 P12 发布证书、创建 mobileprovision 描述文件,再用 Xcode/Transporter 上传 IPA,硬件成本高、多账号极易触发苹果 3.2 (f) 关联风控批量封号。
很多中小团队没有 Mac 设备,虚拟机隔离又存在底层设备指纹泄露、卡顿超时、隐性账号关联等致命缺陷;而iOSUploader完美解决痛点,全 Windows 兼容(Win7/8/10/11),仅 45.2MB 轻量化工具,
无需 Mac、无需虚拟机,一站式完成 Bundle ID 创建、P12 证书生成、描述文件制作、HBuilderX 云打包 IPA 分片上传、App Store 后台元数据管理,同时内置独立隔离环境,规避苹果多账号关联封号风险。

官网地址:https://iosuploader.xinxishehui.com/

核心优势:
全 Windows 兼容,最低支持 Win7 老旧办公电脑;
纯软件隔离,斩断设备 / 网络指纹,规避 3.2 (f) 批量封号;
全程不用 Apple ID 密码,仅 P8 密钥 API 授权,杜绝账号泄露;
一站式证书、Bundle ID、设备 UDID、描述文件管理;
直接上传 IPA 至 App Store Connect,替代 Xcode、Transporter;
批量管理多开发者账号,适配 UniApp、Flutter 跨平台项目。

**一、前期准备工作

  1. 基础环境**
    Windows 系统:Win7/Win8/Win10/Win11 32/64 位均可;
    下载 iOSUploader v2.1.3,大小 45.2MB,解压直接运行无需安装;
    有效苹果开发者付费账号(个人 / 企业账号,免费账号无法上架 App Store);
    Uni-App 项目(HBuilderX 开发完成,manifest.json 提前规划 Bundle ID);
    提前获取 App Store Connect API 三要素:Issuer ID、Key ID、P8 密钥文件(全程免账号密码登录)。
  2. 提前获取 P8 密钥(关键,免 Apple ID 登录)
    登录 App Store Connect → 用户和访问 → API 密钥;
    点击「+」新建密钥,命名自定义,权限选 App 管理员;
    生成后仅一次下载 AuthKey_xxx.p8 文件,妥善保存;
    复制页面上方 Issuer ID、列表内 Key ID,填入 iOSUploader 设置面板;
    优势:不用输入 Apple ID 与登录密码,多人协作不会泄露账号,大幅降低 3.2 (f) 违规关联风险。

二、Windows 端用 iOSUploader 创建 Bundle ID(应用唯一包名)
Bundle ID 是 UniApp iOS 应用唯一标识,证书、描述文件、打包必须保持完全一致,传统操作需登录苹果开发者网页,iOSUploader 内置可视化创建面板:
打开 iOSUploader,左侧菜单栏切换「Bundle ID 管理」;
点击「创建 Bundle」,填写名称、自定义包名(格式:com. 公司名。项目名,例:com.xxx.uniappshop);
按需勾选 App 权限服务:推送通知、Apple 登录、iCloud、支付、NFC、Game Center 等 UniApp 所需能力;
确认创建,工具自动同步至苹果开发者后台,列表可查看、管理所有 Bundle ID;
复制 Bundle ID,保存至 HBuilderX,后续打包统一填写。

三、Windows 无 Mac 生成 P12 发布证书(打包必备签名文件)
传统 Mac 流程:钥匙串生成 CSR 证书签名请求→开发者后台创建证书→导出 P12,Windows 无钥匙串无法操作,iOSUploader 内置证书生成引擎,一步导出.p12 文件:
步骤 1:进入证书管理面板
左侧菜单「证书管理」→「创建证书」,选择证书类型:
iOS App Development:真机测试、TestFlight 内测;
iOS Distribution(App Store):正式上架打包,本文上架选此项。
步骤 2:生成并导出 P12 文件
填写证书名称,设置 P12 加密密码(打包时必须填写,牢记);
工具自动生成 CSR 并提交苹果服务器,无需手动操作;
创建成功后,本地导出.p12证书文件,单独存放;
工具列表可加载、查看所有证书过期时间,支持批量管理多账号证书;
注意:单个开发者账号最多 3 个发布证书,旧证书无用可直接在工具内删除释放名额。

四、Windows 制作.mobileprovision 描述文件
描述文件绑定 Bundle ID+P12 证书,是 UniApp 云打包签名核心文件,分开发 / 发布两类:
iOSUploader 左侧「描述文件管理」→「创建描述文件」;
类型选择:App Store(发布上架);
选择上一步创建的 Bundle ID,勾选刚生成的 Distribution 发布证书;
自定义描述文件名称,确认生成;
下载.mobileprovision描述文件保存本地;
开发测试版额外勾选设备 UDID,可在工具「设备管理」批量录入测试机 UDID。

五、HBuilderX Uni-App 云打包 IPA(Windows 全程操作)

无需 Mac 本地编译,DCloud 云打包直接产出 IPA 安装包:
HBuilderX 打开 UniApp 项目,顶部菜单:发行 → 原生 App - 云打包 → iOS;
打包参数配置:
应用包名(Bundle ID):与 iOSUploader 创建的包名完全一致;
版本号、build 内部版本号按需填写;
证书选择「自有证书」,上传 Windows 导出的.p12文件,输入 P12 加密密码;
上传对应.mobileprovision描述文件;
勾选应用图标、启动图,确认打包;
等待云端编译完成,下载生成的.ipa安装包到 Windows 本地。

六、iOSUploader Windows 上传 IPA 至 App Store Connect(免 Mac 上传)
摒弃 Xcode、Transporter 仅 Mac 可用限制,单台 Win7 电脑即可分片上传 IPA,自带防关联隔离通道:
打开 iOSUploader「上传管理」,顶部设置填入提前准备的 Issuer ID、Key ID、P8 证书路径,保存 API 授权;
点击「选择 IPA」,选中 HBuilderX 下载的 ipa 文件;
工具自动分片上传(超大文件分块传输,断点续传),实时显示上传日志;
上传完成自动创建 App Store 构建版本,无需登录网页后台;
配套功能:
截图管理:批量上传各尺寸 iPhone/iPad 截图,支持多语言;
应用元数据编辑:简介、关键词、销售地区、价格、年龄分级;
审核消息中心:查看苹果官方留言、回复审核问题、管理附件;
批量管理多应用、多账号切换,每个窗口独立隔离环境,杜绝账号关联。

七、关键:规避苹果 3.2 (f) 多账号关联封号(iOSUploader 核心价值)
大量 UniApp 多项目团队踩坑:同一台电脑、同一网络操作多个苹果开发者账号,被苹果风控判定环境关联,触发 3.2 (f) 条款连锁封号,所有账号应用下架、收益冻结、申诉成功率极低。
传统方案短板对比
表格
方案 成本 风控风险 Windows 适配
多台 Mac 物理隔离 极高,设备折旧运维贵 共用网络仍存在关联风险 不支持
Windows 虚拟机 高,占用大量内存硬盘 底层设备标识泄露,批量封号频发 卡顿、上传超时
iOSUploader 纯软件隔离 极低,单台电脑管理上百账号 独立隔离环境,无硬件指纹交叉 Win7 全兼容
工具防关联机制
独立隔离上传通道,不携带本机硬件、网卡、系统缓存信息;
多开工具窗口,每个账号独立运行环境,数据完全隔离;
API P8 密钥授权,全程不登录 Apple ID,消除账号登录轨迹关联;
上传、证书、Bundle ID 操作无统一设备指纹留痕,规避风控追溯链路。

九、常见报错排查(Windows 免 Mac 流程高频问题)
云打包签名失败:P12 密码错误、Bundle ID 与描述文件不匹配、证书过期;
IPA 上传失败:P8 密钥失效(重新生成下载)、网络波动(工具支持分片续传);
账号关联标记:停止共用虚拟机 / 旧上传工具,切换 iOSUploader 独立隔离窗口操作;
Win7 运行异常:关闭系统防火墙兼容拦截,解压工具至纯英文路径。

结语
对于全部使用 Windows 开发 UniApp 的团队,iOSUploader 彻底打破「iOS 上架必须买 Mac」的行业固有认知,从证书制作、描述文件生成、云打包到 IPA 上传、应用后台管理实现全流程 Windows 闭环,最低老旧 Win7 电脑即可运行。同时依托软件级账号隔离能力,从根源规避苹果 3.2 (f) 关联封号风险,大幅降低硬件采购与账号资产损失成本,是 UniApp、Flutter 跨平台开发者无 Mac 上架 iOS 的刚需工具。
工具官网:https://iosuploader.xinxishehui.com/

继续阅读 »

前言
做 Uni-App 开发的团队大多以 Windows 电脑为主,传统 iOS 上架必须依赖 Mac 电脑,通过钥匙串生成 CSR、制作 P12 发布证书、创建 mobileprovision 描述文件,再用 Xcode/Transporter 上传 IPA,硬件成本高、多账号极易触发苹果 3.2 (f) 关联风控批量封号。
很多中小团队没有 Mac 设备,虚拟机隔离又存在底层设备指纹泄露、卡顿超时、隐性账号关联等致命缺陷;而iOSUploader完美解决痛点,全 Windows 兼容(Win7/8/10/11),仅 45.2MB 轻量化工具,
无需 Mac、无需虚拟机,一站式完成 Bundle ID 创建、P12 证书生成、描述文件制作、HBuilderX 云打包 IPA 分片上传、App Store 后台元数据管理,同时内置独立隔离环境,规避苹果多账号关联封号风险。

官网地址:https://iosuploader.xinxishehui.com/

核心优势:
全 Windows 兼容,最低支持 Win7 老旧办公电脑;
纯软件隔离,斩断设备 / 网络指纹,规避 3.2 (f) 批量封号;
全程不用 Apple ID 密码,仅 P8 密钥 API 授权,杜绝账号泄露;
一站式证书、Bundle ID、设备 UDID、描述文件管理;
直接上传 IPA 至 App Store Connect,替代 Xcode、Transporter;
批量管理多开发者账号,适配 UniApp、Flutter 跨平台项目。

**一、前期准备工作

  1. 基础环境**
    Windows 系统:Win7/Win8/Win10/Win11 32/64 位均可;
    下载 iOSUploader v2.1.3,大小 45.2MB,解压直接运行无需安装;
    有效苹果开发者付费账号(个人 / 企业账号,免费账号无法上架 App Store);
    Uni-App 项目(HBuilderX 开发完成,manifest.json 提前规划 Bundle ID);
    提前获取 App Store Connect API 三要素:Issuer ID、Key ID、P8 密钥文件(全程免账号密码登录)。
  2. 提前获取 P8 密钥(关键,免 Apple ID 登录)
    登录 App Store Connect → 用户和访问 → API 密钥;
    点击「+」新建密钥,命名自定义,权限选 App 管理员;
    生成后仅一次下载 AuthKey_xxx.p8 文件,妥善保存;
    复制页面上方 Issuer ID、列表内 Key ID,填入 iOSUploader 设置面板;
    优势:不用输入 Apple ID 与登录密码,多人协作不会泄露账号,大幅降低 3.2 (f) 违规关联风险。

二、Windows 端用 iOSUploader 创建 Bundle ID(应用唯一包名)
Bundle ID 是 UniApp iOS 应用唯一标识,证书、描述文件、打包必须保持完全一致,传统操作需登录苹果开发者网页,iOSUploader 内置可视化创建面板:
打开 iOSUploader,左侧菜单栏切换「Bundle ID 管理」;
点击「创建 Bundle」,填写名称、自定义包名(格式:com. 公司名。项目名,例:com.xxx.uniappshop);
按需勾选 App 权限服务:推送通知、Apple 登录、iCloud、支付、NFC、Game Center 等 UniApp 所需能力;
确认创建,工具自动同步至苹果开发者后台,列表可查看、管理所有 Bundle ID;
复制 Bundle ID,保存至 HBuilderX,后续打包统一填写。

三、Windows 无 Mac 生成 P12 发布证书(打包必备签名文件)
传统 Mac 流程:钥匙串生成 CSR 证书签名请求→开发者后台创建证书→导出 P12,Windows 无钥匙串无法操作,iOSUploader 内置证书生成引擎,一步导出.p12 文件:
步骤 1:进入证书管理面板
左侧菜单「证书管理」→「创建证书」,选择证书类型:
iOS App Development:真机测试、TestFlight 内测;
iOS Distribution(App Store):正式上架打包,本文上架选此项。
步骤 2:生成并导出 P12 文件
填写证书名称,设置 P12 加密密码(打包时必须填写,牢记);
工具自动生成 CSR 并提交苹果服务器,无需手动操作;
创建成功后,本地导出.p12证书文件,单独存放;
工具列表可加载、查看所有证书过期时间,支持批量管理多账号证书;
注意:单个开发者账号最多 3 个发布证书,旧证书无用可直接在工具内删除释放名额。

四、Windows 制作.mobileprovision 描述文件
描述文件绑定 Bundle ID+P12 证书,是 UniApp 云打包签名核心文件,分开发 / 发布两类:
iOSUploader 左侧「描述文件管理」→「创建描述文件」;
类型选择:App Store(发布上架);
选择上一步创建的 Bundle ID,勾选刚生成的 Distribution 发布证书;
自定义描述文件名称,确认生成;
下载.mobileprovision描述文件保存本地;
开发测试版额外勾选设备 UDID,可在工具「设备管理」批量录入测试机 UDID。

五、HBuilderX Uni-App 云打包 IPA(Windows 全程操作)

无需 Mac 本地编译,DCloud 云打包直接产出 IPA 安装包:
HBuilderX 打开 UniApp 项目,顶部菜单:发行 → 原生 App - 云打包 → iOS;
打包参数配置:
应用包名(Bundle ID):与 iOSUploader 创建的包名完全一致;
版本号、build 内部版本号按需填写;
证书选择「自有证书」,上传 Windows 导出的.p12文件,输入 P12 加密密码;
上传对应.mobileprovision描述文件;
勾选应用图标、启动图,确认打包;
等待云端编译完成,下载生成的.ipa安装包到 Windows 本地。

六、iOSUploader Windows 上传 IPA 至 App Store Connect(免 Mac 上传)
摒弃 Xcode、Transporter 仅 Mac 可用限制,单台 Win7 电脑即可分片上传 IPA,自带防关联隔离通道:
打开 iOSUploader「上传管理」,顶部设置填入提前准备的 Issuer ID、Key ID、P8 证书路径,保存 API 授权;
点击「选择 IPA」,选中 HBuilderX 下载的 ipa 文件;
工具自动分片上传(超大文件分块传输,断点续传),实时显示上传日志;
上传完成自动创建 App Store 构建版本,无需登录网页后台;
配套功能:
截图管理:批量上传各尺寸 iPhone/iPad 截图,支持多语言;
应用元数据编辑:简介、关键词、销售地区、价格、年龄分级;
审核消息中心:查看苹果官方留言、回复审核问题、管理附件;
批量管理多应用、多账号切换,每个窗口独立隔离环境,杜绝账号关联。

七、关键:规避苹果 3.2 (f) 多账号关联封号(iOSUploader 核心价值)
大量 UniApp 多项目团队踩坑:同一台电脑、同一网络操作多个苹果开发者账号,被苹果风控判定环境关联,触发 3.2 (f) 条款连锁封号,所有账号应用下架、收益冻结、申诉成功率极低。
传统方案短板对比
表格
方案 成本 风控风险 Windows 适配
多台 Mac 物理隔离 极高,设备折旧运维贵 共用网络仍存在关联风险 不支持
Windows 虚拟机 高,占用大量内存硬盘 底层设备标识泄露,批量封号频发 卡顿、上传超时
iOSUploader 纯软件隔离 极低,单台电脑管理上百账号 独立隔离环境,无硬件指纹交叉 Win7 全兼容
工具防关联机制
独立隔离上传通道,不携带本机硬件、网卡、系统缓存信息;
多开工具窗口,每个账号独立运行环境,数据完全隔离;
API P8 密钥授权,全程不登录 Apple ID,消除账号登录轨迹关联;
上传、证书、Bundle ID 操作无统一设备指纹留痕,规避风控追溯链路。

九、常见报错排查(Windows 免 Mac 流程高频问题)
云打包签名失败:P12 密码错误、Bundle ID 与描述文件不匹配、证书过期;
IPA 上传失败:P8 密钥失效(重新生成下载)、网络波动(工具支持分片续传);
账号关联标记:停止共用虚拟机 / 旧上传工具,切换 iOSUploader 独立隔离窗口操作;
Win7 运行异常:关闭系统防火墙兼容拦截,解压工具至纯英文路径。

结语
对于全部使用 Windows 开发 UniApp 的团队,iOSUploader 彻底打破「iOS 上架必须买 Mac」的行业固有认知,从证书制作、描述文件生成、云打包到 IPA 上传、应用后台管理实现全流程 Windows 闭环,最低老旧 Win7 电脑即可运行。同时依托软件级账号隔离能力,从根源规避苹果 3.2 (f) 关联封号风险,大幅降低硬件采购与账号资产损失成本,是 UniApp、Flutter 跨平台开发者无 Mac 上架 iOS 的刚需工具。
工具官网:https://iosuploader.xinxishehui.com/

收起阅读 »

1

1

1

1

1

1

2

2

2

1

1

1

uniCloud

uniCloud

背景和优势
20年前,restful接口开发开始流行,服务器编写接口,客户端调用接口,传输json。

现在,替代restful的新模式来了。

云对象,服务器编写API,客户端调用API,不再开发传输json的接口。思路更清晰、代码更精简。

比如服务端编写一个云对象todo,该对象有add、get、remove、update等方法。客户端的js则可以直接import这个todo云对象,直接调用add等方法。

服务器示例代码如下:

HBuilderX中在uniCloud/cloudfunctions目录新建云函数,选择类型为云对象,起名为todo。打开云对象入口index.obj.js,添加一个add方法。

// 云对象名:todo
module.exports = {
add(title, content) {
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...其他逻辑
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
复制代码
然后在客户端的js中,import这个todo对象,调用它的add方法

const todo = uniCloud.importObject('todo') //第一步导入云对象
async function addTodo () {
try {
const res = await todo.add('title demo', 'content demo') //导入云对象后就可以直接调用该对象的方法了,注意使用异步await
uni.showToast({
title: '创建成功'
})
} catch (e) {
// 符合uniCloud响应体规范 https://doc.dcloud.net.cn/uniCloud/cf-functions?id=resformat,自动抛出此错误
uni.showModal({
title: '创建失败',
content: e.errMsg,
showCancel: false
})
}
}
复制代码
可以看到云对象的代码非常清晰,代码行数也只有33行。

而同样的逻辑,使用传统的接口方式则需要更多代码,见下:

// 传统方式调用云函数-云函数代码
// 云函数名:todo
// 云函数入口index.js内容如下
'use strict';
exports.main = async (event, context) => {
const {
method,
params
} = event
switch(method) {
case 'add': {
let {
title,
content
} = params
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...省略其他逻辑
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
return {
errCode: 'METHOD_NOT_FOUND',
errMsg: Method[${method}] not found
}
};

// 传统方式调用云函数-客户端代码
async function addToDo () {
try {
const res = await uniCloud.callFunction({
name: 'todo',
data: {
method: 'add',
params: {
title: 'title demo',
content: 'content demo'
}
}
})
const {
errCode,
errMsg
} = res.result
if(errCode) {
uni.showModal({
title: '创建失败',
content: errMsg,
showCancel: false
})
return
}
uni.showToast({
title: '创建成功'
})
} catch (e) {
uni.showModal({
title: '创建失败',
content: e.message,
showCancel: false
})
}
}
复制代码
以上传统开发需要68行代码,对比云对象的33行代码,不但工作量大,而且逻辑也不如云对象清晰。

_注:以上例子仅用于方便初学者理解。实际开发中对于简单的数据库操作,使用clientDB在前端直接操作数据库是更简单、代码更少的方案,都不需要写云端代码。

总结下云对象带来的好处:

更清晰的逻辑
更精简的代码
更少的协作成本(以及矛盾~)
客户端调用时在ide里有完善的代码提示,方法参数均可提示。(传输json可没法在ide里提示)
默认支持uniCloud响应体规范,方便错误拦截和统一处理
快速上手
创建云对象
云对象,其实是对云函数的封装。和创建云函数一样,在uniCloud/cloudfunctions目录右键新建云函数,选择云对象类型,输入云对象名称创建云对象,此处以云对象todo为例,创建的云对象包含一个index.obj.js。

创建云对象

一个空的云对象内容如下

// cloudfunctions/todo/index.obj.js
module.exports = {

}
复制代码
默认云对象模板是不包含任何方法的,我们为此对象添加一个add方法作为示例。

// cloudfunctions/todo/index.obj.js
module.exports = {
add: function(title = '', content = '') {
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...其他逻辑,如操作todo数据表添加数据
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
复制代码
至此云对象todo已经有了一个可以访问的方法了。接下来看如何使用客户端调用此云对象内的方法

客户端调用
客户端通过uniCloud.importObject方法获取云对象的实例,并可以通过此实例调用云对象内的方法。用法如下

const todo = uniCloud.importObject('todo')
const res = await todo.add('title demo', 'content demo')
复制代码
通过代码块cco可以快捷的输入以下代码:

const todo = uniCloud.importObject('todo')
复制代码
实际业务中需要考虑错误捕获,调用方式有两种:

try catch
const todo = uniCloud.importObject('todo')
try {
const res = await todo.add('title demo', 'content demo') //导入云对象后就可以直接调用该对象的方法了,注意使用异步await
console.log(res)
} catch (e) {
console.log(e.errCode)
console.log(e.errMsg)
}
复制代码
then catch(promise写法)
const todo = uniCloud.importObject('todo')
todo.add('title demo', 'content demo').then(res => {
console.log(res)
}).catch(e => {
console.log(e.errCode)
console.log(e.errMsg)
})
复制代码
importObject参数说明

interface ImportObjectOptions {
/**

  • 是否移除自动展示的ui
    */
    customUI?: boolean;
    /**
  • loading界面配置
    */
    loadingOptions?: ImportObjectLoadingOptions;
    /**
  • 错误提示配置
    */
    errorOptions?: ImportObjectErrorOptions;
    /**
  • 使用安全网络的方法及安全网络类型
    */
    secretMethods?: Record<string, 'none' | 'request' | 'response' | 'both'>;
    /**
  • 转化云对象内未捕获的错误或客户端网络错误
    */
    parseSystemError?: (params: ParseSystemErrorParams) => Promise<ParsedSystemError> | ParsedSystemError;
    }
    复制代码
    云对象的API
    云对象作为云函数的一种,可以调用所有node的API和uniCloud的API。

uniCloud有众多API,另见:uniCloud的API清单

除上述API之外,云对象的this对象还有一批专用方法来获取当前请求的上下文信息。

与云函数入参时的context不同,云对象没有context。它通过this对象挂载的几个内置方法来获取上下文信息。请注意开发者避免在this上挂载同名方法。

获取客户端信息
HBuilderX 3.4.9起此接口可获取所有客户端getSystemInfo返回的客户端信息,完整字段列表参考:getSystemInfo

接口形式

this.getClientInfo()

示例:

module.exports = {
add: function() {
const clientInfo = this.getClientInfo()
// clientInfo = {
// clientIP,
// appId,
// deviceId,
// source,
// //... 其他getSystemInfoSync返回值
// }
}
}
复制代码
返回值

getClientInfo返回的信息,是在客户端的uni.getSystemInfo的基础之上,增加了一些额外的信息。

除了getSystemInfo返回字段外,还包含以下信息

属性名 类型 说明
clientIP string 客户端ip
userAgent string 客户端ua,注意非本地运行环境下客户端getSystemInfoSync也会获取ua参数并上传给云对象,但是云对象会从http请求头里面获取ua而不是clientInfo里面的ua
source string 调用来源,返回值见下。HBuilderX 3.5.1+
requestId string 请求id。HBuilderX 3.5.1+
scene string 场景值。客户端uni.getLaunchOptionsSync返回的scene参数,新增于HBuilderX 3.5.1
getClientInfo().source,返回云函数调用来源,它的值域为:

取值 说明
client uni-app客户端导入云对象调用
function 由其他云函数或云对象调用
http 云对象URL化后通过http访问调用 HBuilderX 3.5.2+
timing 定时任务调用云对象 HBuilderX 3.5.2+
server 云函数上传并运行
注意事项

客户端上报的信息在理论上存在被篡改可能,实际业务中应验证前端传来的数据的合法性
除了clientIP外,其他客户端信息只有使用uni-app客户端以云对象的方式调用才能获取
云对象与云函数内获取客户端platform稍有不同,云函数未拉齐vue2、vue3版本app平台的platform值,vue2为app-plus,vue3为app。云对象无论客户端是vue2还是vue3,在app平台获取的platform均为app。这一点在使用uni-id时需要特别注意,详情见:uni-id文档 preferedAppPlatform
获取云端信息
接口形式

this.getCloudInfo()

示例

继续阅读 »

背景和优势
20年前,restful接口开发开始流行,服务器编写接口,客户端调用接口,传输json。

现在,替代restful的新模式来了。

云对象,服务器编写API,客户端调用API,不再开发传输json的接口。思路更清晰、代码更精简。

比如服务端编写一个云对象todo,该对象有add、get、remove、update等方法。客户端的js则可以直接import这个todo云对象,直接调用add等方法。

服务器示例代码如下:

HBuilderX中在uniCloud/cloudfunctions目录新建云函数,选择类型为云对象,起名为todo。打开云对象入口index.obj.js,添加一个add方法。

// 云对象名:todo
module.exports = {
add(title, content) {
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...其他逻辑
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
复制代码
然后在客户端的js中,import这个todo对象,调用它的add方法

const todo = uniCloud.importObject('todo') //第一步导入云对象
async function addTodo () {
try {
const res = await todo.add('title demo', 'content demo') //导入云对象后就可以直接调用该对象的方法了,注意使用异步await
uni.showToast({
title: '创建成功'
})
} catch (e) {
// 符合uniCloud响应体规范 https://doc.dcloud.net.cn/uniCloud/cf-functions?id=resformat,自动抛出此错误
uni.showModal({
title: '创建失败',
content: e.errMsg,
showCancel: false
})
}
}
复制代码
可以看到云对象的代码非常清晰,代码行数也只有33行。

而同样的逻辑,使用传统的接口方式则需要更多代码,见下:

// 传统方式调用云函数-云函数代码
// 云函数名:todo
// 云函数入口index.js内容如下
'use strict';
exports.main = async (event, context) => {
const {
method,
params
} = event
switch(method) {
case 'add': {
let {
title,
content
} = params
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...省略其他逻辑
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
return {
errCode: 'METHOD_NOT_FOUND',
errMsg: Method[${method}] not found
}
};

// 传统方式调用云函数-客户端代码
async function addToDo () {
try {
const res = await uniCloud.callFunction({
name: 'todo',
data: {
method: 'add',
params: {
title: 'title demo',
content: 'content demo'
}
}
})
const {
errCode,
errMsg
} = res.result
if(errCode) {
uni.showModal({
title: '创建失败',
content: errMsg,
showCancel: false
})
return
}
uni.showToast({
title: '创建成功'
})
} catch (e) {
uni.showModal({
title: '创建失败',
content: e.message,
showCancel: false
})
}
}
复制代码
以上传统开发需要68行代码,对比云对象的33行代码,不但工作量大,而且逻辑也不如云对象清晰。

_注:以上例子仅用于方便初学者理解。实际开发中对于简单的数据库操作,使用clientDB在前端直接操作数据库是更简单、代码更少的方案,都不需要写云端代码。

总结下云对象带来的好处:

更清晰的逻辑
更精简的代码
更少的协作成本(以及矛盾~)
客户端调用时在ide里有完善的代码提示,方法参数均可提示。(传输json可没法在ide里提示)
默认支持uniCloud响应体规范,方便错误拦截和统一处理
快速上手
创建云对象
云对象,其实是对云函数的封装。和创建云函数一样,在uniCloud/cloudfunctions目录右键新建云函数,选择云对象类型,输入云对象名称创建云对象,此处以云对象todo为例,创建的云对象包含一个index.obj.js。

创建云对象

一个空的云对象内容如下

// cloudfunctions/todo/index.obj.js
module.exports = {

}
复制代码
默认云对象模板是不包含任何方法的,我们为此对象添加一个add方法作为示例。

// cloudfunctions/todo/index.obj.js
module.exports = {
add: function(title = '', content = '') {
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...其他逻辑,如操作todo数据表添加数据
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
复制代码
至此云对象todo已经有了一个可以访问的方法了。接下来看如何使用客户端调用此云对象内的方法

客户端调用
客户端通过uniCloud.importObject方法获取云对象的实例,并可以通过此实例调用云对象内的方法。用法如下

const todo = uniCloud.importObject('todo')
const res = await todo.add('title demo', 'content demo')
复制代码
通过代码块cco可以快捷的输入以下代码:

const todo = uniCloud.importObject('todo')
复制代码
实际业务中需要考虑错误捕获,调用方式有两种:

try catch
const todo = uniCloud.importObject('todo')
try {
const res = await todo.add('title demo', 'content demo') //导入云对象后就可以直接调用该对象的方法了,注意使用异步await
console.log(res)
} catch (e) {
console.log(e.errCode)
console.log(e.errMsg)
}
复制代码
then catch(promise写法)
const todo = uniCloud.importObject('todo')
todo.add('title demo', 'content demo').then(res => {
console.log(res)
}).catch(e => {
console.log(e.errCode)
console.log(e.errMsg)
})
复制代码
importObject参数说明

interface ImportObjectOptions {
/**

  • 是否移除自动展示的ui
    */
    customUI?: boolean;
    /**
  • loading界面配置
    */
    loadingOptions?: ImportObjectLoadingOptions;
    /**
  • 错误提示配置
    */
    errorOptions?: ImportObjectErrorOptions;
    /**
  • 使用安全网络的方法及安全网络类型
    */
    secretMethods?: Record<string, 'none' | 'request' | 'response' | 'both'>;
    /**
  • 转化云对象内未捕获的错误或客户端网络错误
    */
    parseSystemError?: (params: ParseSystemErrorParams) => Promise<ParsedSystemError> | ParsedSystemError;
    }
    复制代码
    云对象的API
    云对象作为云函数的一种,可以调用所有node的API和uniCloud的API。

uniCloud有众多API,另见:uniCloud的API清单

除上述API之外,云对象的this对象还有一批专用方法来获取当前请求的上下文信息。

与云函数入参时的context不同,云对象没有context。它通过this对象挂载的几个内置方法来获取上下文信息。请注意开发者避免在this上挂载同名方法。

获取客户端信息
HBuilderX 3.4.9起此接口可获取所有客户端getSystemInfo返回的客户端信息,完整字段列表参考:getSystemInfo

接口形式

this.getClientInfo()

示例:

module.exports = {
add: function() {
const clientInfo = this.getClientInfo()
// clientInfo = {
// clientIP,
// appId,
// deviceId,
// source,
// //... 其他getSystemInfoSync返回值
// }
}
}
复制代码
返回值

getClientInfo返回的信息,是在客户端的uni.getSystemInfo的基础之上,增加了一些额外的信息。

除了getSystemInfo返回字段外,还包含以下信息

属性名 类型 说明
clientIP string 客户端ip
userAgent string 客户端ua,注意非本地运行环境下客户端getSystemInfoSync也会获取ua参数并上传给云对象,但是云对象会从http请求头里面获取ua而不是clientInfo里面的ua
source string 调用来源,返回值见下。HBuilderX 3.5.1+
requestId string 请求id。HBuilderX 3.5.1+
scene string 场景值。客户端uni.getLaunchOptionsSync返回的scene参数,新增于HBuilderX 3.5.1
getClientInfo().source,返回云函数调用来源,它的值域为:

取值 说明
client uni-app客户端导入云对象调用
function 由其他云函数或云对象调用
http 云对象URL化后通过http访问调用 HBuilderX 3.5.2+
timing 定时任务调用云对象 HBuilderX 3.5.2+
server 云函数上传并运行
注意事项

客户端上报的信息在理论上存在被篡改可能,实际业务中应验证前端传来的数据的合法性
除了clientIP外,其他客户端信息只有使用uni-app客户端以云对象的方式调用才能获取
云对象与云函数内获取客户端platform稍有不同,云函数未拉齐vue2、vue3版本app平台的platform值,vue2为app-plus,vue3为app。云对象无论客户端是vue2还是vue3,在app平台获取的platform均为app。这一点在使用uni-id时需要特别注意,详情见:uni-id文档 preferedAppPlatform
获取云端信息
接口形式

this.getCloudInfo()

示例

收起阅读 »

2

2

2