热修复


art_method.h

/*
 *
 * Copyright (c) 2011 The Android Open Source Project
 * Copyright (c) 2015, alipay.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * 	art_5_1.h
 *
 * @author : sanping.li@alipay.com
 *
 */
#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <fcntl.h>
#include <dlfcn.h>

#include <stdint.h>    /* C99 */
typedef unsigned char u1;
typedef unsigned short u2;
typedef unsigned int u4;
typedef signed char s1;
typedef signed short s2;
typedef signed int s4;

namespace art {
    namespace mirror {
        class Object {
        public:
            // The number of vtable entries in java.lang.Object.
            uint32_t klass_;

            uint32_t monitor_;
        };
        class Class: public Object {
        public:
            // Interface method table size. Increasing this value reduces the chance of two interface methods
            // colliding in the interface method table but increases the size of classes that implement
            // (non-marker) interfaces.
            // defining class loader, or NULL for the "bootstrap" system loader
            uint32_t class_loader_;
            // For array classes, the component class object for instanceof/checkcast
            // (for String[][][], this will be String[][]). NULL for non-array classes.
            uint32_t component_type_;
            // DexCache of resolved constant pool entries (will be NULL for classes generated by the
            // runtime such as arrays and primitive classes).
            uint32_t dex_cache_;
            // Short cuts to dex_cache_ member for fast compiled code access.
            uint32_t dex_cache_strings_;
            // static, private, and <init> methods
            uint32_t direct_methods_;
            // instance fields
            //
            // These describe the layout of the contents of an Object.
            // Note that only the fields directly declared by this class are
            // listed in ifields; fields declared by a superclass are listed in
            // the superclass's Class.ifields.
            //
            // All instance fields that refer to objects are guaranteed to be at
            // the beginning of the field list.  num_reference_instance_fields_
            // specifies the number of reference fields.
            uint32_t ifields_;
            // The interface table (iftable_) contains pairs of a interface class and an array of the
            // interface methods. There is one pair per interface supported by this class.  That means one
            // pair for each interface we support directly, indirectly via superclass, or indirectly via a
            // superinterface.  This will be null if neither we nor our superclass implement any interfaces.
            //
            // Why we need this: given "class Foo implements Face", declare "Face faceObj = new Foo()".
            // Invoke faceObj.blah(), where "blah" is part of the Face interface.  We can't easily use a
            // single vtable.
            //
            // For every interface a concrete class implements, we create an array of the concrete vtable_
            // methods for the methods in the interface.
            uint32_t iftable_;
            // Descriptor for the class such as "java.lang.Class" or "[C". Lazily initialized by ComputeName
            uint32_t name_;
            // Static fields
            uint32_t sfields_;
            // The superclass, or NULL if this is java.lang.Object, an interface or primitive type.
            uint32_t super_class_;
            // If class verify fails, we must return same error on subsequent tries.
            uint32_t verify_error_class_;
            // Virtual methods defined in this class; invoked through vtable.
            uint32_t virtual_methods_;
            // Virtual method table (vtable), for use by "invoke-virtual".  The vtable from the superclass is
            // copied in, and virtual methods from our class either replace those from the super or are
            // appended. For abstract classes, methods may be created in the vtable that aren't in
            // virtual_ methods_ for miranda methods.
            uint32_t vtable_;
            // Access flags; low 16 bits are defined by VM spec.
            uint32_t access_flags_;
            // Total size of the Class instance; used when allocating storage on gc heap.
            // See also object_size_.
            uint32_t class_size_;
            // Tid used to check for recursive <clinit> invocation.
            pid_t clinit_thread_id_;
            // ClassDef index in dex file, -1 if no class definition such as an array.
            // TODO: really 16bits
            int32_t dex_class_def_idx_;
            // Type index in dex file.
            // TODO: really 16bits
            int32_t dex_type_idx_;
            // Number of instance fields that are object refs.
            uint32_t num_reference_instance_fields_;
            // Number of static fields that are object refs,
            uint32_t num_reference_static_fields_;
            // Total object size; used when allocating storage on gc heap.
            // (For interfaces and abstract classes this will be zero.)
            // See also class_size_.
            uint32_t object_size_;
            // Primitive type value, or Primitive::kPrimNot (0); set for generated primitive classes.
            uint32_t primitive_type_;
            // Bitmap of offsets of ifields.
            uint32_t reference_instance_offsets_;
            // Bitmap of offsets of sfields.
            uint32_t reference_static_offsets_;
            // State of class initialization.
            int32_t status_;
            // TODO: ?
            // initiating class loader list
            // NOTE: for classes with low serialNumber, these are unused, and the
            // values are kept in a table in gDvm.
            // InitiatingLoaderList initiating_loader_list_;
            // The following data exist in real class objects.
            // Embedded Imtable, for class object that's not an interface, fixed size.
            // ImTableEntry embedded_imtable_[0];
            // Embedded Vtable, for class object that's not an interface, variable size.
            // VTableEntry embedded_vtable_[0];
            // Static fields, variable size.
            // uint32_t fields_[0];
            // java.lang.Class
            static void* java_lang_Class_;
        };

        class ArtField : public Object{
        public:
            uint32_t declaring_class_;
            int32_t access_flags_;
            int32_t field_dex_idx_;
            int32_t offset_;
        };

        class ArtMethod: public Object {
        public:
            // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
            // The class we are a part of. 适配andfix  不能做到这一改
            uint32_t declaring_class_;


            // Short cuts to declaring_class_->dex_cache_ member for fast compiled code access. dex
            uint32_t dex_cache_resolved_methods_;
            // Short cuts to declaring_class_->dex_cache_ member for fast compiled code access.
            uint32_t dex_cache_resolved_types_;
            // Access flags; low 16 bits are defined by spec.
            uint32_t access_flags_;
            /* Dex file fields. The defining dex file is available via declaring_class_->dex_cache_ */
            // Offset to the CodeItem.
            uint32_t dex_code_item_offset_;
            // Index into method_ids of the dex file associated with this method.
            uint32_t dex_method_index_;
            /* End of dex file fields. */
            // Entry within a dispatch table for this method. For static/direct methods the index is into
            // the declaringClass.directMethods, for virtual methods the vtable and for interface methods the
            // ifTable.
            uint32_t method_index_;
            // Fake padding field gets inserted here.
            // Must be the last fields in the method.
            struct PtrSizedFields {
                // Method dispatch from the interpreter invokes this pointer which may cause a bridge into
                // compiled code.java方法   ----》 虚拟机   ----》方法的入口 entry_point_from_interpreter_
                //art  解释模式  机器码
                void* entry_point_from_interpreter_;
                // Pointer to JNI function registered to this method, or a function to resolve the JNI function.
                void* entry_point_from_jni_;
                // Method dispatch from quick compiled code invokes this pointer which may cause bridging into
                // portable compiled code or the interpreter.
//                 机器码模式
                void* entry_point_from_quick_compiled_code_;
            } ptr_sized_fields_;
            static void* java_lang_reflect_ArtMethod_;
        };

    }
}

dalvik.h

/*
 *
 * Copyright (c) 2008 The Android Open Source Project
 * Copyright (c) 2015, alipay.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * dalvik.h
 *
 *
 * @author : sanping.li@alipay.com
 *
 */
#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <fcntl.h>
#include <dlfcn.h>

#include <stdint.h>    /* C99 */


typedef uint8_t u1;
typedef uint16_t u2;
typedef uint32_t u4;
typedef uint64_t u8;
typedef int8_t s1;
typedef int16_t s2;
typedef int32_t s4;
typedef int64_t s8;

/*
 * access flags and masks; the "standard" ones are all <= 0x4000
 *
 * Note: There are related declarations in vm/oo/Object.h in the ClassFlags
 * enum.
 */
enum {
	ACC_PUBLIC = 0x00000001,       // class, field, method, ic
	ACC_PRIVATE = 0x00000002,       // field, method, ic
	ACC_PROTECTED = 0x00000004,       // field, method, ic
	ACC_STATIC = 0x00000008,       // field, method, ic
	ACC_FINAL = 0x00000010,       // class, field, method, ic
	ACC_SYNCHRONIZED = 0x00000020,       // method (only allowed on natives)
	ACC_SUPER = 0x00000020,       // class (not used in Dalvik)
	ACC_VOLATILE = 0x00000040,       // field
	ACC_BRIDGE = 0x00000040,       // method (1.5)
	ACC_TRANSIENT = 0x00000080,       // field
	ACC_VARARGS = 0x00000080,       // method (1.5)
	ACC_NATIVE = 0x00000100,       // method
	ACC_INTERFACE = 0x00000200,       // class, ic
	ACC_ABSTRACT = 0x00000400,       // class, method, ic
	ACC_STRICT = 0x00000800,       // method
	ACC_SYNTHETIC = 0x00001000,       // field, method, ic
	ACC_ANNOTATION = 0x00002000,       // class, ic (1.5)
	ACC_ENUM = 0x00004000,       // class, field, ic (1.5)
	ACC_CONSTRUCTOR = 0x00010000,       // method (Dalvik only)
	ACC_DECLARED_SYNCHRONIZED = 0x00020000,       // method (Dalvik only)
	ACC_CLASS_MASK = (ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT
			| ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM),
	ACC_INNER_CLASS_MASK = (ACC_CLASS_MASK | ACC_PRIVATE | ACC_PROTECTED
			| ACC_STATIC),
	ACC_FIELD_MASK = (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC
			| ACC_FINAL | ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC
			| ACC_ENUM),
	ACC_METHOD_MASK = (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC
			| ACC_FINAL | ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS
			| ACC_NATIVE | ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC
			| ACC_CONSTRUCTOR | ACC_DECLARED_SYNCHRONIZED),
};

typedef struct DexProto {
	u4* dexFile; /* file the idx refers to */
	u4 protoIdx; /* index into proto_ids table of dexFile */
} DexProto;

typedef void (*DalvikBridgeFunc)(const u4* args, void* pResult,
		const void* method, void* self);

struct Field {
	void* clazz; /* class in which the field is declared */
	const char* name;
	const char* signature; /* e.g. "I", "[C", "Landroid/os/Debug;" */
	u4 accessFlags;
};

struct Method;
struct ClassObject;

typedef struct Object {
	/* ptr to class object */
	struct ClassObject* clazz;

	/*
	 * 类的加载过程
	 * A word containing either a "thin" lock or a "fat" monitor.  See
	 * the comments in Sync.c for a description of its layout.
	 */
	u4 lock;
} Object;

struct InitiatingLoaderList {
	/* a list of initiating loader Objects; grown and initialized on demand */
	void** initiatingLoaders;
	/* count of loaders in the above list */
	int initiatingLoaderCount;
};

enum PrimitiveType {
	PRIM_NOT = 0, /* value is a reference type, not a primitive type */
	PRIM_VOID = 1,
	PRIM_BOOLEAN = 2,
	PRIM_BYTE = 3,
	PRIM_SHORT = 4,
	PRIM_CHAR = 5,
	PRIM_INT = 6,
	PRIM_LONG = 7,
	PRIM_FLOAT = 8,
	PRIM_DOUBLE = 9,
}typedef PrimitiveType;

enum ClassStatus {
	CLASS_ERROR = -1,

	CLASS_NOTREADY = 0, CLASS_IDX = 1, /* loaded, DEX idx in super or ifaces */
	CLASS_LOADED = 2, /* DEX idx values resolved */
	CLASS_RESOLVED = 3, /* part of linking */
	CLASS_VERIFYING = 4, /* in the process of being verified */
	CLASS_VERIFIED = 5, /* logically part of linking; done pre-init */
	CLASS_INITIALIZING = 6, /* class init in progress */
	CLASS_INITIALIZED = 7, /* ready to go */
}typedef ClassStatus;

typedef struct ClassObject {
	struct Object o; // emulate C++ inheritance, Collin

	/* leave space for instance data; we could access fields directly if we
	 freeze the definition of java/lang/Class */
	u4 instanceData[4];

	/* UTF-8 descriptor for the class; from constant pool, or on heap
	 if generated ("[C") */
	const char* descriptor;
	char* descriptorAlloc;

	/* access flags; low 16 bits are defined by VM spec */
	u4 accessFlags;

	/* VM-unique class serial number, nonzero, set very early */
	u4 serialNumber;

	/* DexFile from which we came; needed to resolve constant pool entries */
	/* (will be NULL for VM-generated, e.g. arrays and primitive classes) */
	void* pDvmDex;

	/* state of class initialization */
	ClassStatus status;

	/* if class verify fails, we must return same error on subsequent tries */
	struct ClassObject* verifyErrorClass;

	/* threadId, used to check for recursive <clinit> invocation */
	u4 initThreadId;

	/*
	 * Total object size; used when allocating storage on gc heap.  (For
	 * interfaces and abstract classes this will be zero.)
	 */
	size_t objectSize;

	/* arrays only: class object for base element, for instanceof/checkcast
	 (for String[][][], this will be String) */
	struct ClassObject* elementClass;

	/* arrays only: number of dimensions, e.g. int[][] is 2 */
	int arrayDim;
	PrimitiveType primitiveType;

	/* superclass, or NULL if this is java.lang.Object */
	struct ClassObject* super;

	/* defining class loader, or NULL for the "bootstrap" system loader */
	struct Object* classLoader;

	struct InitiatingLoaderList initiatingLoaderList;

	/* array of interfaces this class implements directly */
	int interfaceCount;
	struct ClassObject** interfaces;

	/* static, private, and <init> methods */
	int directMethodCount;
	struct Method* directMethods;

	/* virtual methods defined in this class; invoked through vtable */
	int virtualMethodCount;
	struct Method* virtualMethods;

	/*
	 * Virtual method table (vtable), for use by "invoke-virtual".  The
	 * vtable from the superclass is copied in, and virtual methods from
	 * our class either replace those from the super or are appended.
	 */
	int vtableCount;
	struct Method** vtable;

} ClassObject;

typedef struct Method {
	struct ClassObject *clazz;
	u4 accessFlags;
//u2 methodIndex   方法表里面的索引
	u2 methodIndex;

	u2 registersSize; /* ins + locals */
	u2 outsSize;
	u2 insSize;

	/* method name, e.g. "<init>" or "eatLunch" */
	const char* name;

	/*
	 * Method prototype descriptor string (return and argument types).
	 *
	 * TODO: This currently must specify the DexFile as well as the proto_ids
	 * index, because generated Proxy classes don't have a DexFile.  We can
	 * remove the DexFile* and reduce the size of this struct if we generate
	 * a DEX for proxies.
	 */
	DexProto prototype;

	/* short-form method descriptor string */
	const char* shorty;

	/*
	 * The remaining items are not used for abstract or native methods.
	 * (JNI is currently hijacking "insns" as a function pointer, set
	 * after the first call.  For internal-native this stays null.)
	 */

	/* the actual code */
	u2* insns;

	/* cached JNI argument and return-type hints */
	int jniArgInfo;

	/*
	 * Native method ptr; could be actual function or a JNI bridge.  We
	 * don't currently discriminate between DalvikBridgeFunc and
	 * DalvikNativeFunc; the former takes an argument superset (i.e. two
	 * extra args) which will be ignored.  If necessary we can use
	 * insns==NULL to detect JNI bridge vs. internal native.
	 */
	DalvikBridgeFunc nativeFunc;

#ifdef WITH_PROFILER
	bool inProfile;
#endif
#ifdef WITH_DEBUGGER
	short debugBreakpointCount;
#endif

	bool fastJni;

	/*
	 * JNI: true if this method has no reference arguments. This lets the JNI
	 * bridge avoid scanning the shorty for direct pointers that need to be
	 * converted to local references.
	 *
	 * TODO: replace this with a list of indexes of the reference arguments.
	 */
	bool noRef;

} Method;


native-lib.cpp

#include <jni.h>
#include <string>
#include "dalvik.h"
#include "art_method.h"

typedef Object *(*FindObject)(void *thread, jobject jobject1);
typedef  void* (*FindThread)();
FindObject  findObject;
FindThread  findThread;
extern "C"{
JNIEXPORT jstring JNICALL
Java_com_ugou88_ugou_ui_activity_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
//com.ugou88.ugou.utils.DexManager
JNIEXPORT void JNICALL
Java_com_ugou88_ugou_utils_DexManager_replace(JNIEnv *env, jobject instance, jint sdk,
                                               jobject wrongMethod,
                                               jobject rightMethod) {
//    做  跟什么有关   虚拟机    java虚拟机 Method
//找到虚拟机对应的Method 结构体
    Method *wrong = (Method *) env->FromReflectedMethod(wrongMethod);

    Method *right = (Method *) env->FromReflectedMethod(rightMethod);

//下一步  把right 对应Object   第一个成员变量ClassObject   status


//    ClassObject
    void *dvm_hand = dlopen("libdvm.so", RTLD_NOW);
//    sdk  10    以前是这样   10会发生变化
    findObject = (FindObject) dlsym(dvm_hand, sdk > 10 ?
                                              "_Z20dvmDecodeIndirectRefP6ThreadP8_jobject" :
                                              "dvmDecodeIndirectRef");
    findThread = (FindThread) dlsym(dvm_hand, sdk > 10 ? "_Z13dvmThreadSelfv" : "dvmThreadSelf");
// method   所声明的Class

    jclass methodClaz = env->FindClass("java/lang/reflect/Method");
    jmethodID rightMethodId = env->GetMethodID(methodClaz, "getDeclaringClass",
                                               "()Ljava/lang/Class;");
//dalvik  odex   机器码
//    firstFiled->status=CLASS_INITIALIZED
//    art不需要    dalvik适配
    jobject ndkObject = env->CallObjectMethod(rightMethod, rightMethodId);
    ClassObject *firstFiled = (ClassObject *) findObject(findThread(), ndkObject);
    firstFiled->status = CLASS_INITIALIZED;
    wrong->accessFlags |= ACC_PUBLIC;

    wrong->methodIndex = right->methodIndex;
    wrong->jniArgInfo = right->jniArgInfo;
    wrong->registersSize = right->registersSize;
    wrong->outsSize = right->outsSize;
//    方法参数 原型
    wrong->prototype = right->prototype;
//
    wrong->insns = right->insns;
    wrong->nativeFunc = right->nativeFunc;
}

JNIEXPORT void JNICALL
Java_com_ugou88_ugou_utils_DexManager_replaceArt(JNIEnv *env, jobject instance,
                                                  jobject wrongMethod, jobject rightMethod) {
//    art虚拟机替换  art  ArtMethod  ---》Java方法
    art::mirror::ArtMethod *wrong = (art::mirror::ArtMethod *) env->FromReflectedMethod(
            wrongMethod);
    art::mirror::ArtMethod *right = (art::mirror::ArtMethod *) env->FromReflectedMethod(
            rightMethod);

    wrong->declaring_class_ = right->declaring_class_;
    wrong->dex_cache_resolved_methods_ = right->dex_cache_resolved_methods_;
    wrong->dex_cache_resolved_types_ = right->dex_cache_resolved_types_;
    wrong->dex_code_item_offset_ = right->dex_code_item_offset_;
    wrong->method_index_ = right->method_index_;
    wrong->dex_method_index_ = right->dex_method_index_;


//入口
    wrong->ptr_sized_fields_.entry_point_from_interpreter_=right->ptr_sized_fields_.entry_point_from_interpreter_;
    wrong->ptr_sized_fields_.entry_point_from_jni_ = right->ptr_sized_fields_.entry_point_from_jni_;
    //    机器码模式
    wrong->ptr_sized_fields_.entry_point_from_quick_compiled_code_ = right->ptr_sized_fields_.entry_point_from_quick_compiled_code_;
}

}


DexManager.java

package com.ugou88.ugou.utils;

import android.content.Context;
import android.os.Build;

import com.alipay.euler.andfix.annotation.MethodReplace;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Enumeration;

import dalvik.system.DexFile;

/**
 * Created by twy on 2017/10/11.
 */

public class DexManager {
    private Context context;
    private static DexManager ourInstance ;

    public static DexManager getInstance(Context context) {
        if(ourInstance==null)
            ourInstance = new DexManager(context);
        return ourInstance;
    }

    private DexManager(Context context) {
        this.context = context;
    }

    public void loadFile(File file) {
        try {
//            dexfile  dex  jar  ali   apkTool  jar文件
            DexFile dexFile = DexFile.loadDex(file.getAbsolutePath(),
                    new File(context.getCacheDir(), "opt").getAbsolutePath(), Context.MODE_PRIVATE);
            //下一步  得到class   ----取出修复好的Method
            Enumeration<String> entry= dexFile.entries();
            while (entry.hasMoreElements()) {
//                拿到全类名
                String className=entry.nextElement();
//                    Class.forName(className);//
                Class clazz=dexFile.loadClass(className, context.getClassLoader());
                if (clazz != null) {
                    fixClazz(clazz);
                }

            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void fixClazz(Class realClazz) {
//        服务器修复好的  realClazz
        Method[] methods=realClazz.getDeclaredMethods();
        for (Method rightMethod : methods) {
            MethodReplace replace = rightMethod.getAnnotation(MethodReplace.class);
            if (replace == null) {
                continue;
            }
            //找到了修复好的Method    找到出bug的Method
            String wrongClazz=replace.clazz();
            String  wrongMethodName=replace.method();
            try {
                Class clazz=Class.forName(wrongClazz);
                Method wrongMethod = clazz.getDeclaredMethod(wrongMethodName, rightMethod.getParameterTypes());
                if (Build.VERSION.SDK_INT <= 18) {
                    replace(Build.VERSION.SDK_INT ,wrongMethod, rightMethod);
                }else {
                    replaceArt(wrongMethod, rightMethod);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }


        }
    }

    private native  void replaceArt(Method wrongMethod, Method rightMethod);

    public native void replace(int  sdk,Method wrongMethod, Method rightMethod);
}




MainActivity.java

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    TextView result;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        result = (TextView) findViewById(R.id.result);
        DexManager.getInstance().setContext(this);
    }


    public void jisuan(View view) {
        Caclutor caclutor=new Caclutor();
        result.setText(" 结果  "+caclutor.cl());
        Log.i("tuch", "jisuan: "+caclutor.cl());
    }

    public void fix(View view) {
        //Log.i("tuch", " 路劲  :  " + Environment.getExternalStorageDirectory());
        //this.getResources().getAssets().li
        //DexManager.getInstance().loadFile(new File(Environment.getExternalStorageDirectory(),"out1.apatch"));
        String newPath = new File(getCacheDir(), "out.apatch").getAbsolutePath();
        copyFilesFassets(this, "out.apatch",newPath);
        DexManager.getInstance().loadFile(new File(newPath));
    }

    /**
     *  从assets目录中复制整个文件夹内容
     *  @param  context  Context 使用CopyFiles类的Activity
     *  @param  oldPath  String  原文件路径  如:/aa
     *  @param  newPath  String  复制后路径  如:xx:/bb/cc
     */
    public void copyFilesFassets(Context context, String oldPath, String newPath) {
        try {
            String fileNames[] = context.getAssets().list(oldPath);//获取assets目录下的所有文件及目录名
            if (fileNames.length > 0) {//如果是目录
                File file = new File(newPath);
                file.mkdirs();//如果文件夹不存在,则递归
                for (String fileName : fileNames) {
                    copyFilesFassets(context,oldPath + "/" + fileName,newPath+"/"+fileName);
                }
            } else {//如果是文件
                InputStream is = context.getAssets().open(oldPath);
                FileOutputStream fos = new FileOutputStream(new File(newPath));
                byte[] buffer = new byte[1024];
                int byteCount=0;
                while((byteCount=is.read(buffer))!=-1) {//循环从输入流读取 buffer字节
                    fos.write(buffer, 0, byteCount);//将读取的输入流写入到输出流
                }
                fos.flush();//刷新缓冲区
                is.close();
                fos.close();
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}




那apatch文件即是我们将要通过服务端下载需要的文件 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值