QigsawBundle技术细节

2021-03-30  本文已影响0人  DonaldDu

最新依赖-jitpack
Google的AAB出来好久了,但在国内一直没法用。知道Qigsaw后就开始学习,弄了好久都没学会,太烦了中途都放弃了。后来有时间了,又来学习这个,因为真实用啊!

直到学会了,还有问题

学会后,我觉得不应该这样麻烦,是可以非常简单的!
可以把Qigsaw拆分为运行框架和打包工具,因此有了QigsawBundle

DynamicProvider

Provider在应用启动时就会被调用,Dynamic中的Provider第一次启动是找不到的,应用会直接报错,无法启动。Qigsaw为每个DynamicProvider生成了一个装饰类,找不到原DynamicProvider时,就调用装饰类。

QigsawBundle不生成任何装饰类,而是通过工具DynamicProviderSwitch自动把DynamicProvider设置为关闭状态(android:enabled="false")。启动应用时,再读取manifest中哪些DynamicProvider类存在,如果存在则启动Provider,不存在则忽略。Split安装后重试未启动成功的DynamicProvider。

DynamicProviderSwitch:编译时自动关闭Split中的Provider,应用启动时,启动存在的DynamicProvider。

DynamicProviderSwitch支持Google的AAB,可以直接用在海外版的App中

Activity/Service/BroadcastReceiver

Qigsaw打包时,织入了一些代码。经测试证明,不需要在编译期间织入代码的,
Activity/Service/BroadcastReceiver都可以通过运行时代码解决。
可以在ActivityLifecycleCallbacks.onActivityPreCreated中loadResources,
另外两个使用的application.resources ,所以不需要处理。

以下代码都测试通过了。

override fun onActivityPreCreated(activity: Activity, savedInstanceState: Bundle?) {
    SplitInstallHelper.loadResources(activity, activity.resources)
}
Service.resources ==applicationContext.resources//true
BroadcastReceiver.context.resources==context.applicationContext.resources//true

onActivityPreCreated 只有Android10+才支持,之前的版本没有用。所以需要用织入代码的方式来解决。

QigsawBundle在onActivityPreCreated中注入resources,因此省去了编译期织入代码。

    private Qigsaw(Context context, Downloader downloader, @NonNull SplitConfiguration splitConfiguration) {
        this.context = context;
        this.downloader = downloader;
        this.splitConfiguration = splitConfiguration;
        this.currentProcessName = ProcessUtil.getProcessName(context);
        this.isMainProcess = context.getPackageName().equals(currentProcessName);
        InjectActivityResource.inject((Application) context);//QigsawBundle注入resources
    }

CompatBundle

为了让独立打包的Split能运行起来,需要Qigsaw框架做一些兼容处理。如果不实现以下接口,则完全按照标准的Qigsaw方式运行。具体使用参考Demo。

public interface ICompatBundle {
    /**
     * for 'parseSplitContentsForDefaultVersion'
     */
    @Nullable
    String readDefaultSplitVersionContent(@NonNull Context context, @NonNull String fileName);

    @NonNull
    String getMD5(@NonNull File file);

    @NonNull
    String getMD5(@NonNull InputStream inputStream);

    /**
     * 在onActivityPreCreated中注入resources
     */
    boolean injectActivityResource();

    /**
     * 因为没有生成任何装饰类,所以ComponentInfoManager是没有数据的,所以需要禁用了
     */
    boolean disableComponentInfoManager();

    /**
     * 没有自动生成的 qigsawConfig,需要指定一个自己创建的
     */
    Class<?> qigsawConfigClass();
}

ApkMd5

QigsawBundle中所有Apk计算MD5都使用的ApkMd5,源码也在项目中。

ApkMd5:"AndroidManifest.xml"去掉版本号,去掉"META-INF/BNDLTOOL.RSA"、 "META-INF/BNDLTOOL.SF"、"META-INF/MANIFEST.MF",所有文件排序,再计算APK的MD5。

QigsawBundle可以做到:只修改Base的版本号(versionName&versionCode),然后打包。所有Split的ApkMd5值都是固定的,仅Base包变了。proguard存在一个BUG,需要特别方法才能做到这样。具体请参考 稳定混淆App

DEMO

有时间了会写个QigsawBundle使用介绍,先写了个原理。
DEMO

最后

如果本文帮助到了你,也帮我点个赞吧!

如果你愿意,还可以赞赏一杯咖啡或一瓶水,非常感觉你的慷慨!

上一篇 下一篇

猜你喜欢

热点阅读