版权声明
本文内容均为搬运,目的只为更方便的学习Telegram编码思维。
本章内容将继续介绍基础模块内容
日志记录(Logging)
该模块TelegramCore
提供了一个简单的日志记录实现。
public final class Logger {
private let queue = Queue(name: "org.telegram.Telegram.log", qos: .utility)
// `false` in AppStore build
public var logToFile: Bool
// `false` in AppStore build
public var logToConsole: Bool
// `true` in AppStore build
public var redactSensitiveData: Bool
public static var shared: Logger
public func log(_ tag: String, _ what: @autoclosure () -> String)
}
// for other modules
Logger.shared.log("Keychain", "couldn't get \(key) — not current")
如果开关打开,它支持在控制台打印和写入文件。用于文件写入的queue在非主线程进行。redactSensitiveData
是另一个开关决定,是否在日志消息中包括敏感数据(例如具体的消息内容)。
if Logger.shared.redactSensitiveData {
messageText = "[[redacted]]"
} else {
messageText = message.text
}
在公开发布的版本中,仍然可以通过上面介绍的应用内调试控制器来更改设置。
对于不依赖TelegramCore
的模块,项目将通过Network.swift当中设置桥函数registeredLoggingFunctions,重定向其他模块(MtProtoKit,Postbox,和TelegramApi等)的记录/打印配置。
这不是一个甚至都不支持日志记录级别的理想框架。还有许多模块根本不进行日志记录,或仅通过Print/NSLog进行日志记录。在我看来,在未来或许会进一步清理。
崩溃报告
Telegram不使用第三方SDK以此来防止用户数据泄漏,这是合理的。令我感到惊讶的是,该项目没有任何内置的崩溃报告模块,甚至没有本地的崩溃报告模块。在查看提交历史之后,它确实集成了Hockey SDK,然后于今年1月通过提交bdc0bb2
将其删除。工程师大概可以依赖AppStore的崩溃报告来检查稳定性问题。
Hockey SDK已被Microsoft淘汰,转而支持App Center。Telegram-iOS使用App Center API来检查更新。没有与SDK集成。
磁盘存储
为了支持main app
、watch app
、intents app extension
之间的数据共享,该项目将大多数数据存储在名为telegram-data
的组容器文件夹中。一些旧组件仍在使用Documents文件夹。以下是telegram-data
典型的布局:
telegram-data/
|-- .tempkey // the key for sqlcipher
|-- account-0123456789/ // data for account 0123456789
| |-- network-stats/ // for `MTNetworkUsageManagerImpl`
| |-- notificationsKey
| `-- postbox/
| |-- db/
| `-- media/ // media cache
| |-- cache/
| |-- short-cache/
|-- accounts-metadata/ // for `AccountManager`
| |-- atomic-state/
| |-- db/
| |-- guard_db/
| |-- media/
| `-- spotlight/
|-- accounts-shared-data/
|-- lockState.json
|-- logs/ // log files
|-- notificationsPresentationData.json
|-- temp/
| `-- app/
|-- widget-data/
`-- widgetPresentationData.json
除了直接读写文件外,该项目还主要SQLite
用于结构化数据。启用了两个SQLite扩展:SQLCipher用于完全数据库加密;FTS5用于全文本搜索。这种方法在其他流行的即时通讯中也很流行,例如WeChat和SignalApp。
LMDB是基于BTree的事务键值存储,它提供了一些Objective-C组件:例如TGEmbedCoubPlayerView(coub.com的嵌入式播放器),TGMediaEditingContext它负责在发送媒体消息时编辑照片和视频。
网络传输
消息传递和VoIP Call
是需要网络传输的两个主要方案。可靠的连接性和实时更新是即时通讯的重要特征,这是一个令人着迷的挑战,因为全球网络环境相当复杂。为此发明了一些工程技巧,并在即时通讯中广泛应用,例如流量混淆,混合端点发现,域前沿等。
MTProto是Telegram
的核心协议,旨在支持多种传输协议。当前版本的Telegram-iOS仅支持TCP传输。HTTP传输已于2018年删除。VoIP模块libtgvoip支持UDP和TCP传输。
Telegram-iOS还利用来自PushKit
的VoIP Notifications来通过Apple的网络接收数据。这是另一个广泛使用的技巧,使应用程序可以将数据封装在通知有效负载中并在后台处理数据,而无需用户进行交互。普通的APNS无法做到相同的行为。这对于某些核心功能至关重要,例如更新未读计数,在应用程序无法连接到后端时检索新端点,更新活动位置等。
由于任何滥用行为都可能导致严重的电池消耗问题,因此自iOS SDK 13以来,Apple在收到VoIP通知后开始要求应用程序必须调用CallKit。但是Telegram-iOS似乎可以从新规则中幸免,因为它获得了Apple的特别授权:com.apple.developer.pushkit.unrestricted-voip。在SignalApp中也可以找到相同的未记录权利。
UI框架
除了使用AsyncDisplayKit作为其核心UI呈现框架之外,Telegram-iOS进一步开发并重新实现了常见的UIKit控制器和视图。大多数UIKit的组件可以找到项目内的替代组件:NavigationController
,TabBarController
,AlertController
,ActionSheetController
,NavigationBar
,ItemListController
(更换的UITableViewController的)等的方法是相当合理的。
题外话。有趣的是,大多数iOS工程师最终都会在UIKit上学到一些技巧。不知何故,重新实现UINavigationController之类的组件并不是一件容易的事,因为要破解原始组件。我最喜欢的细节之一是UINavigationController如何设法推送和弹出仅横向模式的控制器
关于UI属性动画,这POP是Objective-C中传统UI组件的一种,而swift模块大多在CADisplayLink或CoreAnimation上使用其自己的动画器实现。
应用程序内置了两个Lottie库rlottie和lottie-ios,以支持After Effects动画。rlottie
主要是为动画贴纸的tgs
格式。Lottie-ios
用于从Bundle资源加载动画文件。似乎实际上没有必要为同一件事使用两个库,lottie-ios
可以用代替rlottie
。
单元测试
项目中基本上没有单元测试。
应用内调试
轻按10次设置可能会显示调试控制器,您可以在其中调整日志设置,收集日志,尝试实验性UI设置等。