1、明确需求
腾讯视频每次进入播放界面时都会先播放广告再播放正片,现在的需求就是去掉片头广告。
2、整理思路
整体方向和喜马拉雅暂停广告一致,找到广告的所属类,然后hook初始化方法返回nil。
第一步:找到需要hook的类
使用Reveal来查看一下广告View层级结构:
广告最外层的View是QNBPlayerVideoAdsView,且它所属的ViewController是QADMediaAdViewController,那么只要hook一下QNBPlayerVideoAdsViewController的初始化方法应该就可以去掉广告了。在QNBPlayerVideoAdsViewController的父类QNBBasePlayerViewController中找到了初始化方法:
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withPageViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5;
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5;
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withAddToParenViewControllerNow:(_Bool)arg4;
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4;
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3;
3、编写代码
尝试hook广告View所属控制器的初始化方法:
%hook QNBPlayerVideoAdsViewController
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withPageViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5 {
return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5 {
return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withAddToParenViewControllerNow:(_Bool)arg4 {
return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4 {
return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 {
return nil;
}
%end
运行后发现虽然片头广告的View层消失了,但是还会播放音频,播放结束后才能观看正片,所以只是将QNBPlayerVideoAdsViewController的初始化方法hook掉是不够的,那么再梳理一下QNBPlayerVideoAdsView的层级结构:
层级 | View | 所属VC | VC父类 |
---|---|---|---|
0 | QNBPlayerVideoAdsView | QNBPlayerVideoAdsViewController | QNBBasePlayerViewController |
1 | QNBPlayerIntellectView | QNBPlayerVideoAdsViewController | |
2 | QADBaseEventView | QADRootViewController | … |
3 | QADGestureView | QADGestureViewController | QADBaseViewController |
3 | QADRichMediaContainerView | QADRichMediaAdViewController | |
3 | QADMediaAdContainSuperView | QADMediaAdViewController | |
4 | QADMediaAdContainView | QADMediaAdViewController |
广告是由多个View组成的,并且由多个控制器管理,那么尝试一下把这些控制器的初始化方法都hook一下试试:
%hook QNBPlayerVideoAdsViewController
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withPageViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5 {
return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5 {
return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withAddToParenViewControllerNow:(_Bool)arg4 {
return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4 {
return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 {
return nil;
}
%end
%hook QADRootViewController
- (id)initWithEventProxy:(id)arg1 withPlayAdInfo:(id)arg2 withParentViewController:(id)arg3 {
return nil;
}
%end
%hook QADGestureViewController
- (id)initWithEventProxy:(id)arg1 withPlayAdInfo:(id)arg2 withParentViewController:(id)arg3 {
return nil;
}
%end
%hook QADRichMediaAdViewController
- (id)initWithEventProxy:(id)arg1 withPlayAdInfo:(id)arg2 withParentViewController:(id)arg3 {
return nil;
}
%end
%hook QADMediaAdViewController
- (id)initWithEventProxy:(id)arg1 withPlayAdInfo:(id)arg2 withParentViewController:(id)arg3 {
return nil;
}
%end
但是结果令人失望,运行后还是之前的效果,广告画面不见了,但是声音还在。但是通过查看这些初始化方法找到了一个共同的特点,都有一个叫做PlayAdInfo的参数中,而且在QNBBasePlayerViewController、QADRootViewController、和QADBaseViewController的头文件中都发现了一个QADPlayAdInfo类的成员变量,所以可以猜测QADPlayAdInfo应该是广告的数据,如果让广告的数据为空,那么广告可能就不会被创建了:
%hook QADPlayAdInfo
- (id)initWithEventProxy:(id)arg1 scrrenMode:(long long)arg2 scenesType:(long long)arg3 {
return nil;
}
%end
运行之后返现广告果然消失了,没想到最后却只用到了这短短的三行代码,但是之前的分析过程也是必不可少的。