深入浅出Android动态载入jar包技术
在实际项目中。因为某些业务频繁变更而导致频繁升级client的弊病会造成较差的用户体验,而这也恰是Web App的优势,于是便衍生了一种思路。将核心的易于变更的业务封装在jar包里然后通过网络下载下来,再由android动态载入运行的方案。以改善频繁升级的毛病
--前言
该技术的详细实现步骤可參考农民伯伯的博客:http://www.cnblogs.com/over140/archive/2011/11/23/2259367.html
本文以此为基础,扩展了一个简单的框架,教大家怎样使用该技术实现业务的动态变更升级
上效果图先:
再看看csdn code上project的项目结构
FrameExample 就是我们的demo
frame是给demo引用的链接库。也就是框架壳
FrameCore 就是核心框架包。用于被android动态载入的jar包
---------------------------------------------------------------------------------------------------------------------------------
test文件夹展开例如以下
hfs2_3b287.rar
一个本地httpserver应用,用于存放測试用的apk和jar包
des.jar 经过优化的可用于动态载入的jar包
BtcMonitor.apk 測试用的apk
----------------------------------------------------------------------------------------------------------------------
httpserver界面例如以下:
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包下代码,否则载入时会出现反复定义错误
同一时候要保持framecoreproject和frameproject该包代码的一致,在扩展接口时把对应接口写在这个包下就可以
--------------------------------------------------------------------------------------------------------------------------------
其他的没啥好说的了,自个儿download代码看吧
以下附上code地址:https://code.csdn.net/geniuseoe2012/dynamicjar
假设童鞋们认为本文实用,最好还是关注我的code主页:https://code.csdn.net/geniuseoe2012
以后一些博文相关的demo会放在上面,这样大家就不用耗下载积分了。同一时候便于代码更正
很多其它开源项目可关注我的github主页:https://github.com/geniusgithub
深入浅出Android动态载入jar包技术的更多相关文章
- Android动态载入JAR包的实现方法
有时候我们须要使用动态更新技术,简单来说就是:当我们把开发jar包发送给用户后.假设后期升级了部分代码.这时让用户的jar包自己主动更新,而不是用户主动手动地去更新的技术就是动态更新.这个须要使用的技 ...
- Android动态载入Dex机制解析
1.什么是类载入器? 类载入器(class loader)是 Java™中的一个非常重要的概念.类载入器负责载入 Java 类的字节代码到 Java 虚拟机中. Java 虚拟机使用 Java 类的方 ...
- Android动态加载代码技术
Android动态加载代码技术 在开发Android App的过程当中,可能希望实现插件式软件架构,将一部分代码以另外一个APK的形式单独发布,而在主程序中加载并执行这个APK中的代码. 实现这个任务 ...
- Android Studio导出Jar包
这篇博客将介绍一下如何用Android Studio导出jar包,希望能给大家带来帮助. 首先需要修改build.gradle文件,在Android Studio中会显示多个build.gradle文 ...
- 如何制作Jar包并在android中调用jar包
android制作jar包: 新建android工程,然后右击,点击导出,选择导出类型为Java下的JAR file,在java file specification 中不要选择androidmani ...
- 使用命令动态更新JAR包中的文件
动态更新JAR包中的文件,经本人实际测试可正常执行! 一.查询jar包中要替换的文件位置 jar -tvf gateway.jar | grep topjui.config.js 二.在当前 ...
- 深入浅出Android动态加载jar包技术
在实际项目中,由于某些业务频繁变更而导致频繁升级客户端的弊病会造成较差的用户体验,而这也恰是Web App的优势,于是便衍生了一种思路,将核心的易于变更的业务封装在jar包里然后通过网络下载下来,再由 ...
- 实现Android 动态载入APK(Fragment or Activity实现)
尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38565345 近期由于项目太大了.导致编译通只是(Android对一个应用中的方法个数貌似有 ...
- android studio 使用jar包,arr包和怎么使用githup开源项目中的aar包或module
我这里的android studio的版本是2.2.3版本 一.现在大家都用android studio了,就有人问怎么使用jar包 其实使用jar包比较简单 直接吧jar放入工程的app目录下的li ...
随机推荐
- C++引用的实质
转自探索c++的底层机制 在看这篇文章之前,请你先要明白一点:那就是c++为我们所提供的各种存取控制仅仅是在编译阶段给我们的限制,也就是说是编译器确保了你在完成任务之前的正确行为,如果你的行为不正确, ...
- Error format not a string literal and no format arguments解决方案
原地址: http://blog.csdn.net/joeblackzqq/article/details/25985299 cData.cpp:355:30:error:format not a s ...
- 玩转AWS CloudWatch微信告警
做海外业务时大多使用亚马逊 AWS 服务,配套AWS 监控 CloudWatch 功能强大,如果能和微信结合就更棒了.现在分享下如何玩转 CloudWatch 微信通知. AWS EC2 云主机配套的 ...
- 这个帖子要收藏,以后用得着--python 实时获取子进程输出
在论坛上找到方法了,http://bbs.csdn.net/topics/340234292 http://blog.csdn.net/junshao90/article/details/821575 ...
- linux 匹配查询列表中包含某一特殊字符的所有行中的某一列
命令: ll | grep sh | awk '{print $9}' 解析: 其中,匹配列的命令为awk '{print $n}',$n为匹配的第几列.
- ServletInvocableHandlerMethod:167 - Error resolving argument
at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(R ...
- Spring AOP实现方式四之注入式AspectJ切面【附源码】
现在我们要讲的是第四种AOP实现之注入式AspectJ切面 通过简单的配置就可以实现AOP了. 源码结构: 1.首先我们新建一个接口,love 谈恋爱接口. package com.spring.ao ...
- Android 内核初识(6)SystemServer进程
简介 SystemServer的进程名实际上叫做“system_server”,通常简称为SS. 系统中的服务驻留在其中,常见的比如WindowManagerServer(Wms).ActivityM ...
- 可否控制<link type=text/css rel=stylesheet href=style.css>
本篇文章主要介绍了"可否控制<link type=text/css rel=stylesheet href=style.css> ", 主要涉及到可否控制<lin ...
- 查找Form的文件名
我们经常会要在ORACLE EBS中寻找我们正在浏览的form页面的执行文件,我们都会直接在Help中的菜单里点击"About Oracle Application",然后查看当前 ...