转载请注明出处: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