Android开发之Tinker源码解析系列—Application代理机制

引言

我们知道Tinker实现热修复的原理是将自己的全量patch包插入到dexElements数组的前段,从而达到热修复的目的。

以下所有对源码的分析均基于Tinker 1.7.7 版本

Application代理机制

通常我们都是在Application中进行一些初始化的工作,包括tinker的初始化,那么application中所涉及到的类,在tinker初始化完成前就已经被类加载器所加载了,那么我们之前所说的通过将我们的补丁dex包插入到dexElements数组的前段的方法就不起作用了,Tinker是怎么解决这一问题的从而达到能修复Application中所使用到的类的呢?

看过tinker的官方接入文档的同学肯定知道,tinker推荐我们将自己的Application继承自ApplicationLike,那么,我们的切入点便是这里,我们先看一下ApplicationLike的源码(源码较长,只贴出关键部分,下同)

public abstract class ApplicationLike implements ApplicationLifeCycle {
    private final Application application;
    private final Intent      tinkerResultIntent;
    private final long        applicationStartElapsedTime;
    private final long        applicationStartMillisTime;
    private final int         tinkerFlags;
    private final boolean     tinkerLoadVerifyFlag;

    public ApplicationLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag,
                           long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) {
        this.application = application;
        this.tinkerFlags = tinkerFlags;
        this.tinkerLoadVerifyFlag = tinkerLoadVerifyFlag;
        this.applicationStartElapsedTime = applicationStartElapsedTime;
        this.applicationStartMillisTime = applicationStartMillisTime;
        this.tinkerResultIntent = tinkerResultIntent;
    }

    ...
}

可以看到,ApplicationLike并不是一个真正意义上的Android中的Application,因为他并没有继承自Application,仅是一个普通的类实现了ApplicationLifeCycle这个接口,我们先看一下ApplicationLifeCycle这个接口源码

public interface ApplicationLifeCycle {

    /**
     * Same as {@link Application#onCreate()}.
     */
    void onCreate();

    /**
     * Same as {@link Application#onLowMemory()}.
     */
    void onLowMemory();

    /**
     * Same as {@link Application#onTrimMemory(int level)}.
     * @param level
     */
    void onTrimMemory(int level);

    /**
     * Same as {@link Application#onTerminate()}.
     */
    void onTerminate();

    /**
     * Same as {@link Application#onConfigurationChanged(Configuration newconfig)}.
     */
    void onConfigurationChanged(Configuration newConfig);

    /**
     * Same as {@link Application#attachBaseContext(Context context)}.
     */
    void onBaseContextAttached(Context base);
}

这个接口里面的几个方法,相信你一定很眼熟,没错,这几个方法均是跟Application有关的生命周期的方法,那么为什么我们继承的是一个普通的类,并不是一个真正的Application,app却没有崩溃并且可以正常运行呢,相信聪明的你可能已经想到了,没错,tinker所采用的方法便是将Application隔离起来,使用了代理的模式,从而解决了我们文章开头提到的问题。所以这里有一个需要注意的点就是,如果你在ApplicationLike中需要使用到Application对象,那么你不能使用this关键字,因为它并不是一个真正意义上的Application,而需要使用ApplicationLike中的getApplication方法获取application对象。

那么在tinker中,真正的Application是哪个呢? 实际上是TinkerApplication,这里我们先看一下TinkerApplication的源码

public abstract class TinkerApplication extends Application {
    ...

    private ApplicationLike applicationLike = null;
    /**
     * current build.
     */
    protected TinkerApplication(int tinkerFlags) {
        this(tinkerFlags, "com.tencent.tinker.loader.app.DefaultApplicationLike", TinkerLoader.class.getName(), false);
    }

    /**
     * @param delegateClassName The fully-qualified name of the {@link ApplicationLifeCycle} class
     *                          that will act as the delegate for application lifecycle callbacks.
     */
    protected TinkerApplication(int tinkerFlags, String delegateClassName,
                                String loaderClassName, boolean tinkerLoadVerifyFlag) {
        this.tinkerFlags = tinkerFlags;
        this.delegateClassName = delegateClassName;
        this.loaderClassName = loaderClassName;
        this.tinkerLoadVerifyFlag = tinkerLoadVerifyFlag;

    }

    protected TinkerApplication(int tinkerFlags, String delegateClassName) {
        this(tinkerFlags, delegateClassName, TinkerLoader.class.getName(), false);
    }

    private ApplicationLike createDelegate() {
        try {
            // 通过反射创建ApplicationLike对象
            Class<?> delegateClass = Class.forName(delegateClassName, false, getClassLoader());
            Constructor<?> constructor = delegateClass.getConstructor(Application.class, int.class, boolean.class,
                long.class, long.class, Intent.class);
            return (ApplicationLike) constructor.newInstance(this, tinkerFlags, tinkerLoadVerifyFlag,
                applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);
        } catch (Throwable e) {
            throw new TinkerRuntimeException("createDelegate failed", e);
        }
    }

    private synchronized void ensureDelegate() {
        if (applicationLike == null) {
            applicationLike = createDelegate();
        }
    }


    private void onBaseContextAttached(Context base) {
        applicationStartElapsedTime = SystemClock.elapsedRealtime();
        applicationStartMillisTime = System.currentTimeMillis();
        //先调用了tinker进行patch等操作
        loadTinker();
       //再创建ApplicationLike对象
        ensureDelegate();
       //最后再执行ApplicationLike的生命周期
        applicationLike.onBaseContextAttached(base);
        ...
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        Thread.setDefaultUncaughtExceptionHandler(new TinkerUncaughtHandler(this));
        onBaseContextAttached(base);
    }

    private void loadTinker() {
        //disable tinker, not need to install
        if (tinkerFlags == TINKER_DISABLE) {
            return;
        }
        tinkerResultIntent = new Intent();
        try {
            //反射调用TinkLoader的tryLoad方法
            Class<?> tinkerLoadClass = Class.forName(loaderClassName, false, getClassLoader());

            Method loadMethod = tinkerLoadClass.getMethod(TINKER_LOADER_METHOD, TinkerApplication.class, int.class, boolean.class);
            Constructor<?> constructor = tinkerLoadClass.getConstructor();
            tinkerResultIntent = (Intent) loadMethod.invoke(constructor.newInstance(), this, tinkerFlags, tinkerLoadVerifyFlag);
        } catch (Throwable e) {
            //has exception, put exception error code
            ShareIntentUtil.setIntentReturnCode(tinkerResultIntent, ShareConstants.ERROR_LOAD_PATCH_UNKNOWN_EXCEPTION);
            tinkerResultIntent.putExtra(INTENT_PATCH_EXCEPTION, e);
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        ensureDelegate();
        applicationLike.onCreate();
    }

    @Override
    public void onTerminate() {
        super.onTerminate();
        if (applicationLike != null) {
            applicationLike.onTerminate();
        }
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        if (applicationLike != null) {
            applicationLike.onLowMemory();
        }
    }

    @TargetApi(14)
    @Override
    public void onTrimMemory(int level) {
        super.onTrimMemory(level);
        if (applicationLike != null) {
            applicationLike.onTrimMemory(level);
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (applicationLike != null) {
            applicationLike.onConfigurationChanged(newConfig);
        }
    }

  ...
}

可以看到,TinkerApplication是继承自Application的,是真正意义上的Application,在它的构造方法中,我们把需要代理的Application类名传递了进来,然后在createDelegate方法中利用反射,构造了一个ApplicationLike的对象,并且在自己的生命周期中调用了ApplicationLike所对应的方法,所以即使ApplicationLike并非真正的Application,却仍能具有Application的生命周期。并且,在onBaseContextAttached方法中,loadTinker方法是先于ensureDelegate方法被调用的,所以能够保证ApplicationLike的创建发生在补丁包合成插入之后,所以也就达到了Application中的类也能被热修复的目的。

到这里,我们已经摸清了整个代理的过程,还有一个问题,就是我们继承了ApplicationLike后的子类是怎么和TinkerApplication关联起来的呢?

这里你当然仍可以采用继承TinkerApplication的方法,然后将所有需要在Application中操作的代码放到继承自ApplicationLike的子类,并将它的类名通过TinkerApplication构造方法进行传递,但是这样很容易对以后维护代码的人造成一定的误解,Tinker为了方便开发者,提供了编译注解的形式以求尽量屏蔽代理的过程,使用注解生成Application类也是Tinker官方文档所推荐的方式。

使用的方式也很简单,在你的ApplicationLike添加以下注解

@DefaultLifeCycle(
application = ".SampleApplication",                       //application类名
flags = ShareConstants.TINKER_ENABLE_ALL,                 //tinkerFlags
loaderClass = "com.tencent.tinker.loader.TinkerLoader",   //loaderClassName, 我们这里使用默认即可!
loadVerifyFlag = false)                                   //tinkerLoadVerifyFlag
public class YourApplicationLike extends DefaultApplicationLike {
      ...
}

这里我们也看一下处理注解逻辑的AnnotationProcessor类,其中processDefaultLifeCycle便是处理该注解的方法

@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class AnnotationProcessor extends AbstractProcessor {

    private static final String APPLICATION_TEMPLATE_PATH = "/TinkerAnnoApplication.tmpl";

    ...
    private void processDefaultLifeCycle(Set<? extends Element> elements) {
        // DefaultLifeCycle
        for (Element e : elements) {
            //获得注解对象
            DefaultLifeCycle ca = e.getAnnotation(DefaultLifeCycle.class);
            //获得全类名
            String lifeCycleClassName = ((TypeElement) e).getQualifiedName().toString();
            //获得包名
            String lifeCyclePackageName = lifeCycleClassName.substring(0, lifeCycleClassName.lastIndexOf('.'));
            //获得类名
            lifeCycleClassName = lifeCycleClassName.substring(lifeCycleClassName.lastIndexOf('.') + 1);
            //获得注解中的Application名
            String applicationClassName = ca.application();
            //补全全类名
            if (applicationClassName.startsWith(".")) {
                applicationClassName = lifeCyclePackageName + applicationClassName;
            }
            String applicationPackageName = applicationClassName.substring(0, applicationClassName.lastIndexOf('.'));
            applicationClassName = applicationClassName.substring(applicationClassName.lastIndexOf('.') + 1);
            //获得注解中的loaderClass名
            String loaderClassName = ca.loaderClass();
            //补全loaderClass类名
            if (loaderClassName.startsWith(".")) {
                loaderClassName = lifeCyclePackageName + loaderClassName;
            }

            System.out.println("*");
            //加载模板
            final InputStream is = AnnotationProcessor.class.getResourceAsStream(APPLICATION_TEMPLATE_PATH);
            final Scanner scanner = new Scanner(is);
            final String template = scanner.useDelimiter("\\A").next();
            //执行替换
            final String fileContent = template
                .replaceAll("%PACKAGE%", applicationPackageName)
                .replaceAll("%APPLICATION%", applicationClassName)
                .replaceAll("%APPLICATION_LIFE_CYCLE%", lifeCyclePackageName + "." + lifeCycleClassName)
                .replaceAll("%TINKER_FLAGS%", "" + ca.flags())
                .replaceAll("%TINKER_LOADER_CLASS%", "" + loaderClassName)
                .replaceAll("%TINKER_LOAD_VERIFY_FLAG%", "" + ca.loadVerifyFlag());

            try {
                //输出为java文件
                JavaFileObject fileObject = processingEnv.getFiler().createSourceFile(applicationPackageName + "." + applicationClassName);
                processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Creating " + fileObject.toUri());
                Writer writer = fileObject.openWriter();
                try {
                    PrintWriter pw = new PrintWriter(writer);
                    pw.print(fileContent);
                    pw.flush();

                } finally {
                    writer.close();
                }
            } catch (IOException x) {
                processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, x.toString());
            }
        }
    }
}

不是很复杂,主要过程就是读取了一个模板文件,然后将对应的字符串进行替换,然后将其以Java文件写入起来,模板文件其实就是TinkerAnnoApplication.tmpl了,内容如下

package %PACKAGE%;

import com.tencent.tinker.loader.app.TinkerApplication;

/**
 *
 * Generated application for tinker life cycle
 *
 */
public class %APPLICATION% extends TinkerApplication {

    public %APPLICATION%() {
        super(%TINKER_FLAGS%, "%APPLICATION_LIFE_CYCLE%", "%TINKER_LOADER_CLASS%", %TINKER_LOAD_VERIFY_FLAG%);
    }

}

到这里,就完成了整个对Application的代理,实现的方式很巧妙,从而使得Tinker也能够对Application中使用到的类进行热修复。

总结

通过阅读源码,我们可以对整个框架的理解和原理更清晰,这里也推荐大家有时间还是要多看看一些优秀的源码,确实对整个编程思想有帮助。那么本文到这里就先告一段落了,如有错误或者不够详细的地方,大家也可以在评论中指出~ 下次将给大家带来Tinker源码中关于patch的部分,敬请期待~ 谢谢大家~

欢迎加入Android开发技术交流群:150923287,获取上图中的技术教程!