Android 插件开发

简介

DexClassLoader 是Android系统中特有的类加载器,其父类为ClassLoader,插件开发主要就是利用了DexClassLoader来实现动态加载类,以便实现动态切换各种功能。

Android 插件开发

实践

  1. 首先一般开发是提供Service的通用接口。此处为CommonService.java ,可导出jar以方便为其他人使用【PluginService.jar】。

public interface CommonService {
	/**
	 * say Hello
	 */
	public void sayHello();

	/**
	 * get sum
	 * 
	 * @param a
	 * @param b
	 * @return
	 */
	public int add(int a, int b);
}

2.新建一个Application,实现上述接口,可为普通java jar包插件(只是业务),也可以为apk应用插件(主题,资源等)。

public class ServiceImpl implements CommonService {

	@Override
	public void sayHello() {
		// TODO Auto-generated method stub
		Log.e("ServiceImpl", "sayHello");
	}

	@Override
	public int add(int a, int b) {
		// TODO Auto-generated method stub
		return a+b;
	}
}

并修改应用程序配置文件中如下
        <activity
            android:name="xx.xx.plugin.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="xx.xx.plugin_1.ACTION" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

3.在自己的主程序中导入PluginService.jar

/**
	 * 定义一个插件的Action
	 */
	public static final String PLUGIN_1_ACTION = "xx.xx.plugin_1.ACTION";
	
    	protected void onPluginLoading() {
    		// 创建一个查找apk意图
    		Intent intent = new Intent(PLUGIN_1_ACTION, null);
    		// 获得应用程序包名
    		PackageManager pm = getPackageManager();
    		List<ResolveInfo> resolveinfoes = pm.queryIntentActivities(intent, 0);
    		ActivityInfo actInfo = resolveinfoes.get(0).activityInfo;
    		String pacageName = actInfo.packageName;
    		
    		// 获得apk的目录或者jar的文件Path
    		String apkPath = actInfo.applicationInfo.sourceDir;
    		
    		//解压后的目录  一般在/data/data/XXXX 自己的私有程序包内
    		String dexOutputDir = getApplicationInfo().dataDir;
    		// native代码的目录
    		String libPath = actInfo.applicationInfo.nativeLibraryDir;
    
    		// 创建dex类加载器
    		DexClassLoader classLoader = new DexClassLoader(apkPath, dexOutputDir,
    				libPath, getClassLoader());
    		// 利用反射调用插件包内的类的方法
    		try {
    			String className = pacageName+".ServiceImpl";
    			Class<?> clazz = Class.forName(className, true, classLoader);
    			// Class<?> clazz = classLoader.loadClass(className);
    			CommonService obj = (CommonService) clazz.newInstance();
    
    			obj.sayHello();
    			Log.e("Host", "return result is " + obj.add(1, 13));
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
	}

先安装apk插件或copy jar文件到制定目录,然后再运行主程序,结果如下:


注意事项:

1.如果出现 ERROR/AndroidRuntime(12705): java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation.一般是因为存在重复的类文件导致的,因为一般主程序直接引用jar包,系统会自动导出该依赖包,所以可以检查插件apk中是否重复导出了PluginService.jar

Android 插件开发

2.如果运行主程序出现找不到接口,可以查看是否正确导入依赖包PluginService.jar

差不多就是这个样子了,


你可能感兴趣的:(Android 插件开发)