1. 程式人生 > >golang iOS 自動打包,上傳到蒲公英

golang iOS 自動打包,上傳到蒲公英

新建一個配置類包含打包的內容

type buildInfo struct {

	Path              string `json:"path"`
	Branch            string `json:"branch"`
	Workspace         string `json:"workspace"`
	Scheme            string `json:"scheme"`
	ArchPath          string `json:"archPath"`
	ExportPath        string `json:"exportPath"`
	Config            string `json:"config"`
	InstallType       string `json:"installType"`
	Password          string `json:"password"`
	UpdateDescription string `json:"updateDescription"`
	Upload            bool   `json:"upload"`
}

根據配置資訊進行打包,主要用到xcodebuild工具的支援,另外就是利用golang對命令列進行呼叫。

func Archive(info buildInfo) {
	e := os.Chdir(info.Path)
	if e != nil {
		panic(e.Error())
	}
	workspace := info.Workspace + ".xcworkspace"
	archCommand := exec.Command("xcodebuild", "archive", "-workspace", workspace,
		"-scheme", info.Scheme, "-archivePath", info.ArchPath)
	archCommand.Stdout = os.Stdout
	e = archCommand.Run()
	if e != nil {
		panic(e.Error())
	}
}

匯出成ipa 最新的xcode 9 需要一個配置檔案,可以手動匯出一次進行獲取

func Export(info buildInfo) {
	arch := info.ArchPath + ".xcarchive"
	export := exec.Command("xcodebuild", "-exportArchive", "-archivePath", arch,
		"-exportPath", info.ExportPath, "-exportOptionsPlist", info.Config)
	export.Stdout = os.Stdout
	e := export.Run()
	if e != nil {
		panic(e.Error())
	}
}



git分支的切換,可以新建一個分支專門對於這個程式的配合使用

func switchBranch(info buildInfo) {
	e := os.Chdir(info.Path)
	if e != nil {
		panic(e.Error())
	}
	branch := info.Branch
	println(branch)
	if len(branch) > 0 {
		git := exec.Command("git", "checkout", branch)
		git.Stdout = os.Stdout
		e = git.Run()
		if e != nil {
			panic(e.Error())
		}
	}
}


配置讀取,引數為config,對應配置Json檔案的路徑

func main() {
	config := flag.String("config", "", "the path of the config file")
	flag.Parse()


	content, e := ioutil.ReadFile(*config)
	if e != nil {
		panic(e.Error())
	}
	var info buildInfo
	e = json.Unmarshal(content, &info)
	if e != nil {
		panic(e.Error())
	}
	switchBranch(info)
	Archive(info)
	Export(info)


        e = Upload(info)
	if e != nil {
        	fmt.Println(e.Error())
	 }
}

蒲公英對應的上傳介面

const (
	userKey = ""
	apiKey  = ""
	apiURL  = "https://qiniu-storage.pgyer.com/apiv1/app/upload"
)


func Upload(info buildInfo) error {
	if !info.Upload {
		println("will not upload to pgy")
		return nil
	}
	file := info.ExportPath + info.Scheme + ".ipa"
	buf := new(bytes.Buffer) // caveat IMO dont use this for large files, \
	w := multipart.NewWriter(buf)
	fw, err := w.CreateFormFile("file", file) 

	if err != nil {
		fmt.Println("c")
		return err
	}
	fd, err := os.Open(file)
	if err != nil {
		fmt.Println("d")
		return err
	}
	defer fd.Close()
	// Write file field from file to upload
	_, err = io.Copy(fw, fd)
	if err != nil {
		fmt.Println("e")
		return err
	}


	w.WriteField("uKey", userKey)
	w.WriteField("_api_key", apiKey)
	w.WriteField("installType", info.InstallType)
	w.WriteField("password", info.Password)
	w.WriteField("updateDescription", info.UpdateDescription)
	e := w.Close()
	if e != nil {
		fmt.Println("e")
		return e
	}
	request, e := http.NewRequest(http.MethodPost, apiURL, buf)
	if e != nil {
		fmt.Println("e")
		return e
	}

//這裡糾結了好久,發現設定了content-type之後貌似引數才能被伺服器取到

	request.Header.Add("Content-Type", w.FormDataContentType())
	request.Header.Set("enctype", "multipart/form-data")
	client := &http.Client{}
	resp, e := client.Do(request)
	if e != nil {
		fmt.Println("e")
		return e
	}
	io.Copy(os.Stdout, resp.Body)
	defer resp.Body.Close()
	return nil
}

配置的json檔案內容

{
	"path":"~/Desktop/demo",
	"branch":"demo",
	"workspace":"demo",
	"scheme":"demo",
	"archPath":"~/demo/demo",
	"exportPath":"~/demo/ipas/",
	"config":"~/demo/config.plist",
	"password":"demo",
	"updateDescription":"demo",
	"installType":"2",
	"upload":true
}

目錄結構

demo tree

.

├── config.plist

├── demo.json

└── ipas

1 directory, 2 files