All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tencent.mm.androlib.ResourceRepackage Maven / Gradle / Ivy

The newest version!
package com.tencent.mm.androlib;

import com.tencent.mm.util.FileOperation;
import com.tencent.mm.util.TypedValue;
import com.tencent.mm.util.Utils;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.HashMap;

public class ResourceRepackage {

  private final String zipalignPath;
  private final String sevenZipPath;
  private File mSignedApk;
  private File mSignedWith7ZipApk;
  private File mAlignedWith7ZipApk;
  private File m7zipOutPutDir;
  private File mStoredOutPutDir;
  private String mApkName;
  private File mOutDir;

  public ResourceRepackage(String zipalignPath, String zipPath, File signedFile) {
    this.zipalignPath = zipalignPath;
    this.sevenZipPath = zipPath;
    mSignedApk = signedFile;
  }

  public void setOutDir(File outDir) {
    mOutDir = outDir;
  }

  public void repackageApk() throws IOException, InterruptedException {
    insureFileName();

    repackageWith7z();
    alignApk();
    deleteUnusedFiles();
  }

  private void deleteUnusedFiles() {
    //删除目录
    FileOperation.deleteDir(m7zipOutPutDir);
    FileOperation.deleteDir(mStoredOutPutDir);
    if (mSignedWith7ZipApk.exists()) {
      mSignedWith7ZipApk.delete();
    }
  }

  /**
   * 这边有点不太一样,就是当输出目录存在的时候是不会强制删除目录的
   *
   * @throws IOException
   */
  private void insureFileName() throws IOException {
    if (!mSignedApk.exists()) {
      throw new IOException(String.format("can not found the signed apk file to repackage" + ", path=%s",
          mSignedApk.getAbsolutePath()
      ));
    }
    //需要自己安装7zip
    String apkBasename = mSignedApk.getName();
    mApkName = apkBasename.substring(0, apkBasename.indexOf(".apk"));
    //如果外面设过,就不用设了
    if (mOutDir == null) {
      mOutDir = new File(mSignedApk.getAbsoluteFile().getParent(), mApkName);
    }

    mSignedWith7ZipApk = new File(mOutDir.getAbsolutePath(), mApkName + "_channel_7zip.apk");
    mAlignedWith7ZipApk = new File(mOutDir.getAbsolutePath(), mApkName + "_channel_7zip_aligned.apk");

    m7zipOutPutDir = new File(mOutDir.getAbsolutePath(), TypedValue.OUT_7ZIP_FILE_PATH);
    mStoredOutPutDir = new File(mOutDir.getAbsolutePath(), "storefiles");
    //删除目录,因为之前的方法是把整个输出目录都删除,所以不会有问题,现在不会,所以要单独删
    FileOperation.deleteDir(m7zipOutPutDir);
    FileOperation.deleteDir(mStoredOutPutDir);
    FileOperation.deleteDir(mSignedWith7ZipApk);
    FileOperation.deleteDir(mAlignedWith7ZipApk);
  }

  private void repackageWith7z() throws IOException, InterruptedException {
    System.out.printf("use 7zip to repackage: %s, will cost much more time\n", mSignedWith7ZipApk.getName());
    HashMap compressData = FileOperation.unZipAPk(mSignedApk.getAbsolutePath(),
        m7zipOutPutDir.getAbsolutePath()
    );
    //首先一次性生成一个全部都是压缩的安装包
    generalRaw7zip();
    ArrayList storedFiles = new ArrayList<>();
    //对于不压缩的要update回去
    for (String name : compressData.keySet()) {
      File file = new File(m7zipOutPutDir.getAbsolutePath(), name);
      if (!file.exists()) {
        continue;
      }
      int method = compressData.get(name);
      if (method == TypedValue.ZIP_STORED) {
        storedFiles.add(name);
      }
    }

    addStoredFileIn7Zip(storedFiles);
    if (!mSignedWith7ZipApk.exists()) {
      throw new IOException(String.format(
          "[repackageWith7z]7z repackage signed apk fail,you must install 7z command line version first, linux: p7zip, window: 7za, path=%s",
          mSignedWith7ZipApk.getAbsolutePath()
      ));
    }
  }

  private void generalRaw7zip() throws IOException, InterruptedException {
    System.out.printf("general the raw 7zip file\n");
    String outPath = m7zipOutPutDir.getAbsoluteFile().getAbsolutePath();
    String path = outPath + File.separator + "*";

    String cmd = Utils.isPresent(sevenZipPath) ? sevenZipPath : TypedValue.COMMAND_7ZIP;
    ProcessBuilder pb = new ProcessBuilder(cmd, "a", "-tzip", mSignedWith7ZipApk.getAbsolutePath(), path, "-mx9");
    Process pro = pb.start();

    InputStreamReader ir = new InputStreamReader(pro.getInputStream());
    LineNumberReader input = new LineNumberReader(ir);
    //如果不读会有问题,被阻塞
    while (input.readLine() != null) {
    }
    //destroy the stream
    pro.waitFor();
    pro.destroy();
  }

  private void addStoredFileIn7Zip(ArrayList storedFiles) throws IOException, InterruptedException {
    System.out.printf("[addStoredFileIn7Zip]rewrite the stored file into the 7zip, file count:%d\n",
        storedFiles.size()
    );
    String storedParentName = mStoredOutPutDir.getAbsolutePath() + File.separator;
    String outputName = m7zipOutPutDir.getAbsolutePath() + File.separator;
    for (String name : storedFiles) {
      FileOperation.copyFileUsingStream(new File(outputName + name), new File(storedParentName + name));
    }
    storedParentName = storedParentName + File.separator + "*";
    //极限压缩
    String cmd = Utils.isPresent(sevenZipPath) ? sevenZipPath : TypedValue.COMMAND_7ZIP;
    ProcessBuilder pb = new ProcessBuilder(cmd,
        "a",
        "-tzip",
        mSignedWith7ZipApk.getAbsolutePath(),
        storedParentName,
        "-mx0"
    );
    Process pro = pb.start();

    InputStreamReader ir = new InputStreamReader(pro.getInputStream());
    LineNumberReader input = new LineNumberReader(ir);
    //如果不读会有问题,被阻塞
    while (input.readLine() != null) {
    }
    //destroy the stream
    pro.waitFor();
    pro.destroy();
  }

  private void alignApk() throws IOException, InterruptedException {
    if (mSignedWith7ZipApk.exists()) {
      alignApk(mSignedWith7ZipApk, mAlignedWith7ZipApk);
    }
  }

  private void alignApk(File before, File after) throws IOException, InterruptedException {
    System.out.printf("zipaligning apk: %s\n", before.getName());
    if (!before.exists()) {
      throw new IOException(String.format("can not found the raw apk file to zipalign, path=%s",
          before.getAbsolutePath()
      ));
    }
    String cmd = Utils.isPresent(zipalignPath) ? zipalignPath : TypedValue.COMMAND_ZIPALIGIN;
    ProcessBuilder pb = new ProcessBuilder(cmd, "4", before.getAbsolutePath(), after.getAbsolutePath());
    Process pro = pb.start();
    //destroy the stream
    pro.waitFor();
    pro.destroy();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy