最近研究了下android动态加载jar,下面总结下。
这里使用的eclipse开发测试。
网上介绍原理的很多,请自行百度.
首先需要创建两个工程,一个是生成需要的jar的工程,一个是实际测试用的工程
接口类工程中建两个包如下图:
IDynamic.java内容如下:
package com.dynamic.interfaces;
import android.app.Activity;
public interface IDynamic {
public int cal(int a,int b);
public String test();
}
Dynamic.java内容如下:
package com.dynamic.impl;
import android.app.Activity;
import android.util.Log;
import android.widget.Toast;
import com.dynamic.interfaces.IDynamic;
public class Dynamic implements IDynamic{
@Override
public int cal(int a, int b) {
// TODO Auto-generated method stub
return (a * b);
}
@Override
public String test() {
// TODO Auto-generated method stub
return "this is Dynamic test1";
}
}
然后分别导出这两个文件为jar
选中IDynamic.java右键点击导出JAR FILE,导出文件名为jarint.jar
注意导出的时候只需要选这一个文件
同样选中Dynamic.java右键点击导出JAR FILE,导出文件名为jartest.jar
注意导出的时候只需要选这一个文件
将jartest.jar拷贝到sdk目录中的build-tools中的对应的api目录中,例如我的是
build-tools\22.0.1
然后在命令行进行这个目录:
执行dx --dex --out dex.jar jartest.jar如下图(注意:中间的--为两个"-")
然后将生成的dex.jar push到系统/sdcard目录下(,我的这个sdcard目录为内部存储挂载路径,我测试的是有root权限的所以可以这么整,没权限的还是通过TF卡)
这两个jar过会需要使用
实际测试应用内容如下:
需要将上面导出的jarint.jar放在这个工程的libs目录下
Main.java内容如下:
package com.example.jartest;
import java.io.File;
import java.util.List;
import com.dynamic.interfaces.IDynamic;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import dalvik.system.DexClassLoader;
import dalvik.system.PathClassLoader;
public class Main extends Activity {
public final static String TAG = "jartest";
final private String BasePath = "/sdcard";//"/storage/sdcard1";
private IDynamic lib;
String jarpath = BasePath + "/dex.jar";
String packname = "com.dynamic.impl";
private Button mytest;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mytest = (Button)findViewById(R.id.mytest);
Log.d(TAG, "jarpath: " + jarpath);
File jar = new File(jarpath);
if(!jar.exists()) {
Log.d(TAG, "++jar file not found");
return;
}
mytest.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
DexLoader();
//PathLoader();
}
});
}
private void PathLoader() {
Intent intent = new Intent(packname, null);
PackageManager pm = getPackageManager();
List<ResolveInfo> resolveinfoes = pm.queryIntentActivities(intent, 0);
Log.d(TAG, "list: " + resolveinfoes.size());
ActivityInfo actInfo = resolveinfoes.get(0).activityInfo;
String apkPath = actInfo.applicationInfo.sourceDir;
String libPath = actInfo.applicationInfo.nativeLibraryDir;
Log.d(TAG, "apkPath: " + apkPath);
Log.d(TAG, "libPath: " + libPath);
PathClassLoader pcl = new PathClassLoader(apkPath,libPath,this.getClassLoader());
try {
Class libProviderClazz = pcl.loadClass("com.dynamic.impl.Dynamic");
lib = (IDynamic)libProviderClazz.newInstance();
if(lib != null){
Log.d(TAG, "---:" + lib.test());
Log.d(TAG, "---cal :" + lib.cal(1,2));
} else
Log.d(TAG, "++lib is null");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
Log.d(TAG, e.getMessage());
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
Log.d(TAG, e.getMessage());
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
Log.d(TAG, e.getMessage());
e.printStackTrace();
}
}
private void DexLoader() {
File dexOutputDir = this.getDir("dex", 0);
String tmpPath = dexOutputDir.getAbsolutePath();
Log.d(TAG," tmpPath: " + tmpPath);
DexClassLoader cl = new DexClassLoader(jarpath,tmpPath,null,this.getClassLoader());
try {
Class libProviderClazz = cl.loadClass("com.dynamic.impl.Dynamic");
lib = (IDynamic)libProviderClazz.newInstance();
if(lib != null){
Log.d(TAG, "---:" + lib.test());
Log.d(TAG, "---cal :" + lib.cal(1,2));
} else
Log.d(TAG, "++lib is null");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
Log.d(TAG, e.getMessage());
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
Log.d(TAG, e.getMessage());
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
Log.d(TAG, e.getMessage());
e.printStackTrace();
}
}
}
注意:使用DexLoader即使用DexClassLoader类加载,如果dex.jar是放在内部存储路径或者外部存储中,需要加相应的权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
如果使用PathLoader即使用PathClassLoader加载,需要在接口类我的为JarInterface的AndroidManifest.xml中增加对应的包名:
<action android:name="com.dynamic.impl"/>
修改后如下:
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".Main"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="com.dynamic.impl"/>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
不然调用不会成功
相关源码下载地址:http://download.csdn.net/download/hclydao/9928304
参考文章: http://blog.csdn.net/jiangwei0910410003/article/details/17679823