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 APIs Terms of Service
- Google API Services User Data Policy
- OAuth 2.0 Policies
- Google Calendar API Terms of Service
应用访问用户的 Google Calendar 数据时,还必须遵守 Google API Services User Data Policy 中的 Limited Use 要求。取得的数据只能用于用户明确同意的功能,不能随意转售、用于广告画像或提供给无关第三方。
2. OAuth 授权
访问私人日历不能只使用 API key,必须通过 OAuth 2.0 获得用户授权。典型流程如下:
- 在 Google Cloud Console 创建项目。
- 启用 Google Calendar API。
- 配置 OAuth consent screen。
- 创建 iOS OAuth client。
- 配置 Bundle ID 和 URL scheme。
- 在 App 中完成 Google 登录或 OAuth 授权。
- 使用 access token 调用 Calendar API。
- 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 当前政策为准。
备注:内容仅供参考。
