全局置灰实现:

思路: 给视图加上饱和度为0的滤镜。即 window 的 layer 上设置 filters。

  1. 生成CAFilter 颜色饱和度滤镜
CAFilter *filter = [CAFilter filterWithName:colorSaturate];
  1. 设置饱和度为0
[filter inputAmount:0];
  1. 赋值给 window (此处可以替换为keywindow)
[NMIoc_App appDelegate].window.layer.filters = @[filter];

部分页面置灰实现:

  1. 在App启动时通过配置中心获取执行黑/白名单模式,以及页面黑名单和页面白名单
  2. Hook viewWillAppearviewDidDisappear,判断是否处于命中页面
  3. viewWillAppear 设置 window 的滤镜
  4. viewDidDisappear 移除 window 滤镜

不把饱和度滤镜加 window 上的话,可能会导致首屏 tabbar 等元素是彩色的。

实现的细节:

  1. App前后台切换,需要更新滤镜状态
  2. 配置变更时更新配置

配置数据样例

缺省配置

[
    {
        "type":"colorSaturateZero",
        "strategy":"none",
        "startTime":1234567890,//单位毫秒
        "endTime":1234567890//单位毫秒
    }
]

全局配置

[
    {
        "type":"colorSaturateZero",
        "strategy":"global",
        "startTime":1234567890,
        "endTime":1234567890
    }
]

白名单模式

[
    {
        "type":"colorSaturateZero",
        "strategy":"whitelist",
        "startTime":1234567890,
        "endTime":1234567890,
        "iOSIdentify":[
            "需要置灰的页面A",
            "需要置灰的页面B"
        ],
        "androidIdentify":[
            "需要置灰的页面A",
            "需要置灰的页面B"
        ]
    }
]

黑名单模式

[
    {
        "type":"colorSaturateZero",
        "strategy":"blacklist",
        "startTime":1234567890,
        "endTime":1234567890,
        "iOSIdentify":[
            "不需要置灰的页面A",
            "不需要置灰的页面B"
        ],
        "androidIdentify":[
            "不需要置灰的页面A",
            "不需要置灰的页面B"
        ]
    }
]

特殊处理

*音乐 iPad 端页面

  1. 大部分分屏页面都没有 viewWillAppearviewDidDisappear 事件,需要结合监听 kNavigationPageChangedNotification 通知来获取页面变动事件。
  2. 需要额外 Hook View的生命周期。在通知产生后核对顶部视图的状态,如果命中置灰逻辑,则将VC对应的View记录下来,在Hook View的生命周期时对记录的View进行置灰处理。
  3. 分屏页面的出现导致无法使用windows滤镜,会污染被部分展示的白名单页面。所以只能设置 VC 对应 view 的滤镜。

广告页的异常情况

在*音乐iPhone端中,广告视图是另外创建的window,需要覆盖广告window的话,还需要Hook UIWindow makeKeyAndVisible来达到对新展示的window的覆盖效果。