字节笔记本

2026年2月23日

V2exOS:SwiftUI 跨平台 V2ex 客户端

V2exOS 是一个使用 SwiftUI 开发的 V2ex 社区客户端,支持 macOS、iOS 和 tvOS 三大平台。该项目采用纯 Swift 编写,充分利用了 SwiftUI 的跨平台特性,为 V2ex 用户提供了原生极致体验。

项目简介

V2exOS 由开发者 isaced 创建并维护,目前在 GitHub 上已获得 684 stars 和 70 forks。项目采用 MIT 许可证开源,代码质量高,是学习 SwiftUI 跨平台开发的优秀范例。

该项目的目标是为 V2ex 社区打造一个三平台原生体验的客户端,最低适配 macOS 12+ / iOS 16+ / tvOS 15+,充分利用系统和语言的新特性。

核心特性

  • 跨平台支持:同时支持 macOS、iOS 和 tvOS
  • Personal Access Token 授权登录:安全的身份验证机制
  • 主题列表浏览:查看 V2ex 各个节点的热门话题
  • 评论列表:阅读话题下的讨论内容
  • 通知列表:实时接收回复和提及通知
  • 深色模式:适配系统外观设置
  • 节点搜索/Google搜索:快速查找感兴趣的内容
  • 热门列表:发现社区热门话题
  • Proxy 代理支持:灵活的网络配置

技术栈

  • SwiftUI:Apple 原生 UI 框架,声明式语法
  • V2exAPI:项目作者封装的 V2ex Open API Swift 包
  • Kingfisher:网络图片加载和缓存库
  • KeychainAccess:Keychain 便捷访问,安全存储 Token
  • MarkdownUI:SwiftUI Markdown 渲染组件

代码示例

以下是项目中 TopicListCellView.swift 的核心代码,展示了如何使用 SwiftUI 构建话题列表单元格:

swift
import Kingfisher
import SwiftUI
import V2exAPI

struct TopicListCellView: View {
    @State var isMemberLoading = false
    @EnvironmentObject private var settingsConfig: SettingsConfig
    @Environment(\.colorScheme) var colorScheme
    let topic: V2Topic
    @State var member: V2Member?

    init(topic: V2Topic) {
        self.topic = topic
        self.isMemberLoading = topic.member == nil
    }

    var body: some View {
        HStack {
            let avatarUrl = (topic.member ?? member)?.avatarLarge
            KFImage.url(URL(string: avatarUrl ?? ""))
                .resizable()
                .fade(duration: 0.25)
                .scaledToFit()
                .background(.gray)
                .frame(width: 48, height: 48)
                .mask(RoundedRectangle(cornerRadius: 8))

            VStack(alignment: .leading, spacing: 6) {
                Text(topic.title ?? "")
                    .lineLimit(2)
                    .font(Font.system(size: settingsConfig.fontSize - 1))

                HStack {
                    if let username = topic.member?.username ?? topic.lastReplyBy {
                        UserName(username, isLink: false)
                        Text("•")
                    }
                    if let lastModified = topic.lastModified {
                        Text(Date(timeIntervalSince1970: TimeInterval(lastModified)).fromNow())
                    }
                }
                .foregroundColor(.gray)
            }

            if let replies = topic.replies {
                Spacer()
                Text(String(replies))
                    .foregroundColor(.white)
                    .padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
                    .background(RoundedRectangle(cornerRadius: 4).fill(.gray))
            }
        }
        .foregroundColor(.label)
        .task {
            if let name = topic.lastReplyBy {
                member = try? await v2ex.memberShow(username: name)
                isMemberLoading = member == nil
            }
        }
    }
}

安装指南

macOS 版本

V2exOS 的 macOS 版本已发布到 App Store,可通过以下方式获取:

  1. App Store 下载点击下载
  2. Release 页面:下载构建好的 .app
  3. 源码构建:克隆仓库后使用 Xcode 打开构建

iOS/tvOS 版本

可通过 TestFlight 参与最新版本测试:TestFlight 链接

源码构建

bash
# 克隆仓库
git clone https://github.com/isaced/V2exOS.git

# 使用 Xcode 打开
open V2exOS.xcodeproj

# 如果遇到 SPM 依赖拉取问题,可尝试:
xcodebuild -resolvePackageDependencies -scmProvider system

使用说明

登录

  1. 在 V2ex 网站登录账号
  2. 进入 设置 -> Tokens 页面
  3. 生成 Personal Access Token(建议设置较长有效期)
  4. 在 V2exOS 中填入 Token 即可

Token 会被安全存储在本地 Keychain 钥匙串中。

设置代理

如遇到数据加载问题,可能需要配置代理:

菜单:V2exOS -> Preferences(快捷键:Command + ,

项目结构

text
V2exOS/
├── V2exOS/              # macOS 主应用
│   ├── Views/           # SwiftUI 视图
│   │   ├── TopicList/   # 话题列表相关视图
│   │   ├── TopicDetail/ # 话题详情视图
│   │   └── ...
│   ├── User/            # 用户相关
│   └── Utils/           # 工具类
├── V2exOSiOS/           # iOS 版本
├── V2exOSTV/            # tvOS 版本
└── V2exAPI/             # API 封装(SPM 依赖)

开发计划

  • Personal Access Token 授权登录
  • 主题列表
  • 评论列表
  • 通知列表
  • 深色模式
  • 节点搜索/Google搜索
  • 热门列表
  • 收藏节点
  • 发表主题/评论(等待 API 支持)

相关链接

许可证

MIT License

分享: