ITPub博客

首页 > 移动开发 > IOS > 我独自发布了我的第一个iOS应用——App Store Connect比应用本身还难搞

我独自发布了我的第一个iOS应用——App Store Connect比应用本身还难搞

IOS 作者:ITPUB社群 时间:1970-01-01 08:33:46 0 删除 编辑

我刚刚发布了 SnapCal,一个我独自用大约两周时间构建的条形码卡路里追踪器:SwiftUI、iOS 17+、零第三方依赖、85 个单元测试。构建它还算顺利。把它发布出去教会了我一些任何教程都不会涉及的东西。

以下就是真正让我踩坑的清单——五个陷阱,附带代码和命令。

1. 那个让我的应用看起来像是坏了的 404

SnapCal 扫描条形码,向 Open Food Facts 查询相关信息,然后让你记录它。我的 HTTP 层是标准形态:

private
static
func
validateResponse
(
_
response
:
URLResponse
)
throws
{
guard
let
httpResponse
=
response
as?
HTTPURLResponse
else
{
throw
APIError
.
invalidResponse
}
guard
(
200
...
299
)
.
contains
(
httpResponse
.
statusCode
)
else
{
throw
APIError
.
httpError
(
statusCode
:
httpResponse
.
statusCode
)
}
}

而 APIError.httpError 被渲染为 "Server error (404)"。

事情是这样的:对于任何格式正确但不在数据库中的条形码,Open Food Facts 会返回 HTTP 404 以及 {"status":0,"status_verbose":"product not found"}。这不是失败——这是你会得到的最常见的回答。覆盖率因国家而严重不均:

| 地区 | OFF 中的产品数 | 有卡路里数据(100 个样本) |
| --- | --- | --- |
| 全球 | 4,759,550 | — |
| 法国 | 1,268,282 | 92 |
| 美国 | 972,695 | 90 |
| 日本 | 44,641 | — |
| 中国 | 1,683 | 51 |

因此,对于随机一个包装,预期结果就是“无数据”,而我的应用却用红色的 "Server error (404)" 来迎接用户。一位测试者告诉我:“有些条形码能用,有些则提示出了点问题——你的服务器逻辑坏了。”他说得对,但不是他以为的那种对:API(应用程序编程接口) 没问题,是我的错误分类错了。

修复方法就是在验证之前提前返回一次:

let
(
data
,
response
)
=
try
await
withRetry
{
try
await
session
.
data
(
for
:
request
(
for
:
url
))
}
// OFF returns 404 for "well-formed barcode, not in the database" — that's
// "nothing found", not "something is wrong". Return nil so the UI can offer
// manual entry instead of a scary server error.
if
let
httpResponse
=
response
as?
HTTPURLResponse
,
httpResponse
.
statusCode
==
404
{
return
nil
}
try
validateResponse
(
response
)

而在视图中,“未找到”有了自己的状态,并提供了继续前进的方式:

if
let
food
=
await
store
.
searchByBarcode
(
barcode
)
{
scannedFood
=
food
}
else
if
store
.
errorMessage
==
nil
{
// nil meaning: no error, just no data
showNotFoundAlert
=
true
// "Product not found" + [Add Manually]
}

然后我又向前迈了一步:当你输入数据库中不存在的食物时,SnapCal 会将其以该条形码为键存储在自己的字典中(userFoodsByBarcode,与 API 缓存分开保存,因此永远不会被清除)。再次扫描同一产品时,它可以立即离线解析。

要点:"未找到"是一种状态,而不是错误。如果你的空状态被伪装成失败,用户会认为你的应用坏了——即使他们搞错了原因,他们对体验的判断也是对的。

2. 新开发者账号会被要求交作业(指南 2.1)

提交 1.0 后的第二天早上,我收到了"需要提供信息——指南 2.1"。没有 bug,应用本身也没有被拒绝。Apple 要求提供:

  • 在物理设备上运行最新操作系统的屏幕录制,从应用启动开始

  • 用途和目标受众

  • 设置说明/演示凭据

  • 应用连接的所有外部服务

  • 地区差异

  • 任何受监管或第三方许可的内容

如果你的应用有账号、UGC 或付费内容,录制必须展示这些流程——包括账号删除,这是一项硬性要求。

我会做的不同之处:在提交之前就录制好那个视频。我的视频是在 iPhone 15 Pro 上录制的 3 分钟内容,而这是事后唯一真正需要花时间制作的东西。其他都是文字说明:"没有账号、没有登录、没有 UGC、没有 IAP,因此这些流程不存在;唯一的外部服务是 Open Food Facts;营养数据采用 ODbL v1.0。"

在 App Review 对话中回复,并将相同的文本粘贴到 App Review Information → Notes——Apple 要求两者都提供,而且备注会延续到未来的提交中。2.1 回复不需要新的构建版本;你只需重新提交即可。

3. "已批准"不等于"已上线",而我的检查在骗我

我发布了 1.0,然后……什么都没出现。我的检查是最显而易见的那种:

curl
-s
"https://itunes.apple.com/lookup?id=6812662105&country=us"
# {"resultCount":0,"results":[]}

零。持续了好几个小时。但换一个查询参数:

curl
-s
"https://itunes.apple.com/lookup?bundleId=tech.wayknow.snapcal&country=us"
# {"resultCount":1, ...  "trackName":"SnapCal: Barcode Calorie Log", "price":0.0}

找到了。id= 形式一直返回 0,而 bundleId= 返回了已上线的应用。我无法告诉你原因——不同的索引、不同的缓存生命周期——但教训很实际:当两种方式询问同一个问题却给出不同答案时,不要相信那个告诉你你所害怕的结果的方式。

同一小时的第二个教训:我通过抓取商店页面来“验证”它。

https://apps.apple.com/us/app/snapcal-barcode-calorie-log/id6812662105  → HTTP 200 ✅

那不是应用页面。我的 IP 定位到一个未分发该应用的店面,而 Apple 没有返回 404,而是提供了该店面的 Today 首页。商店页面返回 HTTP 200 并不能说明什么——检查标题,或按店面检查:

for
c
in
us gb de cn jp
;
do
printf
"%s: "
"
$c
"
curl
-s
"https://itunes.apple.com/lookup?bundleId=tech.wayknow.snapcal&country=
$c
"
\
|
grep
-o
'"resultCount":[0-9]*'
done

## 4. 27 个国家缺失,却没有任何警告

正是这个循环发现了真正的问题:

us
:
1   gb: 1   jp: 1   ca: 1   au: 1   sg: 1   hk: 1   tw: 1   kr: 1   br: 1   mx: 1
de
:
0   fr: 0   it: 0   es: 0   nl: 0   pl: 0   se: 0   ie: 0   at: 0   be: 0

每个非欧盟店面:在线。每个欧盟店面:消失。这不是传播延迟,这是一条规则。

原因是我在 App Store Connect 中滚动过去的一个横幅,关于欧盟《数字服务法》:Apple 必须验证并显示在欧盟分发的应用的交易者联系信息,而未声明交易者状态的应用不会在那里分发。

声明位于 Business → Agreements → Compliance → Digital Services Act。两个选择:

  • “这是一个交易者账户”——你输入地址、电话和电子邮件,它们会在欧盟的 App Store 产品页面上公开,你上传证明你的企业名称和地址的文件,并通过 2FA 验证电子邮件和电话。

  • “这不是一个交易者账户”——没有联系信息,点击 Done,你就完成了。

SnapCal 1.0 是免费的,没有广告也没有应用内购买,所以“不是交易者”是诚实的答案,而且这是可逆的。但一旦你销售任何东西——即使是一次性解锁——你就是交易者,你的地址会在 27 个国家公开。值得在变现之前决定,而不是之后。

店面在声明后一天内恢复,而且是自行恢复的——没有重新提交,没有新构建。(中国大陆仍为 0,但那是另一条规则:在中国分发的应用需要 ICP 备案。)

## 5. 提交日的两个陷阱

待处理的协议会静默阻止每次提交。Apple 更新了开发者计划许可协议。Business 页面上有一个关于它的横幅,在账户持有人审阅并接受之前,你无法提交新版本。版本页面上没有错误——提交就是不可用。修复:Business → Agreements → “Free Apps”行 → Review and Accept Terms。

Xcode Organizer 看不到你的归档文件。我用以下命令构建了 1.0.1:

xcodebuild archive
-project
SnapCal.xcodeproj
-scheme
SnapCal
\
-destination
'generic/platform=iOS'
-archivePath
build/SnapCal.xcarchive

Organizer 只会列出 ~/Library/Developer/Xcode/Archives/ 中的归档文件。所以当我打开 Distribute App → Upload 时,唯一可选的归档是旧的 1.0 构建,Apple 拒绝了它:

This bundle is invalid. The value for key CFBundleShortVersionString [1.0.0]
must contain a higher version than that of the previously approved version [1.0.0]  (90062)
Invalid Pre-Release Train. The train version '1.0.0' is closed for new build submissions  (90186)

将归档文件复制到 Organizer 监视的文件夹中,或者直接归档到默认位置。并且在点击 Upload 之前,始终确认 Organizer 显示的版本/构建号。

我想告诉过去的自己

  • 将 404 视为数据,而非失败——并为“未找到”提供真正的 UI。

  • 在提交前录制 App Review 视频;新账户会被要求提供。

  • 使用 bundleId 验证启动,并按 storefront 逐一检查——永远不要信任一次 curl。

  • 在发布前声明 DSA 交易者身份;“非交易者”是可逆的,“未声明”会让你失去欧盟市场。

  • 接受待处理的协议,并仔细检查你正在上传的是哪个归档文件。

这些都不在应用中。但所有这些都决定了是否有人能安装它。

SnapCal 是免费的:条码扫描、无广告、无账户,所有数据都保留在你的设备上。1.0.1(Quick Add 中最近记录的食物、一键删除、更好的“不在数据库中”处理)正在审核中。如果你想挑毛病,我随时在——App Store 链接在这里。



转载声明:本文为转载整理,原文版权归原作者及原站点所有。

原文来源:DEV.to

原创地址:https://dev.to/wayknow123/i-shipped-my-first-ios-app-solo-app-store-connect-was-harder-than-the-app-3cnk

原文作者:wayknow;如有侵权,请联系管理员删除。

下一篇: 聚焦SIG Apps
请登录后发表评论 登录
全部评论

注册时间:2022-11-21

  • 博文量
    1090
  • 访问量
    547019