美文网首页Android知识Android进阶之路Android开发
Tinker源码解析系列(一)—Application代理机制

Tinker源码解析系列(一)—Application代理机制

作者: EoniJJ | 来源:发表于2017-04-11 16:17 被阅读1491次

    上次我们分析了一下热修复的原理并着手实践了一下,这次将带大家一起探究Tinker源码。

    引言

    从上一篇Android热修复原理探索与实践中我们知道,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的部分,敬请期待~ 谢谢大家~

    相关文章

      网友评论

        本文标题:Tinker源码解析系列(一)—Application代理机制

        本文链接:https://www.haomeiwen.com/subject/gxhqattx.html