Android dynamic framework 學(xué)習(xí)[1]

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è)置文件
    如圖:

    res 目錄結(jié)構(gòu)

  • 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 手動編譯打包詳解圖

    android aapt 手動編譯打包詳解圖

    android編譯和運(yùn)行基本結(jié)構(gòu)圖

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列出當(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)圖

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)
插件一項(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)目結(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();
            }
        }
    }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末撞鹉,一起剝皮案震驚了整個(gè)濱河市疟丙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鸟雏,老刑警劉巖享郊,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異孝鹊,居然都是意外死亡炊琉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苔咪,“玉大人锰悼,你說我怎么就攤上這事⊥派停” “怎么了箕般?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長舔清。 經(jīng)常有香客問我丝里,道長,這世上最難降的妖魔是什么体谒? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任杯聚,我火速辦了婚禮,結(jié)果婚禮上抒痒,老公的妹妹穿的比我還像新娘幌绍。我一直安慰自己,他們只是感情好故响,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布傀广。 她就那樣靜靜地躺著,像睡著了一般被去。 火紅的嫁衣襯著肌膚如雪主儡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天惨缆,我揣著相機(jī)與錄音糜值,去河邊找鬼。 笑死坯墨,一個(gè)胖子當(dāng)著我的面吹牛寂汇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播捣染,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼骄瓣,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了耍攘?” 一聲冷哼從身側(cè)響起榕栏,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蕾各,沒想到半個(gè)月后扒磁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡式曲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年妨托,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缸榛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡兰伤,死狀恐怖内颗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情敦腔,我是刑警寧澤均澳,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站符衔,受9級特大地震影響负懦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜柏腻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望系吭。 院中可真熱鬧五嫂,春花似錦、人聲如沸肯尺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽则吟。三九已至槐臀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間氓仲,已是汗流浹背水慨。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留敬扛,地道東北人晰洒。 一個(gè)月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像啥箭,于是被迫代替她去往敵國和親谍珊。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容