Android dynamic framework 学习
@(深入理解OSGI 应用与最佳实践)[ 资源管理, java反射, 动态代理, android aapt 学习, dexFile, 资源管理]
知识点
- 资源管理[res+assets]
- java反射
- 动态代理
- android aapt 学习
- android dexopt 优化
- android dexFile pathclassloader DexClassLoader 学习
资源管理
-
res 资源介绍
介绍:
主要存放 图片资源 和 布局文件 和一些简单的color 值 、values 值 、style样式、动画设置文件
如图:
assets 介绍,管理
介绍
这是一个 read only 文件夹 ,系统提供了一个AssetManager ,可将文件进行读取
源代码如下
package com.example.assetmanager;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.AssetManager;
/**
*
* @author james
*
*/
public class AssetUtil {
public Context context;
public String hello = "hello world";
public AssetUtil(Context context) {
this.context = context;
}
@SuppressLint("NewApi")
public void createFinder(String filePath) {
try {
File file = new File(filePath);
if (!file.exists()) {
file.mkdir();
file.setExecutable(true, true);
file.setReadable(true,true);
file.setWritable(true, true);
File file1 = new File(filePath+"/log.txt");
file1.createNewFile();
BufferedOutputStream bufferOutputStream = new BufferedOutputStream(new FileOutputStream(file1));
bufferOutputStream.write(hello.getBytes());
bufferOutputStream.flush();
bufferOutputStream.close();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public List getAssetsList(){
try {
String[] listfile = context.getAssets().list("");
for(int i = 0; i < listfile.length;i++){
System.out.println("assets path" +listfile[i]);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public void assetsToDdPack(){
try{
String path = "/data/data/com.example.assetmanager/plug_core";
FileOutputStream fileOutputStream = new FileOutputStream(new File(path));
AssetManager as =context.getAssets();
InputStream inputStream = as.open("aapt_mac");
byte[] buffer = new byte[1024];
int len = 0;
while((len = inputStream.read(buffer)) != -1){
fileOutputStream.write(buffer);
}
fileOutputStream.flush();
fileOutputStream.close();
inputStream.close();
}catch(Exception e){
e.printStackTrace();
}finally{
}
}
}
java 反射
java.lang.reflect java反射包
import java.lang.reflect.Constructor; 构造
import java.lang.reflect.Field;声明
import java.lang.reflect.Method;方法
- getFields():获得类的public类型的属性
- getDeclaredFields():获得类的所有属性,包括public、protected、默认和private访问级别的属性。
- getMethods():获得类的public类型的方法。
- getDeclaredMethods():获得类的所有方法。
package com.james.reflectmanager;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
*
* @author james
*
*
*/
public class ReflectManagerDemo {
public static void main1(String[] args) {
try {
String testStr = "goodleiwei";
Class testStrClass = testStr.getClass();
Class stringClass = String.class;
String forNameClass = (String) Class.forName("java.lang.String")
.newInstance();
forNameClass = "this is java.lang.String";
System.out.println(forNameClass);
String str1 = (String) Class.forName("java.lang.String")
.getConstructor(StringBuffer.class)
.newInstance(new StringBuffer("abc"));
System.out.println(str1.charAt(2));
User user = new User();
Class clazz = user.getClass();
String classGetName = clazz.getName();
System.out.println(classGetName);
User newUser = (User) Class
.forName("com.james.reflectmanager.User").newInstance();
/**
* getFields():获得类的public类型的属性。
* getDeclaredFields():获得类的所有属性,包括public、protected、默认和private访问级别的属性。
* getMethods():获得类的public类型的方法。
* getDeclaredMethods():获得类的所有方法。
*/
// 方法
Method[] method = newUser.getClass().getMethods();
for (int i = 0; i < method.length; i++) {
System.out.println("getMethods() = "+method[i].getName());
}
// 获取当前对象的所有的public 声明 以及父类 声明字段
Field[] field = newUser.getClass().getFields();
for (int j = 0; j < field.length; j++) {
System.out.println("getFields()="+field[j].getName());
}
Method[] methodDeclared = newUser.getClass().getDeclaredMethods();
for (Method methods : methodDeclared) {
System.out.println("getDeclaredMethods()="+methods.getName());
}
// 方法的调用
Method oldValMethod = newUser.getClass().getDeclaredMethod("setName",new String().getClass());
oldValMethod.setAccessible(true);
oldValMethod.invoke(newUser, "james");
System.out.println("newUser.getName = "+newUser.getName());
Field[] fieldDeclared = newUser.getClass().getDeclaredFields();
for(Field fields : fieldDeclared){
System.out.println("getDeclaredFields()="+fields.getName());
}
/**
* 构造方法
*/
Constructor[] constructors = newUser.getClass().getDeclaredConstructors();
for (Constructor constructor :constructors) {
System.out.println("构造方法"+constructor.getName());
Class[] parameterTypes = constructor.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
System.out.println("parameterTypes="+parameterTypes[i]);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
动态代理+静态代理[设计模式]
代理模式主要是设计模式里面的结构模式,主要分为动态代理和静态代理,代理所应用的场景和案例
场景:
1:用于在不修改源码的情况下,增强一些方法,可以在执行源码方法之前和之后,做你想做的事情。
2: 可作为远程调用。
案例:spring AOP Dubbo等...
Code
静态代理
package proxy;
/**
*
* @author james
*/
public abstract class AbstractObject {
// 操作
public abstract void operation();
}
package proxy;
/**
*
* @author james
*/
public class ProxyObject extends AbstractObject{
RealObject realObject = new RealObject();
@Override
public void operation() {
//调用目标对象之前可以做相关操作
System.out.println("before");
realObject.operation();
//调用目标对象之后可以做相关操作
System.out.println("after");
}
}
package proxy;
/**
* 目标对象角色
* @author james
*/
public class RealObject extends AbstractObject {
@Override
public void operation() {
System.out.println("目标对象角色");
}
}
package proxy;
/**
* 代理模式
* @author james
*/
public class Proxy {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
ProxyObject object = new ProxyObject();
object.operation();
}
}
动态代理
Code
package com.james.reflectmanager.invocationhandlerdemo;
public interface SubJect {
public void request();
public void response(String str);
}
package com.james.reflectmanager.invocationhandlerdemo;
public class RealSubject implements SubJect {
@Override
public void request() {
// TODO Auto-generated method stub
System.out.println("From real subject.");
}
@Override
public void response(String str) {
// TODO Auto-generated method stub
System.out.println(str);
}
}
package com.james.reflectmanager.invocationhandlerdemo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicSubject implements InvocationHandler {
private Object obj;
public DynamicSubject() {
}
public DynamicSubject(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println(proxy.getClass().getName());
System.out.println(method.getName());
if (args != null) {
System.out.println(args[0]);
}
System.out.println("before calling " + method);
method.invoke(obj, args);
System.out.println("after calling " + method);
return null;
}
}
package com.james.reflectmanager.invocationhandlerdemo;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class client {
public static void main(String[] args) {
SubJect subJect = new RealSubject();
InvocationHandler invocationHandler = new DynamicSubject(subJect);
Class> clazz = subJect.getClass();
SubJect newsubject = (SubJect) Proxy.newProxyInstance(
clazz.getClassLoader(), clazz.getInterfaces(),
invocationHandler);
System.out.println("运行结果");
newsubject.request();
newsubject.response("this is response");
// 获取当前对象的所有的public 声明 以及父类 声明字段
// Field[] field = newsubject.getClass().getFields();
// for (int j = 0; j < field.length; j++) {
// System.out.println("getFields()=" + field[j].getName());
// }
// Method[] methods = newsubject.getClass().getMethods();
//
// for(Method method: methods){
// System.out.println("getMethods()="+method.getName());
// }
}
}
android aapt 学习
android aapt 简介
aapt (Android Asset Packaging Tool ) 在androidsdk的build-tools目录下,aapt可以查看、创建、更新ZIP格式的文档附件(zip,jar,apk),也可以将资源文件编译成二进制文件。android aapt使用方法
1: aapt list [-v | -a] xxx.apk 列出当前压缩文件的所有目录
2: aapt dump badging xxx.apk 查看apk包packageName,versionCode,applicationLabel、launcherActivity、Permission等
3:aapt dump permissions xxx.apk 查看权限
4:aapt dump resources xxx.apk 查看资源列表
5:aapt dump configurations xxx.apk 查看apk配置信息
6:aapt dump xmltree xxx.apk res/xxx.xml 查看指定apk的指定xml文件
7:aapt package -m -J /Users/dream/Documents/work/dynamic1/gen/com/example/dynamic1 -S /Users/dream/Documents/work/dynamic1/res -I /Users/dream/Documents/android/android/adt-bundle-mac-x86_64-20140624/sdk/platforms/android-23/android.jar -M ../AndroidManifest.xml 使用aapt 生成R.java 文件
8:aapt package -f -S /Users/dream/Documents/work/dynamic1/res -I /Users/dream/Documents/android/android/adt-bundle-mac-x86_64-20140624/sdk/platforms/android-23/android.jar -A /Users/dream/Documents/work/dynamic1/assets -M ../AndroidManifest.xml -F /Users/dream/Documents/work/dynamic1/assets/dynamic.apk使用aapt 生成资源包文件
9 apkbuilder dynamic1.apk -u -z dynamic.apk -f ../bin/classes.dex -rf ../src/
将资源包文件与classes 文件打包成为apk文件"-
android aapt 手动编译打包详解图
CODE 源代码
#!/bin/bash
###
# aapt 批处理
# 主要列举了 aapt 的一系列操作方法 和案例
# 案例 以微信为例
###
source log.sh
source keytool.sh
source zipalign.sh
source javatoclass.sh
source sh_init.sh
init # 脚本初始化
echo "aapt 说明"
aapt >> log.txt
echo "***********************aapt 批处理******************************"
echo "1:aapt list [-v | -a] xxx.apk列出当前压缩文件的所有目录"
echo "2:aapt dump badging xxx.apk 查看apk包packageName,versionCode,applicationLabel、launcherActivity、Permission等"
echo "3:aapt dump permissions xxx.apk 查看权限"
echo "4:aapt dump resources xxx.apk 查看资源列表"
echo "5:aapt dump configurations xxx.apk 查看apk配置信息"
echo "6:aapt dump xmltree xxx.apk res/xxx.xml 查看指定apk的指定xml文件"
echo "7:aapt package -m -J -S -I -M 使用aapt 生成R.java 文件"
echo "8:aapt package -f -S -I -A -M -F <输出的包目录+包名> 使用aapt 生成apk包文件"
echo "***********************aapt 批处理******************************"
printf_log "列出当前zip jar apk 压缩文件里面的目录"
aapt lisr weixin.apk >> log.txt
printf_log "以table的方式把包里面的信息全部列出来"
aapt list -v weixin.apk >> log.txt
printf_log "列出详细的信息"
aapt list -a weixin.apk >> log.txt
printf_log "查看apk包packageName,versionCode,applicationLabel、launcherActivity、Permission等"
aapt dump badging weixin.apk >> log.txt
printf_log "查看权限"
aapt dump permissions weixin.apk >> log.txt
printf_log "查看资源列表"
aapt dump resources weixin.apk >> log.txt
printf_log "查看apk配置信息"
aapt dump configurations weixin.apk >> log.txt
printf_log "将工程的资源编译到R.java文件"
#aapt package -m -J /Users/dream/Documents/work/dynamic1/gen/com/example/dynamic1 -S /Users/dream/Documents/work/dynamic1/res -I /Users/dream/Documents/android/android/adt-bundle-mac-x86_64-20140624/sdk/platforms/android-23/android.jar -M ../AndroidManifest.xml
javac_class
class_dex
printf_log "将工程编译成 资源包文件"
aapt package -f -S /Users/dream/Documents/work/dynamic1/res -I /Users/dream/Documents/android/android/adt-bundle-mac-x86_64-20140624/sdk/platforms/android-23/android.jar -A /Users/dream/Documents/work/dynamic1/assets -M ../AndroidManifest.xml -F /Users/dream/Documents/work/dynamic1/assets/dynamic.apk
printf_log "将资源包文件与classes 文件打包成为apk文件"
apkbuilder dynamic1.apk -u -z dynamic.apk -f ../bin/classes.dex -rf ../src/
create_keystore
zipalign_tools
exit 0
#!/bin/bash
##########
# 输出日志
#
#########
#打印日志
function printf_log(){
echo $1 >> log.txt
}
#!/bin/bash
####
# 创建一个签名文件
#
####
source log.sh
function create_keystore(){
printf_log "创建一个签名文件"
#keytool -genkey -alias dynamic.keystore -keyalg RSA -validity 40000 -keystore dynamic.keystore >> log.txt
printf_log "生成签名的apk文件"
jarsigner -verbose -keystore dynamic.keystore -signedjar dynamic_signed.apk dynamic1.apk dynamic.keystore
}
#!/bin/bash
###
# 压缩优化 apk文件
#
###
source log.sh
function zipalign_tools(){
printf_log "压缩优化apk文件"
zipalign -v 4 dynamic_signed.apk dynamic_final.apk
}
#!/bin/bash
#####
# 编译java类文件生成class文件
# 使用android dx 生成classes.dex文件
#
#####
source log.sh
function javac_class(){
echo "将java类文件生成class 文件"
javac -encoding GB18030 -target 1.7 -bootclasspath /Users/dream/Documents/android/android/adt-bundle-mac-x86_64-20140624/sdk/platforms/android-23/android.jar -d ../bin ../src/com/example/dynamic1/*.java ../gen/com/example/dynamic1/R.java
}
function class_dex(){
echo "将classes 文件输出成为 classes.dex 文件"
dx --dex --output=../bin/classes.dex ../bin/classes
}
#!/bin/bash
##
# shell script 执行之前的初始化
# 1:日志文件删除与创建
# 2:各个apk文件删除
#
##
function init(){
init_log
rm_apk_file_init
}
#日志删除
function init_log(){
create_log
}
# 创建和删除日志
function create_log(){
if [ -f "$log.txt" ];then
echo "创建日志文件"
touch log.txt
else
echo "删除之前的日志文件"
rm -rf log.txt
echo "创建新的日志文件"
touch log.txt
fi
}
#删除已经存在的apk文件
function rm_apk_file_init(){
if [ -f "$dynamic1.apk" ];then
echo "dynamic1.apk 不存在"
else
echo "dynamic1.apk 删除"
rm -rf dynamic1.apk
fi
if [ -f "$dynamic_signed.apk" ];then
echo "dynamic_signed.apk 不存在"
else
echo "dynamic_signed.apk 删除"
rm -rf dynamic_signed.apk
fi
if [ -f "$dynamic_final.apk"];then
echo "dynamic_final.apk 不存在"
else
echo "dynamic_final.apk 删除"
rm -rf dynamic_final.apk
fi
}
#!/bin/bash
######
# 创建android项目
#
######
function create_android_project(){
echo "创建android新的项目"
android create project \
--target 6 \ # android list targets
--name MyAndroidApp \
--path ./MyAndroidAppProject \
--activity MyAndroidAppActivity \
--package com.example.myandroid
}
function create_library_project(){
echo "创建android library 新项目"
android create lib-project
--name MyLibrary \
--target 6 \
--path path/to/your/project \
--package com.example.mylibrary
}
android dexopt 优化
dexopt 介绍
dexopt 主要用来优化dex中的类文件,它会初始化一个VM,加载DEX文件并执行verification和optimization过程。
android dexFile pathclassloader DexClassLoader 学习
classloader类架构图
针对于dexclassloader、pathclassloader、URLclassLoader、DexFile说明讲解
DexClassLoader 说明
public DexClassLoader (String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) 创建一个DexClassLoader用来找出指定的类和本地代码(c/c++代码)。用来解释执行在DEX文件中的class文件。 路径的分隔符使用通过System的属性 path.separator 获得; String separeater = System.getProperty("path.separtor"); Parameters (参数介绍) dexPath 需要装载的APK或者Jar文件的路径。包含多个路径用File.pathSeparator间隔开,在Android上默认是 ":" optimizedDirectory 优化后的dex文件存放目录,不能为null libraryPath 目标类中使用的C/C++库的列表,每个目录用File.pathSeparator间隔开; 可以为 null parent 该类装载器的父装载器,一般用当前执行类的装载器
PathClassLoader 说明
系统加载器,只能加载/data/app 目录下的 apk文件 >
public PathClassLoader (String dexPath, ClassLoader parent)
Added in API level 1
Creates a PathClassLoader that operates on a given list of files and directories. This method is equivalent to calling PathClassLoader(String, String, ClassLoader) with a null value for the second argument (see description there).
Parameters
dexPath String: the list of jar/apk files containing classes and resources, delimited by File.pathSeparator, which defaults to ":" on Android
parent ClassLoader: the parent class loader*public PathClassLoader (String dexPath, String libraryPath, ClassLoader parent)
*Added in API level 1
Creates a PathClassLoader that operates on two given lists of files and directories. The entries of the first list should be one of the following:
JAR/ZIP/APK files, possibly containing a "classes.dex" file as well as arbitrary resources.
Raw ".dex" files (not inside a zip file).
The entries of the second list should be directories containing native library files.
Parameters
dexPath String: the list of jar/apk files containing classes and resources, delimited by File.pathSeparator, which defaults to ":" on Android
libraryPath String: the list of directories containing native libraries, delimited by File.pathSeparator; may be null
parent ClassLoader: the parent class loader
DexFIle 说明
DexFIle加载jar 和apk包 >
DexFile.loadDex(pluginsPath, optimizedDirectory, 0);
第一个参数为插件的路径
第二个参数为插件的dexopt 之后的文件 ,必须是文件不能是文件夹
第三个暂时 可选功能 官方说未定义
加载普通的dex源码块
plug1项目:
- 项目结构
- 源码
package com.james.dynamicdemo;
public interface IHelloWorld {
public void testPlug();
}
package com.james.dynamicdemo;
public class HelloWorld implements IHelloWorld {
public HelloWorld(){
}
/**
* 测试插件
*/
public void testPlug(){
System.out.println("hello world plug");
}
}
宿主项目
- 项目结构
- 项目源码
package com.james.dynamicdemo;
public interface IHelloWorld {
public void testPlug();
}
package com.james.dynamichostdemo.log;
public interface ILog {
public static final String TAG = "LOADDEX";
}
package com.james.dynamichostdemo.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import android.util.Log;
import com.james.dynamichostdemo.log.ILog;
/**
* 加上动态代理
* @author james
*
*/
public class DynamicProxy implements InvocationHandler,ILog {
private Object obj;
public DynamicProxy(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
Log.d(TAG, "开始运行普通插件");
method.invoke(this.obj, args);
Log.d(TAG, "运行普通插件结束");
return null;
}
}
package com.james.dynamichostdemo.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import com.james.dynamichostdemo.MainActivity;
import com.james.dynamichostdemo.log.ILog;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.util.Log;
/**
* 支付宝data/data 目录下的文件目录
* CrashSDK // 程序crash sdk
* app_crash // app crash
* app_fileCmdConfig// app文件命令行的配置
* app_h5container// h5 容器
* app_installApkCache
* //安装apk 的cache 缓冲
* app_installApkOtpCache//apk 进行dexopt 优化的apk 缓冲
* app_plugins
* app plugins 插件集合
* app_plugins_lib app 插件
* lib app_plugins_opt app 插件优化
* app_sslcache ssl 缓存
* app_ucmsdk
* app_webview
* cache databases files // 日志文件
* hotpatch lib shared_prefs
*
* @author james 初始化文件创建
*/
public class FileUtil implements ILog {
private Context context;
private String datapath = "/data/data/";
String packageName = null;
private String thisPackagePath = null;
private String files[] = { "/CrashSDK",// 0
"/app_crash",// 1
"/app_fileCmdConfig",// 2
"/app_h5container",// 3
"/app_installApkCache",// 4
"/app_installApkOtpCache",// 5
"/app_plugins",// 6
"/app_plugins_lib",// 7
"/app_plugins_opt",// 8
"/app_sslcache",// 9
"/file"// 10
};
public FileUtil(Context context) {
this.context = context;
packageName = this.context.getPackageName();
thisPackagePath = datapath + packageName;
}
@SuppressLint("NewApi")
public void init() {
try {
File file = new File(thisPackagePath);
if (!file.exists()) {
Log.d(TAG, thisPackagePath + "不存在!!");
return;
}
for (int i = 0; i < files.length; i++) {
File createFile = new File(thisPackagePath + files[i]);
if (!createFile.exists()) {
createFile.mkdir();
createFile.setReadable(true, true);
createFile.setWritable(true, true);
}
}
} catch (Exception e) {
Log.e(TAG, "文件初始化失败");
}
}
/**
* 把插件从assets 移动到package 下面app_plugins
*/
public String assetsMvtoPackage(String plugName) {
InputStream inputStream = null;
FileOutputStream fileOutputStream = null;
AssetManager assetsmanage = null;
AssetFileDescriptor assetFileDescriptor;
try {
assetsmanage = this.context.getAssets();
assetFileDescriptor = assetsmanage.openFd(plugName);
long filesize = assetFileDescriptor.getLength();
inputStream = assetFileDescriptor.createInputStream();
String newplugName = plugName.substring(0,plugName.lastIndexOf("."));
String finalPlugName = newplugName+".dex";
File file = new File(this.thisPackagePath + files[6] + "/"+ finalPlugName);
if (!file.exists()) {
file.createNewFile();
}
int BUFFERSIZE = 128;
byte[] buffer = null;
if(filesize < BUFFERSIZE){
buffer = new byte[(int)filesize];
}else{
buffer = new byte[BUFFERSIZE];
}
fileOutputStream = new FileOutputStream(file);
int len = 0;
int readsize = 0;
while ((len = inputStream.read(buffer)) > 0) {
fileOutputStream.write(buffer);
readsize = len+readsize;
long nextSize = filesize - readsize;
if(nextSize < BUFFERSIZE ){
buffer = new byte[(int)nextSize];
}else{
buffer = new byte[BUFFERSIZE];
}
}
fileOutputStream.flush();
return file.getAbsolutePath();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
inputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
fileOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
public String getoptimizedDirectory(){
try{
return this.thisPackagePath+files[8];
}catch(Exception e){
Log.e(TAG, "获取dexopt 缓存的目录");
}
return null;
}
}
package com.james.dynamichostdemo;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import com.james.dynamicdemo.IHelloWorld;
import com.james.dynamichostdemo.log.ILog;
import com.james.dynamichostdemo.proxy.DynamicProxy;
import com.james.dynamichostdemo.util.FileUtil;
import dalvik.system.DexClassLoader;
import dalvik.system.DexFile;
import dalvik.system.PathClassLoader;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.pm.ApplicationInfo;
import android.os.Bundle;
import android.util.Log;
/**
* @author james
*
*/
public class MainActivity extends Activity implements ILog {
private FileUtil fileUtil;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
fileUtil = new FileUtil(MainActivity.this);
fileUtil.init();
//new Thread(new dexClassLoaderDex()).start();
//new pathClassLoaderDex().runs();
new Thread(new dexFileLoaderDex()).start();
}
/**
* 加载普通的dex 普通jar->dex
* @author james
*
*/
public class dexClassLoaderDex implements Runnable{
@SuppressLint("NewApi")
@Override
public void run() {
// TODO Auto-generated method stub
try{
String pluginsPath = fileUtil.assetsMvtoPackage("plug_demo.mp3");
Log.d(TAG, "最新的插件路径"+pluginsPath);
String optimizedDirectory = fileUtil.getoptimizedDirectory();
DexClassLoader dexClassLoader = new DexClassLoader(
pluginsPath,
optimizedDirectory,
null,
this.getClass().getClassLoader());
Class> clazz = dexClassLoader.loadClass("com.james.dynamicdemo.HelloWorld");
Object obj = clazz.newInstance();
InvocationHandler invocationHandler = new DynamicProxy(obj);
IHelloWorld newHelloWorld = (IHelloWorld)Proxy.newProxyInstance(
clazz.getClassLoader(), clazz.getInterfaces(), invocationHandler);
newHelloWorld.testPlug();
}catch(Exception e){
e.printStackTrace();
Log.e(TAG,"读取plug_demo.dex 失败!!");
}
}
}
/**
*
* @author james
*
*/
public class pathClassLoaderDex implements Runnable{
@SuppressLint("NewApi")
public void runs() {
// TODO Auto-generated method stub
try {
//String pluginsPath = "/data/data/com.example.dynamic_host_demo/app_plugins/plug_demo_temp.jar";//fileUtil.assetsMvtoPackage("plug_demo.mp3");
//Log.d(TAG, "最新的插件路径"+pluginsPath);
ApplicationInfo info = getPackageManager().getApplicationInfo("com.example.dynamic1", 0);
System.out.println(info.sourceDir);
String pluginsPath = info.sourceDir;
PathClassLoader pathClassLoader = new PathClassLoader(pluginsPath, ClassLoader.getSystemClassLoader());
Class> clazz = pathClassLoader.loadClass("com.example.dynamic1.HelloWorld");
Object obj = clazz.newInstance();
// InvocationHandler invocationHandler = new DynamicProxy(obj);
// IHelloWorld newHelloWorld = (IHelloWorld)Proxy.newProxyInstance(clazz.getClassLoader(),
// clazz.getInterfaces(),
// invocationHandler);
// newHelloWorld.testPlug();
Method method = obj.getClass().getMethod("testPlug", null);
method.invoke(obj, null);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
// TODO Auto-generated method stub
}
}
/**
*
* @author james
*
*/
public class dexFileLoaderDex implements Runnable {
public void run() {
// TODO Auto-generated method stub
try {
String pluginsPath = fileUtil.assetsMvtoPackage("dynamic1.mp3");
//File file = new File(pluginsPath);
String optimizedDirectory = fileUtil.getoptimizedDirectory()+"/dynamic1.odex";
DexFile dexFile = DexFile.loadDex(pluginsPath, optimizedDirectory, 0);
Class> clazz = dexFile.loadClass("com.example.dynamic1.HelloWorld",this.getClass().getClassLoader());
Object obj = clazz.newInstance();
// InvocationHandler invocationHandler = new DynamicProxy(obj);
// IHelloWorld newHelloWorld = (IHelloWorld)Proxy.newProxyInstance(clazz.getClassLoader(),
// clazz.getInterfaces(),
// invocationHandler);
// newHelloWorld.testPlug();
Method method = obj.getClass().getMethod("testPlug", null);
method.invoke(obj, null);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
*
* @author james
*
*/
public class dexFileLoaderDexLoaderActivity{
public void run(Bundle bundle) {
// TODO Auto-generated method stub
try {
String pluginsPath = fileUtil.assetsMvtoPackage("dynamic1.mp3");
//File file = new File(pluginsPath);
String optimizedDirectory = fileUtil.getoptimizedDirectory()+"/dynamic1.odex";
DexFile dexFile = DexFile.loadDex(pluginsPath, optimizedDirectory, 0);
Class> clazz = dexFile.loadClass("com.example.dynamic1.PlugActivity",this.getClass().getClassLoader());
Object obj = clazz.newInstance();
// InvocationHandler invocationHandler = new DynamicProxy(obj);
// IHelloWorld newHelloWorld = (IHelloWorld)Proxy.newProxyInstance(clazz.getClassLoader(),
// clazz.getInterfaces(),
// invocationHandler);
// newHelloWorld.testPlug();
Method contextMethod = obj.getClass().getDeclaredMethod("setContext", new Class[]{Activity.class});
contextMethod.setAccessible(true);
contextMethod.invoke(obj, new Object[] { MainActivity.this });
Method method = obj.getClass().getDeclaredMethod("onCreate",new Class[]{ Bundle.class });
method.setAccessible(true);
Bundle paramBundle = new Bundle();
paramBundle.putBoolean("KEY_START_FROM_OTHER_ACTIVITY", true);
paramBundle.putString("str", "MainActivity");
method.invoke(obj, paramBundle);
AssetManager assetManager = AssetManager.class.newInstance();
Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
Object objs = addAssetPath.invoke(assetManager, pluginsPath);
AssetManager mAssetManager = assetManager;
Resources superRes = getResources();
Resources mResources = new Resources(
mAssetManager,
superRes.getDisplayMetrics(),
superRes.getConfiguration()
);
Theme mTheme = mResources.newTheme();
mTheme.setTo(getTheme());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}