Orange Cloud is dual-licensed:
- This repository: AGPL-3.0 + Commons Clause — free for
personal use and self-compiled builds (all features unlocked via the
OPENSOURCE_UNLOCKEDcompilation condition); no commercial use/resale; derivative distributions must stay open source, keep origin notices, and use their own name/icon (see TRADEMARK.md). - Official App Store build: proprietary license by the copyright holder, with a free tier and a paid Pro tier.
Every contribution requires signing the CLA (comment "I have read the CLA Document and I hereby sign the CLA" on your first PR). This grants the maintainer the right to ship your code in both the open-source and the App Store builds. PRs without a signed CLA cannot be merged — no exceptions, however small the change.
- Xcode 26+ (iOS 26 SDK). Open
apps/ios/Orange Cloud/Orange Cloud.xcodeproj. - OAuth client:
Core/Auth/OAuthConfig.swiftships with the official client ID. Under OAuth PKCE this is a public identifier, not a secret — but the official client and theo-c.docallback relay are not for third-party builds: create your own Cloudflare OAuth client and deploy your own callback relay (seeapps/web/), then replace the client ID and redirect URI inOAuthConfig.swift. - Full unlock: add
OPENSOURCE_UNLOCKEDtoSWIFT_ACTIVE_COMPILATION_CONDITIONSof the Orange Cloud target. Self-compiled builds then have every Pro feature enabled — this is intentional, not a hack. - Change your Bundle ID / App Group / signing team to your own.
Native Kotlin + Jetpack Compose in apps/android/
(min API 31, target/compile API 36).
- JDK 17 + Android SDK (
android-36). Openapps/android/in Android Studio, or use the bundled Gradle wrapper directly:./gradlew :app:assembleOssDebug. - Two product flavors:
play(Google Play, with Billing) andoss(self-compiled, no Billing,isProalways true — the equivalent of the iOSOPENSOURCE_UNLOCKEDbuild). - OAuth client: the
playflavor embeds the official client ID (a public PKCE identifier, same value as iOS). Theossflavor ships empty — set your own inapps/android/local.properties(OAUTH_CLIENT_ID=…) and deploy your own callback relay; the official client is not for third-party builds.
See apps/android/README.md for the full
build matrix and architecture.
- MVVM boundaries: Views never call the API directly — they bind to
@ObservableViewModels; ViewModels never ownURLSession— they call Services, which go throughCFAPIClient. - Tokens live in the Keychain only — never UserDefaults, never hardcoded.
- async/await everywhere; no completion handlers. Errors surface as
APIErrorand are caught in the ViewModel. - Data models are
Codablestructs withCodingKeysmapping snake_case fields. - Localization: source language is Simplified Chinese; new
user-facing strings must be added to the string catalogs (en,
zh-Hant, zh-HK, ja) in
Localizable.xcstrings— both the app's and the widget extension's if the string is used inShared/. InStringcontexts (notLocalizedStringKey), wrap withString(localized:).
本项目双许可:公开仓库为 AGPL-3.0 + Commons Clause——
自编译自用完全自由(OPENSOURCE_UNLOCKED 编译条件解锁全部功能)、禁止
商业使用与转售、二开分发必须保持开源并保留来源声明、且须更换名称与图标
(见 TRADEMARK.md);App Store 官方版为专有授权,提供
免费层 + Pro 付费层。
所有贡献必须先签署 CLA:在你的第一个 PR 里留言 "I have read the CLA Document and I hereby sign the CLA"。该协议授予 维护者把你的代码同时用于开源版与 App Store 专有版的权利。未签署的 PR 一律不合并。
- Xcode 26+,打开
apps/ios/Orange Cloud/Orange Cloud.xcodeproj。 - OAuth Client:
OAuthConfig.swift内置官方 Client ID——OAuth PKCE 下它是公开标识符而非机密,但官方 Client 与o-c.do回调中转不向第三方构建开放:请自建 Cloudflare OAuth Client 并部署自己的回调中转(见apps/web/),然后在OAuthConfig.swift中替换为你自己的 Client ID 与 redirect URI。 - 全功能解锁:向主 App target 的
SWIFT_ACTIVE_COMPILATION_CONDITIONS添加OPENSOURCE_UNLOCKED, 即可解锁全部 Pro 功能——这是设计意图,不是漏洞。 - Bundle ID / App Group / 签名团队请改为你自己的。
原生 Kotlin + Jetpack Compose,位于 apps/android/
(最低 API 31,目标 / 编译 API 36)。
- JDK 17 + Android SDK(
android-36)。用 Android Studio 打开apps/android/,或直接用内置的 Gradle Wrapper:./gradlew :app:assembleOssDebug。 - 两个产品风味:
play(Google Play,带 Billing)与oss(自编译、 无 Billing、isPro恒真——等价于 iOS 的OPENSOURCE_UNLOCKED构建)。 - OAuth Client:
play风味内置官方 Client ID(OAuth PKCE 下为 公开标识符,与 iOS 同值);oss风味默认空串,请在apps/android/local.properties填入自建 Client(OAUTH_CLIENT_ID=…) 并部署自己的回调中转——官方 Client 不向第三方构建开放。
完整构建矩阵与架构见 apps/android/README.md。
- MVVM 边界:View 不直接调 API,只绑定
@ObservableViewModel; ViewModel 不持有URLSession,只调 Service,Service 统一走CFAPIClient。 - Token 只进 Keychain——不写 UserDefaults,不硬编码。
- 全部 async/await,不用 completion handler;错误统一为
APIError,在 ViewModel 中捕获。 - 数据模型为
Codablestruct,snake_case 字段用CodingKeys映射。 - 本地化:源语言为简体中文;新增用户可见文案须同步写入
Localizable.xcstrings的四个目标语言(en / zh-Hant / zh-HK / ja),Shared/中用到的 key 主 App 与 Widget 两份 catalog 都要有;String上下文(非LocalizedStringKey)必须包String(localized:)。