# 101 - 从开放平台到受控生态:谷歌宣布 Android 开发者验证政策

发表于

Article Image

Photo by Franck on Unsplash

谷歌宣布从 2026 年 9 月起,将 Play 商店的开发者验证要求扩展到所有 Android 应用安装方式,这从根本上改变了该平台的开放分发模式。这项政策要求所有在 Google Play 之外分发应用的开发者必须向谷歌注册、提供政府身份证明并支付费用。该政策将首先在巴西、印度尼西亚、新加坡和泰国实施,2027 年扩展至全球。这代表着 Android 自诞生以来对其开放生态系统原则的最重大背离。

尽管谷歌强调实施该政策的主要原因是安全考量——来自互联网侧载源的恶意软件比 Google Play 上的应用多 50 倍以上,限制任意来源的应用侧载可以有效改善欺诈问题。但与苹果生态的开发者早已习惯类似政策不同,Android 生态的开发者对这一改变表达了强烈的抵触情绪。许多开发者表示,出于合理的隐私、政治或安全原因,不愿向谷歌提供身份文件。对于 F-Droid 等开源应用商店而言,这一政策更是生存危机——社区估计约 85% 的应用可能因签名密钥冲突等技术问题而无法适应新要求。

从调整 AOSP 公共分支的发布节奏(Android 核心开发将全部集中到内部分支进行,不再像过去那样部分内容在 AOSP 的公共分支实时开发和合并)、提高 AOSP 的授权门槛、强化 Play 商店的应用审核,到如今针对侧载应用的开发者验证,谷歌收紧 Android 政策的步伐已越走越远。这一方面体现了谷歌意图将 Android 平台打造成类似 iOS 的”围墙花园”模式,另一方面也反映出谷歌急需深化 Android 平台的商业价值,以应对 Chrome 可能被拆分、AI 对搜索业务产生持续冲击等不利因素。

或许,Android 与 iOS 之间最后的差异正在消失,这既是危机,但未尝不是转机。Android 的普及得益于其开放特性,在当下的情况下,或许又给了某个新平台、新生态提供了不错的发展时机。当然,对于商业机构而言,开源与闭源、开放与封闭往往都是实现更大经济价值的手段,它们会在这些策略间灵活切换以保证自身利益最大化。因此,即便之后出现了新的搅局者,未来还是会重现类似的循环。社会就是在这样的螺旋中不断发展的。

本期赞助

需要在 iPhone 上调试 HTTPS?

试试 Proxyman!这是一款顶级的 macOS 应用,只需点击几下,即可轻松捕获和调试 HTTP(s) 流量。支持 iOS设备和模拟器。

🚀 立即试用 →

原创

用 MainActor.assumeIsolated 解决旧 API 与 Swift 6 适配问题

尽管 Swift 提供严格并发检查已有一段时间,但许多苹果官方 API 仍未对此进行充分适配,这种情况可能还会持续相当长的时间。随着 Swift 6 的逐步普及,这个问题变得愈发突出:开发者一方面希望享受 Swift 编译器带来的并发安全保障,另一方面又对如何让代码满足编译要求感到困惑。本文将通过一个 NSTextAttachmentViewProvider 的实现案例,介绍 MainActor.assumeIsolated 在特定场景下的妙用。

近期推荐

何时使用 Actor?(When should you use an actor?)

在 Swift 的并发模型中,actor 作为一种新的引用类型,为“可变状态”的保护提供了安全保障,能有效避免数据竞争(data race)。因此,许多开发者在了解这一特性后,往往会对 actor 倾心不已。但正如 Matt Massicotte 在本文中所指出的,actor 并非没有代价。它带来了异步访问、Sendable 要求等设计限制,也并不能完全取代 GCD。在本文中,作者结合 Swift 的类型系统与并发模型,深入探讨了 actor 的适用场景、常见误区,并总结出一套清晰的判断标准,帮助我们在设计时作出更合理的选择。

如果你希望更深入地探讨这篇文章的内容,不妨参考 这个 Reddit 帖子,社区中有不少精彩的观点。


为什么 SwiftUI 中需要 ViewModel (SwiftUI is Stifling your App’s Maintainability and Testability)

与 UIKit 不同,苹果并没有为 SwiftUI 提供明确的架构范式,而 SwiftUI 的声明式语法和响应式数据流也打破了许多传统的设计假设。因此,在实际开发中,关于状态管理、逻辑组织以及是否应该使用 ViewModel,始终存在不少争议。在这篇文章中,Matteo Manferdini 针对“MVVM 过时论”和“Apple 不推荐 MVVM”的观点,提出了系统性的反驳。他不仅从软件工程原则(如封装、SRP、SOLID)出发分析了使用 ViewModel 的优势,还通过对实际代码的分析,指出忽视 ViewModel 带来的可测试性与可维护性问题。

我个人倾向于在实践中使用 ViewModel,但也不会为了“架构”而“架构”。在 SwiftUI 中,过度抽象反而可能带来样板代码和额外的状态管理成本。架构的选择,始终应该服务于项目的复杂度与可维护性目标。


macOS 文件大小的迷思 (How Large is That File?)

如果你的 macOS 应用中包含文件或文件夹大小显示功能,你可能已经发现:显示结果与 Finder 并不总是一致。这并不一定是你代码的问题,而是因为 Finder 和系统 API 所提供的信息本身就存在偏差,而且它们默认会忽略许多重要的文件内容部分。在本文中,Howard Oakley 从一个看似简单的问题出发——“一个文件到底有多大?”——带领读者回顾了 macOS 文件系统从 Classic Mac OS 到 APFS 的演变过程,并对这一看似简单却充满历史遗留与实现细节的问题进行了系统性的梳理。

Howard 指出,macOS 在计算文件大小时的逻辑仍然延续了 25 年前的架构思维,尤其是在处理 xattrs(扩展属性) 与 resource fork(资源分叉) 等结构时,展示结果缺乏一致性与透明度。在 APFS 和现代沙盒系统普及的今天,macOS 对“文件大小”的展示方式仍显得过于简化甚至误导性强,这对备份、权限审计和开发工作都可能带来困扰。


使用 GitHub Actions 自动发布二进制文件 (Automating Swift Binary Releases Using GitHub Actions)

在使用 GitHub 管理代码时,开发者有时不仅需要托管源代码,也希望同步提供可运行的二进制版本,甚至只发布二进制文件。这个流程其实可以完全依赖 GitHub 的 CI/CD 系统自动化完成。Tiago Henriques 以他的 SwiftDummyGen 项目为例,展示了如何通过 GitHub Actions 自动构建并发布 Swift 命令行工具的 macOS 二进制文件,为希望提升发布效率的 Swift 开发者提供了一个简洁实用的参考范式。


Swift 字符串插值的默认值 (Swift Default Value in String Interpolations)

可选值是 Swift 的一个强大特性,但在字符串插值时却带来了一些麻烦。以往当处理可选值时,要么使用 ?? 提供默认值(但必须匹配原类型),要么使用 String(describing:)(会显示 nil)。Swift 6.2 引入的新特性优雅地解决了这个问题:通过 default 参数,可以为任意类型的可选值提供统一的默认字符串。Keith Harrison 在本文中详细介绍了该功能的用法,并指出了当前的一个限制:LocalizedStringKey 尚不支持此特性。


macOS 的 Accessibility

与 iOS 相比,macOS 的多窗口机制为开发者在实现无障碍功能(Accessibility)时带来了额外挑战,尤其是对于第三方输入法。在本文中,zonble 分享了他为 macOS 输入法实现 VoiceOver 支持的完整过程:从解决焦点抢占导致选字窗无法显示的问题,到使用 NSAccessibility 通知机制手动控制 VoiceOver 的播报行为,最后深入系统中的 SQLite 数据库,获取字符的注音、部首和范例词信息。整篇文章融合了实践技巧与底层探索,不仅帮助开发者理解 macOS Accessibility 的实际工作方式,也揭示了苹果系统在处理输入法语音反馈方面的一些“黑盒子”设计。

作者通过逆向分析多个系统 SQLite 数据库,揭示了 macOS 内建注音输入法如何提供字符的语音描述与结构讲解。这不仅是实用技巧,也为 Accessibility 的深入实现提供了启发。

工具

OpenAttributeGraph 文档

SwiftUI 的核心运行机制背后,有一个至关重要但鲜为人知的组件:AttributeGraph。它负责追踪视图状态与数据依赖,是高效增量更新 UI 的关键引擎。然而,由于是私有实现,一直以来相关资料相当匮乏,深入理解它的机制对开发者而言极具挑战性。最近,OpenAttributeGraph 项目(隶属于 OpenSwiftUI 团队)发布了详尽的文档,对其 AttributeGraph 的开源实现进行了系统讲解。这让开发者不仅能更透彻地了解 SwiftUI 的状态依赖管理机制,也为希望参与 OpenSwiftUI 或优化 SwiftUI 状态更新机制的开发者提供了坚实基础。


Subprocess

Swift 官方发布了 Subprocess 0.1,这是一个全新的进程管理库,旨在替代老旧的 Process(NSTask)API。Subprocess 完全拥抱了 Swift 的现代特性:原生 async/await 支持、跨平台一致性(macOS、Linux、Windows)、类型安全以及灵活的 I/O 处理。无论是开发 CLI 工具、服务端应用,还是需要在 macOS App 中调用系统命令,Subprocess 都提供了更现代的解决方案。

Swift
// 简洁的 API 设计
let result = try await run(.name("ls"), output: .string(limit: 4096))
print(result.standardOutput ?? "")

目前 0.1 版本需要 Swift 6.1+,暂不支持 iOS 等移动平台。作为 Swift Foundation 项目的一部分,它代表了 Swift 生态系统基础设施现代化的重要一步。

每周精选 Swift 与 SwiftUI 精华!