前段时间到阿里巴巴参加支付宝技术分享沙龙,看到支付宝在Android使用插件化的技术,挺好奇的。正好这几天看到了农民伯伯的相关文章,因此简单整理了下,有什么错误希望大神指正。

核心类

1.1 DexClassLoader类
   可以加载jar/apk/dex,可以从SD卡中加载未安装的apk。
  1.2 PathClassLoader类  
   只能加载已经安装到Android系统中的apk文件。


一、正文

1.1动态加载jar

类似于eclipse的插件化实现, 首先定义好接口, 用户实现接口功能后即可通过动态加载的方式载入jar文件, 以实现具体功能。注意, 这里的jar包需要经过android dx工具的处理 , 否则不能使用。

首先我们定义如下接口 :

package com.example.interf;  /**  * @Title: ILoader.java  * @Package com.example.loadjardemo  * @Description:  通用接口, 需要用户实现 * @version V1.0  */public interface ILoader { public String sayHi();}  
用户需实现,该接口, 并且将工程导出为jar包的形式。

示例如下 :

public class JarLoader implements ILoader {public JarLoader() {}@Overridepublic String sayHi() {return "I am jar loader.";}}

最后, 实现功能的代码打包成jar包 :

首先选中工程, 右键后选择“导出”, 然后选择“java”-----“jar文件”, 然后将你的具体功能实现类导出为jar,文件名为loader.jar,如下图所示 :

Android动态加载jar、apk的实现_第1张图片

将打包好的jar拷贝到SDK安装目录android-sdk-windows\platform-tools下,DOS进入这个目录,执行如下命令:

dx --dex --output=loader_dex.jar loader.jar

然后将loader_dex.jar放到android手机中, 这里我们放到SD卡根目录下。


动态加载代码 :

/** *  * @Title: loadJar  * @Description: 项目工程中必须定义接口, 而被引入的第三方jar包实现这些接口,然后进行动态加载 。 *          相当于第三方按照接口协议来开发, 使得第三方应用可以以插件的形式动态加载到应用平台中。 * @return void     * @throws */private void loadJar(){        final File optimizedDexOutputPath = new File(Environment.getExternalStorageDirectory().toString()                + File.separator + "loader_dex.jar");                        BaseDexClassLoader cl = new BaseDexClassLoader(Environment.getExternalStorageDirectory().toString(),            optimizedDexOutputPath, optimizedDexOutputPath.getAbsolutePath(), getClassLoader());            Class libProviderClazz = null;                        try {                // 载入JarLoader类, 并且通过反射构建JarLoader对象, 然后调用sayHi方法                libProviderClazz = cl.loadClass("com.example.interf.JarLoader");                ILoader loader = (ILoader)libProviderClazz.newInstance();                Toast.makeText(MainActivity.this, loader.sayHi() , Toast.LENGTH_SHORT).show();            } catch (Exception exception) {                // Handle exception gracefully here.                exception.printStackTrace();            }}

效果如下图所示 :
Android动态加载jar、apk的实现_第2张图片



1.2 加载未安装的apk

首先新建一个Android项目, 定义如下接口 :

public interface ISayHello {public String sayHello()  ;}

定义一个Activity实现该接口, 如下:

package com.example.loaduninstallapkdemo;import android.app.Activity;import android.os.Bundle;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Toast;/** *  * @ClassName: UninstallApkActivity  * @Description: 这是被动态加载的Activity类 * */public class UninstallApkActivity extends Activity implements ISayHello{private View mShowView = null ;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mShowView = findViewById(R.id.show) ;mShowView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(UninstallApkActivity.this, "这是已安装的apk被动态加载了", Toast.LENGTH_SHORT).show();}}) ;}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.activity_main, menu);return true;}@Overridepublic String sayHello(){return "Hello, this apk is not installed";}}
然后将该编译生apk, 并且将该apk拷贝到SD卡根目录下。

动态加载未安装的apk

/** *  * @Title: loadUninstallApk  * @Description: 动态加载未安装的apk * @return void     * @throws */private void loadUninstallApk(){        String path = Environment.getExternalStorageDirectory() + File.separator;        String filename = "LoadUninstallApkDemo.apk";        // 4.1以后不能够将optimizedDirectory设置到sd卡目录, 否则抛出异常.        File optimizedDirectoryFile = getDir("dex", 0) ;        DexClassLoader classLoader = new DexClassLoader(path + filename, optimizedDirectoryFile.getAbsolutePath(),                null, getClassLoader());        try {        // 通过反射机制调用, 包名为com.example.loaduninstallapkdemo, 类名为UninstallApkActivity            Class mLoadClass = classLoader.loadClass("com.example.loadunstallapkdemo.UninstallApkActivity");            Constructor constructor = mLoadClass.getConstructor(new Class[] {});            Object testActivity = constructor.newInstance(new Object[] {});                        // 获取sayHello方法            Method helloMethod = mLoadClass.getMethod("sayHello", null);            helloMethod.setAccessible(true);            Object content = helloMethod.invoke(testActivity, null);            Toast.makeText(MainActivity.this, content.toString(), Toast.LENGTH_LONG).show();                    } catch (Exception e) {            e.printStackTrace();        }}


DexClassLoader 注意点 :

A class loader that loads classes from.jarand.apkfiles containing aclasses.dexentry. This can be used to execute code not installed as part of an application.

This class loader requires an application-private, writable directory to cache optimized classes. UseContext.getDir(String, int)to create such a directory:

 File dexOutputDir = context.getDir("dex", 0); 

Do not cache optimized classes on external storage.External storage does not provide access controls necessary to protect your application from code injection attacks.


效果如图 :

Android动态加载jar、apk的实现_第3张图片


1.3 加载已安装的apk

将1.2中的apk安装到手机中,我的例子中,该apk的包名为“com.example.loaduninstallapkdemo”,Activity名为"UninstallApkActivity". 加载代码如下 :

        /** *  * @Title: loadInstalledApk  * @Description: 动态加载已安装的apk     * @return void     * @throws */private void loadInstalledApk() {try {String pkgName = "com.example.loaduninstallapkdemo";Context context = createPackageContext(pkgName,        Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE) ;// 获取动态加载得到的资源Resources resources = context.getResources() ;// 过去该apk中的字符串资源"tips", 并且toast出来,apk换肤的实现就是这种原理String toast = resources.getString(resources.getIdentifier("tips", "string", pkgName) ) ;Toast.makeText(MainActivity.this, toast, Toast.LENGTH_SHORT).show() ;Class cls = context.getClassLoader().loadClass(pkgName + ".UninstallApkActivity") ;// 跳转到该ActivitystartActivity(new Intent(context, cls)) ;} catch (NameNotFoundException e) {e.printStackTrace();}catch (ClassNotFoundException e) {Log.d("", e.toString()) ;}}</span>


效果如图:

Android动态加载jar、apk的实现_第4张图片

消息被Toast出来, 并且跳转到了目标Activity.

相关资料 :探秘腾讯Android手机游戏平台之不安装游戏apk直接启动法

更多相关文章

  1. 自己写的一套应用管理系统(包含一套app系统,一套后台web管理系统《
  2. Android studio 使用NDK 实现串口 动态库
  3. android imageview显示不全或者gilde加载不全
  4. [置顶] 如何演示你的App?Android录制Gif动态图教程
  5. Android 利用addView 动态给Activity添加View组件
  6. Android 动态加载布局文件
  7. Android Bitmap的加载和Cache
  8. webview 笔记二(android和js交互、包括链接跳转常见问题处理,加载
  9. 第二章 Android动态加载、热更新、热修复、插件化系列文章 之 认

随机推荐

  1. 【Android(安卓)Studio使用教程2】Androi
  2. Android(安卓)Studio设置国内镜像网站
  3. Android(安卓)系统framework 概述
  4. Android有用代码片断(六)
  5. android:关于主工程和library project
  6. android EditText中inputType的属性列表
  7. android线性布局之比例
  8. Android(安卓)TextView内容过长加省略号
  9. android的adb常用命令使用
  10. Android(安卓)XML 绘图