Android动态部署六:如何从插件apk中启动BroadcastReceiver和ContentProvider

本文详细介绍了在Android动态部署过程中,如何动态注册BroadcastReceiver以及ContentProvider的安装和使用流程。通过解析AndroidManifest.xml并调用相关API,实现了无需修改插件apk代码即可启动组件的目标。同时,文章探讨了ContentProvider的安装过程,从应用启动到查询、安装ContentProvider的步骤,为Android开发者提供了实现动态部署的思路。
摘要由CSDN通过智能技术生成

转载请注明出处:http://blog.csdn.net/ximsfei/article/details/51083464

github地址:https://github.com/ximsfei/DynamicDeploymentApk

实现Android动态部署的过程中最重要的是从插件apk中启动四大组件,经过前面几篇文章的分析,现在只剩下BroadcastReceiver和ContentProvider了,BroadcastReceiver是可以通过java代码动态注册的,可想而知,偷懒一点的办法就是在解析完AndroidManifest.xml文件后手动注册一下就好了,这篇文章中会详细分析一下ContentProvider的安装流程以及调用getContentResolver方法后的获取ContentProvider的流程。

动态注册BroadcastReceiver

在解析完AndroidManifest.xml之后可以调用如下代码动态注册:

private void registerStaticBroadcastReceiver(DynamicApkInfo info) {
    int N = info.receivers.size();
    for (int i = 0; i < N; i++) {
   
        int M = info.receivers.get(i).intents.size();
        for (int j = 0; j < M; j++) {
   
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(info.receivers.get(i).intents.get(j).getAction(0));
            try {
                mApplicationContext.registerReceiver((BroadcastReceiver) info.classLoader
                        .loadClass(info.receivers.get(i).info.name).newInstance(), intentFilter);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
}

注:在实际项目中应用的时候,要注意,在整个应用生命周期中,不要多次调用该方法。

ContentProvider使用

Uri uri = Uri.parse("content://dynamic/content/1");
getContentResolver().query(uri, null, null, null, null);
<provider
    android:name=".PluginContentProvider"
    android:authorities="dynamic"
    android:enabled="true"
    android:exported="true" >
</provider>

相信大部分的读者都知道,在Android中通过上面简单的两行代码就可以调用注册在manifest文件中的PluginContentProvider的query方法,接下来我们先分析一下,调用getContentResolver().query()方法之后,源码的执行流程,下图就是调用该方法后的时序图:
这里写图片描述
首先会从ContextImpl中获取ContextImpl$ApplicationContentResolver对象, 该类继承自ContentResolver,并且在ContextImpl构造方法中创建:

private static final class ApplicationContentResolver extends ContentResolver {
   }

private ContextImpl(ContextImpl container, ActivityThread mainThread,
            LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
            Display display, Configuration overrideConfiguration, int createDisplayWithId) {
    ...
    mContentResolver = new ApplicationContentResolver(this, mainThread, user);
}

在ContentResolver的query方法中会调用ContextImpl$ApplicationContentResolver类重写的acquireUnstableProvider方法,并且最终会调用ActivityThread中的acquireProvider方法:

@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
    return mMainThread.acquireProvider(c,
            ContentProvider.getAuthorityWithoutUserId(auth),
            resolveUserIdFromAuthority(auth), false);
}

ActivityThread.java

public final IContentProvider acquireProvider(
        Context c, String auth, int userId, boolean stable) {
    final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);//如果在mProviderMap中存在,则返回
    if (provider != null) {
        return
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值