Android插件技术——(四)加载未安装apk
2015-08-19 17:03
483 查看
上一篇虽然研究了如何加载未安装apk的资源,然而由于只是当做普通的Java类来加载,没有Android系统上下文,所以无法启动Activity,展开布局,进行各种界面交互,本篇将研究如何解决这些问题。
首先介绍一下核心思路,未安装的apk是没有系统上下文的,所以导致上述一系列问题,由此可见,解决问题的关键是给插件赋予一个系统上下文。而这个上下文如何生成呢?一种可行的方案是采用主App的上下文做代理,以主App的代理为壳,行插件之实。例如主App的Activity是受生命周期控制的,在生命周期各个回调如onCreate,onResume内,我们调用插件的onCreate,onResume。至于如何获取插件资源上一篇已讨论过了,这里就不再赘述。
接下来介绍一下各个工程,一共分Host,Plugin,PluginLib,Host和Plugin就不用多说了,PluginLib是一个插件功能库,包括一些基础接口和类。Host和Plugin都要导入该库,然而区别是Host中该库是作为普通jar导入的,而PluginLib中是作为External Jar导入的,这点切记。
Host工程主要有两个类很重要,PluginManager和PluginProxyActivity,PluginManager用于加载插件,PluginProxyActivity即为插件的代理Activity。废话不说了,直接上代码:
![](http://img.blog.csdn.net/20150819170622666)
接下来要说的是PluginLib,主要包括两个接口IPlugin和IProxy,此外还有PluginBaseActivity,插件中的Activity都要继承自这个类,里面封装了与Host代理Activity进行交互的一些操作。
![](http://img.blog.csdn.net/20150819171854808)
接下来介绍插件工程,由于只是为了演示,这个插件就做的很简单,只包括了加载布局和资源,插件内跳转Activity。
![](http://img.blog.csdn.net/20150819172108414)
首先介绍一下核心思路,未安装的apk是没有系统上下文的,所以导致上述一系列问题,由此可见,解决问题的关键是给插件赋予一个系统上下文。而这个上下文如何生成呢?一种可行的方案是采用主App的上下文做代理,以主App的代理为壳,行插件之实。例如主App的Activity是受生命周期控制的,在生命周期各个回调如onCreate,onResume内,我们调用插件的onCreate,onResume。至于如何获取插件资源上一篇已讨论过了,这里就不再赘述。
接下来介绍一下各个工程,一共分Host,Plugin,PluginLib,Host和Plugin就不用多说了,PluginLib是一个插件功能库,包括一些基础接口和类。Host和Plugin都要导入该库,然而区别是Host中该库是作为普通jar导入的,而PluginLib中是作为External Jar导入的,这点切记。
Host工程主要有两个类很重要,PluginManager和PluginProxyActivity,PluginManager用于加载插件,PluginProxyActivity即为插件的代理Activity。废话不说了,直接上代码:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btn = (Button) findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub startPlugin(); } }); } private void startPlugin() { Intent intent = new Intent(); intent.setClass(this, PluginProxyActivity.class); File apkFile = new File(getExternalCacheDir(), "AndroidPlugin.apk"); PluginManager.loadPluginApk(this, apkFile.getAbsolutePath()); intent.putExtra(PluginProxyActivity.EXTRA_APK, apkFile.getAbsolutePath()); intent.putExtra(PluginProxyActivity.EXTRA_CLASS, "com.example.androidplugin.MainActivity"); startActivity(intent); } }
public class PluginManager { private static HashMap<String, Plugin> mPluginMap = new HashMap<String, Plugin>(); public static Plugin getPlugin(String apkPath) { return mPluginMap.get(apkPath); } public static void loadPluginApk(Context context, String apkPath) { String dexOutputPath = context.getDir("plugin", 0).getAbsolutePath(); FileUtils.deleteDirectory(dexOutputPath); DexClassLoader dexClassLoader = new DexClassLoader(apkPath, dexOutputPath, null, PluginManager.class.getClassLoader()); AssetManager assetManager = createAssetManager(apkPath); Resources resources = createResources(context, assetManager); Plugin plugin = new Plugin(dexClassLoader, assetManager, resources); mPluginMap.put(apkPath, plugin); } private static AssetManager createAssetManager(String dexPath) { try { AssetManager assetManager = AssetManager.class.newInstance(); Method addAssetPath = assetManager.getClass().getMethod( "addAssetPath", String.class); addAssetPath.invoke(assetManager, dexPath); return assetManager; } catch (Exception e) { e.printStackTrace(); return null; } } private static Resources createResources(Context context, AssetManager assetManager) { Resources superRes = context.getResources(); Resources resources = new Resources(assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration()); return resources; } public static class Plugin { public Resources resources; public AssetManager assetManager; public DexClassLoader dexClassLoader; public Plugin(DexClassLoader dexClassLoader, AssetManager assetManager, Resources resources) { this.resources = resources; this.assetManager = assetManager; this.dexClassLoader = dexClassLoader; } } }
public class PluginProxyActivity extends FragmentActivity implements IProxy { public static final String EXTRA_APK = "extra_apk"; public static final String EXTRA_CLASS = "extra_class"; private String mApkPath; private Plugin mPlugin; private Theme mTheme; private PluginBaseActivity mPluginActivity; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); Intent intent = getIntent(); mApkPath = intent.getStringExtra(EXTRA_APK); String className = intent.getStringExtra(EXTRA_CLASS); mPlugin = PluginManager.getPlugin(mApkPath); launchActivity(intent, className); } private void launchActivity(Intent intent, String className) { try { Class<?> localClass = mPlugin.dexClassLoader.loadClass(className); Constructor<?> localConstructor = localClass .getConstructor(new Class[] {}); Object instance = localConstructor.newInstance(new Object[] {}); mPluginActivity = (PluginBaseActivity) instance; handleActivityTheme(); mPluginActivity.attach(this); mPluginActivity.setIntent(intent); mPluginActivity.onCreate(intent.getExtras()); } catch (Exception e) { finish(); return; } } private void handleActivityTheme() { Theme superTheme = super.getTheme(); mTheme = mPlugin.resources.newTheme(); mTheme.setTo(superTheme); } @Override public Theme getTheme() { if (mTheme == null) { return super.getTheme(); } else { return mTheme; } } @Override public AssetManager getAssets() { if (mPlugin == null) { return super.getAssets(); } else { return mPlugin.assetManager; } } @Override public ClassLoader getClassLoader() { if (mPlugin == null) { return super.getClassLoader(); } else { return mPlugin.dexClassLoader; } } @Override public Resources getResources() { if (mPlugin == null) { return super.getResources(); } return mPlugin.resources; } @Override public FragmentActivity getProxyActivity() { // TODO Auto-generated method stub return this; } @Override public void startActivityForResult(Intent bundle, String className, int requestCode) { // TODO Auto-generated method stub Intent intent = new Intent(this, PluginProxyActivity.class); if (bundle != null) { intent.putExtras(bundle); } intent.putExtra(EXTRA_APK, mApkPath); intent.putExtra(EXTRA_CLASS, className); startActivityForResult(intent, requestCode); } }
接下来要说的是PluginLib,主要包括两个接口IPlugin和IProxy,此外还有PluginBaseActivity,插件中的Activity都要继承自这个类,里面封装了与Host代理Activity进行交互的一些操作。
public interface IPlugin { public void attach(IProxy proxy); }
public interface IProxy { public FragmentActivity getProxyActivity(); public void startActivityForResult(Intent intent, String className, int requestCode); }
public class PluginBaseActivity extends FragmentActivity implements IPlugin { private IProxy mProxy; private FragmentActivity mProxyActivity; @Override public void attach(IProxy proxy) { // TODO Auto-generated method stub mProxy = proxy; mProxyActivity = proxy.getProxyActivity(); } @Override public void onCreate(Bundle savedInstanceState) { } @Override public void setContentView(int layoutResID) { // TODO Auto-generated method stub mProxyActivity.setContentView(layoutResID); } @Override public View findViewById(int id) { return mProxyActivity.findViewById(id); } @Override public Intent getIntent() { return mProxyActivity.getIntent(); } @Override public void setIntent(Intent newIntent) { mProxyActivity.setIntent(newIntent); } @Override public Resources getResources() { return mProxyActivity.getResources(); } public void startActivity(Intent intent) { startActivity(intent, intent.getComponent().getClassName()); } public void startActivity(Intent intent, Class<?> clazz) { startActivity(intent, clazz.getName()); } public void startActivity(Intent intent, String className) { startActivityForResult(intent, className, -1); } public void startActivityForResult(Intent intent, String className, int requestCode) { mProxy.startActivityForResult(intent, className, requestCode); } }
接下来介绍插件工程,由于只是为了演示,这个插件就做的很简单,只包括了加载布局和资源,插件内跳转Activity。
public class MainActivity extends PluginBaseActivity { private Button mBtn; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mBtn = (Button) findViewById(R.id.btn); mBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub startTestActivity(); } }); } private void startTestActivity() { Intent intent = new Intent(); startActivity(intent, TestActivity.class); } }
相关文章推荐
- Android 编程下的代码混淆
- Android内存泄漏研究
- Android(java)学习笔记179:BroadcastReceiver之 有序广播和无序广播(BroadcastReceiver优先级)
- Android Studio百度地图(二)
- ViewPager点击每一项设置的监听
- android binder
- Android学习要点
- Android js相互调用
- android布局------RelativeLayout(相对布局)详解
- Android adb命令启动系统组件
- Android 点击空白处隐藏键盘
- android开发工具
- Android自定义布局
- Android笔记(二)LogCat
- 大约Android 了解权限管理
- 分享:Android系统的常用权限整理
- Android开发之ExpandableListView扩展
- android加密解密完美教程
- Android 管理Log日志
- Android 代码混淆