flutter项目使用jenkins自动部署
操作系统:macOS Big Sur
前置需求:
# Terminal:homebrew、rvm、ruby、gem、cocoapods
# 编译器:vscode、androidStudio、xcode
# Flutter:flutter sdk、dart
# Android&iOS:android sdk、gradle、jdk、.keystore、P12、.mobileprovision等
# terminal运行flutter doctor无异常
# vscode编译运行flutter项目成功
# androidStudio和xcode单独编译运行flutter项目下的android和ios项目成功
ok,开始搞jenkins
1、使用homebrew安装jenkins
Terminal运行命令brew install Jenkins
2、运行jenkins
Terminal运行命令jenkins,最终出现 Jenkins is fully up and running代表运行成功
3、初始化jenkins
在浏览器地址栏输入http://localhost:8080/
然后首次安装启动就会出现新手引导,根据引导操作
自定义jenkins那里选择安装推荐的插件
PS:这里我很多插件都安装失败了,这个没关系,可以进去再自己安装或者不再安装貌似也没啥影响,继续向下操作即可
最后的实例配置那,默认即可,也可以设置一个地址
PS:如果要设置的话,就是自己的电脑ip地址+8080端口就行,配置完之后系统管理里报了一个反向代理设置有误,目前没发现这个报错有什么不好的影响,这个地址也可以以后在jenkins系统管理-系统配置里改的,这个主要是用来让别的同事来访问时要用的,自己用的话就不用设置,额外说一个,如果同事电脑挂了vpn,大概率是访问不了你设置的这个地址的,退掉vpn即可
4、安装插件
进来第一步就是安装插件了,这里要用到哪些我也是根据别人的博客找的,但是由于我主要是用shell命令,所以好像很多都没用上,但是安装了也不亏。。。
gitLab Plugin、gitLab Hook Plugin、Xcode integration、keychains and provisioning profiles Management,DingTalk等
PS:说下这个Upload Keychain or Provisioning Profile File插件,这个是用来管理iOS证书和配置文件的,但是吐血的是,无论如何都传不上去,搞到头秃,最后没办法,放弃治疗,好在还有别的办法,往下看
然后DingTalk这个是在构建成功后自动通知到钉钉群的插件,我这边用到了,下面也有介绍
5、iOS相关设置
系统管理-Manage Credentials
WX20210624-114517.png
点击 Stores scoped to Jenkins下面的域-全局,然后就可以添加全局凭据了,这里要添加的是:
gitLab或者gitHub账号密码(Username with password)
/Library/Keychains路径(macOS Keychain password and path)
mobileprovision文件(Apple Developer Profile)
P12文件(Certificate)
Upload Keychain or Provisioning Profile File插件用不了,配置文件在这里添加也是一样的
6、Android相关设置
系统管理-系统配置-全局属性-环境变量
Android SDK设置
2.png
系统管理-全局工具配置
JDK设置
3.png
Gradle设置
4.png
7、钉钉插件通知配置
在钉钉群的设置-智能群助手-添加自定义机器人
要复制一下webhook链接,下面要用,还有关键字设置,要钉钉和jenkins一致
5.png
在jenkins系统管理-系统配置中,设置钉钉,点击测试如果群聊能收到通知就可以
6.png
8、新建任务
这里是Android和iOS各建一个,选择freestyle即可,两边别的都一样,就是shell命令不一样,下面会贴
点开新建的任务,点击配置
①描述和钉钉
8.png
②git信息
9.png
git这里是自己项目的git地址和之前全局配置的git账号密码,也可以再这里添加新的账号密码
③构建触发器和构建环境都不用选
④构建
选择执行shell,然后填写shell命令(iOS和Android我都贴上了,可以自己参考和修改)
里面的一些关键密码和文件名等,我改成了文字描述或者***,都填自己的
此shell支持的一些功能:清空指定文件夹,替换指定文件,替换指定文件的指定内容,导出安装包,上传蒲公英,安装包重命名(version+build+时间),安装包上传svn
iOS打包shell
# keychain-这里可能你进去看到只有login.keychain-db,复制一份然后去掉-db即可
security unlock-keychain -p 电脑密码 ${HOME}/library/keychains/login.keychain
# 工程名-在xcode中查看PROJECT
APP_NAME="Runner"
# target-在xcode中查看TARGETS
TARGET_NAME="primary"
# 证书
# 这里是钥匙串中证书的显示简介-常用名称
CODE_SIGN_DISTRIBUTION="Apple Development: *** (Q3******UZ)"
# 这里是mobileprovision文件的UUID
provisoning_profile="e4270330-***********-473b3a50de58"
# 模式
CONFIGURATION="Release"
# 路径 这个路径要自己看/Users/你的电脑用户名/.jenkins/workspace/下的,你每建一个项目,构建后都会在这下面创建对应的文件夹存放git clone下来的项目
WORKSPACE_PATH=${WORKSPACE}/witparking/ios/${APP_NAME}.xcworkspace
# 这个是导出ipa用的文件,用xcode导出一个对应模式的ipa就能获取到,把那个文件的路径放这里
EXPORT_OPTIONS=/Users/你的电脑用户名/Desktop/***/ExportOptions.plist
ArchivePath=/Users/***/.jenkins/workspace/witParkingIOS@tmp/
EXPORTIPA=/Users/***/.jenkins/workspace/witParkingIOS@tmp/
# 清空存放ipa的文件夹
cd ${EXPORTIPA}
rm -rf *
# 将指定文件的指定内容替换掉pro/dev/test
# 这里是修改main_primary文件的指定内容,切换环境
# 如下示例意思是,使用app5test.wit替换该文件的从app开始,到wit结束的指定字段
cd ${WORKSPACE}/witparking/lib/flavors
sed -i '' "s/app.*wit/app5test.wit/" main_primary.dart
# flutter pub get
cd ${WORKSPACE}/witparking/
flutter pub get
# build app,里面的primary是前面的target
flutter build ios --release --flavor primary -t lib/flavors/main_primary.dart
# 进入原生项目 archive和export
cd ${WORKSPACE}/witparking/ios/
pod install
# 导出achive,里面的primary是前面的target
xcodebuild archive -workspace ${WORKSPACE_PATH} -scheme "primary" -configuration ${CONFIGURATION} -sdk iphoneos -archivePath ${ArchivePath}runner.xcarchive
# 导出ipa
xcodebuild -exportArchive -archivePath ${ArchivePath}runner.xcarchive -exportPath ${EXPORTIPA}runner -exportOptionsPlist ¥{EXPORT_OPTIONS}
# echo "=================上传到蒲公英分发平台 ================="
curl -F "file=@${EXPORTIPA}runner/Runner.ipa" \
# uKey和api_key都可以去蒲公英自己的账号信息里查看
-F "uKey=662aad68ce*****32c8114d87a13" \
-F "_api_key=46755cd719*******b4fd8fa55f" \
[https://www.pgyer.com/apiv1/app/upload](https://www.pgyer.com/apiv1/app/upload)
# ipa重命名(这里重命名是因为上传svn有统一的命名格式)
# info.plist路径
project_infoplist_path=${WORKSPACE}/witparking/ios/Info.plist
# 取版本号
bundleVersion=$(/usr/libexec/PlistBuddy -c "print CFBundleShortVersionString" "${project_infoplist_path}")
# 取build值
bundleBuild=$(/usr/libexec/PlistBuddy -c "print CFBundleVersion" "${project_infoplist_path}")
# 获取年月日时分
DATE="$(date +%Y%m%d%H%M)"
cd ${EXPORTIPA}runner
# 拼接新名字
ipaReName=${bundleVersion}-${bundleBuild}-${DATE}.ipa
# 替换
mv Runner.ipa ${ipaReName}
# 上传svn
# 账号信息
svnname=账号
svnpwd=密码
hostname=root
hostpwd=rootpwd
# 待提交文件
myFile=${ipaReName}
# ipa文件地址
resource_dir=${EXPORTIPA}runner/${myFile}
# 本地仓库地址
commit_dir=/Users/***/Desktop/APP/测试环境/IOS
# svn路径
target_svn_dir=svn://*****/测试/版本管理/APP版本/APP
cd $commit_dir
# 先更新项目
svn update --username $svnname --password $svnpwd
# 复制安装包到提交目录
cp $resource_dir $commit_dir
#增加项目
svn add $commit_dir/$myFile
#上传项目
svn commit -m "commit file ipa" $commit_dir --username $svnname --password $svnpwd
echo "====================== svn commit end ======================"
Android apk打包shell
# apk目录
WORKSPACE_PATH=${WORKSPACE}/witparking/build/app/outputs/apk/primary/release
# 将指定文件的指定内容替换掉pro/dev/test
cd ${WORKSPACE}/witparking/lib/flavors
sed -i '' "s/app.*wit/app5test.wit/" main_primary.dart
# 清空存放apk的文件夹(首次编译没有这个路径的文件夹,因此首次编译需要注释掉这里)
cd ${WORKSPACE_PATH}
rm -rf *
# flutter pub get
cd ${WORKSPACE}/witparking/
flutter pub get
# 安卓down下来的插件有个错误,会导致运行失败,因此需要替换文件内容
# 被替换文件
A=/Users/***/Desktop/flutter/.pub-cache/hosted/pub.flutter-io.cn/contact_picker-0.0.2/android/src/main/java/net/goderbauer/flutter/contactpicker/ContactPickerPlugin.java
# 替换文件
B=/Users/****/Desktop/WitParkingDEV/ContactPickerPlugin.java
cat $B > $A
echo "==========已替换插件文件=========="
# 编译apk
flutter build apk --flavor primary -t lib/flavors/main_primary.dart --no-shrink
# 获取最新apk包的名称
cd ${WORKSPACE_PATH}
# apk名称
fileName="xx"
# 遍历获取后缀为apk的文件名
traverse_dir()
{
filepath=${WORKSPACE_PATH}
for file in `ls -a $filepath`
do
if [ -d ${filepath}/$file ]
then
if [[ $file != '.' && $file != '..' ]]
then
# 递归
traverse_dir ${filepath}/$file
fi
else
# 调用查找指定后缀文件
check_suffix $file
fi
done
}
# 获取后缀为apk的文件
check_suffix()
{
file=$1
if [ "${file##*.}" = "apk" ];
then
fileName=${file}
fi
}
traverse_dir ${WORKSPACE_PATH}
# apk签名
# 别名
aliase='****'
# 库密码
storepass='****'
# 签名密码
keypass='****'
# 秘钥
keystore='/Users/****/Desktop/WitParkingDEV/com.rpms.uaandroid.keystore'
output="output"
if [ ! -d "$output" ];then
mkdir $output
fi
# 签名
function sign(){
jarsigner -verbose -digestalg SHA1 -sigalg MD5withRSA -keystore $keystore -storepass $storepass -keypass $keypass -signedjar $tempname $filename $aliase
}
# $output"/"$(basename $filename .apk)"_signed.apk"
for filename in *
do
if [ "${filename##*.}" = "apk" ]; then
outputname=$output"/"${filename//_unsign/_signed}
echo "签名: "$filename
tempname=$(basename $filename .apk)"_temp.apk"
sign
rm -rf $tempname
fi
done
echo "-------签名已完成------"
# echo "=================上传到蒲公英分发平台 ================="
同上
# apk加时间戳
# 获取年月日时分
DATE="$(date +%Y%m%d%H%M)"
# 获取不带apk后缀的包名并重命名--从右边开始,删除第一个.及右边的字符
rename=${filename%.*}-${DATE}.apk
mv ${fileName} ${rename}
# 上传svn
同上
⑤构建后操作也不用做,保存
9、点击立即构建
如果构建失败可以点击当次构建,然后点击查看控制台输出,查看具体报错进行修改,一般来说只要androidStudio和xcode能够编译成功的话,这边问题都不大,一般都是一些小问题要改,如果构建成功,就会通知到钉钉群了
10.png