Android感知View的出现

最近在做一个播放组件端上防作弊的效果,播放的时候判断广告是否被部分或者完全遮挡了。

比较重要的载体是Window,实际的表现形式是View,所以重点往监控Window和View的创建这样的思路出发。

目前的话一共想到三种方案:
①监控View的创建:
通过给LayoutInflater 设置factory2来感知View的创建:

LayoutInflater.from(context).setFactory2()

当LayoutInflater调用createViewFromTag时:

 View view;
  	 if (mFactory2 != null) {
  	     view = mFactory2.onCreateView(parent, name, context, attrs);
  	 } else if (mFactory != null) {
  	     view = mFactory.onCreateView(name, context, attrs);
  	 } else {
  	     view = null;
  	 }

给设置的factory2接口方法onCreateView就能感知到。
缺点是场景有限,只有需要解析xml生成View的时候才能感知到,直接new View就不行了。

②监听Window的创建
创建Window是这么创建的:

Window w = PolicyManager.makeNewWindow(mContext);
#PolicyManager
public static Window makeNewWindow(Context context) {
    return sPolicy.makeNewWindow(context);
}

而这个spolicy是个静态接口对象
private static final IPolicy sPolicy;
实现是com.android.internal.policy.impl.Policy
所以我们可以hook这个sPolicy对象,感知makeNewWindow的时机。
缺点:高版本中不用PolicyManager创建Window,相应的代码处直接变为new PhoneWindow()

③监听WindowManager.addView方法
WindowManagerService服务在app本地的代理对象为WindowMangerImpl,而里面依赖了WindowManagerGlobal这个对象,它是个单例,但是不是个接口,就不能用动态代理的方式去hook。hook WindowManagerGlobal的好处是兼容性强,这个类从低版本到高版本几乎没修改过。

在WindowManagerGlobal有几个:

private final ArrayList mViews = new ArrayList();
private final ArrayList mRoots = new ArrayList();
private final ArrayList mParams =
        new ArrayList();

他们会在调用addView,removeView,updateView时做操作,所以通过hook这些集合也可以感知到addView的出现:写一个继承ArrayList的ObserverList,覆写add的方法,替换回去。

还有一个比较关键的是需要知道加进来这个View在屏幕的位置,通过是
view.getLocationOnScreen(int[])
这个方法可以得到view在屏幕的位置,接着拿到view的宽高判断和我们View的重叠和层级关系。

④跨进程的Dialog,比如crash弹窗:
这个可以根据点击事件的MotionEvent的flag来判断是否有遮挡:
https://stackoverflow.com/questions/44197671/detecting-android-screen-overlays-programmatically

你可能感兴趣的:(android学习笔记)