├── AndroidDeploy
├── androidarchive.py
├── androiddeploy.py
├── androidtest.py
└── libs
│ ├── __init__.py
│ ├── chinanetcenter.py
│ ├── dingtalk.py
│ ├── fir.py
│ └── libsoss.py
├── IOSDeploy.sh
└── README.md
/AndroidDeploy/androidarchive.py:
--------------------------------------------------------------------------------
1 | #-*- coding: utf-8 -*-
2 | __author__ = 'geekwolf'
3 |
4 | import os
5 | import sys
6 | import shutil
7 | from libs.libsoss import OssUtils
8 | from libs.dingtalk import DingTalkNotice
9 | import hashlib
10 | from oss.oss_api import *
11 |
12 |
13 | class AndroidDeploy():
14 |
15 | def __init__(self):
16 |
17 | self.channel_to_deploy = str(os.getenv("ChannelToDeploy"))
18 | self.workspace = '/usr/share/tomcat/.jenkins/workspace/Android-Test'
19 | self.build_dir = self.workspace + '/app/build/outputs/apk/'
20 | self.channel_to_deploy = os.getenv('ChannelToDeploy')
21 | self.archive_pack_apk = '/data/android_archive/android/'
22 | #self.storepass = ''
23 | #self.keypass = ''
24 | #self.keystore = self.workspace+'/key.jks'
25 |
26 | if not os.listdir(self.build_dir):
27 | sys.exit('APK文件不存在,请先构建!!!')
28 |
29 | self.version = os.popen("ls "+ self.build_dir +"|grep -vE *unaligned|head -1|awk -F '-|.apk' '{print $3}'").read().strip()
30 | print self.version
31 |
32 | if self.version:
33 | self.now_apk = self.build_dir + "app-release-"+ self.version + ".apk ".strip()
34 | else:
35 | sys.exit('APK文件不存在,请先构建2!!!')
36 |
37 | if not os.path.exists(self.archive_pack_apk + self.version):
38 | os.mkdir(self.archive_pack_apk + self.version)
39 |
40 | if not os.path.exists(self.build_dir + 'META-INF'):
41 | os.mkdir(self.build_dir + 'META-INF')
42 |
43 | self.archive_pack_apk_dir = self.archive_pack_apk + self.version + "/"
44 |
45 |
46 |
47 | def archive_apk(self):
48 |
49 | tag = os.popen('cd '+self.workspace+'&& git pull > /dev/null && git tag -l|grep "^v[0-9]" |grep '+self.version).read().strip()
50 |
51 | if tag:
52 |
53 | print "已经创建发布时Tag:" + tag
54 |
55 | else:
56 |
57 | try:
58 | os.popen('cd '+self.workspace+' && git checkout master && git tag V' + self.version + ' && git push origin --tags ' + "V" + self.version)
59 | except:
60 | sys.exit('Tag创建失败,请重新执行脚本!!!')
61 |
62 | if self.channel_to_deploy == 'All Channels':
63 |
64 | shutil.rmtree(self.archive_pack_apk + self.version)
65 | os.mkdir(self.archive_pack_apk + self.version)
66 |
67 | f = open(self.workspace + "/" + 'channels','r')
68 | for channel in f.readlines():
69 |
70 | channel = channel.strip()
71 |
72 | if channel == 'ma':
73 | apk_name = 'MA'
74 |
75 | elif "_" in channel:
76 | apk_name = 'ma_android'+ channel
77 |
78 | else:
79 | apk_name = 'ma_android'+ "_" + channel
80 | try:
81 | self.pack_apk(channel,self.archive_pack_apk_dir,apk_name)
82 |
83 | except:
84 | sys.exit('签名失败,请检查!!!')
85 | else:
86 |
87 | if "_" in self.channel_to_deploy:
88 | apk_name = 'ma_android'+ self.channel_to_deploy
89 | else:
90 | apk_name = 'ma_android'+ "_" + self.channel_to_deploy
91 | self.pack_apk(self.channel_to_deploy,self.archive_pack_apk_dir,apk_name)
92 |
93 | return self.archive_pack_apk
94 |
95 | def pack_apk(self,channel,archive_pack_apk_dir,apk_name):
96 |
97 | old_channel_file = os.popen("unzip -l " + self.now_apk + "|grep 'META-INF/channel'|awk '{ print $NF }'").read().strip()
98 | print old_channel_file
99 | remove_old_channel_file = os.popen("cd " + self.build_dir + "&& zip -d " + self.now_apk + '\t' + old_channel_file).read().strip()
100 | new_channel_file = os.popen("cd " + self.build_dir + "&&touch " + "META-INF/channel_" + channel).read().strip()
101 | print new_channel_file
102 | os.popen( "cd " + self.build_dir + "&& zip -u " + self.now_apk + " " + "META-INF/channel_" + channel)
103 | print self.now_apk,archive_pack_apk_dir + apk_name.strip() + '.apk'
104 | dest = archive_pack_apk_dir + apk_name.strip() + '.apk'
105 | shutil.copyfile(self.now_apk,dest )
106 |
107 | if __name__ == "__main__":
108 |
109 | pack = AndroidDeploy()
110 | libsoss = OssUtils()
111 | pack.archive_apk()
112 | version_dir = pack.version
113 | filespath = pack.archive_pack_apk + version_dir + "/"
114 | channel = pack.channel_to_deploy
115 | archive_download_url = libsoss.upload_oss(filespath,version_dir,channel)
116 | content = '各渠道正式包' + version_dir + '版本已经归档OSS(未发布),代码库已经自动创建发布Tag:' + version_dir + '访问地址为:http://download.simlinux.com/app/archive/' + version_dir +'/index.html'
117 | notice = DingTalkNotice()
118 | notice.post_msg(content=content)
119 |
--------------------------------------------------------------------------------
/AndroidDeploy/androiddeploy.py:
--------------------------------------------------------------------------------
1 | #-*- coding: utf-8 -*-
2 | __author__ = 'geekwolf'
3 |
4 | import os
5 | import sys
6 | import shutil
7 | from libs.libsoss import OssUtils
8 | from libs.dingtalk import DingTalkNotice
9 | from libs.chinanetcenter import ChinaNetCenter
10 | import hashlib
11 | from oss.oss_api import *
12 |
13 |
14 | if __name__ == "__main__":
15 |
16 | libsoss = OssUtils()
17 | url_list = libsoss.copy_oss()
18 | content = '_11到_40,渠道包已经上线,可通过http://download.simlinux.com/app/ma_android_11.apk访问,相关CDN地址已经刷新!!!'
19 | chinanetcenter = ChinaNetCenter()
20 | chinanetcenter.flush_files(url_list)
21 | notice = DingTalkNotice()
22 | notice.post_msg(content=content)
23 |
--------------------------------------------------------------------------------
/AndroidDeploy/androidtest.py:
--------------------------------------------------------------------------------
1 | #-*- coding: utf-8 -*-
2 | __author__ = 'geekwolf'
3 |
4 | from libs.fir import FirUtils
5 | from libs.dingtalk import DingTalkNotice
6 | import requests
7 | import requests.packages.urllib3.util.ssl_
8 | print(requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS)
9 | requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'ALL'
10 |
11 |
12 | if __name__ == "__main__":
13 |
14 | fir = FirUtils()
15 | version = fir.upload_apk()
16 | pic_msg_url = fir.get_qrcode()
17 | title ='Android测试发布'
18 | text = '本次发布为Debug-' + version + ',已经上传fir,请扫描二维码安装!'
19 | notice = DingTalkNotice()
20 | notice.send_link(title=title,text=text,pic_url=pic_msg_url[0],message_url=pic_msg_url[1])
21 |
--------------------------------------------------------------------------------
/AndroidDeploy/libs/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'geekwolf'
2 |
--------------------------------------------------------------------------------
/AndroidDeploy/libs/chinanetcenter.py:
--------------------------------------------------------------------------------
1 | #-*- coding: utf-8 -*-
2 | __author__ = 'geekwolf'
3 |
4 | import requests
5 | import json
6 | import datetime
7 | import hashlib
8 |
9 | class ChinaNetCenter():
10 |
11 | def __init__(self):
12 |
13 | self.username = '推送用户'
14 | self.password = '推送密码'
15 |
16 | def flush_files(self,url_list):
17 | #print url_list
18 | time = datetime.datetime.now().strftime("%Y%m%d")
19 | headers = {'content-type': 'application/json'}
20 | post_url = 'http://cm.chinanetcenter.com/CM/cm-publish!json.do'
21 | check_code = hashlib.new("md5", time + self.username + 'chinanetcenter' + self.password).hexdigest()
22 | __content = {"user_name":self.username,"check_code":check_code,"need_feedback":"0","fetchOption":"N","url_list":url_list}
23 | content = json.dumps(__content)
24 | print content
25 | try:
26 | r = requests.post(post_url, data=content, headers=headers)
27 | print r.text
28 | except:
29 | print '刷新失败,请重试!!!'
30 |
31 |
--------------------------------------------------------------------------------
/AndroidDeploy/libs/dingtalk.py:
--------------------------------------------------------------------------------
1 | #-*- coding: utf-8 -*-
2 | __author__ = 'geekwolf'
3 |
4 | import json
5 | import requests
6 | import os
7 | import qrcode
8 | import base64
9 | import requests.packages.urllib3.util.ssl_
10 | print(requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS)
11 | requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'ALL'
12 |
13 | class DingTalkNotice():
14 |
15 | def __init__(self,**kwargs):
16 |
17 | #self.source_image = ''
18 | self.sender = "发送这ID"
19 | self.chat_id = '会话ID'
20 |
21 | def get_token(self):
22 |
23 | get_url = 'https://oapi.dingtalk.com/gettoken?corpid=钉钉后台coreid&corpsecret=钉钉后台coresecret'
24 |
25 | try:
26 | r = requests.get(get_url)
27 | except:
28 | print "DingTalk token获取失败!!!"
29 |
30 | data = json.loads(r.content)
31 | access_token = data['access_token']
32 | return access_token
33 |
34 | def post_images(self):
35 |
36 | __access_token = self.get_token()
37 | headers = {'content-type': 'application/json'}
38 | post_url = 'https://oapi.dingtalk.com/media/upload?access_token=' + __access_token + '&type=image'
39 | files = {'media': open(self.source_img,'rb')}
40 | try:
41 | r = requests.post(post_url, files=files)
42 | media_id = json.loads(r.text)['media_id']
43 | templates = {"chatid": self.chat_id,"sender":self.sender,"msgtype":"image","image":{"media_id":media_id}}
44 | post_data = json.dumps(templates)
45 | r = requests.post(post_url, data=post_data, headers=headers)
46 |
47 | except:
48 | print "DingTalk POST数据失败!!!"
49 |
50 | return r.text
51 |
52 | def post_msg(self,content):
53 |
54 | __access_token = self.get_token()
55 |
56 | headers = {'content-type': 'application/json'}
57 | post_url = 'https://oapi.dingtalk.com/chat/send?access_token=' + __access_token
58 | templates = { "chatid": self.chat_id, "sender": self.sender,"msgtype": "text", "text": { "content": content }}
59 | post_data = json.dumps(templates)
60 | try:
61 | r = requests.post(post_url, data=post_data, headers=headers)
62 | if json.loads(r.content)['errmsg'] != 'ok':
63 | print "发送者ID不存在(sender)"
64 | except:
65 | print "DingTalk POST数据失败!!!"
66 |
67 | return r.text
68 |
69 | def send_link(self,title,text,pic_url,message_url):
70 |
71 | __access_token = self.get_token()
72 |
73 | headers = {'content-type': 'application/json'}
74 | post_url = 'https://oapi.dingtalk.com/chat/send?access_token=' + __access_token
75 | templates = {"chatid":self.chat_id ,"sender":self.sender,"msgtype":"link","link":{"title": title ,"text": text,"pic_url": pic_url,"message_url":message_url}}
76 | post_data = json.dumps(templates)
77 | try:
78 | r = requests.post(post_url, data=post_data, headers=headers)
79 | print r.text
80 | except:
81 | print "DingTalk POST数据失败!!!"
82 |
--------------------------------------------------------------------------------
/AndroidDeploy/libs/fir.py:
--------------------------------------------------------------------------------
1 | #-*- coding: utf-8 -*-
2 | __author__ = 'geekwolf'
3 |
4 | import os
5 | import qrcode
6 | import base64
7 |
8 | class FirUtils():
9 |
10 | def __init__(self):
11 |
12 | self.token = 'Fir Token'
13 | self.message_url ='http://fir.im/simlinux?utm_source=fir&utm_medium=qr'
14 |
15 | def upload_apk(self):
16 |
17 | workspace = os.getenv('WORKSPACE')+"/app/build/outputs/apk/"
18 | version = os.popen("ls "+workspace+"|grep -vE *unaligned|head -1|awk -F '-|.apk' \'{print $3}\' ").read().strip()
19 |
20 | if version:
21 |
22 | try:
23 | os.popen('fir login ' + self.token)
24 | fir_status = os.popen('fir publish ' + workspace + "app-debug-" + version + '.apk').read()
25 | print 'Fir 上传成功...'+'http://fir.im/simlinux' + '\t'+version
26 |
27 | return version
28 | except:
29 | sys.exit("Fir 上传失败!!!")
30 |
31 |
32 | def get_qrcode(self):
33 |
34 | img = qrcode.make(self.message_url)
35 |
36 | try:
37 |
38 | img.save('/tmp/simlinuxAqrcode.png')
39 | __pic = '/tmp/simlinuxAqrcode.png'
40 | f = open(__pic,'rb')
41 | pic_url = 'data:image/png;base64,' + base64.b64encode(f.read())
42 | f.close()
43 | print "Qrcode二维码生成成功..." + '\t二维码访问地址:http://fir.im/simlinux'
44 | except:
45 | print 'Qrcode generation failure!!!'
46 | return pic_url,self.message_url
47 |
--------------------------------------------------------------------------------
/AndroidDeploy/libs/libsoss.py:
--------------------------------------------------------------------------------
1 | #-*- coding: utf-8 -*-
2 | __author__ = 'geekwolf'
3 |
4 | import os
5 | import re
6 | import sys
7 | import hashlib
8 | from oss.oss_api import *
9 | from itertools import islice
10 | import oss2
11 |
12 | class OssUtils():
13 |
14 | def __init__(self):
15 |
16 | self.workspace = '/usr/share/tomcat/.jenkins/workspace/Android-Test'
17 | self.endpoint="oss-cn-beijing.aliyuncs.com"
18 | self.accessKeyId, self.accessKeySecret="",""
19 | self.oss = OssAPI(self.endpoint, self.accessKeyId, self.accessKeySecret)
20 | self.header={"Cache-Control":"max-age=31536000","Content-Type":"application/vnd.android.package-archive"}
21 | self.bucket='staticfiles'
22 | self.filespath=''
23 |
24 | def upload_oss(self,filespath,version_dir,channel):
25 |
26 | version_dir = version_dir + "/"
27 | if channel == 'All Channels':
28 |
29 | listfile=os.listdir(filespath)
30 | file = '/tmp/index.html'
31 | os.remove(file)
32 | f=open('/tmp/index.html','a')
33 |
34 | for src in listfile:
35 |
36 | __channel_tmp = re.split('_|.apk',src)
37 |
38 | try:
39 |
40 | res=self.oss.put_object_from_file(self.bucket,"app/archive/"+ version_dir +src,filespath+src,headers=self.header)
41 |
42 | if __channel_tmp[0] == 'MA':
43 | __channel = 'MA'
44 | else:
45 | __channel = __channel_tmp[2]
46 |
47 | f.write(''+ __channel + '' +'\t' + 'http://download.simlinux.com/app/archive/'+ version_dir + str(src) + '
')
48 | except:
49 |
50 | system.exit('上传不完整或失败!!!')
51 |
52 | res=self.oss.put_object_from_file(self.bucket,"app/archive/"+ version_dir + 'index.html',file,headers={"Content-Type":"text/html"})
53 |
54 | f.close()
55 |
56 | else:
57 | try:
58 | src = os.popen('cd '+ filespath +';ls *' + channel + '* ').read().strip()
59 | res = self.oss.put_object_from_file(self.bucket,"app/archive/"+ version_dir + src,filespath + src,headers=self.header)
60 | except:
61 |
62 | system.exit('上传不完整或失败!!!')
63 |
64 | archive_download_url = 'http://download.simlinux.com/app/archive/' + version_dir + 'index.html'
65 | return archive_download_url
66 |
67 | def copy_oss(self):
68 |
69 | auth = oss2.Auth(self.accessKeyId,self.accessKeySecret)
70 | bucket = oss2.Bucket(auth,self.endpoint,self.bucket)
71 | latest_version = max(os.popen('cd '+self.workspace+'&& git pull > /dev/null && git tag -l|grep "^v[0-9]"').read().strip().split("\n")).replace('v','')
72 | apk_name = 'app/archive/' + latest_version + '/' + 'MA.apk'
73 | dest_name = 'app/' + latest_version + '/' + 'MA.apk'
74 | result = bucket.copy_object(self.bucket, apk_name , dest_name)
75 | url_list = []
76 |
77 | #要发布渠道11-41,可根据自身情况改写
78 | for channel in range(11,41):
79 |
80 | apk_name = 'app/archive/' + latest_version + '/ma_android_'+ str(channel) + '.apk'
81 | dest_name = 'app/' + latest_version + '/' + 'ma_android_'+ str(channel) + '.apk'
82 | url_list.append('http://download.simlinux.com/app/' + 'ma_android_'+ str(channel) + '.apk')
83 | result = bucket.copy_object(self.bucket, apk_name , dest_name)
84 | if result.resp.status == 200:
85 | print 'APK发布:由' + apk_name + '\t----->\t' + dest_name
86 | else:
87 | sys.exit('APK拷贝失败,请重试!!!')
88 | url_list.append('http://download.simlinux.com/app/' + 'MA.apk')
89 | return url_list
90 |
--------------------------------------------------------------------------------
/IOSDeploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #说明依赖xcode工具集和fir(ruby包),by 公司ioser-lijing
4 | export LC_ALL=zh_CN.UTF-8;export LANG=zh_CN.UTF-8
5 |
6 | now=$(date +"%Y_%m_%d-%H_%M")
7 |
8 | projectname="IOS_TEST_DEMO"
9 | path_project="~/Desktop/workspace/${projectname}/"
10 | path_output_root="~/Desktop/buildtool/"
11 | path_workspace="$path_project/$p{rojectname}.xcworkspace"
12 |
13 | #info
14 | buildConfig=""
15 | scheme=""
16 | infoPlist=""
17 | version_project=""
18 | buildversion_project=""
19 | bundleid_project=""
20 | provisioning_profile=""
21 | code_sign_identity=""
22 | export_option_plist=""
23 | path_export=""
24 |
25 | if [[ ! -d $path_project ]];then
26 | echo "项目目录错误:\n$path_project"
27 | exit
28 | fi
29 |
30 | if [[ ! -d $path_output_root ]];then
31 | mkdir -p $path_output_root
32 | fi
33 |
34 | function project_info(){
35 | local plist=$1
36 | version_project=`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" $plist`
37 | buildversion_project=`/usr/libexec/PlistBuddy -c "Print CFBundleVersion" $plist`
38 | }
39 |
40 | # function set_bversion(){
41 | # local plist=$1
42 | # lastversion=project_build_version
43 | # echo "$lastversion"
44 | # newversion=100
45 | # `/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $newversion" "$plist"`
46 | # }
47 |
48 | #询问打包环境
49 | trap "echo -e \"\n已中断执行\";exit 0" INT
50 | for((i=1;i<=100;i++));do
51 | read -n1 -p "打包是否为国内版[y/n]:" input
52 | if [ "$input" == "y" ] ; then
53 | is_chin=true
54 | break
55 | else
56 | if [ "$input" == "n" ]; then
57 | is_chin=false
58 | break
59 | else
60 | echo "输入有误"
61 | fi
62 | fi
63 | input=""
64 | done
65 |
66 | echo ""
67 |
68 | for((i=1;i<=100;i++));do
69 | read -n1 -p "打包是否为测试版[y/n]:" input
70 | if [ "$input" == "y" ] ; then
71 | is_fir=true
72 | break
73 | else
74 | if [ "$input" == "n" ]; then
75 | is_fir=false
76 | break
77 | else
78 | echo "输入有误"
79 | fi
80 | fi
81 | input=""
82 | done
83 |
84 | echo ""
85 |
86 | #整理打包所需材料
87 | if $is_chin ; then
88 | #statements
89 | scheme="Demo_CN"
90 | infoPlist="${path_project}${projectname}/${scheme}_Info.plist"
91 | echo "$infoPlist"
92 | project_info $infoPlist
93 | if $is_fir ; then
94 | #statements
95 | buildConfig="Debug"
96 |
97 | bundleid_project="com.simlinux.demo"
98 | provisioning_profile="dc2117ff-9bfe-4234-8047-01d220238fdb"
99 | code_sign_identity="Demo Communication Co., Ltd"
100 |
101 | name_output="${scheme}-FIR_v${version_project}(b${buildversion_project})_${now}"
102 | export_option_plist="${path_output_root}/plist/FirExportOptions.plist"
103 | echo "国内测试包"
104 | else
105 | buildConfig="Release"
106 |
107 | bundleid_project="com.simlinux.demo"
108 | provisioning_profile="dc2117ff-9bfe-4234-8047-01d220238fdb"
109 | code_sign_identity="Demo Communication Co., Ltd"
110 |
111 | name_output="${scheme}-APS_v${version_project}(b${buildversion_project})_${now}"
112 | export_option_plist="${path_output_root}/plist/AppstoreExportOptions.plist"
113 | echo "国内正式包"
114 | fi
115 |
116 | else
117 | scheme="Demo_Inter"
118 | infoPlist="${path_project}${projectname}/${scheme}_Info.plist"
119 | project_info $infoPlist
120 | if $is_fir ; then
121 | #statements
122 | buildConfig="Debug"
123 |
124 | bundleid_project="com.simlinux.demo"
125 | provisioning_profile="dc2117ff-9bfe-4234-8047-01d220238fdb"
126 | code_sign_identity="Demo Communication Co., Ltd"
127 |
128 | name_output="${scheme}-FIR_v${version_project}(b${buildversion_project})_${now}"
129 | export_option_plist="${path_output_root}/plist/FirExportOptions.plist"
130 | echo "国际测试包"
131 | else
132 | buildConfig="Release"
133 |
134 | bundleid_project="com.simlinux.demo"
135 | provisioning_profile="dc2117ff-9bfe-4234-8047-01d220238fdb"
136 | code_sign_identity="Demo Communication Co., Ltd"
137 |
138 | name_output="${scheme}-APS_v${version_project}(b${buildversion_project})_${now}"
139 | export_option_plist="${path_output_root}/plist/AppstoreExportOptions.plist"
140 | echo "国际正式包"
141 | fi
142 | fi
143 |
144 | path_export="${path_output_root}/${scheme}/${name_output}"
145 | path_archive="${path_export}/$scheme.xcarchive"
146 |
147 | #clean
148 | xcodebuild clean -workspace ${path_workspace} -scheme ${scheme} -configuration ${buildConfig}
149 |
150 | #archive
151 | xcodebuild -workspace ${path_workspace} -scheme ${scheme} -configuration ${buildConfig} archive -archivePath ${path_archive} CODE_SIGN_IDENTITY="${code_sign_identity}" PROVISIONING_PROFILE="${provisioning_profile}" PRODUCT_BUNDLE_IDENTIFIER=${bundleid_project}
152 |
153 | #ipa
154 | xcodebuild -exportArchive -archivePath ${path_archive} -exportPath ${path_export} -exportOptionsPlist ${export_option_plist}
155 |
156 | if $is_fir ; then
157 | #statements
158 | #上传到Fir
159 | api_token_fir="Fir Token"
160 | fir login $api_token_fir
161 | ipaPath="${path_export}/${scheme}.ipa"
162 | echo "$ipaPath"
163 | fir publish $ipaPath
164 | fi
165 |
166 |
167 | #上传到AppStore
168 |
169 |
170 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #### Android多渠道打包流程:
2 | - 执行gradlew clean清除build目录
3 | - 执行gradlew assemble编译打包Debug/Release(已自动签名)
4 | - 上传Debug包到Fir
5 | - 通过DingTalk发送通知信息到QA讨论组(发送提测apk包版本,下载地址及扫描下载二维码)
6 | - 提测不通过,修复bug后再次执行前四步
7 | - 提测通过后,点击Jenkins打包归档多渠道按钮,将执行生成多渠道包并归档包到本地目录/data/2.0.1/xxx.apk
8 | - 可选择此步上传归档文件到OSS
9 | - 点击Jenkins发布按钮将最新版本相关渠道归档拷贝至OSS发布目录
10 | - 刷新CDN生效
11 | - 通过DingTalk发送通知信息到QA讨论组哪些渠道已经发布
12 |
13 | #### IOS打包流程:
14 | - xcodebuild clean 清理build目录
15 | - xcodebuild archive 选择不同的环境/BundleID/ProvisionProfile/CodeSigningIdentify 编译,签名生成xcarchive文件
16 | - xcodebuild -exportArchive 打包生成ipa
17 | - 测试包自动上传Fir,生产包手动更新AppStore
18 |
19 | #### Android7.0打包方式:
20 | - http://tech.meituan.com/android-apk-v2-signature-scheme.html
21 |
--------------------------------------------------------------------------------