最近需要实现在android上开发插件,下面把一个简单例子分享一下...
首先我们需要创建两个工程,一个是主程序,一个是插件工程
1.首先在主程序中定义一个接口.
package com.mutour.testplugin;
import android.content.Context;
import android.view.View;
public interface Plugin {
public void load();
public void create(Context context, View view);
public void create(View view);
public void show();
public void hide();
public View getView();
}
2.接着在主程序中创建一个layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<LinearLayout
android:id="@+id/LinearLayoutContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical" >
</LinearLayout>
</LinearLayout>
3.然后把主程序中的interface Plugin打包成jar.
主程序工程右键,Export, 选择Java-JAR file,(注意保存的路径), 一路的next
只选择Plugin.java.
4.把生成的jar文件放到插件工程中
5.在插件工程中写一个layout文件R.layout.activity_number_plugin,随便放点什么控件
6.在插件工程中写插件类
package com.mutour.testplugin.plugin;
import com.mutour.testplugin.Plugin;
import com.mutour.testplugin.plugin.R;
import android.content.Context;
import android.view.View;
import android.widget.LinearLayout;
public class NumberPlugin implements Plugin {
private static final String TAG = "NumberPlugin";
private Context mContext;
private View mView;
private View viewNumber;
/**
* 必须有一个无参构造函数,否则无法用newInstance()获取句柄
*/
public NumberPlugin() {
}
public void setContext(Context context) {
mContext = context;
}
public NumberPlugin(Context context) {
this();
mContext = context;
}
@Override
public void load() {
}
@Override
public void show() {
((LinearLayout) mView).addView(viewNumber);
}
@Override
public void hide() {
if (mView != null)
((LinearLayout) mView).removeAllViews();
}
@Override
public void create(View view) {
mView = view;
viewNumber = View.inflate(mContext, R.layout.activity_number_plugin,
null);
}
@Override
public void create(Context context, View view) {
mContext = context;
this.create(view);
}
@Override
public View getView() {
return viewNumber;
}
}
7.编译工程,把bin目录中的classes.dex文件放入手机的sd卡里.本文中放在sd卡根目录中
8.编写主程序调用插件dex文件
package com.mutour.testplugin;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.mutour.testplugin.plugin.QwertyPlugin;
import dalvik.system.DexClassLoader;
import android.os.Bundle;
import android.os.Environment;
import android.annotation.SuppressLint;
import android.app.ActionBar.LayoutParams;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
@SuppressLint("NewApi")
public class MainActivity extends Activity {
Plugin mPlugin;
private LinearLayout mLinearLayoutContainer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLinearLayoutContainer = (LinearLayout) findViewById(R.id.LinearLayoutContainer);
String filepath = Environment.getExternalStorageDirectory().toString()
+ File.separator + "classes.dex";
DexClassLoader cl = new DexClassLoader(filepath, MainActivity.this
.getDir("dex", 0).getAbsolutePath(), null, getClassLoader());
Class libProviderClazz = null;
Plugin plugin = null;
try {
Context pluginContext = createPackageContext(
"com.mutour.testplugin.plugin",
Context.CONTEXT_IGNORE_SECURITY);
libProviderClazz = cl.loadClass("com.mutour.testplugin.plugin"
+ ".NumberPlugin");
plugin = (Plugin) libProviderClazz.newInstance();
if (plugin != null) {
switchPlugin(pluginContext, plugin);
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private void switchPlugin(Context context, Plugin plugin) {
if (mPlugin != null) {
mPlugin.hide();
}
plugin.load();
plugin.create(context, mLinearLayoutContainer);
plugin.show();
mPlugin = plugin;
}
}
大功告成..............
其中有几个需要注意的地方
1..需要先获取dex的路径,使用DexClassLoader加载这个dex,然后使用包名和类名获取Class,然后使用newInstance获取句柄,把类型转换成Plugin
2.必须使用下面的方法获取插件包的Context,否则无法获取到插件包里的layout或其他资源
Context pluginContext = createPackageContext(
"com.mutour.testplugin.plugin",
Context.CONTEXT_IGNORE_SECURITY);
........................................................................................................................................
下面连接是该主程序和插件程序的代码..TestPlugin.rar是主程序 NumberPlugin.rar是插件程序
本方法是使用的dex方式,也可以使用apk方式安装插件.....