Soul 去除截屏限制与广告与聊天限制 ?解决方法

Posted by 国庆节,要开心 on 2026年10月01日

Soul 隐私图片去除禁止截屏 · MT 管理器修改教程

适用对象: [soul_6.37.0.apk](http://soul_6.37.0.apk) (包名  [cn.soulapp.android](http://cn.soulapp.android) ,versionCode 26091510)

修改效果:隐私保护预览页等原本禁止截屏的页面,恢复为可正常截屏 / 录屏

改动量:只需修改 1 处(隐私保护预览页 PrivacyProtectPreviewActivity)

一、修改位置总览

# 文件(相对 smali 目录) 所在 dex 作用 是否必须改
1 cn/soulapp/android/component/chat/snapchat/ [PrivacyProtectPreviewActivity.smali](http://PrivacyProtectPreviewActivity.smali) classes12 隐私保护预览页(聊天中发送的隐私图片 / 视频) ✅ 必须改(本教程核心)

💡 提示:只改第 1 处就够了。

文件位置: [classes12.dex](http://classes12.dex)  → cn/soulapp/android/component/chat/snapchat/PrivacyProtectPreviewActivity


二、操作步骤(核心:修改隐私保护预览页)

2.1 反编译

  1. 1. 打开 MT 管理器 → 文件管理器 → 找到  [soul_6.37.0.apk](http://soul_6.37.0.apk)

  2. 2. 查看 →  classes12.dex  → 用 Dex编辑器++ 打开

2.2 定位文件

  1. 1. 在 Dex编辑器++ 中打开  [classes12.dex](http://classes12.dex)

  2. 2. 搜索 0x2000,类型选择 代码

  3. 3. 下滑定位到 cn/soulapp/android/component/chat/snapchat/ 目录

  4. 4. 在 PrivacyProtectPreviewActivity 中找到如下片段:

    const/16 v2, 0x2000

  5. 图片

2.3 修改(只改 1 处)

修改前:

.line  34const/16   v2, 0x2000.line  36if-eqz   v1,   :cond_2d

修改后: 将 const/16 v2, 0x2000 替换为 const/4 v2, 0x0,即:

.line  34const/4   v2, 0x0.line  36if-eqz   v1,   :cond_2d

🔍 说明:寄存器 v2 后面被两个分支引用 ——

  • • 当 banScreenshotAndSave == true 时执行 setFlags(v2, v2)

  • • 否则执行 clearFlags(v2)

将立即数改为 0 后,两个分支均变为空操作,无需删除任何代码,逻辑依然保持完整。

2.4 保存、打包、签名

  1. 1. 修改完成后返回,保存该 dex 文件

  2. 2. 在功能菜单中执行 去签名校验(⚠️ 不做这一步的话,安装后会闪退)

  3. 3. 重新打包 APK 并签名

⚠️ 安装前务必先卸载旧版 Soul —— 签名证书不同,无法覆盖安装。

2.5 验证

在聊天中发送一张带「隐私保护」标记的图片 / 视频 → 点开预览 → 此时可以正常截屏,即修改成功 ✅。

Soul 去除开屏广告 / 全部广告位 / 私聊限制弹窗 · MT 管理器修改教程

适用对象:soul_6.37.0.apk(包名 cn.soulapp.android,versionCode 26091510)

修改效果:启动不再展示开屏广告;信息流、插屏、激励视频、原生等所有广告位不再加载广告;带「火热图标」的高热度会话点进去不再弹「送花提升回复率」拦截弹窗,可直接正常私聊

改动量:共 3 处(另有 1 处可选)

一、修改位置总览

# 文件(相对 smali 目录) 所在 dex 作用 是否必须改
1 cn/soulapp/android/component/startup/main/MainScheduler$onCreate$6 classes15 启动调度:决定要不要展示开屏广告 ✅ 必须改
2 cn/soulapp/android/ad/core/requseter/AdRequester classes11 广告请求统一入口(信息流 / 插屏 / 激励 / 原生) ✅ 必须改
3 cn/soulapp/android/component/chat/style/BaseConversationStyleProcess classes12 私聊页限额拦截弹窗(送花提升回复率) ✅ 必须改
4 cn/soulapp/android/lib/common/bean/ChatLimitModel classes16 「会话是否受限」的判定(可选:连火热图标一起处理) ⬜ 可选

💡 提示:1、2、3 三处是核心,改完即可达到「无广告 + 无限制弹窗」。

第 4 处只有在你想把「私聊」按钮旁边的火热图标也去掉时才需要改;想保留图标就不要动它。


二、操作步骤

2.1 反编译

  1. 1. 打开 MT 管理器 → 文件管理器 → 找到 soul_6.37.0.apk
  2. 2. 查看 → 选中 classes11.dex、classes12.dex、classes15.dex(可多选)→ 用 Dex编辑器++ 打开

💡 提示:也可以只打开一个 dex,按类名搜索定位;MT 的 Dex编辑器++ 会显示类所在的 dex。


2.2 第一部分:去除开屏广告

所在 dex:classes15.dex → cn/soulapp/android/component/startup/main/MainScheduler$onCreate$6

  1. 1. 定位到 MainScheduler$onCreate$6,打开 invoke()V 方法
  2. 2. 搜索 display_ad,可以看到下面这段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
:cond_27
if-eqz v0, :cond_37

.line 3
sget-object v0, Lcn/soulapp/android/client/component/middle/platform/utils/push/NotifierClickUtils;->a:Lcn/soulapp/android/client/component/middle/platform/utils/push/NotifierClickUtils;

invoke-virtual {v0}, Lcn/soulapp/android/client/component/middle/platform/utils/push/NotifierClickUtils;->h()Z

move-result v0

if-eqz v0, :cond_37

.line 4
iget-object v0, p0, Lcn/soulapp/android/component/startup/main/MainScheduler$onCreate$6;->this$0:Lcn/soulapp/android/component/startup/main/MainScheduler;

invoke-static {v0}, Lcn/soulapp/android/component/startup/main/MainScheduler;->e(Lcn/soulapp/android/component/startup/main/MainScheduler;)V

goto :goto_3c

.line 5
:cond_37
iget-object v0, p0, Lcn/soulapp/android/component/startup/main/MainScheduler$onCreate$6;->this$0:Lcn/soulapp/android/component/startup/main/MainScheduler;

invoke-static {v0}, Lcn/soulapp/android/component/startup/main/MainScheduler;->c(Lcn/soulapp/android/component/startup/main/MainScheduler;)V

:goto_3c
return-void

修改前:

if-eqz   v0,   :cond_37

修改后: 把这一条改成无条件跳转,即改为:

goto   :cond_37

🔍 说明:上面的 :cond_37 分支调用的是 MainScheduler.c()(→ s() → 直接做主页初始化,不展示开屏);下面的 :cond_37 之后那段调用的是 MainScheduler.e()(→ doShowAd(),展示开屏广告)。

把 if-eqz v0, :cond_37 改成 goto :cond_37 后,判断结果被忽略,无条件走”不展示开屏”分支,启动直接进主页。原广告分支变成不可达代码,dex 允许存在,无需删除。

补充:NotifierClickUtils.h() 在 <clinit> 里被置为 true,所以正常冷启动原本是满足展示条件的 —— 这就是不改就一直有开屏的原因。


2.3 第二部分:去除其他广告(信息流 / 插屏 / 激励 / 原生)

所在 dex:classes11.dex → cn/soulapp/android/ad/core/requseter/AdRequester

  1. 1. 定位到 AdRequester,

打开

1
e0(Lcn/soulapp/android/ad/bean/ReqInfo;Lcn/soulapp/android/ad/core/services/plaforms/listener/SoulAdRequestListener;Lcn/soulapp/android/ad/core/services/plaforms/listener/ColdTimingAdRequestListener;)V

方法

  1. 2. 把整个方法体替换为下面这段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
.method public final declared-synchronized e0(Lcn/soulapp/android/ad/bean/ReqInfo;Lcn/soulapp/android/ad/core/services/plaforms/listener/SoulAdRequestListener;Lcn/soulapp/android/ad/core/services/plaforms/listener/ColdTimingAdRequestListener;)V
    .registers 14

    monitor-enter p0

    :try_start_0
    const/4 v0, 0x3

    new-array v1, v0, [Ljava/lang/Object;

    const/4 v8, 0x0

    aput-object p1, v1, v8

    const/4 v9, 0x1

    aput-object p2, v1, v9

    const/4 v2, 0x2

    aput-object p3, v1, v2

    sget-object v3, Lcn/soulapp/android/ad/core/requseter/AdRequester;->changeQuickRedirect:Lcn/soul/android/plugin/ChangeQuickRedirect;

    const/4 v4, 0x0

    const/4 v5, 0x2

    new-array v6, v0, [Ljava/lang/Class;

    const-class v7, Lcn/soulapp/android/ad/bean/ReqInfo;

    aput-object v7, v6, v8

    const-class v7, Lcn/soulapp/android/ad/core/services/plaforms/listener/SoulAdRequestListener;

    aput-object v7, v6, v9

    const-class v7, Lcn/soulapp/android/ad/core/services/plaforms/listener/ColdTimingAdRequestListener;

    aput-object v7, v6, v2

    sget-object v7, Ljava/lang/Void;->TYPE:Ljava/lang/Class;

    move-object v2, p0

    invoke-static/range {v1 .. v7}, Lcn/soul/android/lib/hotfix/PatchProxy;->proxy([Ljava/lang/Object;Ljava/lang/Object;Lcn/soul/android/plugin/ChangeQuickRedirect;ZI[Ljava/lang/Class;Ljava/lang/Class;)Lcn/soul/android/lib/hotfix/PatchProxyResult;

    move-result-object v1

    iget-boolean v1, v1, Lcn/soul/android/lib/hotfix/PatchProxyResult;->isSupported:Z
    :try_end_0
    .catchall {:try_start_0 .. :try_end_0} :catchall_0

    if-eqz v1, :cond_0

    monitor-exit p0

    return-void

    :cond_0
    :try_start_1
    iput-object p1, p0, Lcn/soulapp/android/ad/core/requseter/AdRequester;->a:Lcn/soulapp/android/ad/bean/ReqInfo;

    invoke-static {}, Ljava/lang/System;->currentTimeMillis()J

    move-result-wide v1

    invoke-virtual {p1, v1, v2}, Lcn/soulapp/android/ad/bean/ReqInfo;->setReqTime(J)Lcn/soulapp/android/ad/bean/ReqInfo;

    iput-object p2, p0, Lcn/soulapp/android/ad/core/requseter/AdRequester;->b:Lcn/soulapp/android/ad/core/services/plaforms/listener/SoulAdRequestListener;

    iput-object p3, p0, Lcn/soulapp/android/ad/core/requseter/AdRequester;->c:Lcn/soulapp/android/ad/core/services/plaforms/listener/ColdTimingAdRequestListener;

    new-instance v0, Lsb/o;

    invoke-virtual {p1}, Lcn/soulapp/android/ad/bean/ReqInfo;->getReqId()Ljava/lang/String;

    move-result-object v1

    invoke-virtual {p1}, Lcn/soulapp/android/ad/bean/ReqInfo;->getAdSlot()Lfa/a;

    move-result-object v2

    invoke-virtual {v2}, Lfa/a;->k()I

    move-result v2

    invoke-direct {v0, v1, v2}, Lsb/o;-><init>(Ljava/lang/String;I)V

    iput-object v0, p0, Lcn/soulapp/android/ad/core/requseter/AdRequester;->g:Lcn/soulapp/android/ad/core/strategy/IRequestStrategy;

    invoke-direct {p0}, Lcn/soulapp/android/ad/core/requseter/AdRequester;->y()V

    const/4 v0, -0x1

    const-string v1, "ads_disabled"

    invoke-virtual {p0, p1, v0, v1}, Lcn/soulapp/android/ad/core/requseter/AdRequester;->onRequestFailed(Lcn/soulapp/android/ad/bean/ReqInfo;ILjava/lang/String;)V
    :try_end_1
    .catchall {:try_start_1 .. :try_end_1} :catchall_0

    monitor-exit p0

    return-void

    :catchall_0
    move-exception v0

    monitor-exit p0

    throw v0
.end method

🔍 说明:e0(...) 是 Soul 自建聚合广告 SDK 的统一请求入口,信息流、插屏、激励视频、原生等所有广告位最终都走这里(穿山甲 com.bytedance.sdk.openadsdk 和优量汇 com.qq.e 只是它下面的 adapter,本身不直接对外)。

改成直接调用 onRequestFailed(reqInfo, -1, "ads_disabled") 后,等于每次请求都回报”没有广告填充”。各广告位会按”无广告”的正常分支收起或隐藏,不会卡在加载中。

⚠️ 前面三行不能删:

  • g(策略对象 Lsb/o)和 y()(写入 ReqInfo.plSlotInfo)是后续 onHandleResult() 必需的前置状态 —— onHandleResult 里会无条件读取 getPlSlotInfo() 和 this.g,缺了会空指针崩溃。

注意:MT 重新汇编后标签名可能被重编号(如 cond_0 变成 cond_2c),属正常现象,不影响逻辑。


2.4 第三部分:去除私聊限制弹窗(送花提升回复率)

所在 dex:classes12.dex → cn/soulapp/android/component/chat/style/BaseConversationStyleProcess

  1. 1. 定位到 BaseConversationStyleProcess,打开 checkLimitOpt(Luj/c0;Lcn/soulapp/imlib/Conversation;Ljava/lang/String;)Z 方法
  2. 2. 搜索 limit_model,可以看到下面这段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
.line 95
invoke-virtual {v0, v2}, Landroid/content/Intent;->getSerializableExtra(Ljava/lang/String;)Ljava/io/Serializable;

.line 98
move-result-object v0

.line 99
goto :goto_64

.line 100
:cond_63
move-object v0, v1

.line 101
:goto_64
instance-of v2, v0, Lcn/soulapp/android/lib/common/bean/ChatLimitModel;

.line 103
if-eqz v2, :cond_6b

.line 105
move-object v1, v0

.line 106
check-cast v1, Lcn/soulapp/android/lib/common/bean/ChatLimitModel;

.line 108
:cond_6b
move-object v2, v1

.line 109
if-eqz v2, :cond_ad

修改前:

instance-of   v2,   v0,   Lcn/soulapp/android/lib/common/bean/ChatLimitModel;

修改后: 把这一条替换为:

const/4   v2,  0x0

🔍 说明:v1 初始为 null,只有 instance-of 判断成立时才会被 check-cast 成 ChatLimitModel。把 instance-of 的结果固定为 0 后,if-eqz v2, :cond_6b 必定跳到 :cond_6b,此时 v1 仍是 null → v2 也是 null → if-eqz v2, :cond_ad 必定跳到 :cond_ad,也就是未受限分支。

语义上完全等价于「Activity 的 Intent 里从来没有 limit_model 这个字段」,和普通不受限会话走完全相同的后续流程(照常执行 ChatUtils.s() 和 p1.l1()),不会少做任何正常初始化。改动极小,且不动任何寄存器类型,不会引入校验问题。

这样就不会再构建 LimitGiftDialogV2(那个左上角有 X、点 X 会 Activity.finish() 把聊天页关掉的弹窗),但「私聊」按钮旁的火热图标是另一条分支控制的,不受影响。


2.5 保存、打包、签名

  1. 1. 修改完成后返回,保存相关 dex 文件
  2. 2. 在功能菜单中执行 去签名校验(⚠️ 不做这一步的话,安装后会闪退)
  3. 3. 重新打包 APK 并签名

⚠️ 安装前务必先卸载旧版 Soul —— 签名证书不同,无法覆盖安装。


2.6 验证

  1. 1. 冷启动 App → 不再出现开屏广告,直接进入主页 ✅
  2. 2. 进 广场 / 消息页滚动信息流 → 广告位空白或直接收起,不再出现广告 ✅
  3. 3. 在会话列表找到带火热图标的会话点进去 → 不再弹「送花提升回复率」弹窗,可直接打字聊天,返回也不会被踢出聊天页 ✅

三、可选:连「火热图标」一起去掉

所在 dex:classes16.dex → cn/soulapp/android/lib/common/bean/ChatLimitModel

那个火热图标(MetaPageUserHomeFragment.applyChatLimitHotIcon)的显示条件是 ChatLimitModel.isLimit() == true。想连它一起去掉,就再改第 4 处:

  1. 1. 定位到 ChatLimitModel,打开 isLimit()Z 方法
  2. 2. 把整个方法体替换为:
1
2
3
4
5
6
7
.method public isLimit()Z
    .registers 2

    const/4 v0, 0x0

    return v0
.end method

🔍 说明:ChatLimitModel 的字段 limit 只被 isLimit() 读取,全 App 有 24 处调用 isLimit()(私聊入口校验、路由拦截器、聊天页样式处理、新版配额体系、广场帖子底部按钮、通知卡片等),全部是限额相关判定。恒返回 false 相当于「这个会话永远不受限」,会一次性把所有付费拦截(含新版 ChatQuota 的「解锁私聊机会」卡片)都压掉。

⚠️ 代价:同时也会让「私聊」按钮上那颗由 isLimit() 驱动的火热图标不再显示。

所以:

  • 想保留火热图标 → 只改 1、2、3 三处,不要动 isLimit()(推荐,本教程默认方案)
  • 想连图标一起清掉 → 额外做这一处

四、关于版本

  • • 本教程基于 Soul 6.37.0 版本(versionCode 26091510)。
  • • 不同版本中,上述类的所在 dex 可能不同(如 classes11 / classes12 / classes15 / classes16 等)。定位方式相同:按类名搜索即可,MT 的 Dex编辑器++ 会显示该类实际所在的 dex。
  • • 混淆后的类名可能变化,但下列特征很稳定,可作为定位锚点:
    • 开屏:搜字符串 display_ad,落在 MainScheduler$onCreate$6 一类里
    • 广告入口:类 cn/soulapp/android/ad/core/requseter/AdRequester,方法名 e0
    • 私聊弹窗:搜字符串 limit_model,落在 BaseConversationStyleProcess.checkLimitOpt 里

⚠️ 重要注意事项

    1. 安装修改版前必须先卸载原版本,聊天记录将会丢失,请提前备份重要数据。
  1. 2. 第 2 处改动会关闭全部广告请求,因此「看广告领 Soul 币 / 看广告解锁」这类功能会一直提示无广告可用,属预期结果。
  2. 3. 本教程仅用于学习 Android 反编译原理,请遵守相关法律法规,勿用于商业用途或侵犯他人权益。

关注微信公众号【素简好物】

  • 回复:soul
  • 获取安装文件 tu1