1、明确需求

腾讯视频每次进入播放界面时都会先播放广告再播放正片,现在的需求就是去掉片头广告。1.gif

2、整理思路

整体方向和喜马拉雅暂停广告一致,找到广告的所属类,然后hook初始化方法返回nil。
第一步:找到需要hook的类
使用Reveal来查看一下广告View层级结构:
image.png
广告最外层的View是QNBPlayerVideoAdsView,且它所属的ViewController是QADMediaAdViewController,那么只要hook一下QNBPlayerVideoAdsViewController的初始化方法应该就可以去掉广告了。在QNBPlayerVideoAdsViewController的父类QNBBasePlayerViewController中找到了初始化方法:

  1. - (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withPageViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5;
  2. - (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5;
  3. - (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withAddToParenViewControllerNow:(_Bool)arg4;
  4. - (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4;
  5. - (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3;

3、编写代码

尝试hook广告View所属控制器的初始化方法:

  1. %hook QNBPlayerVideoAdsViewController
  2. - (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withPageViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5 {
  3. return nil;
  4. }
  5. - (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5 {
  6. return nil;
  7. }
  8. - (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withAddToParenViewControllerNow:(_Bool)arg4 {
  9. return nil;
  10. }
  11. - (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4 {
  12. return nil;
  13. }
  14. - (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 {
  15. return nil;
  16. }
  17. %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一下试试:

  1. %hook QNBPlayerVideoAdsViewController
  2. - (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withPageViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5 {
  3. return nil;
  4. }
  5. - (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5 {
  6. return nil;
  7. }
  8. - (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withAddToParenViewControllerNow:(_Bool)arg4 {
  9. return nil;
  10. }
  11. - (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4 {
  12. return nil;
  13. }
  14. - (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 {
  15. return nil;
  16. }
  17. %end
  18. %hook QADRootViewController
  19. - (id)initWithEventProxy:(id)arg1 withPlayAdInfo:(id)arg2 withParentViewController:(id)arg3 {
  20. return nil;
  21. }
  22. %end
  23. %hook QADGestureViewController
  24. - (id)initWithEventProxy:(id)arg1 withPlayAdInfo:(id)arg2 withParentViewController:(id)arg3 {
  25. return nil;
  26. }
  27. %end
  28. %hook QADRichMediaAdViewController
  29. - (id)initWithEventProxy:(id)arg1 withPlayAdInfo:(id)arg2 withParentViewController:(id)arg3 {
  30. return nil;
  31. }
  32. %end
  33. %hook QADMediaAdViewController
  34. - (id)initWithEventProxy:(id)arg1 withPlayAdInfo:(id)arg2 withParentViewController:(id)arg3 {
  35. return nil;
  36. }
  37. %end

但是结果令人失望,运行后还是之前的效果,广告画面不见了,但是声音还在。但是通过查看这些初始化方法找到了一个共同的特点,都有一个叫做PlayAdInfo的参数中,而且在QNBBasePlayerViewController、QADRootViewController、和QADBaseViewController的头文件中都发现了一个QADPlayAdInfo类的成员变量,所以可以猜测QADPlayAdInfo应该是广告的数据,如果让广告的数据为空,那么广告可能就不会被创建了:

  1. %hook QADPlayAdInfo
  2. - (id)initWithEventProxy:(id)arg1 scrrenMode:(long long)arg2 scenesType:(long long)arg3 {
  3. return nil;
  4. }
  5. %end

运行之后返现广告果然消失了,没想到最后却只用到了这短短的三行代码,但是之前的分析过程也是必不可少的。

4、最终效果

3.gif