Apk重新签名的工具

该工具可以完成以下几个工作

  1. 删除老的签名
  2. 对apk进行重新签名
  3. 对齐操作

缺点

  1. 只支持mac和linux,不支持window,原因为zip命令在window上面需要额外的配置

使用条件

  1. 必须安装了java环境
  2. 需要支持zipalign,jarsigner,zip命令

使用方式

切换到该目录后,执行appSign即可

工具目录说明

工具目录说明
基本说明
  1. 为生成的工具
  2. 待重新签名的apk
  3. 签名文件
  4. 生成未对其的apk,上传google 需要对齐
  5. 对齐后的apk包
  6. 配置文件,用于配置签名信息,以及待签名的apk名字以及签名后的apk包名
SignConfig.json说明
配置参数说明,你应该一看就懂

具体代码实现

package main

import (
   "encoding/json"
   "fmt"
   "github.com/yanghai23/GoLib/atfile"
   "io/ioutil"
   "os/exec"
   "runtime"
   "time"
)

var ip, whoami []byte
var err error
var cmd, cmd1, cmd2 *exec.Cmd
var status = false

func main() {

   data, err := readConfig()
   if err != nil {
       fmt.Println("读取配置文件失败")
       return
   }
   res := config2Obj(data)
   fmt.Println("配置数据读取成功", res.KeyAlias)

   //jarsigner -verbose -keystore foyoos.keystore
   // -storepass foyoosgame
   // -signedjar sign.apk %1 foyoos.keystore
   // -digestalg SHA1
   // -sigalg MD5withRSA
   go wait()
   //TODO 动态删除apk中的META-INF目录
   fmt.Println("开始删除签名文件信息")
   cmd2 = exec.Command("zip", "-d", res.SourceAppName+".apk", "META-INF/*")
   if whoami, err = cmd2.Output(); err != nil {
       fmt.Println("签名文件已经被删除!")
   } else {
       fmt.Println("成功删除老的签名文件信息")
   }

   fmt.Println("开始签名")
   camd := fmt.Sprintf("jarsigner -verbose  -keystore %s -keypass %s -storepass %s -signedjar %s %s %s -digestalg SHA1 -sigalg MD5withRSA",
       res.StoreFile,
       res.KeyPassword,
       res.StorePassword,
       res.TargetAppName,
       res.SourceAppName,
       res.KeyAlias)
   fmt.Println("请稍等,每个小点为表示1s,一排60个小点")
   fmt.Println(camd)

   targetFileName := res.TargetAppName + GetTimeStr() + "_sign.apk"
   cmd = exec.Command("jarsigner",
       "-verbose",
       "-keystore", res.StoreFile,
       "-keypass", res.KeyPassword,
       "-storepass", res.StorePassword,
       "-signedjar", targetFileName, res.SourceAppName+".apk",
       res.KeyAlias,
       "-digestalg", "SHA1",
       "-sigalg", "MD5withRSA")

   if whoami, err = cmd.Output(); err != nil {
       fmt.Println("发生异常=", err)
       fmt.Println("签名失败")
       status = true
       return
   }
   fmt.Println(string(whoami))
   fmt.Println("重新签名成功")

   fmt.Println("开始对齐操作")
   camd2 := fmt.Sprintf("zipalign -f -v 4  %s %s", targetFileName, res.TargetAppName+GetTimeStr()+"_sign_final.apk")
   fmt.Println(camd2)
   cmd1 = exec.Command("zipalign", "-f", "-v", "4",
       targetFileName, res.TargetAppName+GetTimeStr()+"_sign_final.apk")
   if whoami, err = cmd1.Output(); err != nil {
       fmt.Println("发生异常=", err)
       fmt.Println("对齐失败")
       status = true
       return
   }
   fmt.Println(string(whoami))
   fmt.Println("对齐成功")
   status = true
   // 默认输出有一个换行

}

func config2Obj(data []byte) *Config {
   config := &Config{}
   json.Unmarshal(data, config)
   return config
}

var ostype = runtime.GOOS

/**
   读取配置
*/

func readConfig() (data []byte, err error) {
   currentPath := atfile.GetCurrentDirectory()
   fmt.Println("操作系统类型 ", ostype)
   if "windows" == ostype {
       data, err = ioutil.ReadFile(currentPath + "\\SignConfig.json")
       fmt.Println("windows 读取配置")
   } else {
       data, err = ioutil.ReadFile(currentPath + "/SignConfig.json")
       fmt.Println("Mac 读取配置")
   }

   if err != nil {
       fmt.Println("err = ", err)
   }
   return data, err
}

func GetTimeStr() string {
   timestamp := time.Now().Unix()
   tm := time.Unix(timestamp, 0)
   return tm.Format("2006_01_02_03_04_05")
}

/**
   创建结构体
*/
type Config struct {
   KeyAlias      string `json:keyAlias`
   KeyPassword   string `json:keyPassword`
   StoreFile     string `json:storeFile`
   StorePassword string `json:storePassword`
   TargetAppName string `json:targetAppName`
   SourceAppName string `json:sourceAppName`
}

func wait() {
   t := 0
   for ; !status; {
       time.Sleep(time.Second)
       t ++
       if t < 60 {
           fmt.Print(".")
       } else {
           t = 0
           fmt.Println(".")
       }
   }
}

推荐阅读更多精彩内容