EventBus Proguard

以前并没用过EventBus,因为业务做的不是很多,后面渐渐地从业务脱离出来,有一阵子项目引入了eventbus,后来同事说不能混淆onEvent*,我说这个不是很不爽吗? 前一阵子再次使用,就研究了一下这东西。 源码SubscriberMethodFinder.java

private static final String ON_EVENT_METHOD_NAME = "onEvent";
private void filterSubscriberMethods(List<SubscriberMethod> subscriberMethods,
                                      HashMap<String, Class> eventTypesFound, StringBuilder methodKeyBuilder,
                                      Method[] methods) {
     for (Method method : methods) {
         String methodName = method.getName();
         if (methodName.startsWith(ON_EVENT_METHOD_NAME)) {
             int modifiers = method.getModifiers();
             Class<?> methodClass = method.getDeclaringClass();
             if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                 Class<?>[] parameterTypes = method.getParameterTypes();
                 if (parameterTypes.length == 1) {
                     ThreadMode threadMode = getThreadMode(methodClass, method, methodName);
                     if (threadMode == null) {
                         continue;
                     }
                     Class<?> eventType = parameterTypes[0];
                     methodKeyBuilder.setLength(0);
                     methodKeyBuilder.append(methodName);
                     methodKeyBuilder.append('>').append(eventType.getName());
                     String methodKey = methodKeyBuilder.toString();
                     Class methodClassOld = eventTypesFound.put(methodKey, methodClass);
                     if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
                         // Only add if not already found in a sub class
                         subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
                     } else {
                         // Revert the put, old class is further down the class hierarchy
                         eventTypesFound.put(methodKey, methodClassOld);
                     }
                 }
             } else if (!skipMethodVerificationForClasses.containsKey(methodClass)) {
                 Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + methodClass + "."
                         + methodName);
             }
         }
     }
 }
 private ThreadMode getThreadMode(Class<?> clazz, Method method, String methodName) {
       String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());
       ThreadMode threadMode;
       if (modifierString.length() == 0) {
           threadMode = ThreadMode.PostThread;
       } else if (modifierString.equals("MainThread")) {
           threadMode = ThreadMode.MainThread;
       } else if (modifierString.equals("BackgroundThread")) {
           threadMode = ThreadMode.BackgroundThread;
       } else if (modifierString.equals("Async")) {
           threadMode = ThreadMode.Async;
       } else {
           if (!skipMethodVerificationForClasses.containsKey(clazz)) {
               throw new EventBusException("Illegal onEvent method, check for typos: " + method);
           } else {
               threadMode = null;
           }
       }
       return threadMode;
   }

核心的两处已经出来了,filterSubscriberMethods会把所有的method判断是否有onEvent开头,如果是的话就过滤出来,然后判断ThreadMode 方法getThreadMode判断onEvent后面的字符串,判断进程模式。 所以原来的一定要keep onEvent*了

支持混淆?

定义接口如下,接口也可能混淆,所以在接口里面定义了两个final类型的常量,一个是方法名,另一个是方法,接口里面只有一个方法,所谓直接去数组里面 就好了,这个是postThread,其余的类似。接口 IEventInterface从四种event模型集成

package de.greenrobot.event.proguard;

import java.lang.reflect.Method;

/**
 * Created by BunnyBlue on 11/6/15.
 */
public interface IEventPostThread {
    public  static  final  String onEventPostThread_METHOD_NAME=IEventPostThread.class.getDeclaredMethods()[0].getName();
    public  static  final Method onEventMainThread_METHOD=IEventPostThread.class.getDeclaredMethods()[0];
    /**
     * 使用onEvent来接收事件,那么接收事件和分发事件在一个线程中执行
     *
     * @param event
     */
    public void onEvent(IEvent event) ;
}

修改filterSubscriberMethods

我们知道IEventInterface继承了四种event模型,我们直接取方法就行了,线性取就好了。

private void filterSubscriberMethods(List<SubscriberMethod> subscriberMethods,
                                         HashMap<String, Class> eventTypesFound, StringBuilder methodKeyBuilder,
                                         Class<IEventInterface> clazz) {


        try {
            Method onevet=IEventPostThread.class.getMethods()[0];
            Method event=    clazz.getDeclaredMethod(onevet.getName(), onevet.getParameterTypes());
            proguardWrap(event, ThreadMode.PostThread, subscriberMethods, eventTypesFound, methodKeyBuilder);
            //
            Method mEventAsync=IEventAsync.class.getMethods()[0];
            Method eventEventAsync=    clazz.getDeclaredMethod(mEventAsync.getName(), mEventAsync.getParameterTypes());
            proguardWrap(eventEventAsync, ThreadMode.Async, subscriberMethods, eventTypesFound, methodKeyBuilder);
            //
            Method mEventMainThread=IEventMainThread.class.getMethods()[0];
            Method eventMainThread=    clazz.getDeclaredMethod(mEventMainThread.getName(), mEventMainThread.getParameterTypes());
            proguardWrap(eventMainThread, ThreadMode.MainThread, subscriberMethods, eventTypesFound, methodKeyBuilder);
            //
            Method iEventBackgroundThread=IEventBackgroundThread.class.getMethods()[0];
            Method mEventBackgroundThread=    clazz.getDeclaredMethod(iEventBackgroundThread.getName(), iEventBackgroundThread.getParameterTypes());
            proguardWrap(mEventBackgroundThread, ThreadMode.BackgroundThread, subscriberMethods, eventTypesFound, methodKeyBuilder);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

    }
    private void proguardWrap(Method method,ThreadMode threadMode,List<SubscriberMethod> subscriberMethods, HashMap<String, Class> eventTypesFound, StringBuilder methodKeyBuilder) {
        String methodName = method.getName();
        int modifiers = method.getModifiers();
        Class<?> methodClass = method.getDeclaringClass();
        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length == 1) {
//                        }
                Class<?> eventType = parameterTypes[0];
                methodKeyBuilder.setLength(0);
                methodKeyBuilder.append(methodName);
                methodKeyBuilder.append('>').append(eventType.getName());
                String methodKey = methodKeyBuilder.toString();
                Class methodClassOld = eventTypesFound.put(methodKey, methodClass);
                if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
                    // Only add if not already found in a sub class
                    subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
                } else {
                    // Revert the put, old class is further down the class hierarchy
                    eventTypesFound.put(methodKey, methodClassOld);
                }
            }
        } else if (!skipMethodVerificationForClasses.containsKey(methodClass)) {
            Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + methodClass + "."
                    + methodName);
        }
        //   }
        //  }
    }

所有的Event从实现IEvent,IEvent只是一个空接口. 这样既可以混淆了

问题来了,接口里面的东西可能被抹掉 新版本的Proguard可能存在这问题

解决方案,新建一个空壳Activity,然后然后走一次空实现,就不需要在keep了

package io.github.bunnyblue.eventbus;

import android.app.Activity;
import android.os.Bundle;

import de.greenrobot.event.proguard.IEvent;
import de.greenrobot.event.proguard.IEventAsync;
import de.greenrobot.event.proguard.IEventBackgroundThread;
import de.greenrobot.event.proguard.IEventInterface;
import de.greenrobot.event.proguard.IEventMainThread;
import de.greenrobot.event.proguard.IEventPostThread;

public class ShellActivity extends Activity implements IEventInterface {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        finish();
        IEventMainThread mainThread=this;
        mainThread.onEventMainThread(new ShellEvent());
        IEventPostThread iEvent=this;
        iEvent.onEvent(new ShellEvent());
        IEventAsync iEventAsync=this;
        iEventAsync.onEventAsync(new ShellEvent());
        IEventBackgroundThread iEventBackgroundThread=this;
        iEventBackgroundThread.onEventBackgroundThread(new ShellEvent());
    }

    @Override
    public void onEventAsync(IEvent event) {

    }

    @Override
    public void onEventBackgroundThread(IEvent event) {

    }

    @Override
    public void onEventMainThread(IEvent event) {

    }

    @Override
    public void onEvent(IEvent event) {

    }
}