爱奇艺框架Qigsaw插件部分源码分析

本文对爱奇艺框架Qigsaw插件部分进行了源码分析。

《咏柳》
碧玉妆成一树高,万条垂下绿丝绦。
不知细叶谁裁出?二月春风似剪刀。
-唐代,贺知章

简介

Qigsaw是一套基于Android App Bundles实现的Android动态组件化方案,它无需应用重新安装即可动态分发插件。

备注:本文基于master分支d9066cc 2020.02.15分析

插件

Qigsaw提供了Gradle插件可以应用在application和dynamic-feature上。如果你想在编译期间将split apk上传到cdn服务器,可以参考SampleSplitApkUploader.groovy自己实现上传逻辑。接下来我们根据Qigsaw提供的demo分析一下Gradle插件的实现,demo中提供了3个feature module,如下图所示:


application插件分析

插件提供了几个任务分别是generateQigsawConfigTask、qigsawInstallTask、qigsawAssembleTask以及qigsawUploadSplitApkTask。

qigsawInstallTask依赖于qigsawAssembleTask的执行,当qigsawAssembleTask执行完成后使用adb完成安装操作。qigsawAssembleTask任务依赖关系如下图,copySplitManifestTask会将dynamic feature的清单文件复制到指定文件夹,copySplitApkTask会将打包成功后的apk复制到指定的文件夹。qigsawAssembleTask任务会收集split的信息存储为json文件,最后会将json和apk文件复制到mergeAssetsTask任务的输出文件夹,apk文件后缀会被修改为zip。

qigsawAssembleTask任务执行完成后会调用app的assembleTask完成打包,可以看到apk的assets目录中存放了各feature的apk(改为了zip后缀)。


json文件中存放了split的各种信息:


dynamic-feature插件分析

QigsawDynamicFeaturePlugin插件中注册了两个Transform。

QigsawDynamicFeaturePlugin.groovy

resourcesLoaderTransform = new SplitResourcesLoaderTransform(project)
SplitLibraryLoaderTransform libraryLoaderTransform = new SplitLibraryLoaderTransform(project)
android.registerTransform(resourcesLoaderTransform)
android.registerTransform(libraryLoaderTransform)

一个是SplitResourcesLoaderTransform,使用asm对activity、service、receiver进行了处理。主要实现逻辑在SplitResourcesLoaderInjector类中:

SplitResourcesLoaderInjector.groovy

byte[] injectClass(Path path, String className) {
    byte[] ret = null
    if (isActivity(className)) {
        println("Inject activity " + className)
        ret = new SplitActivityWeaver().weave(path.newInputStream())
    } else if (isService(className)) {
        println("Inject service " + className)
        ret = serviceWeaver.weave(path.newInputStream())
    } else if (isReceiver(className)) {
        println("Inject receiver " + className)
        ret = receiverWeaver.weave(path.newInputStream())
    }
    return ret
}

针对activity组件重写了getResources方法插入了以下代码:

public Resources getResources() {
   SplitInstallHelper.loadResources(this, super.getResources());
   return super.getResources();
}

针对service组件在onCreate方法中调用了 SplitInstallHelper.loadResources方法,针对receiver组件在onReceive方法中调用了SplitInstallHelper.loadResources方法。

另一个是SplitLibraryLoaderTransform,使用asm新增了一个名为工程名+SplitLibraryLoader的类:
SplitLibraryLoaderTransform.groovy

class SplitLibraryLoaderTransform extends SimpleClassCreatorTransform {
    ...
    @Override
    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
        super.transform(transformInvocation)
        transformInvocation.getOutputProvider().deleteAll()
        def dest = prepareToCreateClass(transformInvocation)
        createSimpleClass(dest, "com.iqiyi.android.qigsaw.core.splitlib." + project.name + "SplitLibraryLoader",
                "java.lang.Object", new SimpleClassCreatorTransform.OnVisitListener() {
            @Override
            void onVisit(ClassWriter cw) {
                MethodVisitor mw = cw.visitMethod(Opcodes.ACC_PUBLIC, "loadSplitLibrary", "(Ljava/lang/String;)V", null, null)
                mw.visitVarInsn(Opcodes.ALOAD, 1)
                mw.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "loadLibrary", "(Ljava/lang/String;)V", false)
                mw.visitInsn(Opcodes.RETURN)
                mw.visitMaxs(2, 1)
                mw.visitEnd()
                System.out.println()
            }
        })
    }
}

生成的类如下:

public class javaSplitLibraryLoader {
    public javaSplitLibraryLoader() {
    }

    public void loadSplitLibrary(String var1) {
        System.loadLibrary(var1);
    }
}

总结

Qigsaw提供了两种插件,一种应用在application工程上,主要作用是新增了几个打包相关的Task,执行打包操作前会先对feature库进行打包,然后会收集split的信息存储为json文件,将json文件和apk文件复制到mergeAssetsTask任务的输出文件夹,apk文件后缀会被修改为zip,最后执行application的打包Task,这样最终会将feature apk和相关json信息内置到assets目录下;另一种是应用在dynamic-feature工程上,主要作用是使用asm对feature库的activity、service、receiver组件插入了获取资源的相关代码SplitInstallHelper.loadResources,另外新增了一个名为工程名+SplitLibraryLoader的类。

参考

  • https://github.com/iqiyi/Qigsaw

你可能感兴趣的:(爱奇艺框架Qigsaw插件部分源码分析)