PAYATHON 2026

iOS app 集成 Google Calendar 的许可与收费问题

支付小周

结论

在 iOS App 中接入 Google Calendar,通常不需要购买 Google Calendar API 年度许可证,也没有按请求量自动计费的订阅费。Google Calendar API 主要通过配额控制使用量。达到配额后,请求通常会受到限制,而不会自动产生超额账单。

接入时需要重点处理以下事项:

  • 遵守 Google API、OAuth 2.0 和用户数据政策。
  • 在 Google Cloud Console 中配置项目、OAuth 客户端和 consent screen。
  • 只申请实现功能所必需的 Calendar OAuth scopes。
  • App 面向公众发布并使用敏感或受限 scope 时,可能需要完成 Google OAuth 应用验证。
  • 提供隐私政策,说明日历数据的收集、使用、保存、共享和删除方式。
  • 符合 Apple App Store Review Guidelines。
  • 遵守所用 iOS SDK 及其依赖项的开源许可证。

Google 可能调整 scope 分类、验证流程和配额。正式上线前,应以 Google Cloud Console 和官方政策页面显示的最新信息为准。

许可和授权要求

1. Google Calendar API 本身

Google Calendar API 不采用购买传统软件许可证的授权方式,其使用受以下协议和政策约束:

应用访问用户的 Google Calendar 数据时,还必须遵守 Google API Services User Data Policy 中的 Limited Use 要求。取得的数据只能用于用户明确同意的功能,不能随意转售、用于广告画像或提供给无关第三方。

2. OAuth 授权

访问私人日历不能只使用 API key,必须通过 OAuth 2.0 获得用户授权。典型流程如下:

  1. 在 Google Cloud Console 创建项目。
  2. 启用 Google Calendar API。
  3. 配置 OAuth consent screen。
  4. 创建 iOS OAuth client。
  5. 配置 Bundle ID 和 URL scheme。
  6. 在 App 中完成 Google 登录或 OAuth 授权。
  7. 使用 access token 调用 Calendar API。
  8. token 失效后,通过 SDK 或安全的后端流程刷新授权。

不要在 iOS App 中嵌入 client secret。移动应用属于 public client,安装包中的任何秘密最终都可能被提取。

3. OAuth scope 应保持最小化

如果只需读取日历,就不应申请完整读写权限。例如:

https://www.googleapis.com/auth/calendar.readonly

如果只管理事件,可以根据实际功能考虑:

https://www.googleapis.com/auth/calendar.events

只有确实需要完整控制日历时,才申请:

https://www.googleapis.com/auth/calendar

scope 是否属于敏感或受限类别,以及需要完成哪种验证,应以最新的 OAuth 2.0 Scopes for Google APIs 和 Cloud Console 提示为准。

4. OAuth 应用验证

如果 App 面向 App Store 用户公开发布,并申请了敏感或受限 scope,通常需要提交 OAuth verification。Google 可能要求提供:

  • 已验证的开发者网站或域名。
  • 可公开访问的隐私政策。
  • 应用名称、Logo 和支持邮箱。
  • scope 用途说明。
  • 展示授权流程和实际功能的视频。
  • 数据保存、共享和删除方式的说明。
  • 针对受限 scope 的额外安全评估。

并非所有 Calendar scope 都会触发相同级别的审核。由于分类和验证要求可能变化,确定最终 scope 后,应以 consent screen 显示的验证状态为准。

处于 Testing 状态的 OAuth 应用通常只适合开发和小范围测试,还可能受到测试用户数量、授权有效期等限制,不应作为正式发布方案。

5. SDK 许可证

Google 的 iOS 客户端组件通常采用开源许可证,但不同 SDK、版本和第三方依赖可能适用不同条款。应检查代码仓库中的 LICENSE、NOTICE,以及通过 Swift Package Manager 或 CocoaPods 引入的依赖。

如果许可证要求保留版权或许可声明,可以统一展示在 App 设置中的“开源许可”页面。不能仅凭组件“由 Google 提供”,就认定它们采用相同的许可条款。

收费和计费方式

Google Calendar API

Google Calendar API 通常不按请求次数收费,也没有固定的年度 API subscription。它通过配额控制请求量,常见的配额维度包括:

  • 每个 Google Cloud 项目的请求配额。
  • 每分钟请求配额。
  • 每分钟、每用户请求配额。
  • 特定方法或写操作的使用限制。

超过配额后,一般会收到 403 或 429 等错误。此时需要退避重试或申请提高配额,并不会自动按超额请求收费。

不要在应用设计中写死具体额度,因为默认值可能随项目、API 和 Google 政策变化。应在 Google Cloud Console 的以下位置查看当前项目的实际额度:

APIs & Services → Enabled APIs & services → Google Calendar API → Quotas

官方说明见 Calendar API Usage Limits。

Google Cloud Billing

创建 Google Cloud 项目并启用 Calendar API,不代表一定会产生 Google Cloud 费用。Calendar API 本身通常没有请求单价,但相关服务可能收费,例如:

  • Cloud Run、Cloud Functions 或 App Engine 后端。
  • Cloud SQL、Firestore、Cloud Storage 等数据存储服务。
  • 日志、监控和网络流量。
  • 第三方身份认证、分析或通知服务。
  • OAuth 受限 scope 可能要求的第三方安全评估。

这些费用按各项服务自己的计价方式结算,可能取决于请求量、运行时间、存储量或月度账期,并不是统一的 Calendar API 年费。

Google Workspace 订阅

用户是否订阅 Google Workspace,与开发者调用 Calendar API 是否收费是两个不同的问题。

  • 普通 Google 账号也可以授权应用访问自己的日历。
  • 企业 Workspace 管理员可能限制第三方 OAuth 应用。
  • 某些企业功能取决于用户所在组织的 Workspace 套餐。
  • 用户拥有 Workspace 账号,不代表开发者会自动承担其订阅费。

Apple Developer Program

在 App Store 发布应用仍需有效的 Apple Developer Program 会员资格。这笔费用由 Apple 收取,与 Google Calendar API 无关。具体金额和续费周期应以 Apple Developer Program 当前页面为准。

调用示例

完成 OAuth 授权并取得 access token 后,可以直接调用 Calendar API。下面的示例读取用户主日历中的事件:

curl \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://www.googleapis.com/calendar/v3/calendars/primary/events?maxResults=10&singleEvents=true&orderBy=startTime"

创建事件的 REST 请求示例:

curl -X POST \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  "https://www.googleapis.com/calendar/v3/calendars/primary/events" \
  -d '{
    "summary": "项目讨论",
    "start": {
      "dateTime": "2026-09-01T10:00:00+08:00",
      "timeZone": "Asia/Shanghai"
    },
    "end": {
      "dateTime": "2026-09-01T11:00:00+08:00",
      "timeZone": "Asia/Shanghai"
    }
  }'

创建事件至少需要一个允许写入事件的 scope,例如:

https://www.googleapis.com/auth/calendar.events

iOS 端取得 access token 后,可以使用 URLSession 发起请求:

import Foundation

func loadCalendarEvents(accessToken: String) async throws -> Data {
    var components = URLComponents(
        string: "https://www.googleapis.com/calendar/v3/calendars/primary/events"
    )!

    components.queryItems = [
        URLQueryItem(name: "maxResults", value: "10"),
        URLQueryItem(name: "singleEvents", value: "true"),
        URLQueryItem(name: "orderBy", value: "startTime")
    ]

    var request = URLRequest(url: components.url!)
    request.setValue(
        "Bearer \(accessToken)",
        forHTTPHeaderField: "Authorization"
    )

    let (data, response) = try await URLSession.shared.data(for: request)

    guard let httpResponse = response as? HTTPURLResponse,
          (200...299).contains(httpResponse.statusCode) else {
        throw URLError(.badServerResponse)
    }

    return data
}

这段代码只展示 API 调用方式。实际项目应使用 Google 当前推荐的 iOS OAuth/Sign-In SDK 管理登录、授权状态和 token 刷新,不要手工长期保存明文 token。

配额和错误处理

遇到 429 Too Many Requests 或与配额有关的 403 错误时,应采用 exponential backoff。例如:

func retryDelay(attempt: Int) -> TimeInterval {
    let cappedAttempt = min(attempt, 6)
    let base = pow(2.0, Double(cappedAttempt))
    return base + Double.random(in: 0...1)
}

同时应避免以下做法:

  • 每次进入页面都重新同步全部事件。
  • 高频轮询 Calendar API。
  • 让多个并发任务重复请求同一日历。
  • 请求失败后立即无限重试。
  • 将多个用户的请求集中到同一个瞬时峰值。

增量同步、缓存、syncToken、批量控制和带随机抖动的退避策略,都可以减少配额消耗。

上线前检查

正式提交 App Store 前,至少应确认:

  • Google Calendar API 已在正确的 Cloud 项目中启用。
  • iOS OAuth client 的 Bundle ID 与发布版本一致。
  • OAuth consent screen 已切换到适合生产环境的状态。
  • 每个已申请的 scope 都有明确的功能用途。
  • OAuth verification 已完成,或者已经确认当前 scope 不需要验证。
  • 隐私政策准确披露 Calendar 数据的用途和删除方式。
  • 用户可以断开 Google 账号并撤销授权。
  • 日志、分析平台和崩溃报告不会记录 access token、refresh token 或日历内容。
  • 应用能够正确处理 401、403、429 和授权被撤销的情况。
  • 已检查 Google SDK 及全部依赖项的许可证声明。
  • 已在 Cloud Console 中设置配额告警或监控。如果使用收费型 Cloud 服务,还应配置预算告警。

收费状态应分别查看 Google Calendar API 文档、Cloud API 配额页面 和 Google Cloud Pricing。最终应以项目控制台显示的配额、账单配置和 Google 当前政策为准。

备注:内容仅供参考。