怎么把 Python 写的 Flet 应用打包成 iOS App 并上架 App Store?

用 Python 写手机应用这件事,Flet 算是目前体验最顺的一条路------底层是 Flutter,你只写 Python。但发 iOS 版的时候有个绕不开的前提:flet build ipa 底层还是走 Flutter 那套,最终要调 Xcode,所以必须在 macOS 上构建,而且要装 Xcode 15 或更新的版本。Windows 上跑这条命令是不行的。

我的分工是:Python 代码在 Windows 上写,出包丢给 macOS 机器;证书、描述文件、IPA 上传这些用开心上架(AppUploader)在 Windows 上处理。下面把签名那部分怎么配讲清楚,这是 Flet 出 iOS 包时最容易卡住的地方。

先说结论:哪一步真绕不开 Mac

环节 我实际怎么做的
注册 Bundle ID、签发证书、生成描述文件 Windows 上做完
flet build ipa 要 macOS + Xcode 15 或更新版本
提交 App Store Windows 上传
装到 iPhone 测试 扫码注册 UDID,再扫码装

说明一下:我用的签证书工具本身在 macOS 上也能用(网页版不挑系统,桌面客户端有 macOS 版)。表里"不需要 Mac"是指这一步不再需要 Xcode、钥匙串访问或 Transporter。

第一步:定好 Bundle ID

Flet 的 iOS 包标识可以在 pyproject.toml 里配,也可以用 flet build ipa 的命令行参数传。定成反向域名,比如 com.yourcompany.appname。

后面注册的 Bundle ID 和描述文件绑定的 App ID 都要和它完全一致。

第二步:在 Windows 上签出证书和描述文件

注册 Bundle ID :开心上架的「Bundle ID」页面点「新建 Bundle ID」,Identifier 填上一步那个值。创建后改不了 。用到推送、相册这些能力的,在这个 Bundle ID 的「权限」页面勾上再保存。

签发证书 :「证书」页面点「新建证书」,上架一定要选发布签名证书 。这点值得强调------Flet 的官方文档专门提醒过,上架要用 distribution 证书签,用开发证书或者 ad hoc 签出来的包传上去会被判签名无效。绑定上面的 Bundle ID,填名称邮箱,设一个 .p12 保护密码,服务器不保存它,忘了只能吊销重签。

勾上「使用开心上架服务同步证书」的话,构建机上能直接下载同一张证书,不用拿 U 盘拷。

生成描述文件 :「描述文件」页面点「新建描述文件」,上架选 App Store 类型,内测选 Ad Hoc 并勾上测试设备,关联上面的 Bundle ID 和证书,提交后下载 .mobileprovision。

第三步:在 macOS 构建机上导入

bash 复制代码
security import dist.p12 -k ~/Library/Keychains/login.keychain-db -P "你的p12密码" -T /usr/bin/codesign

mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
cp AppStore.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/

第四步:配签名参数并构建

Flet 的签名配置有两种写法。一种写在 pyproject.toml 里:

toml 复制代码
[tool.flet.ios]
team_id = "你的TeamID"
signing_certificate = "Apple Distribution: Your Company (TEAMID)"
provisioning_profile = "你的描述文件名称"

另一种直接作为参数传给命令:

bash 复制代码
flet build ipa \
  --team <你的TeamID> \
  --ios-signing-certificate "Apple Distribution: Your Company (TEAMID)" \
  --ios-provisioning-profile "你的描述文件名称"

具体参数名在不同 Flet 版本里有过调整,以你装的那个版本 flet build ipa --help 输出的为准。

几个值从哪来:

  • Team ID 就是开发者账号那串 10 位字符,在开心上架的账号概览里能直接看到;
  • signing certificate 填证书的通用名称,也就是钥匙串里显示的那一整串;
  • provisioning profile 填描述文件的名称------你在开心上架创建时填的那个名字,不是文件名也不是 UUID。

Flet 社区里报过一批上传时报签名无效的问题,大部分最后查出来是这三个值有一个对不上,或者用错了证书类型。构建完先别急着传,下一步会讲怎么先自查。

第五步:把 IPA 传上去

拿到 IPA 之后我不直接传,先在开心上架的「文件&提交」页面把包打开看一眼------Bundle ID 对不对、用的是不是 App Store 类型的描述文件、证书是不是发布类型、有没有过期。上面说的那类签名问题,在这一步基本就能看出来,比传上去等 Apple 退回来快多了。

确认没问题再点「提交 App Store」,日志实时滚。

命令行版本,Runner 是 Windows 或 Linux 也能跑:

bash 复制代码
appuploader-cli upload -f build/ipa/app.ipa -u dev@example.com -p abcd-efgh-ijkl-mnop

-p 是 Apple 生成的 App 专用密码(xxxx-xxxx-xxxx-xxxx),不是 Apple ID 登录密码。也可以用 API 密钥:

bash 复制代码
appuploader-cli upload -f build/ipa/app.ipa --api-key <KeyID> --api-issuer <IssuerID> --private-key Auth_Key.p8

密钥方式只收 .ipa,且 App 要先在 App Store Connect 里建好。

第六步:发内测包

「设备」页面点「注册设备」,二维码发出去让人扫上报 UDID(一年 100 台,免费账号 3 台)。回描述文件那边点「重建」,生成一份包含这些设备的 Ad Hoc 描述文件。

把签名配置里的描述文件换成新的重新构建,然后在「文件&提交」页面生成二维码让人扫码装。

写在最后

Flet 让 Python 开发者不用学 Dart 也能出移动端应用,代价是 iOS 那次构建得借 macOS。但真正折腾人的从来不是那条命令,而是签名配置里那三个值------把它们的来源搞清楚,后面就是重复劳动了。

相关推荐
茶底世界之下4 小时前
类型擦除之后,Metal 滤镜组合为什么不能只执行一个 Filter?
ios·swift
省钱兄--zs4 小时前
北京24小时自助健身房系统软件开发实战:从架构设计到部署指南
java·数据仓库·spring boot·小程序·需求分析
传奇开心果编程6 小时前
【SwiftUI提高练中学】第8课 网络层架构:拦截器、重试、缓存与离线优先
学习·macos·ui·ios·swiftui
Lsetea7 小时前
OpenSSL verify报unhandled critical extension:error 34与关键扩展排查
运维·https·ssl证书·openssl·证书链
Ai-_Man7 小时前
您您这可以把Grok的多个会话比如说。左侧的多个会话一次性导出吗?不是单条会话里面的多次会对话。AI导出鸭
javascript·人工智能·ai·小程序·电脑
三少爷的鞋7 小时前
AI 时代,我们都将成为通才型开发者:只懂 Android,已经不够了
android
光影少年9 小时前
Taro 是如何解析入口配置 app.config.ts 和页面配置的?
微信小程序·小程序·typescript·reactjs·百度小程序·taro
Dovis(誓平步青云)11 小时前
家里设备越来越多,如何用一张空间地图控制灯光和温度![
android·java·前端·javascript·人工智能·电脑
晚风叙码12 小时前
MySQL 数据类型详解:从数值到字符串,一篇讲透
android·mysql·adb
传奇开心果编程13 小时前
【Compose Multiplatform 跨端开发学与练】第3课 布局与组件
android·windows·学习·ui·ios·kotlin·composer