前言
每次打開微信,總有一些公眾號(hào)推送煩人的且無(wú)營(yíng)養(yǎng)消息俄周,而微信又沒(méi)提供全部已閱的功能驴剔,本章詳細(xì)講述一鍵閱讀所有消息.
- 安裝一個(gè)砸殼的微信碟刺,或者自己去App Store下載一個(gè)再砸殼.
- 恢復(fù)微信符號(hào)表 iOS符號(hào)表恢復(fù)
- 給微信添加調(diào)試權(quán)限.
- 分析.
- Tweak.xm
- 總結(jié).
0x1:
0x2:
Reveal分析:
11.png
- 小紅點(diǎn)是個(gè)封裝的圖片控件 MMBadgeView
- 紅點(diǎn)中的數(shù)字是個(gè)封裝了UILabel控件 MMUILabel
XCode加載微信進(jìn)程:
從MMBadgeView控件入手:
這里選擇直接從MMBadgeView入手串稀,po [MMBadgeView _shortMethodDescription] 命令除抛,打印出MMBadgeView的所有屬性和方法,發(fā)現(xiàn)三個(gè)方法格外顯眼.
Symbolic BreakPoint下斷:
放開斷點(diǎn)后母截,小號(hào)發(fā)送條信息給這個(gè)微信到忽,看看斷點(diǎn)是否被斷下.
微信在收到消息之后經(jīng)過(guò)非常多的頁(yè)面UI處理,然后再設(shè)置小紅點(diǎn)的數(shù)量清寇。這個(gè)時(shí)候往上回溯發(fā)現(xiàn)除了系統(tǒng)的渲染函數(shù)喘漏,第一個(gè)被調(diào)用的微信函數(shù)是[MMTableView layoutSubviews]
,這個(gè)函數(shù)是微信首頁(yè)這個(gè)表格加載子視圖的函數(shù),我們所看到的首頁(yè)上的任何東西都是這個(gè)函數(shù)加載出來(lái)的华烟,那么在這之前發(fā)生了什么翩迈?如何收到的消息?怎么計(jì)算的未讀消息數(shù)量盔夜?
繼續(xù)下一步分析:
現(xiàn)在程序停留在了UITableView這個(gè)控件的一系列渲染和布局函數(shù)上面负饲,如果繼續(xù)盯著這塊分析,最后會(huì)發(fā)現(xiàn)在做無(wú)用功.
理論上是喂链,當(dāng)微信收到消息后返十,經(jīng)過(guò)一系列處理,最后通知微信的首頁(yè)椭微,刷新這個(gè)表格(UITableView)洞坑,給對(duì)應(yīng)欄目(Cell)上的小紅點(diǎn)+1.
至于為什么有那么多UI渲染函數(shù)是因?yàn)槲⑿攀盏较⒑螅绻且粋€(gè)沒(méi)有在首頁(yè)列表的朋友發(fā)過(guò)來(lái)的呢蝇率?微信會(huì)發(fā)出通知聲音迟杂,然后加入一個(gè)新的欄目(Cell)并置頂.
跳出這個(gè)UITableView控件的渲染層,轉(zhuǎn)到這個(gè)UITableView的父級(jí)本慕,也就是首頁(yè)的控制器
NewMainFrameViewController
逢慌,在前面Reveal分析中已經(jīng)得到了這個(gè)控制器.
分析 NewMainFrameViewController:
po [NewMainFrameViewController _shortMethodDescription] 打印輸出控制器.
在列舉的方法中尋找
Undead
,這個(gè)關(guān)鍵字如何來(lái)的间狂?在前面UITableView的視圖渲染中就有這么個(gè)函數(shù)[MainFrameitemView updateUnreadCountView]
,簡(jiǎn)潔明了一看就知道是修改未讀數(shù)量.-
記錄所有和這個(gè)關(guān)鍵字有關(guān)的方法:
- (void) cleanAllUnreadSession;
-(void)setNewMainFrameTableViewContentOffsetToTheFirstUnreadSessionAndOpen:(BOOL)arg1;
- (unsigned int) getTotalUnreadCount;
- (void) onNextUnreadChat;
- (void) notifyTaskBarOnWillFocusOnFirstUnreadSession;
- (void) updateUnReadCount;
- (void) openMessageContentView:(id)arg1 startSendMessage:(BOOL)arg2 msgWrapToAdd:(id)arg3 animated:(BOOL)arg4 jumpToFirstUnreadNode:(BOOL)arg5 indexPath:(id)arg6 reuse:(BOOL)arg7 extraInfo:(id)arg8;
- (void) openMessageContentView:(id)arg1 startSendMessage:(BOOL)arg2 msgWrapToAdd:(id)arg3 animated:(BOOL)arg4 jumpToFirstUnreadNode:(BOOL)arg5 indexPath:(id)arg6;
從字面意思
- (void) cleanAllUnreadSession;
方法是取消所有未讀會(huì)話攻泼,貌似是我們要的,實(shí)際上這是個(gè)坑鉴象,執(zhí)行了這個(gè)方法忙菠,微信首頁(yè)所有的消息都沒(méi)了,包括欄目(Cell)纺弊,再次打開微信牛欢,首頁(yè)就是個(gè)白板.-
最后定位到
- (void) updateUnReadCount;
Symbolic BreakPoint下斷
77.jpg
微信收到消息后斷在- (void) updateUnReadCount;
,注意:如果這個(gè)時(shí)候已經(jīng)在當(dāng)前會(huì)話的聊天房間淆游,并不會(huì)觸發(fā)這個(gè)函數(shù).
* 這個(gè)時(shí)候出現(xiàn)了一個(gè)新的類在堆棧調(diào)用過(guò)程中 MMNewSessionMgr
* 當(dāng)微信收到消息傍睹,如果這個(gè)消息欄目(Cell)在首頁(yè)列表中隔盛,小紅點(diǎn)的數(shù)量會(huì)遞增.
* 點(diǎn)擊某個(gè)有小紅點(diǎn)的欄目進(jìn)去后,小紅點(diǎn)會(huì)消失,說(shuō)明當(dāng)前欄目是已讀的.
* 未讀消息為0拾稳,表示當(dāng)前欄目已讀吮炕,小紅點(diǎn)消失.
* 邏輯推測(cè):收到消息,未讀數(shù)量遞增. 進(jìn)入房間未讀數(shù)置0访得,隱藏小紅點(diǎn).說(shuō)明都會(huì)改變消息未讀數(shù)
-
查看進(jìn)入房間的堆棧調(diào)用:
88.jpg
進(jìn)入單間龙亲,表示消息已讀,調(diào)用了MMNewSessionMgr
類的三個(gè)函數(shù)悍抑。分別給三個(gè)函數(shù)下斷鳄炉,查看參數(shù)的值.
* MMNewSessionMgr
類 - 函數(shù):
-
$arg3
表示第一個(gè)參數(shù)$agr4
表示第二個(gè)po
printObject
通過(guò)三個(gè)函數(shù)調(diào)用,然后調(diào)用微信首頁(yè)控制器的- (void) updateUnReadCount
方法搜骡,會(huì)清除小紅點(diǎn)拂盯。 -
[MMNewSessionMgr OnUnReadCountChange:]
的參數(shù)是一串字符串
-
[MMNewSessionMgr ChangeSessionUnReadCount:to:]
的兩個(gè)參數(shù)分別是 上一個(gè)函數(shù)的參數(shù) 和 一個(gè) 0|假 . - 返回到首頁(yè),剛剛進(jìn)去過(guò)的欄目小紅點(diǎn)消失记靡,其余的還是存在谈竿。
- 再進(jìn)入一個(gè)別的有未讀消息的房間,
[MMNewSessionMgr OnUnReadCountChange:]
又會(huì)不同簸呈,說(shuō)明這個(gè)參數(shù)很可能是一個(gè)ID榕订,代表首頁(yè)的每一個(gè)欄目(Cell). - 羊毛出在羊身上店茶,打印一波
MMNewSessionMgr
類:
aa.jpg
-
嘗試調(diào)用一下那些不需要參數(shù)就有返回值的函數(shù):
bb.png- 至此能拿到的東西已經(jīng)很多 - 整理一下邏輯就能完成一鍵閱讀
Tweak.xm
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
%hook MMServiceCenter
%end
%hook MMNewSessionMgr
%end
%hook MMSessionInfo
%end
%hook NewMainFrameViewController
- (void) viewDidAppear:(BOOL)arg1{
%log;
%orig;
//微信首頁(yè)左上角添加一個(gè)功能按鈕
UIBarButtonItem *barBtn = [[UIBarButtonItem alloc]initWithTitle:@"?" style:UIBarButtonItemStylePlain target:self action:@selector(cleanAllUnreadSession)];
[((UIViewController *)self).navigationItem setLeftBarButtonItem:barBtn];
}
%new
- (void)cleanAllUnreadSession{
//獲取 MMNewSessionMgr 實(shí)例
MMNewSessionMgr *sessionObj = [[%c(MMServiceCenter) defaultCenter] getService:[%c(MMNewSessionMgr) class]];
//獲取所有的 sessionID
NSArray *SessionListArray = [sessionObj GetUserNamesOnSessionList];
for (NSString *str in SessionListArray) {
// 循環(huán)修改每個(gè)會(huì)話 改成已讀
[sessionObj ChangeSessionUnReadCount:str to:0];
}
}
%end
總結(jié)
實(shí)際上分析過(guò)程中會(huì)用到 Hopper Disassembler
靜態(tài)分析.
實(shí)際上部分公眾號(hào)推送的消息還是有價(jià)值的.
我沒(méi)有任何針對(duì)微信的意思蜕便,如果你非要問(wèn)我支持不支持微信,我當(dāng)然支持贩幻,可以很明確的告訴你轿腺,我不支持我還天天用微信。??
最后附上效果圖丛楚。