Telegram-iOS 源码分析:第三部分(Other Foundations)

版权声明
本文内容均为搬运,目的只为更方便的学习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 appwatch appintents 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的组件可以找到项目内的替代组件:NavigationControllerTabBarControllerAlertControllerActionSheetControllerNavigationBarItemListController(更换的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设置等。

part3-debug.jpeg

你可能感兴趣的:(Telegram-iOS 源码分析:第三部分(Other Foundations))