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

--前言

该技术的具体实现步骤可参考农民伯伯的博客:http://www.cnblogs.com/over140/archive/2011/11/23/2259367.html
本文以此为基础,扩展了一个简单的框架,教大家如何使用该技术实现业务的动态变更升级
上效果图先:

再看看csdn code上工程的项目结构

FrameExample 就是我们的demo

frame是给demo引用的链接库,也就是框架壳

FrameCore 就是核心框架包,用于被android动态加载的jar包

---------------------------------------------------------------------------------------------------------------------------------

test目录展开如下

hfs2_3b287.rar   
一个本地http服务器应用,用于存放测试用的apk和jar包
des.jar           经过优化的可用于动态加载的jar包
BtcMonitor.apk   测试用的apk

----------------------------------------------------------------------------------------------------------------------

http服务器界面如下:

demo通过frame库提供的api接口调用到framecore核心包里的具体实现代码
这样当业务具体实现有变更时,只需修改framecore里的内容,然后放到网络上
framecore里可以实现一个自检测jar包版本并自动更新下载jar包的功能,本例去掉了这个功能

有兴趣的童鞋可以自己尝试一下,另外本例只提供了下载的接口,其它接口根据框架模板定义自行添加即可

再贴一个核心类FrameInstance的实现:

public class FrameInstance implements IFrame{

	private static final CommonLog log = LogFactory.createLog();

	private static FrameInstance mInstance;
private boolean isFrameInit = false; private Context mContext; private Handler mJarHandler;
private DownloadJARProxy mJARProxy;
private ISimpleDownloadCallback mJARDownloadCallback; public static synchronized FrameInstance getInstance(Context context) {
if (mInstance == null){
mInstance = new FrameInstance(context);
}
return mInstance;
} private FrameInstance(Context context)
{
mContext = context; mJarHandler = new Handler(){ @Override
public void handleMessage(Message msg) {
switch(msg.what){
case IHandlerMsg.ON_START: break;
case IHandlerMsg.ON_PROGRESS:
{
int cur = msg.arg1;
int max = msg.arg2; double rate = cur * 1.0 / max;
int value = (int) (rate * 100);
String conString = String.valueOf(value) + "%";
log.e("download jar percent:" + conString);
}
break;
case IHandlerMsg.ON_SUCCESS:
if (mJARDownloadCallback != null){
mJARDownloadCallback.onDownload(true);
}
break;
case IHandlerMsg.ON_FAIL:
if (mJARDownloadCallback != null){
mJARDownloadCallback.onDownload(false);
}
break;
case IHandlerMsg.ON_CANCEL:
break;
}
} }; } @Override
public boolean startFramework() { if (isFrameInit){
return true;
}
isFrameInit = loadFrameCore();
log.e("startFramework ret = " + isFrameInit); if (mIFrameCore != null){
mIFrameCore.startEngine(mContext);
} return isFrameInit;
} @Override
public boolean stopFramework() { if (!isFrameInit){
return true;
} if (mIFrameCore != null){
mIFrameCore.stopEngine(mContext);
} releaseFrameCore();
isFrameInit = false;
log.e("stopFramework... "); return true;
} @Override
public boolean isFrameworkInit() {
return isFrameInit;
} @Override
public boolean isFrameCoreExist() { if (!FrameTool.hasSDCard())
return false; File file = new File(FrameTool.getJARSavePath());
if (!file.exists()){
return false;
} return true;
} @Override
public boolean startDownloadFrameCore(ISimpleDownloadCallback callback) { if (!FrameTool.hasSDCard()){
log.e("SDCard not exist!!!");
return false;
} if (mJARProxy != null){
if (mJARProxy.isTaskRunning()){
return true;
}
} mJARProxy = new DownloadJARProxy(mJarHandler);
mJARProxy.startDownloadTask(FrameTool.getJARURL(), FrameTool.getJARSavePath());
mJARDownloadCallback = callback;
log.e("startDownloadFrameCore...JAR_URL:" + FrameTool.getJARURL() + ", SAVE_PATH:" + FrameTool.getJARSavePath()); return true;
} public boolean updateDownloadAPK(String url, String dstPath, IUpdateDownloadCallback callback){
if (mIUpdateTools == null){
log.e("mIUpdateTools = null!!!");
return false;
} if (TextUtils.isEmpty(url) || TextUtils.isEmpty(dstPath)){
return false;
} mIUpdateTools.updateDownloadAPK(url, dstPath, callback); return true;
} public boolean cancelDownloadAPK(){
if (mIUpdateTools == null){
log.e("mIUpdateTools = null!!!");
return false;
} mIUpdateTools.cancelDownloadAPK(); return true;
} public boolean checkJARVersion(){ return true;
} public boolean installAPK(String path){ if (TextUtils.isEmpty(path)){
return false;
} Intent i = new Intent(Intent.ACTION_VIEW);
i.setDataAndType(Uri.parse("file://" + path), "application/vnd.android.package-archive");
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(i); return true;
} private IFrameCore mIFrameCore;
private IUpdateTools mIUpdateTools;
private boolean loadFrameCore(){ // if (true){
// mIVersionTools = new VersionTools();
// mIUpdateTools = new UpdateTools();
// return true;
// } if (!isFrameCoreExist()){
return false;
} DexClassLoader classLoader = DexClassLoadTools.newDexClassLoader(mContext, FrameTool.getJARSavePath());
if (classLoader == null){
return false;
} mIFrameCore = ClassFactory.newFrameCore(classLoader);
if (mIFrameCore == null){
return false;
} mIUpdateTools = ClassFactory.newUpdateTools(classLoader);
return true;
} private void releaseFrameCore(){
mIFrameCore = null;
mIUpdateTools = null;
} private static class ClassFactory{
public static IFrameCore newFrameCore(DexClassLoader classLoader){
IFrameCore object = null;
Class cls = newFrameCoreClass(classLoader, "com.lance.framecore.externex.FrameCore");
if (cls != null){
try {
object = (IFrameCore) cls.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return object;
} public static IUpdateTools newUpdateTools(DexClassLoader classLoader){
IUpdateTools object = null;
Class cls = newFrameCoreClass(classLoader, "com.lance.framecore.externex.UpdateTools");
if (cls != null){
try {
object = (IUpdateTools) cls.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return object;
} public static Class newFrameCoreClass(DexClassLoader classLoader, String className){ Class libProviderClazz = null;
try {
libProviderClazz = classLoader.loadClass(className);
} catch (Exception exception) {
exception.printStackTrace();
}
return libProviderClazz;
} } public static class FrameTool{ private final static String JAR_URL = "http://192.168.1.101/jar/des.jar";
public static boolean hasSDCard() {
String status = Environment.getExternalStorageState();
if (!status.equals(Environment.MEDIA_MOUNTED)) {
return false;
}
return true;
} public static String getRootFilePath() {
if (hasSDCard()) {
return Environment.getExternalStorageDirectory().getAbsolutePath() + "/";
} else {
return Environment.getDataDirectory().getAbsolutePath() + "/data/";
}
} public static String getJARURL(){
return JAR_URL;
} public static String getJARSavePath(){
return getRootFilePath() + "FrameCore.jar";
} } private static class DexClassLoadTools{ public static DexClassLoader newDexClassLoader(Context context, String jarPath){ final File optimizedDexOutputPath = new File(jarPath);
if (!optimizedDexOutputPath.exists()){
return null;
} File file = context.getDir("osdk", 0);
log.e("getDir:" + file.getAbsolutePath()); DexClassLoader cl = new DexClassLoader(optimizedDexOutputPath.getAbsolutePath(),
file.getAbsolutePath(),
null,
context.getClassLoader()); return cl;
}
} @Override
public boolean deleteFrameCore() {
log.e("deleteFrameCore"); if (!isFrameCoreExist()){
log.e("framecore.jar is not exist:" + FrameTool.getJARSavePath());
return false;
} FileTools.deleteDirectory(FrameTool.getJARSavePath()); return true;
} @Override
public FrameCoreInfo getFrameCoreInfo() { try {
if (mIFrameCore == null){
return new FrameCoreInfo();
} return mIFrameCore.getFrameCoreInfo(mContext);
} catch (Exception e) {
e.printStackTrace();
return new FrameCoreInfo();
} } }

值得注意的是

在导出framecore时无需导出com.lance.framecore.extern包下代码,否则加载时会出现重复定义错误

同时要保持framecore工程和frame工程该包代码的一致,在扩展接口时把相应接口写在这个包下即可

--------------------------------------------------------------------------------------------------------------------------------

其它的没啥好说的了,自个儿download代码看吧
下面附上code地址:https://code.csdn.net/geniuseoe2012/dynamicjar

如果童鞋们觉得本文有用,不妨关注我的code主页:https://code.csdn.net/geniuseoe2012

以后一些博文相关的demo会放在上面,这样大家就不用耗下载积分了,同时便于代码更正

更多开源项目可关注我的github主页:https://github.com/geniusgithub

深入浅出Android动态加载jar包技术的更多相关文章

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

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

  2. JAVA动态加载JAR包的实现

    如何动态的加载这些驱动!不可能把所有的数据库驱动都集成到JAR包中吧?!于是动态加载驱动的JAR包就产生了!其实这些在做系统基础代码时,经常用到,只是一般我们没有机会去搞而已. 动态加载JAR包,使用 ...

  3. Android动态加载jar/dex

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

  4. java动态加载jar包,并运行其中的类和方法

    动态加载jar包,在实际开发中经常会需要用到,尤其涉及平台和业务的关系的时候,业务逻辑部分可以独立出去交给业务方管理,业务方只需要提供jar包,就能在平台上运行. 下面通过一个实例来直观演示: 第一: ...

  5. Android动态加载jar、apk的实现

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

  6. 动态加载jar包(二)

    上次说的加载jar包,有几个问题没有解决: 1.如果项目包含了其他的jar包如何解决? 2.如何规范上传的jar包的类和方法? 下面就解决一下上面两个问题 一.首先编写被调用的类,这次使用maven工 ...

  7. 动态加载jar包(一)

    一.编写被调用的类 package com.qunar.helloworld; public class HelloWorld { public String sayHello(){ return ( ...

  8. 动态加载jar包中的类(方式一)

    嘛, 直接上代码 public static class TestClassLoader extends ClassLoader { @Override protected Class<?> ...

  9. Java动态加载JAR包

    参考代码: package org; import java.io.File; import java.net.URL; import java.net.URLClassLoader; import ...

随机推荐

  1. IO多路复用模型之epoll实现机制

    设想一下如下场景:有100万个客户端同时与一个服务器进程保持着TCP连接.而每一时刻,通常只有几百上千个TCP连接是活跃的(事实上大部分场景都是这种情况).如何实现这样的高并发? 在select/po ...

  2. python optparse模块的简单用法

    # coding = utf-8 from optparse import OptionParser from optparse import OptionGroup usage = 'Usage: ...

  3. rsync(三)算法原理和工作流程分析

    在开始分析算法原理之前,简单说明下rsync的增量传输功能. 假设待传输文件为A,如果目标路径下没有文件A,则rsync会直接传输文件A,如果目标路径下已存在文件A,则发送端视情况决定是否要传输文件A ...

  4. 实用的MVVM:ImageView

    最近在学习WPF,遇到一本入门好书,推荐给大家<Windows Presentation Foundation 4.5 Cookbook> 做项目首先要从MVVM开始,现在把他的Simpl ...

  5. @Autowired注解和启动自动扫描的三种方式(spring bean配置自动扫描功能的三种方式)

    前言: @Autowired注解代码定义 @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, Elemen ...

  6. 1.10-1.11 hive交互式命令讲解

    一.hive 交互式命令参数 #帮助 [root@hadoop-senior hive-0.13.1]# bin/hive -h Missing argument for option: h usag ...

  7. sql语句之连表操作

    内连接 select * from employee inner join department on employee.dep_id = department.id 左连接 在内连接的基础上保留左表 ...

  8. java的Set, List, Map简单介绍

    Set, List, Map Set和List,Map都是集合,Set和List都是继承于Collection接口,而Map不是. 1.Map(映射) :Map是以key,Value的形式存储数据的映 ...

  9. Installing cmake 2.8.8 or higher on Ubuntu 12.04 (Precise Pangolin) (转载)

    转自:http://cameo54321.blogspot.com/2014/02/installing-cmake-288-or-higher-on.html Check the version o ...

  10. E20190114-hm

    anonymous adj. 匿名的; 无名的; 假名的; 没有特色的;