android 如何动态的加载类----app插件技术

来源:互联网 发布:软件sp版本是什么意思 编辑:程序博客网 时间:2024/05/16 16:09

前言:

      在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势。现如今很多项目要求需要采用类似于微信或Q游这样的插件化开发模式越来越多,本文就是阐述android的动态加载技术来满足插件化开发模式的文章。

1.基本概念

1.1  在Android中可以动态加载,但无法像Java中那样方便动态加载jar。

Android的虚拟机(DalvikVM)是不认识Java打出jar的byte code,需要通过dx工具来优化转换成Dalvikbyte code才行。这一点在咱们Android项目打包的apk中可以看出:引入其他Jar的内容都被打包进了classes.dex。即android要加载的java类必须dex格式的代码文件.

1.2  在Android中可以加载基于NDK的so库。

NDK的执行效率很高,加密性很好,但同时开发入门难度大,一般用于加解密、数学运算等场合。so的加载很简单,如果APK发布时已经携带了so文件,只需要在加载时调用System.loadLibrary(libName)方法即可。由于软件的安装目录中存放so的目录是没有写权限的,开发者不能更改该目录的内容,所以如果要动态加载存放在其他地方的so文件,用System.load(pathName)方法即可。

1.3  在Android中支持动态加载dex文件的两种方式:

DexClassLoader这个可以加载jar/apk/dex,也可以从SD卡中加载,也是本文的重点

PathClassLoader只能加载已经安装到Android系统中的apk文件。也就是 /data/app 目录下的 apk 文件。其它位置的文件加载的时候都会出现 ClassNotFoundException.因为 PathClassLoader 会去读取 /data/dalvik-cache 目录下的经过 Dalvik 优化过的 dex 文件,这个目录的 dex 文件是在安装 apk 包的时候由 Dalvik 生成的。


2.注意

2.1 采用不用安装的插件开发模式,只能够使用 DexClassLoader进行加载.不过动态加载是有一些限制的,比如插件(子apk)包中的Activity、Service类是不能动态加载的,因为缺少声明;即使你在Manifest文件中进行了声明,系统默认也是到安装apk所在的路径中去寻找类,所以你会遇到一个ClassNotFound的异常。插件里你可以用主apk中先前放入的layout、strings等资源。但是插件中自带的界面只能用纯代码进行编写,插件中是不能加载插件(子apk)中的xml作为layout等资源使用的。所以在开发上一些特效会比较困难些,建议预先植入主apk中。

2.2 大家可以看看DexClassLoader的API文档,里面不提倡从SD卡加载,不安全

3.如何制作插件

3.1 把工程导出为jar包

3.2 执行SDK安装目录android-sdk-windows\platform-tools下的dx命令,把jar包转换为dex格式

dx --dex --output=dex名 jar包名

4.如何做到启动未安装的apk中的activity?

   采用反射机制,把主apk中的activity的context传递到插件的activity中,然后采用反射进行回调插件activity的方法。不足之出就是,插件中的activity并不是真正的activity,它只是运行在主activity中。比如:点击返回直接退出当前activity而不是回到主activity。实例如下:

这是调用的Activity:

[java] view plaincopy
  1. package com.beyondsoft.activity;  
  2.   
  3. import java.lang.reflect.Constructor;  
  4. import java.lang.reflect.InvocationTargetException;  
  5. import java.lang.reflect.Method;  
  6.   
  7. import dalvik.system.DexClassLoader;  
  8. import android.app.Activity;  
  9. import android.content.pm.PackageInfo;  
  10. import android.os.Bundle;  
  11. import android.util.Log;  
  12.   
  13. public class PlugActivity extends Activity {  
  14.   
  15.     private Class mActivityClass;  
  16.     private Object mActivityInstance;  
  17.     Class localClass;  
  18.     private Object instance;  
  19.   
  20.     @Override  
  21.     protected void onCreate(Bundle savedInstanceState) {  
  22.         super.onCreate(savedInstanceState);  
  23.   
  24.         Bundle paramBundle = new Bundle();  
  25.         paramBundle.putBoolean("KEY_START_FROM_OTHER_ACTIVITY"true);  
  26.         paramBundle.putString("str""PlugActivity");  
  27.         String dexpath = "/sdcard/FragmentProject.apk";  
  28.         String dexoutputpath = "/mnt/sdcard/";  
  29.         LoadAPK(paramBundle, dexpath, dexoutputpath);  
  30.     }  
  31.   
  32.     @Override  
  33.     protected void onStart() {  
  34.         super.onStart();  
  35.         Method start;  
  36.         try {  
  37.             start = localClass.getMethod("onStart");  
  38.                 start.invoke(instance);  
  39.         } catch (Exception e) {  
  40.             // TODO Auto-generated catch block  
  41.             e.printStackTrace();  
  42.         }  
  43.     }  
  44.   
  45.     @Override  
  46.     protected void onResume() {  
  47.         // TODO Auto-generated method stub  
  48.         super.onResume();  
  49.         Method resume;  
  50.         try {  
  51.             resume = localClass.getMethod("onResume");  
  52.             resume.invoke(instance);  
  53.         } catch (Exception e) {  
  54.             // TODO Auto-generated catch block  
  55.             e.printStackTrace();  
  56.         }  
  57.     }  
  58.   
  59.     @Override  
  60.     protected void onPause() {  
  61.         super.onPause();  
  62.         Method pause;  
  63.         try {  
  64.             pause = localClass.getMethod("onPause");  
  65.             pause.invoke(instance);  
  66.         } catch (Exception e) {  
  67.             e.printStackTrace();  
  68.         }  
  69.     }  
  70.   
  71.     @Override  
  72.     protected void onStop() {  
  73.         super.onStop();  
  74.         try {  
  75.             Method stop = localClass.getMethod("onStop");  
  76.             stop.invoke(instance);  
  77.         } catch (Exception e) {  
  78.             e.printStackTrace();  
  79.         }  
  80.     }  
  81.   
  82.     @Override  
  83.     protected void onDestroy() {  
  84.         // TODO Auto-generated method stub  
  85.         super.onDestroy();  
  86.         try {  
  87.             Method des = localClass.getMethod("onDestroy");  
  88.             des.invoke(instance);  
  89.         } catch (Exception e) {  
  90.             // TODO Auto-generated catch block  
  91.             e.printStackTrace();  
  92.         }  
  93.     }  
  94.   
  95.     public void LoadAPK(Bundle paramBundle, String dexpath, String dexoutputpath) {  
  96.         ClassLoader localClassLoader = ClassLoader.getSystemClassLoader();  
  97.         DexClassLoader localDexClassLoader = new DexClassLoader(dexpath, dexoutputpath, null, localClassLoader);  
  98.         try {  
  99.             PackageInfo plocalObject = getPackageManager().getPackageArchiveInfo(dexpath, 1);  
  100.   
  101.             if ((plocalObject.activities != null) && (plocalObject.activities.length > 0)) {  
  102.                 String activityname = plocalObject.activities[0].name;  
  103.                 Log.d("sys""activityname = " + activityname);  
  104.   
  105.                 localClass = localDexClassLoader.loadClass(activityname);//结果:"com.example.fragmentproject.FristActivity"  
  106.                 mActivityClass = localClass;  
  107.                 Constructor localConstructor = localClass.getConstructor(new Class[] {});  
  108.                 instance = localConstructor.newInstance(new Object[] {});  
  109.                 Log.d("sys""instance = " + instance);  
  110.                 mActivityInstance = instance;  
  111.   
  112.                 Method des = localClass.getMethod("test");  
  113.                 des.invoke(instance);  
  114.                   
  115.                 Method localMethodSetActivity = localClass.getDeclaredMethod("setActivity"new Class[] { Activity.class });  
  116.                 localMethodSetActivity.setAccessible(true);  
  117.                 localMethodSetActivity.invoke(instance, new Object[] { this });  
  118.   
  119.                  Method methodonCreate = localClass.getDeclaredMethod("onCreate"new Class[] { Bundle.class });  
  120.                  methodonCreate.setAccessible(true);  
  121.                  methodonCreate.invoke(instance, paramBundle);  
  122.             }  
  123.             return;  
  124.         } catch (Exception ex) {  
  125.             ex.printStackTrace();  
  126.         }  
  127.     }  
  128.   
  129. }  


这是被调用的Activity:

[java] view plaincopy
  1. public class FristActivity extends Activity{  
  2.   
  3.     private Button fragment;  
  4.     private Button listFragment;  
  5.     private Button controlFragment;  
  6.     private Button viewFlipper;  
  7.     private Button viewPager;  
  8.     private Activity otherActivity;  
  9.   
  10.     public void test() {  
  11.         Log.i("sys""测试方法执行了");  
  12.     }  
  13.   
  14.     @Override  
  15.     public void onCreate(Bundle savedInstanceState) {  
  16.         super.onCreate(savedInstanceState);  
  17.          // 测试DexClassLoader 动态加载未安装Apk中的类  
  18.         TextView t = new TextView(otherActivity);  
  19.         t.setText("我是测试");  
  20.         otherActivity.setContentView(t);// R.layout.frist_activity_main  
  21.   
  22.         Log.i("sys""Fragment项目启动了");  
  23.     }  
  24.   
  25.     public void setActivity(Activity paramActivity) {  
  26.         Log.d("sys""setActivity..." + paramActivity);  
  27.         this.otherActivity = paramActivity;  
  28.     }  
  29.   
  30.     @Override  
  31.     public void onSaveInstanceState(Bundle outState) {  
  32.         super.onSaveInstanceState(outState);  
  33.         Log.i("sys""OnSaveInstance被调了");  
  34.     }  
  35.   
  36.     @Override  
  37.     public void onStart() {  
  38.         Log.i("sys""onStart被调了");  
  39.         // TODO Auto-generated method stub  
  40.         super.onStart();  
  41.     }  
  42.   
  43.     @Override  
  44.     public void onResume() {  
  45.         Log.i("sys""onResume被调了");  
  46.         // TODO Auto-generated method stub  
  47.         super.onResume();  
  48.     }  
  49.   
  50.     @Override  
  51.     public void onPause() {  
  52.         Log.i("sys""onPause被调了");  
  53.         // TODO Auto-generated method stub  
  54.         super.onPause();  
  55.     }  
  56.   
  57.     @Override  
  58.     public void onStop() {  
  59.         Log.i("sys""onStop被调了");  
  60.         // TODO Auto-generated method stub  
  61.         super.onStop();  
  62.     }  
  63.   
  64.     @Override  
  65.     protected void onDestroy() {  
  66.         Log.i("sys""onDestroy被调了");  
  67.         // TODO Auto-generated method stub  
  68.         super.onDestroy();  
  69.     }  
  70. }  
5.参考文章

1.http://www.cnblogs.com/over140/archive/2011/11/23/2259367.html

2.http://blog.csdn.net/mirkerson/article/details/8771723

3.http://blog.csdn.net/scliu0718/article/details/8438823

4.http://www.verydemo.com/demo_c131_i24569.htmlAndroid 通过反射启动未安装的APK中的Activity的实例代码)

5.http://www.myexception.cn/android/1217391.htmlAndroid 通过反射启动未安装的APK中的Activity的实例图形说明)

 

转载:http://blog.csdn.net/mingli198611/article/details/8858076

另操作例子:http://blog.csdn.net/qingye_love/article/details/12621147

http://www.blogjava.net/zh-weir/archive/2011/10/29/362294.html

原创粉丝点击