Android dynamic framework 學(xué)習(xí)
@(深入理解OSGI 應(yīng)用與最佳實(shí)踐)[ 資源管理, java反射, 動態(tài)代理, android aapt 學(xué)習(xí), dexFile, 資源管理]
知識點(diǎn)
- 資源管理[res+assets]
- java反射
- 動態(tài)代理
- android aapt 學(xué)習(xí)
- android dexopt 優(yōu)化
- android dexFile pathclassloader DexClassLoader 學(xué)習(xí)
資源管理
-
res 資源介紹
介紹:
主要存放 圖片資源 和 布局文件 和一些簡單的color 值 糟把、values 值 荆永、style樣式淑廊、動畫設(shè)置文件
如圖:
assets 介紹,管理
介紹
這是一個(gè) read only 文件夾 芜壁,系統(tǒng)提供了一個(gè)AssetManager ,可將文件進(jìn)行讀取
源代碼如下
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<String> 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; 構(gòu)造
import java.lang.reflect.Field;聲明
import java.lang.reflect.Method;方法
- getFields():獲得類的public類型的屬性
- getDeclaredFields():獲得類的所有屬性,包括public典徘、protected碰缔、默認(rèn)和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碑宴、默認(rèn)和private訪問級別的屬性软啼。
* getMethods():獲得類的public類型的方法。
* getDeclaredMethods():獲得類的所有方法延柠。
*/
// 方法
Method[] method = newUser.getClass().getMethods();
for (int i = 0; i < method.length; i++) {
System.out.println("getMethods() = "+method[i].getName());
}
// 獲取當(dāng)前對象的所有的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());
}
// 方法的調(diào)用
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());
}
/**
* 構(gòu)造方法
*/
Constructor[] constructors = newUser.getClass().getDeclaredConstructors();
for (Constructor constructor :constructors) {
System.out.println("構(gòu)造方法"+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();
}
}
}
動態(tài)代理+靜態(tài)代理[設(shè)計(jì)模式]
代理模式主要是設(shè)計(jì)模式里面的結(jié)構(gòu)模式祸挪,主要分為動態(tài)代理和靜態(tài)代理,代理所應(yīng)用的場景和案例
場景:
1:用于在不修改源碼的情況下贞间,增強(qiáng)一些方法贿条,可以在執(zhí)行源碼方法之前和之后,做你想做的事情增热。
2: 可作為遠(yuǎn)程調(diào)用整以。
案例:spring AOP Dubbo等...
Code
靜態(tài)代理
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() {
//調(diào)用目標(biāo)對象之前可以做相關(guān)操作
System.out.println("before");
realObject.operation();
//調(diào)用目標(biāo)對象之后可以做相關(guān)操作
System.out.println("after");
}
}
package proxy;
/**
* 目標(biāo)對象角色
* @author james
*/
public class RealObject extends AbstractObject {
@Override
public void operation() {
System.out.println("目標(biāo)對象角色");
}
}
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();
}
}
動態(tài)代理
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("運(yùn)行結(jié)果");
newsubject.request();
newsubject.response("this is response");
// 獲取當(dāng)前對象的所有的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 學(xué)習(xí)
android aapt 簡介
aapt (Android Asset Packaging Tool ) 在androidsdk的build-tools目錄下,aapt可以查看峻仇、創(chuàng)建公黑、更新ZIP格式的文檔附件(zip,jar,apk),也可以將資源文件編譯成二進(jìn)制文件帆调。android aapt使用方法
1: aapt list [-v | -a] xxx.apk 列出當(dāng)前壓縮文件的所有目錄
2: aapt dump badging xxx.apk 查看apk包packageName奠骄,versionCode,applicationLabel番刊、launcherActivity、Permission等
3:aapt dump permissions xxx.apk 查看權(quán)限
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列出當(dāng)前壓縮文件的所有目錄"
echo "2:aapt dump badging xxx.apk 查看apk包packageName影锈,versionCode芹务,applicationLabel、launcherActivity鸭廷、Permission等"
echo "3:aapt dump permissions xxx.apk 查看權(quán)限"
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 <R.java文件夾> -S <res路徑> -I <android.jar路徑> -M<AndroidManifest.xml路徑> 使用aapt 生成R.java 文件"
echo "8:aapt package -f -S <res路徑> -I <android.jar路徑> -A <assert路徑> -M <AndroidManifest.xml路徑> -F <輸出的包目錄+包名> 使用aapt 生成apk包文件"
echo "***********************aapt 批處理******************************"
printf_log "列出當(dāng)前zip jar apk 壓縮文件里面的目錄"
aapt lisr weixin.apk >> log.txt
printf_log "以table的方式把包里面的信息全部列出來"
aapt list -v weixin.apk >> log.txt
printf_log "列出詳細(xì)的信息"
aapt list -a weixin.apk >> log.txt
printf_log "查看apk包packageName枣抱,versionCode,applicationLabel辆床、launcherActivity佳晶、Permission等"
aapt dump badging weixin.apk >> log.txt
printf_log "查看權(quán)限"
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
####
# 創(chuàng)建一個(gè)簽名文件
#
####
source log.sh
function create_keystore(){
printf_log "創(chuàng)建一個(gè)簽名文件"
#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
###
# 壓縮優(yōu)化 apk文件
#
###
source log.sh
function zipalign_tools(){
printf_log "壓縮優(yōu)化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 執(zhí)行之前的初始化
# 1:日志文件刪除與創(chuàng)建
# 2:各個(gè)apk文件刪除
#
##
function init(){
init_log
rm_apk_file_init
}
#日志刪除
function init_log(){
create_log
}
# 創(chuàng)建和刪除日志
function create_log(){
if [ -f "$log.txt" ];then
echo "創(chuàng)建日志文件"
touch log.txt
else
echo "刪除之前的日志文件"
rm -rf log.txt
echo "創(chuàng)建新的日志文件"
touch log.txt
fi
}
#刪除已經(jīng)存在的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
######
# 創(chuàng)建android項(xiàng)目
#
######
function create_android_project(){
echo "創(chuàng)建android新的項(xiàng)目"
android create project \
--target 6 \ # android list targets
--name MyAndroidApp \
--path ./MyAndroidAppProject \
--activity MyAndroidAppActivity \
--package com.example.myandroid
}
function create_library_project(){
echo "創(chuàng)建android library 新項(xiàng)目"
android create lib-project
--name MyLibrary \
--target 6 \
--path path/to/your/project \
--package com.example.mylibrary
}
android dexopt 優(yōu)化
dexopt 介紹
dexopt 主要用來優(yōu)化dex中的類文件,它會初始化一個(gè)VM讼载,加載DEX文件并執(zhí)行verification和optimization過程轿秧。
android dexFile pathclassloader DexClassLoader 學(xué)習(xí)
classloader類架構(gòu)圖
針對于dexclassloader、pathclassloader咨堤、URLclassLoader菇篡、DexFile說明講解
DexClassLoader 說明
public DexClassLoader (String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) 創(chuàng)建一個(gè)DexClassLoader用來找出指定的類和本地代碼(c/c++代碼)。用來解釋執(zhí)行在DEX文件中的class文件一喘。 路徑的分隔符使用通過System的屬性 path.separator 獲得; String separeater = System.getProperty("path.separtor"); Parameters (參數(shù)介紹) dexPath 需要裝載的APK或者Jar文件的路徑驱还。包含多個(gè)路徑用File.pathSeparator間隔開,在Android上默認(rèn)是 ":" optimizedDirectory 優(yōu)化后的dex文件存放目錄,不能為null libraryPath 目標(biāo)類中使用的C/C++庫的列表,每個(gè)目錄用File.pathSeparator間隔開; 可以為 null parent 該類裝載器的父裝載器凸克,一般用當(dāng)前執(zhí)行類的裝載器
PathClassLoader 說明
系統(tǒng)加載器议蟆,只能加載/data/app 目錄下的 apk文件 >
<font color= red>
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</font>
DexFIle 說明
DexFIle加載jar 和apk包 >
DexFile.loadDex(pluginsPath, optimizedDirectory, 0);
第一個(gè)參數(shù)為插件的路徑
第二個(gè)參數(shù)為插件的dexopt 之后的文件 ,必須是文件不能是文件夾
第三個(gè)暫時(shí) 可選功能 官方說未定義
加載普通的dex源碼塊
plug1項(xiàng)目:
- 項(xiàng)目結(jié)構(gòu)
- 源碼
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");
}
}
宿主項(xiàng)目
- 項(xiàng)目結(jié)構(gòu)
- 項(xiàng)目源碼
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;
/**
* 加上動態(tài)代理
* @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, "開始運(yùn)行普通插件");
method.invoke(this.obj, args);
Log.d(TAG, "運(yùn)行普通插件結(jié)束");
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 進(jìn)行dexopt 優(yōu)化的apk 緩沖
* app_plugins
* app plugins 插件集合
* app_plugins_lib app 插件
* lib app_plugins_opt app 插件優(yōu)化
* app_sslcache ssl 緩存
* app_ucmsdk
* app_webview
* cache databases files // 日志文件
* hotpatch lib shared_prefs
*
* @author james 初始化文件創(chuàng)建
*/
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"http:// 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 失斘健8廊荨!");
}
}
}
/**
*
* @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();
}
}
}