ARCore 中文文档 下载 App

Cloud Anchors 托管解析超时和失败排查

问题描述

Cloud Anchors 的 Host 或 Resolve 操作一直没有完成,或最终返回错误状态:

现象可能原因
一直处于 PENDING网络问题、Cloud 服务延迟
ERROR_INTERNALGoogle 内部错误,通常可重试
ERROR_NOT_AUTHORIZEDAPI Key 配置问题
ERROR_RATE_LIMITED频率超限
ERROR_RESOURCE_EXHAUSTED配额用完
TTL_EXPIRED锚点已过期
NOT_FOUNDanchorId 无效或被删除

排查流程

Cloud Anchors 操作失败
    ↓
第一步:网络检查
    ↓ OK
第二步:API Key 验证(Google Cloud Console)
    ↓ OK
第三步:确认 Cloud Anchors API 已启用
    ↓ OK
第四步:检查配额用量
    ↓ OK
第五步:检查 API Key 绑定的包名/Bundle ID
    ↓ OK
第六步:检查设备时间是否准确
    ↓ OK
第七步:重试(ERROR_INTERNAL 通常是暂时性的)
    ↓ OK但仍失败
第八步:在完全不同的网络和设备上测试

步骤一:网络检查

Cloud Anchors 需要稳定的互联网连接(建议 WiFi,移动网络在信号差时容易超时)。

// 在 Host / Resolve 之前检查网络
fun isNetworkAvailable(context: Context): Boolean {
    val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val networkInfo = connectivityManager.activeNetworkInfo
    return networkInfo != null && networkInfo.isConnected
}

中国国内的特殊情况

Cloud Anchors 在中国大陆可能不可用或极不稳定——Google Cloud 服务受网络环境限制。表现:

解决方案:检测到设备在中国时降级 Cloud Anchors 功能(只保留本地 Anchor),或提示用户需要境外网络。

步骤二:API Key 完整验证

API Key 是 Cloud Anchors 最常见的问题来源。以下是完整验证清单:

Android 端

1. GCP Console 中有这个 Key 吗?
   → 打开 console.cloud.google.com → APIs & Services → Credentials → 找你的 Key

2. Key 限制了哪些应用可以用?
   → 限制类型:Android apps → 包名和签名 SHA1 是否正确?
   → 用你的 APK 的实际签名 SHA1,不要用 debug.keystore 的 SHA1

3. Key 限制了哪些 API?
   → 确保 ARCore Cloud Anchor API 在白名单里
   → 不要把 Key 限制得太死(比如只允许某个 IP)

4. AndroidManifest 中的 Key 对吗?
   → <meta-data android:name="com.google.android.ar.API_KEY" android:value="你的Key">
   → 注意是 com.google.android.ar.API_KEY(Android 的),不是其他名字

iOS 端

1. GCP Console 中有这个 Key 吗?
   → 限制类型:iOS apps → Bundle ID 是否正确?

2. Info.plist 中的 Key 对吗?
   → <key>GARAPIKey</key><string>你的Key</string>
   → Key 是字符串值,直接写进去(注意引号)

3. 同时用了 ARCore iOS SDK + Cloud Anchors 吗?
   → 必须集成 GoogleARCore 这个 CocoaPods / Swift Package

跨平台共享时的 Key 注意

Android 和 iOS 的 Key 必须来自同一个 GCP 项目——Cloud Anchors 的 Host 和 Resolve 是跨设备的,两端必须共享同一个项目配额。

步骤三:Cloud Anchors API 启用

1. 打开 Google Cloud Console
2. APIs & Services → Library
3. 搜索 "ARCore Cloud Anchor API"
4. 确保 API 已 ENABLED(不是 DISABLED)
5. 如果是首次启用,可能需要等几十分钟生效

步骤四:配额检查

1. GCP Console → APIs & Services → ARCore Cloud Anchor API
2. 查看 Metrics 页面的 Host 和 Resolve 用量
3. 免费配额:每月 10,000 Host + 10,000 Resolve
4. 超出后 → ERROR_RESOURCE_EXHAUSTED
5. 可以升级配额或付费购买
// 捕获配额错误
cloudAnchorFuture.addListener({
    val state = cloudAnchorFuture.result?.cloudAnchorState
    if (state == CloudAnchorState.ERROR_RESOURCE_EXHAUSTED) {
        showQuotaExhaustedMessage()
        // 或者排队等待下个月配额重置
    }
}, mainHandler)

步骤五:设备时间校准

Cloud Anchors 的请求包含时间戳,Google 会验证时间的合理性。设备时间偏离网络时间太大时,Cloud Anchors 可能拒绝请求:

// 检查设备时间是否在合理范围
fun isDeviceTimeReasonable(): Boolean {
    val deviceTime = System.currentTimeMillis() / 1000
    val networkTime = NtpClient.getNetworkTime()  // 需要自己实现或用库
    return Math.abs(deviceTime - networkTime) < 60  // 允许 ±60 秒偏差
}

如果设备时间不准,提示用户"请检查手机的自动时间设置"。

步骤六:重试策略

Cloud Anchors 的错误大多是暂时性的——Google 云端偶发性波动或网络抖动。实现自动重试:

private const val MAX_RETRY = 3
private const val RETRY_DELAY_MS = 1000L

fun hostCloudAnchor(anchor: Anchor, retryCount: Int = 0) {
    val future = session.hostCloudAnchor(anchor)
    future.addListener({
        val state = future.result?.cloudAnchorState
        when {
            state == CloudAnchorState.SUCCESS -> {
                // 成功
                onHostSuccess(future.result!!.anchorId)
            }
            (state == CloudAnchorState.ERROR_INTERNAL ||
             state == CloudAnchorState.ERROR_NETWORK) && retryCount < MAX_RETRY -> {
                // 可重试错误,等一会再试
                handler.postDelayed({
                    hostCloudAnchor(anchor, retryCount + 1)
                }, RETRY_DELAY_MS * (retryCount + 1))  // 线性退避
            }
            else -> {
                // 不可重试错误,报告给用户
                onHostFailed(state)
            }
        }
    }, handler)
}

适合重试的错误

错误状态是否可重试原因
ERROR_INTERNAL✅Google 内部服务暂不可用
ERROR_NETWORK✅网络波动
ERROR_RATE_LIMITED⚠️可以延迟重试,但不要太频繁
ERROR_NOT_AUTHORIZED❌需要修复 API Key
ERROR_RESOURCE_EXHAUSTED❌等配额重置
TTL_EXPIRED❌锚点已永久过期
NOT_FOUND❌anchorId 无效

步骤七:极端情况

如果所有排查都做了还是失败:

  1. 在完全不同的网络上测试:换 WiFi / 换移动网络 / 换地区
  2. 在不同设备上测试:同一应用包在不同手机上测
  3. 换一个新的 GCP 项目:排除项目级配置问题
  4. 使用 Google 官方 Cloud Anchors Demo:确认是你的应用问题还是 Google 服务问题
  5. 等几小时再试:Google Cloud 偶发波动会影响所有用户

调试工具

ARCore Debug Overlay

session.configure(
    Session.Config(context).apply {
        setShowDiagnostics(true)
    }
)

Debug Overlay 会显示 Cloud Anchors 的托管/解析状态——在 Host 或 Resolve 时能实时看到进度和错误信息。

Google Cloud Console 日志

打开 GCP Console → Cloud Logging → 查看 Cloud Anchors API 的请求日志,可以看到 Google 返回的具体错误码。