如何混用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 上传完整教程
前言
做 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 跨平台项目。
**一、前期准备工作
- 基础环境**
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 密钥文件(全程免账号密码登录)。 - 提前获取 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 跨平台项目。
**一、前期准备工作
- 基础环境**
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 密钥文件(全程免账号密码登录)。 - 提前获取 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/
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()
示例
收起阅读 »




