Avalonia 是 .NET 生态里跨平台 UI 的另一条路,和 MAUI 走的不是一套渲染思路——它自己画界面,所以在各平台上长得一模一样。iOS 这边它靠的是 .NET 的 iOS 工作负载,工程结构上会有一个单独的
.iOS 头项目(head project),最终由它产出 IPA。
因为底层用的是 .NET iOS SDK,
编译签名这一步还是要 Apple 的工具链:要么在 macOS 上直接
dotnet publish,要么在 Windows 上通过 Visual Studio 的 Pair to Mac 转交,要么丢给 macOS CI。这步省不掉。但证书、描述文件、上传这些我用开心上架(AppUploader)在 Windows 上处理,没为了签个名去开钥匙串。
| 环节 | 我实际怎么做的 |
|---|---|
| 注册 Bundle ID、签发证书、生成描述文件 | Windows 上做完 |
| 写代码、跑桌面端调试 | Windows |
| 编译签名成 IPA | 要 macOS——Pair to Mac 或 macOS CI |
| 提交 App Store | Windows 上传 |
| 装到 iPhone 测试 | 扫码注册 UDID,再扫码装 |
说明一下:我用的签证书工具本身在 macOS 上也能用(网页版不挑系统,桌面客户端有 macOS 版)。表里"不需要 Mac"是指这一步不再需要 Xcode、钥匙串访问或 Transporter。
Avalonia 模板生成的解决方案里会有个
YourApp.iOS 项目,iOS 的包标识写在它的
Info.plist 的
CFBundleIdentifier 里,也可以用
.csproj 的
ApplicationId 属性覆盖。
定成反向域名,比如
com.yourcompany.appname。顺便把
CFBundleShortVersionString(版本号)和
CFBundleVersion(build number)也确认一下——build number 每次上传都得比上次大,忘了改会直接被顶回来。
用到相机、相册、定位的话,对应的
NS*UsageDescription 也要在这份
Info.plist 里写全,缺了上传阶段会被打回。
注册 Bundle ID:开心上架的「Bundle ID」页面点「新建 Bundle ID」,Identifier 填上一步那个值。 创建后改不了。要用推送、App Groups 这些能力的,在这个 Bundle ID 的「权限」页面勾上再保存。
签发证书:「证书」页面点「新建证书」,上架选发布签名证书(对应 Apple Distribution),真机调试选开发签名证书(Apple Development)。绑定上面的 Bundle ID,填名称邮箱,设一个
.p12 保护密码——导入构建机钥匙串时要输,服务器不保存它。

勾上「使用开心上架服务同步证书」的话,构建机和团队成员都能下同一张证书,不用互相发文件。
生成描述文件:「描述文件」页面点「新建描述文件」,上架选 App Store 类型,内测选 Ad Hoc 并勾上测试设备,关联上面的 Bundle ID 和证书,提交后下载
.mobileprovision。

私钥和 CSR 都在本机生成后封进
.p12,不用在 Mac 上走一遍申请证书的流程。
不管是 Pair to Mac 连的那台还是 CI Runner,都是这两件事:
1security import dist.p12 -k ~/Library/Keychains/login.keychain-db -P "你的p12密码" -T /usr/bin/codesign23mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles4cp AppStore.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/
Visual Studio 在 Windows 上配好 Pair to Mac 之后,iOS 签名相关的下拉框读的就是这台 Mac 的钥匙串和描述文件目录。下拉框空的话先确认 Mac 上开了远程登录、装了对应版本的 Xcode——这基本都是环境问题,跟证书无关。
在
.iOS 项目的
.csproj 里指定手动签名用的证书和描述文件:
1<PropertyGroup Condition="'$(Configuration)'=='Release'">2 <CodesignKey>Apple Distribution: Your Company (TEAMID)</CodesignKey>3 <CodesignProvision>你的描述文件名称</CodesignProvision>4 <ArchiveOnBuild>true</ArchiveOnBuild>5 <RuntimeIdentifier>ios-arm64</RuntimeIdentifier>6</PropertyGroup>
然后:
1dotnet publish YourApp.iOS/YourApp.iOS.csproj -f net9.0-ios -c Release
(目标框架名按你实际用的 .NET 版本替换。)
这两个属性我在别的 .NET 项目上也踩过同样的坑,说一下:
CodesignKey 填证书的通用名称,就是钥匙串里显示的那一整串。报找不到匹配项的话,通常是
.p12 没导进钥匙串,或者导进去的是不含私钥的
.cer;CodesignProvision 填描述文件的
名称——你在开心上架创建时填的那个名字,不是文件名,也不是 UUID。产物是个
.ipa,在
bin/Release/<tfm>/ios-arm64/publish/ 下面。
到这一步不需要 Mac 了。我一般先在开心上架的「文件&提交」页面把包打开看一眼签名信息,确认了再点「提交 App Store」,日志实时滚。
命令行版本,Windows/Linux 的 Runner 也能跑:
1appuploader-cli upload -f YourApp.ipa -u dev@example.com -p abcd-efgh-ijkl-mnop
-p 是 Apple 生成的 App 专用密码(
xxxx-xxxx-xxxx-xxxx),不是登录密码。团队用 API 密钥更合适:
1appuploader-cli upload -f YourApp.ipa --api-key <KeyID> --api-issuer <IssuerID> --private-key Auth_Key.p8
密钥方式只收
.ipa,且 App 要先在 App Store Connect 里建好。
「设备」页面点「注册设备」,二维码发出去让人扫上报 UDID(一年 100 台,免费账号 3 台)。回描述文件那边点「重建」,生成一份包含这些设备的 Ad Hoc 描述文件。
把
CodesignProvision 换成这份描述文件重新 publish,然后在「文件&提交」页面生成二维码让人扫码装。
Avalonia 的 iOS 头项目本质上就是个 .NET iOS 应用,签名那套和别的 .NET 项目是通的——搞明白
CodesignKey 和
CodesignProvision 分别要填什么,剩下就是重复劳动。那台 Mac 配好之后基本不用再登录。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70044672/viewspace-3181187/ ,如需转载,请注明出处,否则将追究法律责任。