Android dynamic framework 学习[1]

Android dynamic framework 学习

@(深入理解OSGI 应用与最佳实践)[ 资源管理, java反射, 动态代理, android aapt 学习, dexFile, 资源管理]

知识点

  • 资源管理[res+assets]
  • java反射
  • 动态代理
  • android aapt 学习
  • android dexopt 优化
  • android dexFile pathclassloader DexClassLoader 学习
资源管理
  • res 资源介绍
    介绍
    主要存放 图片资源布局文件 和一些简单的color 值 、values 值 、style样式、动画设置文件
    如图:

    res 目录结构

  • 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<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; 构造
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 手动编译打包详解图

    android aapt 手动编译打包详解图

    android编译和运行基本结构图

android编译示意图
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 <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 "列出当前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类架构图

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文件 >
<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);
第一个参数为插件的路径
第二个参数为插件的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();
            }
        }
    }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容