Tinker源码分析(一):TinkerApplication

栏目: 编程工具 · 发布时间: 5年前

内容简介:接入 Tinker 第一步就是改造 Application 。官方推荐是利用 @DefaultLifeCycle 动态生成 Application那我们来解析一下 Tinker 是如何生成 Application 以及在 Application 中做了什么事?看到 @DefaultLifeCycle 注解,我们可想而知应该是经过 processor 处理后动态生成了 Application 。

接入 Tinker 第一步就是改造 Application 。官方推荐是利用 @DefaultLifeCycle 动态生成 Application

@DefaultLifeCycle(application = "tinker.sample.android.app.SampleApplication",
                  flags = ShareConstants.TINKER_ENABLE_ALL,
                  loadVerifyFlag = false)
public class SampleApplicationLike extends DefaultApplicationLike {
}

那我们来解析一下 Tinker 是如何生成 Application 以及在 Application 中做了什么事?

看到 @DefaultLifeCycle 注解,我们可想而知应该是经过 processor 处理后动态生成了 Application 。

查看 Tinker 工程可以发现在 tinker-android-anno 下面有一个 AnnotationProcessor

@Override
public Set<String> getSupportedAnnotationTypes() {
    final Set<String> supportedAnnotationTypes = new LinkedHashSet<>();

    supportedAnnotationTypes.add(DefaultLifeCycle.class.getName());

    return supportedAnnotationTypes;
}

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    processDefaultLifeCycle(roundEnv.getElementsAnnotatedWith(DefaultLifeCycle.class));
    return true;
}

发现它正是处理 @DefaultLifeCycle 的。

下面重要看 processDefaultLifeCycle 方法。

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);

        String applicationClassName = ca.application();
        if (applicationClassName.startsWith(".")) {
            applicationClassName = lifeCyclePackageName + applicationClassName;
        }
        String applicationPackageName = applicationClassName.substring(0, applicationClassName.lastIndexOf('.'));
        applicationClassName = applicationClassName.substring(applicationClassName.lastIndexOf('.') + 1);

        String loaderClassName = ca.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 {
            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());
        }
    }
}

整个 processDefaultLifeCycle 方法看下来,其实主要在做的就是去读取一份模版,然后用注解中设置的值替换里面的一些占位符。这个模版就是 resouces/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%);
    }

}

最终生成的 SampleApplication 效果:

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

    public SampleApplication() {
        super(7, "tinker.sample.android.app.SampleApplicationLike", "com.tencent.tinker.loader.TinkerLoader", false);
    }

}

解析 TinkerApplication

想要知道 TinkerApplication 里面干了什么?

一起看看 TinkerApplication.onCreate

@Override
public void onCreate() {
    super.onCreate();
    try {
        ensureDelegate();
        try {
            ComponentHotplug.ensureComponentHotplugInstalled(this);
        } catch (UnsupportedEnvironmentException e) {
            throw new TinkerRuntimeException("failed to make sure that ComponentHotplug logic is fine.", e);
        }
        invokeAppLikeOnCreate(applicationLike);
    } catch (TinkerRuntimeException e) {
        throw e;
    } catch (Throwable thr) {
        throw new TinkerRuntimeException(thr.getMessage(), thr);
    }
}

第一步,调用 ensureDelegate 创建 application 代理,即 applicationLike

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

private Object createDelegate() {
    try {
        // Use reflection to create the delegate so it doesn't need to go into the primary dex.
        // And we can also patch it
        Class<?> delegateClass = Class.forName(delegateClassName, false, getClassLoader());
        Constructor<?> constructor = delegateClass.getConstructor(Application.class, int.class, boolean.class,
            long.class, long.class, Intent.class);
        return constructor.newInstance(this, tinkerFlags, tinkerLoadVerifyFlag,
            applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);
    } catch (Throwable e) {
        throw new TinkerRuntimeException("createDelegate failed", e);
    }
}

然后调用 invokeAppLikeOnCreate(applicationLike) 去回调 applicationLike 的 onCreate 方法。这样,applicationLike 和 application 的生命周期方法就做到同步了。另外,其余的生命周期方法也是如此来实现同步的,这里就不详细讲解了。

那么 Tinker 是什么时候加载的呢?

答案就在 attachBaseContext 中

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

private void onBaseContextAttached(Context base) {
    try {
        applicationStartElapsedTime = SystemClock.elapsedRealtime();
        applicationStartMillisTime = System.currentTimeMillis();
        loadTinker();
        ensureDelegate();
        invokeAppLikeOnBaseContextAttached(applicationLike, base);
        //reset save mode
        if (useSafeMode) {
            ShareTinkerInternals.setSafeModeCount(this, 0);
        }
    } catch (TinkerRuntimeException e) {
        throw e;
    } catch (Throwable thr) {
        throw new TinkerRuntimeException(thr.getMessage(), thr);
    }
}

可以看到调用了 loadTinker 方法。

private void loadTinker() {
    try {
        //reflect tinker loader, because loaderClass may be define by user!
        Class<?> tinkerLoadClass = Class.forName(loaderClassName, false, getClassLoader());
        Method loadMethod = tinkerLoadClass.getMethod(TINKER_LOADER_METHOD, TinkerApplication.class);
        Constructor<?> constructor = tinkerLoadClass.getConstructor();
        tinkerResultIntent = (Intent) loadMethod.invoke(constructor.newInstance(), this);
    } catch (Throwable e) {
        //has exception, put exception error code
        tinkerResultIntent = new Intent();
        ShareIntentUtil.setIntentReturnCode(tinkerResultIntent, ShareConstants.ERROR_LOAD_PATCH_UNKNOWN_EXCEPTION);
        tinkerResultIntent.putExtra(INTENT_PATCH_EXCEPTION, e);
    }
}

这里的 loaderClassName 就是上面 @DefaultLifeCycle 中定义的 loaderClass 。默认的是 com.tencent.tinker.loader.TinkerLoader ,也支持用户自定义 TinkerLoader 。

所以 loadTinker 中干的事就是利用反射执行了 TinkerLoader.tryLoad 方法。

至于在 tryLoad 方法中到底做了什么事,我们等到下一篇再讲吧。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Data Mining

Web Data Mining

Bing Liu / Springer / 2006-12-28 / USD 59.95

Web mining aims to discover useful information and knowledge from the Web hyperlink structure, page contents, and usage data. Although Web mining uses many conventional data mining techniques, it is n......一起来看看 《Web Data Mining》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具