因为 App Store 的内容审核政策,Telegram iOS 很多群组(尤其 NSFW 群组)都无法进入,部分正常的群也遭到屏蔽,而安卓和 PC/Mac 端不受影响,这还是带来了一些不方便。鉴于 telegram 的代码是开源的,于是我尝试通过修改代码的方式来绕过限制。

Telegram X 是官方使用 Swift 语言写的新的 Telegram 客户端,相比于原版更加丝滑流畅。由于原版的 Telegram iOS 已经六个月没有更新代码了,而 Telegram X 正在保持稳定的开发步伐,从长远来看我们还是修改新出的 Telegram X 比较好。

下载代码

首先我们从 GitHub 下载代码,项目地址是 https://github.com/peter-iakovlev/Telegram-iOS

然后进入目录,下载 git 子模块:git submodule update --init --recursive
然后打开 XCode 的 workspace。

申请 API Key

你需要在 https://my.telegram.org/auth 申请一个 API Key 以和服务器进行通讯。

运行代码

在开始修改之前,我们先尝试运行一下。首先选择 target 为 Telegram-iOS-Fork。

修改 target

替换 API Key

然后来到 Telegram-IOS/Supporting Files/BuildConfig.m,将 275 到 331 行的代码替换为如下代码:

_apiId = 123456;
_apiHash = @"aaaabbbbccccddddeeeeffffededeeee";
_hockeyAppId = nil;

其中,apiId 和 apiHash 为上一步官网申请时获得的。

其实单看提示来看是缺了一个 APP_CONFIG_DATA,它是包含了 apiId、apiHash 和 hockeyAppId 的一个 hex,但是并不知道如何将这三个值变成一个 hex。所以暂时只能替换代码。GitHub 上有关于这个的讨论

修改前
修改后

XCode 10.2 兼容性问题

如果你是用的 XCode 版本是 10.2,你可能会遇到这个问题,否则你可以跳过这个步骤。在 XCode 10.2 中,会出现 Swift 3 到 Swift 4 的兼容性问题,具体表现是 ManagedAudioSession.swift 中有一个 Expression type 'Bool' is ambiguous without more context 的警告。GitHub 上也有对应的 issue。目前只能把那一行注释掉来解决问题。

注释代码

运行

完成以上步骤后,我们就可以点击左上角的播放按钮来编译运行了。不出意外你可以看到编译成功并弹出 iOS 模拟器窗口。登录后你会发现此时频道屏蔽依然有效。

修改代码

在自己开始上手之前,我曾经在群里问过有没有人尝试过。有一个人说自己尝试过并且成功了,不过他使用的是原版的 Telegram 客户端。根据他的描述,原版客户端的代码逻辑比较易读,只需要修改以下几个地方即可:

可以看到业务逻辑非常清晰易读,只需要去掉 hasExplicitContent 的判断即可。不过在 Telegram X 中似乎没有这么幸运,这段代码在 Telegram X 中并不存在,因此我被迫寻找别的出路。

经过不断地调试,我最后在 API 调用的反序列化步骤中加入了代码,通过位运算修改了服务器返回的群组的属性实现了频道解禁。

修改的位置在 TelegramCore/Network/Api1.swift 的 parse_channel 函数中,我们在读取流的操作之后(1733行)加入位运算代码,将从右数的第九位和第十八位置零,并清空 _9_12 的内容:

_1 = _1! & ~(1 << 9) & ~(1 << 18)
_9 = nil
_12 = nil

这时候我们再编译运行,可以看到 channel 屏蔽已经解除。

真机调试

到这里其实我们只完成了一半:现在只能在模拟器里运行,而由于苹果的限制,真机运行非常麻烦。如果你没有苹果开发者账号(99刀一年),你会无法使用包括通知推送在内的许多功能。在进行下面的步骤之前,你需要先在 XCode 中登录自己的 Apple ID。

取消没有权限的 capabilities

对于我们的免费证书,很多功能都不能使用。为了通过编译,我们需要把这些“能力”关掉。在左侧列表中点击“Telegram-iOS”、在右边的 target 列表中选择 “Telegram-iOS”,然后在 Capabilities 选项卡中关掉 Associated Domains、iCloud、Push notifications、Siri。

关闭后

另外,还需要通过修改代码关闭 Siri 的授权申请,否则运行时会白屏卡住。具体的做法是将 AppDelegate.swift 中的 Siri 授权逻辑部分由判断逻辑直接改成拒绝状态。

修改前
修改后

使用自己的证书对 App 签名

对于所有的 targets,在 signing 区块中勾选 Automatically manage signing。

然后在每一个 targets 的 Build settings 中的 signing 区块中清空 Code Signing Entitlements。

清空 Code Signing Entitlements

自定义 Bundle Identifier

把每一个 target 的 bundle identifier 都改掉。除了 Telegram-iOS 之外,其他的 target 的 bundle identifier 应该以 Telegram-iOS 的 bundle identifier 为前缀。比如如果 Telegram-iOS 的新 bundle identifier 是“pro.admirable.telegram”,则 Share 的新 bundle identifier 应该设置为“pro.admirable.telegram.Share”。

除此之外,还需要去每一个 target 里的 build settings 选项卡中,修改 User-defined 下的 APP_BUNDLE_ID 为 Telegram-iOS 的 bundle identifier:

修改 APP_BUNDLE_ID

自定义 App Group

在 Target “Telegram-iOS”的 capabilities -> App Groups 中新建一个 App Groups,名字自己起(疑似必须与“Telegram-iOS”的 Bundle identifier 保持一致,否则运行时会黑屏出现 Error 2 错误,不确定是否为 XCode 的 bug。这个问题坑了我好几个小时。)。然后关闭 App Groups 功能再重新打开,然后选择你刚刚新建的项目。接下来的每一个 target 都需要先关闭 App Groups 功能再重新打开,然后选择你刚刚新建的项目

除此之外,你还需要前往每一个 target 的 build settings,然后将 User-defined -> Provisioning profile 清空。否则 App Groups 列表下面会有警告。

清空 Provisioning profile

运行

在完成了以上步骤之后,我们就可以运行了。点击播放图标。经过编译的过程后,telegram 就安装到了你的手机上。为了运行你签名的应用程序,你需要在 iPhone 上前往设置->通用->描述文件,然后信任你自己的开发者证书。

后记

对于我这个后端,使用 XCode 修改 iOS 项目还是有点难度的。经过了很多个小时的斗(keng)争,终于实现了频道(channel)屏蔽的解除。不确定对于群组(group)是否有效,欢迎在评论区留言讨论。