前段时间到阿里巴巴参加支付宝技术分享沙龙,看到支付宝在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() {
} @Override
public String sayHi() {
return "I am jar loader.";
} }

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

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

将打包好的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();
}
}

效果如下图所示 : 


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 ; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mShowView = findViewById(R.id.show) ;
mShowView.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
Toast.makeText(UninstallApkActivity.this, "这是已安装的apk被动态加载了", Toast.LENGTH_SHORT).show();
}
}) ;
} @Override
public 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;
} @Override
public 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 .jar and .apk files containing a classes.dex entry. 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. Use Context.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.

效果如图 :


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") ;
// 跳转到该Activity
startActivity(new Intent(context, cls)) ;
} catch (NameNotFoundException e) {
e.printStackTrace();
}catch (ClassNotFoundException e) {
Log.d("", e.toString()) ;
}
}

效果如图:

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

Android动态加载jar、apk的实现的更多相关文章

  1. 【Android】Android动态加载Jar、APK的实现

    本文介绍Android中动态加载Jar.APK的实现.而主要用到的就是DexClassLoader这个类.大家都知道Android和普通的Java虚拟机有差别,它只能加载经过处理的dex文件.而加载这 ...

  2. Android动态加载jar/dex

    前言 在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优 ...

  3. 深入浅出Android动态加载jar包技术

    在实际项目中,由于某些业务频繁变更而导致频繁升级客户端的弊病会造成较差的用户体验,而这也恰是Web App的优势,于是便衍生了一种思路,将核心的易于变更的业务封装在jar包里然后通过网络下载下来,再由 ...

  4. Android应用开发提高系列(4)——Android动态加载(上)——加载未安装APK中的类

    前言 近期做换肤功能,由于换肤程度较高,受限于平台本身,实现起来较复杂,暂时搁置了该功能,但也积累了一些经验,将分两篇文章来写这部分的内容,欢迎交流! 关键字:Android动态加载 声明 欢迎转载, ...

  5. Android 动态加载 (二) 态加载机制 案例二

    探秘腾讯Android手机游戏平台之不安装游戏APK直接启动法 重要说明 在实践的过程中大家都会发现资源引用的问题,这里重点声明两点: 1. 资源文件是不能直接inflate的,如果简单的话直接在程序 ...

  6. Android 动态加载 (一) 态加载机制 案例一

    在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势.本 ...

  7. android动态加载

    转载自: http://www.cnblogs.com/over140/archive/2012/03/29/2423116.html http://www.cnblogs.com/over140/a ...

  8. [转载] Android动态加载Dex机制解析

    本文转载自: http://blog.csdn.net/wy353208214/article/details/50859422 1.什么是类加载器? 类加载器(class loader)是 Java ...

  9. Android动态加载技术初探

    一.前言: 现在,已经有实力强大的公司用这个技术开发应用了,比如淘宝,大众点评,百度地图等,之所以采用这个技术,实际上,就是方便更新功能,当然,前提是新旧功能的接口一致,不然会报Not Found等错 ...

随机推荐

  1. Warning: Unable to send packet: Error with PF_PACKET send() [11]: Message too long (errno = 90)

    今天在使用tcpreplay重放流量时,发现有的数据包没有发送成功: Warning: Unable to send packet: Error with PF_PACKET send() [215] ...

  2. 邮件发送 emailsend .net开发

    protected void Button1_Click(object sender, EventArgs e) { MailSender.Send("lizihong3@163.com&q ...

  3. if和switch的区别,循环的for 和while的区别, 字符串常用的7种方法

    相同点: 都是用于多重选择 不同点: 多重IF没有switch选择结构的限制,特别适合变量处于某个连续区间的情况 switch只能处理等值条件判断的情况,而且条件必须是整型变量或者字符串变量 字符串的 ...

  4. codeforces 569A Music

    codeforces  569A   Music   解题报告 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=88890#pro ...

  5. Arduino101 中使用 Mirf 库的问题(2016-04-04)

    Mirf 库在使用 NRF24L01 的时候接触到,感觉很好用.但在用 Arduino101 的时候遇到一些问题,记录一下,对于底层不了解,希望有熟悉的同学能给点指点: 编译会提示 MirfHardw ...

  6. C#中foreach语句的迭代器实现机制

    C#中的foreach语句可用于循环遍历某个集合中的元素,而所有的只要支持了IEnumerable或IEnumerable<T>泛型接口的类型都是可以 用foreach遍历的.其具体的遍历 ...

  7. OpenGL ES 正反面设置指令

    在OpenGL ES 中,仅有一种表面网格表示方式,那就是三角形. 三角形的三个顶点,可以组几个面?有答 1 的没有?有!那就是还不懂OpenGL ES 的我. 事实上,一张纸是有正反面的,那么一个三 ...

  8. JQuery标签去重与数组去重

    如图所示: 代码: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head ...

  9. ubuntu下配置nginx+uwsgi+django

    服务器配置是Ubuntu14.04 64位OS ubuntu14.04默认是安装好了python2.7版本不用自己安装了. 先更新下源 sudo apt-get update 第一步先安装pip su ...

  10. C陷阱与缺陷(三)

    第三章 语义陷阱 3.1 指针与数组 C语言中只有一维数组,而且数组的大小必须字编译期就作为一个常数确定下来.数组中的元素可以是另外一个数组.任何一个数组下标运算都等同于一个对应的指针运算.int a ...