上文已經(jīng)知道收到紅包消息與開紅包方法,那么只需在收到紅包消息時带膀,調(diào)用開紅包方法,就可以完成自動搶紅包
完整的工程地址
一 紅包消息時調(diào)用開紅包方法
上篇hook到了收到紅包消息的方法就是CMessageMgr類中的onNewSyncAddMessage:方法,于是把開紅包的代碼放到此方法中。
onNewSyncAddMessage:方法中叹侄,當(dāng)m_uiMessageType=49的時候是紅包消息,此時判斷是否開啟了自動搶紅包功能
- (void)onNewSyncAddMessage:(CMessageWrap *)m_Wrap{
if(MSHookIvar<unsigned int>(m_Wrap,"m_uiMessageType") != 49){//不是紅包消息
%orig;
return;
}
if([WCDefaults boolForKey:WCSWITCHKEY] == NO){//是否開啟自動搶紅包
%orig;
return;
}
WCPayInfoItem *item =[m_Wrap m_oWCPayInfoItem];
NSString *url =[item m_c2cNativeUrl];
NSInteger length = [@"wxpay://c2cbizmessagehandler/hongbao/receivehongbao?" length];
id componets = [url substringFromIndex:length];
NSDictionary *dictionary=[%c(WCBizUtil) dictionaryWithDecodedComponets:componets separator:@"&"];
NSMutableDictionary *mul_dict =[%c(NSMutableDictionary) dictionary];
[mul_dict setObject:@"1" forKey:@"msgType"];
[mul_dict setObject:dictionary[@"sendid"] forKey:@"sendId"];
[mul_dict setObject:dictionary[@"channelid"] forKey:@"channelId"];
CContactMgr *server =[[%c(MMServiceCenter) defaultCenter] getService:[%c(CContactMgr) class]];
CContact *contact = [server getSelfContact];
id displayName = [contact getContactDisplayName];
[mul_dict setObject:displayName forKey:@"nickName"];
id m_nsHeadImgUrl = [contact m_nsHeadImgUrl];
[mul_dict setObject:m_nsHeadImgUrl forKey:@"headImg"];
if ( url )
{
[mul_dict setObject:url forKey:@"nativeUrl"];
}
NSString *m_nsUsrName = MSHookIvar<NSString *>(m_Wrap,"m_nsFromUsr");
[mul_dict setObject:m_nsUsrName forKey:@"sessionUserName"];
NSLog(@"---%@",m_nsUsrName);
//因?yàn)閙_data獲取不到昨登,所以編譯不過
NSDictionary *m_struct = [m_data m_structDicRedEnvelopesBaseInfo];
NSString *timingIdentifier= [m_struct objectForKey:@"timingIdentifier"];
if ( [timingIdentifier length])
{ [mul_dict setObject:timingIdentifier forKey:@"timingIdentifier"];}
WCPayLogicMgr *payLogicMgr =[[%c(MMServiceCenter) defaultCenter] getService:[%c(WCPayLogicMgr) class]];
[payLogicMgr setRealnameReportScene:1003];
id subScript = [m_struct objectForKeyedSubscript:@"agree_duty"];
[payLogicMgr checkHongbaoOpenLicense:subScript acceptCallback:^(){
WCRedEnvelopesLogicMgr *envelopesLogicMgr = [[%c(MMServiceCenter) defaultCenter] getService:[%c(WCRedEnvelopesLogicMgr) class]];
[envelopesLogicMgr OpenRedEnvelopesRequest:mul_dict];
}denyCallback:^(){
}];
}
%end
這個方法主要就是拼接mul_dict然后作為參數(shù)趾代,調(diào)用WCRedEnvelopesLogicMgr類的OpenRedEnvelopesRequest:函數(shù)。mul_dict需要的參數(shù)丰辣,能從CMessageWrap中獲取的直接獲取撒强,但是timingIdentifier獲取不到禽捆,所以要另作分析,要想辦法獲取到timingIdentifier飘哨。
二 其他方法獲取timingIdentifier
當(dāng)紅包消息收到后胚想,點(diǎn)擊紅包消息時有菊花在轉(zhuǎn),說明在請求網(wǎng)絡(luò)杖玲,請求過后才是紅包彈出的界面顿仇,所以現(xiàn)在可以進(jìn)行hook點(diǎn)擊紅包消息時的方法
-
通過分析知道WCRedEnvelopesLogicMgr類就是紅包管理類淘正,所以直接hook這個類中的所有方法:
然后進(jìn)行分析摆马,發(fā)現(xiàn)以下三個方法是點(diǎn)擊紅包消息時調(diào)用的方法:
[<WCRedEnvelopesLogicMgr: 0x10ef9aff0> ReceiverQueryRedEnvelopesRequest:{
agreeDuty = 0;
channelId = 1;
inWay = 1;
msgType = 1;
nativeUrl = "wxpay://c2cbizmessagehandler/hongbao/receivehongbao?msgtype=1&channelid=1&sendid=1000039501201805287004922762149&sendusername=wxid_hy6hye79l4q241&ver=6&sign=9995652ef3b076bbc7b626c0272f7cbbb2168732bc1a9af34777acbf4206d97062af9a8e3c84ad8812d45b48039d9c74e2f6fadb01223e74a9361a61947d4a19789abfde732b339ffb17c05c7bd7a2a0";
sendId = 1000039501201805287004922762149;
} ]
2018-05-28 10:21:42.258137+0800 WeChat[28565:2640576] -[<WCRedEnvelopesLogicMgr: 0x10ef9aff0> GetHongbaoBusinessRequest:{
agreeDuty = 0;
channelId = 1;
inWay = 1;
msgType = 1;
nativeUrl = "wxpay://c2cbizmessagehandler/hongbao/receivehongbao?msgtype=1&channelid=1&sendid=1000039501201805287004922762149&sendusername=wxid_hy6hye79l4q241&ver=6&sign=9995652ef3b076bbc7b626c0272f7cbbb2168732bc1a9af34777acbf4206d97062af9a8e3c84ad8812d45b48039d9c74e2f6fadb01223e74a9361a61947d4a19789abfde732b339ffb17c05c7bd7a2a0";
sendId = 1000039501201805287004922762149;
} CMDID:3 OutputType:1 ]
2018-05-28 10:21:42.490993+0800 WeChat[28565:2640576] [<WCRedEnvelopesLogicMgr: 0x10ef9aff0> OnWCToHongbaoCommonResponse:<HongBaoRes: 0x10efd1550> Request:<HongBaoReq: 0x10ed82840> ]
ReceiverQueryRedEnvelopesRequest:方法和GetHongbaoBusinessRequest:方法都是紅包請求方法,參數(shù)也差不多鸿吆,通過ida分析ReceiverQueryRedEnvelopesRequest:發(fā)現(xiàn)這個方法就是對GetHongbaoBusinessRequest:方法的封裝囤采。
- 那么可以得到ReceiverQueryRedEnvelopesRequest:和OnWCToHongbaoCommonResponse:Request:這兩個就是關(guān)鍵方法
- 在onNewSyncAddMessage:收到紅包消息的時候,主動調(diào)用GetHongbaoBusinessRequest:方法
WCRedEnvelopesLogicMgr *envelopesLogicMgr = [[%c(MMServiceCenter) defaultCenter] getService:[%c(WCRedEnvelopesLogicMgr) class]];
NSMutableDictionary *param =[%c(NSMutableDictionary) dictionary];
[param setObject:@"1" forKey:@"msgType"];
[param setObject:dictionary[@"channelid"] forKey:@"channelId"];
[param setObject:@"0" forKey:@"agreeDuty"];
[param setObject:@"1" forKey:@"inWay"];
if([m_nsUsrName cons containsString:@"@chatroom"]){//群紅包
[param setObject:@"0" forKey:@"inWay"];
}
[param setObject:dictionary[@"sendid"] forKey:@"sendId"];
[param setObject:url forKey:@"nativeUrl"];
[envelopesLogicMgr ReceiverQueryRedEnvelopesRequest:param];
- 拼接參數(shù)惩淳,m_nsFromUsr字段包含@chatroom就是群紅包
可以得到蕉毯,主動調(diào)用ReceiverQueryRedEnvelopesRequest:方法和手動點(diǎn)擊紅包消息是一樣的效果。那么我們再來分析OnWCToHongbaoCommonResponse:Request:方法思犁,通過打印參數(shù)類型得到此方法的發(fā)第一個參數(shù)是HongBaoRes代虾,然后通過頭文件得到HongBaoRes如下:
@interface SKBuiltinBuffer_t : NSObject
@property(retain, nonatomic) NSData *buffer;
@property(nonatomic) unsigned int iLen;
@end
@interface SKBuiltinString_t : NSObject
@property(retain, nonatomic) NSString *string;
@end
@interface BaseResponse : NSObject
@property(retain, nonatomic) SKBuiltinString_t *errMsg;
@property(nonatomic) int ret;
@end
@interface HongBaoRes : NSObject
@property(retain, nonatomic) BaseResponse *baseResponse;
@property(nonatomic) int cgiCmdid; // @dynamic cgiCmdid;
@property(retain, nonatomic) NSString *errorMsg; // @dynamic errorMsg;
@property(nonatomic) int errorType; // @dynamic errorType;
@property(retain, nonatomic) NSString *platMsg; // @dynamic platMsg;
@property(nonatomic) int platRet; // @dynamic platRet;
@property(retain, nonatomic) SKBuiltinBuffer_t *retText; // @dynamic retText;
@end
然后我們在OnWCToHongbaoCommonResponse:Request:中打印第一個參數(shù)的相關(guān)信息:
- (void)OnWCToHongbaoCommonResponse:(HongBaoRes *)arg1 Request:(id)arg2
{
NSLog(@"platMsg:%@",arg1.platMsg);
NSLog(@"cgiCmdid:%d",arg1.cgiCmdid);
NSLog(@"platRet:%d",arg1.platRet);
NSLog(@"errorType:%d",arg1.errorType);
NSLog(@"errorMsg:%@",arg1.errorMsg);
NSData *buffer = arg1.retText.buffer;
NSString *aString = [[NSString alloc] initWithData:buffer encoding:NSUTF8StringEncoding];
NSLog(@"retText:%@",aString);
%orig;
}
打印輸出:
2018-05-28 11:31:44.197315+0800 WeChat[28877:2671064] platMsg:
2018-05-28 11:31:44.197483+0800 WeChat[28877:2671064] cgiCmdid:3
2018-05-28 11:31:44.197575+0800 WeChat[28877:2671064] platRet:0
2018-05-28 11:31:44.197654+0800 WeChat[28877:2671064] errorType:0
2018-05-28 11:31:44.197852+0800 WeChat[28877:2671064] errorMsg:ok
2018-05-28 11:31:44.198045+0800 WeChat[28877:2671064] retText:{"retcode":0,"retmsg":"ok","sendId":"1000039501201805287004922762149","wishing":"恭喜發(fā)財,大吉大利","isSender":0,"receiveStatus":0,"hbStatus":2,"statusMess":"給你發(fā)了一個紅包","hbType":0,"watermark":"","sendUserName":"wxid_hy6hye79l4q241","timingIdentifier":"35971B49DE4AE3E604E17E3EAB463272"}
可以得到retText:中有timingIdentifier
- 所以獲取timingIdentifier
在收到紅包消息時主動調(diào)用ReceiverQueryRedEnvelopesRequest:方法激蹲,然后在- (void)OnWCToHongbaoCommonResponse:(HongBaoRes *)arg1 Request:(id)arg2方法中的第一個參數(shù)HongBaoRes的retText屬性里面包含timingIdentifier - 分析HongBaoRes參數(shù)
cgiCmdid==3棉磨,點(diǎn)擊紅包消息,沒有被搶過的紅包
HongBaoRes的retText中:
receiveStatus == 0沒有搶過的紅包 receiveStatus == 2搶過的紅包;isSender==0自己不是發(fā)紅包消息的人;isSender==1自己發(fā)的紅包
- 獲取到timingIdentifier
要在紅包還沒有搶過的情況下才搶紅包
NSError *error;
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:arg1.retText.buffer options:NSJSONReadingMutableContainers error:&error];
NSString *receiveStatus =[NSString stringWithFormat:@"%@",responseDict[@"receiveStatus"]];
if(arg1 !=nil && arg2 !=nil && arg1.cgiCmdid==3 && [receiveStatus isEqualToString:@"0"])//沒有被搶過的紅包
{
NSString *timingIdentifier = responseDict[@"timingIdentifier"];
}
那么獲取到timingIdentifier后怎么通知收到紅包消息的方法->CMessageMgr類中的onNewSyncAddMessage:方法呢学辱?而且紅包消息方法一下來很多條呢乘瓤?
我們可以用單例隊(duì)列來保存紅包消息,在獲取到timingIdentifier后取出隊(duì)列中的參數(shù)策泣,然后調(diào)用開紅包方法
三 開始搶紅包
- 單例隊(duì)列來保存紅包消息
WeChatMessageWarp.h
@interface WeChatMessageWarp : NSObject
+(instancetype)shareInstanceQueue;
- (void)inputQueue:(NSMutableDictionary *)param;
- (NSMutableDictionary *)getParamQueue;
@end
WeChatMessageWarp.m
@interface WeChatMessageWarp()
@property (nonatomic,strong)NSMutableArray *queue;
@end
@implementation WeChatMessageWarp
+(instancetype)shareInstanceQueue
{
static WeChatMessageWarp *queue = nil;
static dispatch_once_t once;
dispatch_once(&once,^{
queue = [[WeChatMessageWarp alloc]init];
});
return queue;
}
- (instancetype)init
{
self = [super init];
if (self) {
_queue = [NSMutableArray array];
}
return self;
}
- (void)inputQueue:(NSMutableDictionary *)param{
[self.queue addObject:param];
}
- (NSMutableDictionary *)getParamQueue{
if (self.queue.count == 0 && !self.queue.firstObject) {
return nil;
}
NSMutableDictionary *first = self.queue.firstObject;
[self.queue removeObjectAtIndex:0];
return first;
}
@end
- 在收到紅包消息的時候保存參數(shù)mul_dict衙傀,參數(shù)重可以標(biāo)記是不是自己寫的紅包插件
WeChatMessageWarp *share = [WeChatMessageWarp shareInstanceQueue];
//標(biāo)記是插件搶紅包
[mul_dict setObject:@"YES" forKey:@"isMySelfMeryin"];
[share inputQueue:mul_dict];
- 然后在獲取到timingIdentifier后把參數(shù)取出來,并判斷是不是自己寫的插件
WeChatMessageWarp *share = [WeChatMessageWarp shareInstanceQueue];
NSMutableDictionary *warp = [share getParamQueue];
NSString *flag = [warp objectForKey:@"isMySelfMeryin"];
if(![flag isEqualToString:@"YES"]){//自己寫的插件搶紅包
return;
}
[warp removeObjectForKey:@"isMySelfMeryin"];
if(timingIdentifier.length >0 && warp.count >0){
[warp setObject:timingIdentifier forKey:@"timingIdentifier"];
}
- 開始搶紅包
搶紅包的時候萨咕,要判斷插件是否設(shè)置了延遲時間统抬,然后延遲幾秒開始搶紅包
//開始開紅包
WCRedEnvelopesLogicMgr *envelopesLogicMgr = [[%c(MMServiceCenter) defaultCenter] getService:[%c(WCRedEnvelopesLogicMgr) class]];
if(envelopesLogicMgr){
//延遲搶紅包時間
NSString *time = [WCDefaults valueForKey:WCTIMEKEY];
float second = 1;
if(time){//默認(rèn)1秒
second =[time floatValue];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(second * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[envelopesLogicMgr OpenRedEnvelopesRequest:warp];
});
}
四 優(yōu)化工程結(jié)構(gòu)
完成了自動搶紅包代碼后,一個類中的代碼太多危队,我們可以按功能拆分代碼
- 把設(shè)置界面的代碼出來
新建->iOS -Other -Empty->WeChatSettingViewControllerCell.xm 注意targets勾選dylib
把設(shè)置界面的代碼拷貝到WeChatSettingViewControllerCell.xm 然后build生成WeChatSettingViewControllerCell.mm聪建,然后把.mm拖到工程中,注意targets勾選dylib