Android 핫 픽스 구현 방법 및 방법

7310 단어
지금은 주로 두 가지 방법이 있다.AriAndFix는 주로 Ndk를 이용하여 방법 지침의 교체를 실현한다.텐센트 팅커가 지금 주로 말하는 것은 틴커의 실현 방법: 1.먼저 다음 두 가지 개념을 소개합니다:public class PathClassLoader extends BaseDexClassLoader {설치된 프로그램을 불러오는 dex
public class DexClassLoader extends Base DexClassLoader {지정한 dex 파일을 불러올 수 있습니다. (제한: 프로그램의 디렉터리 아래에 있어야 하기 때문에 다운로드하려면 이 디렉터리에 복사해야 합니다.)
둘.분명히 우리는 DexClassLoader를 사용하여 수요를 실현해야 한다
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
            String libraryPath, ClassLoader parent) {
        super(parent);
        this.originalPath = dexPath;
        this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
    }

DexPathList
    public DexPathList(ClassLoader definingContext, String dexPath,
            String libraryPath, File optimizedDirectory) {
        ……
        this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory);
    }

    private static Element[] makeDexElements(ArrayList files,
            File optimizedDirectory) {
        ArrayList elements = new ArrayList();
        for (File file : files) {
            ZipFile zip = null;
            DexFile dex = null;
            String name = file.getName();
            if (name.endsWith(DEX_SUFFIX)) {
                dex = loadDexFile(file, optimizedDirectory);
            } else if (name.endsWith(APK_SUFFIX) || name.endsWith(JAR_SUFFIX)
                    || name.endsWith(ZIP_SUFFIX)) {
                zip = new ZipFile(file);
            }
            ……
            if ((zip != null) || (dex != null)) {
                elements.add(new Element(file, zip, dex));
            }
        }
        return elements.toArray(new Element[elements.size()]);
    }

    private static DexFile loadDexFile(File file, File optimizedDirectory)
            throws IOException {
        if (optimizedDirectory == null) {
            return new DexFile(file);
        } else {
            String optimizedPath = optimizedPathFor(file, optimizedDirectory);
            return DexFile.loadDex(file.getPath(), optimizedPath, 0);
        }
    }

    /**
     * Converts a dex/jar file path and an output directory to an
     * output file path for an associated optimized dex file.
     */
    private static String optimizedPathFor(File path,
            File optimizedDirectory) {
        String fileName = path.getName();
        if (!fileName.endsWith(DEX_SUFFIX)) {
            int lastDot = fileName.lastIndexOf(".");
            if (lastDot < 0) {
                fileName += DEX_SUFFIX;
            } else {
                StringBuilder sb = new StringBuilder(lastDot + 4);
                sb.append(fileName, 0, lastDot);
                sb.append(DEX_SUFFIX);
                fileName = sb.toString();
            }
        }
        File result = new File(optimizedDirectory, fileName);
        return result.getPath();
    }
optimizedDirectory            dex   ,     DexFile  ,    null,       dex          DexFile
  。

클래스를 로드하는 과정: ClassLoader는 loadClass를 통해 필요한 클래스를 로드합니다.
 public Class> loadClass(String className) throws ClassNotFoundException {
        return loadClass(className, false);
    }

    protected Class> loadClass(String className, boolean resolve) throws ClassNotFoundException {
        Class> clazz = findLoadedClass(className);
        if (clazz == null) {
            ClassNotFoundException suppressed = null;
            try {
                clazz = parent.loadClass(className, false);
            } catch (ClassNotFoundException e) {
                suppressed = e;
            }

            if (clazz == null) {
                try {
                    clazz = findClass(className);
                } catch (ClassNotFoundException e) {
                    e.addSuppressed(suppressed);
                    throw e;
                }
            }
        }
        return clazz;
    }

마지막으로 DexPathList의findClass를 호출했습니다.
    public Class findClass(String name) {
        for (Element element : dexElements) {
            DexFile dex = element.dexFile;
            if (dex != null) {
                Class clazz = dex.loadClassBinaryName(name, definingContext);
                if (clazz != null) {
                    return clazz;
                }
            }
        }
        return null;
    }

위 코드에서 보듯이 요소에서class를 찾으면 for 순환이 종료됩니다. 따라서 dexElements라는 집합을 수정하면 됩니다. 우리가 만든 dexElements와 원시적인 dexElements를 합치면 됩니다.dexA: 원래 app의 dex 파일 dexB: 패치 dex 파일로 여러 개가 가능합니다.먼저 다운로드한 dex 파일을 파일 형식으로 집합에 저장합니다
        //        dex
        File fileDir = context.getDir(MyConstants.DEX_DIR,Context.MODE_PRIVATE);
        File[] listFiles = fileDir.listFiles();
        for(File file:listFiles){
            if(file.getName().startsWith("classes")&&file.getName().endsWith(".dex")){
                loadedDex.add(file);//    
            }
        }

2. 반사로dexA,dexB의classLoader,dexA의classLoader는PathClassLoader,dexB의classLoader는dexClassLoader로 가져오기
            PathClassLoader pathLoader = (PathClassLoader) appContext.getClassLoader();

            for (File dex : loadedDex) {
                //2.        dex  。
                DexClassLoader classLoader = new DexClassLoader(
                        dex.getAbsolutePath(),//String dexPath,
                        fopt.getAbsolutePath(),//String optimizedDirectory,
                        null,//String libraryPath,
                        pathLoader//ClassLoader parent
                );
            }   

3. classloader를 통해 dexA와 dexB의 pathList 가져오기
                Object dexObj = getPathList(classLoader);
                Object pathObj = getPathList(pathLoader);

4. pathList를 통해 dexA와 dexB의 dexElements를 가져오고 이 두 가지를 합친다
                Object mDexElementsList = getDexElements(dexObj);
                Object pathDexElementsList = getDexElements(pathObj);
                //    
                Object dexElements = combineArray(mDexElementsList,pathDexElementsList);

5. 병합된 dexElements를 dexA의classLoader의pathList의dexElements에 값을 부여
                Object mDexElementsList = getDexElements(dexObj);
                Object pathDexElementsList = getDexElements(pathObj);
                //    
                Object dexElements = combineArray(mDexElementsList,pathDexElementsList);
                                //   PathList   lement[] dexElements;  
                Object pathList = getPathList(pathLoader);
                setField(pathList,pathList.getClass(),"dexElements",dexElements);

그러면 구체적인 절차는 이미 완성되었다.
6.dex백을 어떻게 칠 수 있습니까?dx를 통과하다.bat 이 시스템에서 제공하는 도구는
1.  MyTestClass.class
    com\app\build\intermediates\bin\MyTestClass.class
2.  dx.bat     
    Android\sdk\build-tools\23.0.3\dx.bat
3.  
dx --dex --output=D:\Users\jiang\Desktop\dex\classes2.dex D:\Users\jiang\Desktop\dex
    :
    --output=D:\Users\jiang\Desktop\dex\classes2.dex         
    D:\Users\jiang\Desktop\dex                  class    (            ,      class)

코드 주소는 다음과 같습니다.

좋은 웹페이지 즐겨찾기