`
iaiai
  • 浏览: 2142003 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android动态加载jar、apk的实现

 
阅读更多
      核心类
      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 
*/  
rivate 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.
  • 大小: 80.3 KB
  • 大小: 77.8 KB
  • 大小: 83 KB
  • 大小: 87.6 KB
分享到:
评论

相关推荐

    Android动态加载未安装apk, jar

    该源码包包含Android平台下动态插件化加载未安装的apk或者jar包

    Qt on Android调用Jar包

    演示如何在Qt on Android应用中通过JNI调用第三方Jar包

    android工程正确导入jar包

    这个主要解决android工程中如何正确导入jar包,并一同打包到apk中!

    apk加壳和动态加载技术

    动态加载技术 该技术在Java中是一个比较成熟的技术,而Android中该技术还没有被大家充分利用起来。该技术思想主要分为以下几步: 1.将核心代码编译成dex文件的Jar包 2. 对jar包进行加密处理 3.在程序主入口利用NDK...

    Android系统定制之Android.mk和Android.bp语法详解(精通版).mp4

    1.Android系统源码定制和编译方法(Android7.0至...4.Android.mk或Android.bp编译生成Apk、静态库、动态库、可执行文件等的使用方法 5.Android系统定制有源码App或无源码App时关于Android.mk或Android.bp的使用方法

    Android 实现读写U盘文件

    Android 基于libaums实现读写U盘文件,相关博客:https://blog.csdn.net/a512337862/article/details/80505128

    dex2jar,apk反编译

    很好用的一个apk反编译软件,本人屡试不爽,不过用配置dex2jar的路径,首先解压dex2jar.zip,然后将解压后的dex2jar拷贝到c盘的根目录下,然后在配置dex2jar的环境变量,就是把dex2jar的路径加入到path路径中,然后再...

    apk反编译工具,脚本以及jar包

    android apk 反编译工具,apktool 以及 apktool.jar ,网站上面的好多都不能用

    验证apk/jar的签名

    修复了android5.0之前的系统版本对apk的验证漏洞,删除,增加,修改都能检测 安装apk和加载jar插件时通过验证cert.RSA, .MF .SF等签名文件证书以及摘要值比对判断是否是非法篡改过得apk/jar文件

    Android代码-dynamic-load-apk

    DL : Apk动态加载框架 开发文档 (Development Help) English README [使用Android Stuido导入项目](Android Studio.md) APK动态加载框架(DL)解析 DL 2.0的新特性 支持多进程模式,插件可以运行在单独的DL进程中...

    安卓USB串口万能驱动JAR包

    支持USB串口芯片,CH34X系列,CP21XX系列,Ftdi系列,采用基于安卓的USB访问API实现,支持跨平台安卓处理器,不需要编译二进制USB驱动支持,读写支持异步,直接加载到工程,直接使用

    Android代码-应用模块化和懒加载在 Instagram 中的实现

    Before this library can be used a module needs to be compiled to a separate jar/dex or apk file. Right now, the library supports java libraries and android libraries which don't rely on android ...

    Android APK 反编译小工具

    Android APK 反编译工具集合 v1.1 ========================================= 系统具备java和.net 2.0运行环境 使用方法: 1:把APKReflector.exe 拖到windows工具栏上或者桌面上建立快捷方式,或者加入右键发送...

    android 添加系统权限 INSTALL_FAILED_SHARED_USER_INCOMPATIBLE

    原因:apk的AndroidManifest.xml中声明了android:sharedUserId="android.uid.system",但没有相应的签名 解决方案: 1. 找到编译目标系统时的签名证书platform.pk8和platform.x509.pem,在android源码目录build\...

    快速Android 反编译 回编译 工具集 含直接调试破解之法

    含Android 反编译 回编译 工具 最新apktool jar查看器jdgui Smali2Java dex2jar 签名signapk Smali2JavaUI AXMLPrinter2 等工具.... 直接调试破解之法->第一步:使用apktool来破解apk java -jar apktool_2.0.0rc4....

    安卓dx.jar包

    安卓dx开发jar包,安卓启动eclipse报错,提示dx加载错误

    java反编译源码保护-ApkAnalyzer:用于分析AndroidAPK文件的Java工具

    来完成,不能使用命令行参数(尚未实现)。 您还可以将其作为 Java 程序使用和运行。 命令行参数 范围 信息 -分析 触发器分析任务。 请参阅 [分析 APK] (#Analyze_APKs) 一章 -比较 触发比较任务

    安卓一键反编译回编译apk+jar格式工具 带演示图

    1--工具可以一键反编译和回编译apk与jar格式的工具 2----工具带实测演示图示 方便操作者对照操作 3----对于一些常用apk操作比较简单。系统类的需要加载系统框架编译。对与有壳的app。需要自行去壳后才可以。 4---...

    计算Android中APK或DEX方法数量工具

    电脑需要java环境,如果dex-method-counts.jar工具放在D盘,直接使用命令java -jar D:\dex-method-counts.jar D:\test.apk,如果需要计算类的field数量 添加“--count-fields”参数,如java -jar D:\dex-method-...

    DexClassloader:这个一个demo,用来实现加载class文件,如果在实际项目中可以实现,动态修改代码的业务逻辑

    DexClassloader 这个一个demo,用来实现加载class文件,如果在实际项目中可以...2: DexClassloader: Android 用来加载 jar/apk/dex 文件 3: URLClassloader: 可以加载java的jar包,但是Dalvik 虚拟机不支持这种加载方式

Global site tag (gtag.js) - Google Analytics