如何拿到插件Apk的Intent Filter?

加载插件时需要获取到插件APK的详细信息,比如AndroidManifest.xml中注册的四大组件。Android SDK提供了接口,如下:

PackageManager pm = getPackageManager();

PackageInfo packageInfo = pm.getPackageArchiveInfo(
        apkFile.getAbsolutePath(), PackageManager.GET_ACTIVITIES
                | PackageManager.GET_SERVICES
                | PackageManager.GET_PROVIDERS
                | PackageManager.GET_RECEIVERS
                | PackageManager.GET_META_DATA);

ActivityInfo[] activityInfos = packageInfo.activities;
ApplicationInfo applicationinfo = packageInfo.applicationInfo;
Bundle metaData = applicationinfo.metaData;
ServiceInfo[] serviceInfos = packageInfo.services;
ProviderInfo[] providerInfos = packageInfo.providers;
ActivityInfo[] receiverInfos = packageInfo.receivers;

我们重点关注一下Activity,发现ActivityInfo中基本的信息都有,包括name、processName、theme、configChanges、launchMode等,不过缺少一个非常关键的东西,那就是Intent-Filter。

为什么我会专门提到这个呢?如果我们启动插件中的组件时直接指定类名,那确实不用理会Intent-Filter了,直接按name查找组件就OK了。比如我们目前使用的插件框架,调起插件Apk中的Activity都是通过指定Activity的类名来查找对应的Activity并将其当做普通类调起,然后在一个Proxy Activity中调用其生命周期的回调。如果要调起插件Apk中的Launcher Activity,宿主APP是无法知道谁是插件的Launcher Activity的,因为我们拿不到Intent-Filter。解决办法是在插件的AndroidManifest.xml的meta-data中声明一个专用类,宿主APP会调用该类的特定函数来启动Launcher Activity,由于是插件内部类调的,所以插件自己当然知道哪个是Launcher Activity,宿主就不用操心了。这一系列做法虽然能解决问题,不过总显得很累赘和不自然,别人为了做插件需要额外增加不少工作量,而本文就是为了解决这一系列问题提出一些思路。

这里核心问题是如何在SDK未提供相应接口的情况下获取Activity的Intent Filter。

我们先看看pm.getPackageArchiveInfo的实现,或许其中可以发现点什么:

public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {
    final PackageParser parser = new PackageParser();
    final File apkFile = new File(archiveFilePath);
    try {
        PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);
        PackageUserState state = new PackageUserState();
        return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
    } catch (PackageParserException e) {
        return null;
    }
}

这里先新建一个PackageParser,调用parseMonolithicPackage生成Package,然后调用其静态函数generatePackageInfo来解析并生成PackageInfo。值得一提的是这个parseMonolithicPackage用于解析单独的apk文件,如果是apk的目录则用parseClusterPackage函数解析。在PackageParser中有一个函数会自动根据apk文件类型来分别调用对应的解析函数,如下:

public Package parsePackage(File packageFile, int flags) throws PackageParserException {
    if (packageFile.isDirectory()) {
        return parseClusterPackage(packageFile, flags);
    } else {
        return parseMonolithicPackage(packageFile, flags);
    }
}

接下来我们看看parseMonolithicPackage的实现:

public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
    final AssetManager assets = new AssetManager();
    try {
        final Package pkg = parseBaseApk(apkFile, assets, flags);
        pkg.codePath = apkFile.getAbsolutePath();
        return pkg;
    } finally {
        IoUtils.closeQuietly(assets);
    }
}

可见这里核心是调用了parseBaseApk,继续看下去:


                
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风语

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值