lazy模式:因为同时负责多个项目,本着fastlane文件写一个就能所有项目拖过去直接用的目的而创建。(涉及到项目的地方已做除密处理)

dingding.jpeg

slack.jpeg
使用方法:
- 把actions和Fastfile拖入项目中的fastlane文件夹中;
- 配置Fastfile文件中相关参数;
- 修改verison值(Build为脚本自动设置yyyyMMddHHmm);
- 把项目文件夹拖入终端窗口;
- 执行命令:
fastlane release 打包并上传到appStore;
fastlane fir 打包上传到 firim;
fastlane pgy 打包上传到 蒲公英;
6.支持钉钉和 slack 机器人
.env文件
Apple_Id = "*" # Your Apple email address
App_Identifier = "*"
Team_Id = "*" # Developer Portal Team ID
Itc_Team_Name = "*"
Itc_Team_Id = "*"
Scheme_Name = "*"
App_Identifier = "*"
# ipa包文件路径
IpaDir_Development = "*/ipa_development"
IpaDir_AppStore = "*/ipa_appStore"
APP_Slogan = "*"
App_Icon_Local = "*/app_icon.jpg"
App_Icon_Link = "*"
App_Store_Link = "itms-apps://apps.apple.com/cn/app/*?mt=8"
Firim_Shortcut_Link = "*"
Pgyer_Shortcut_Link = "*"
Dingtalk_Url = "*"
Slack_Url = "*"
# APP元数据及截图存放路径
App_Icon_Local = "./fastlane/metadata/app_icon.jpg"
Metadata_Path = "./fastlane/metadata"
Screenshots_Path = "./fastlane/screenshots"
Fastfile文件
# fastlane_version "2.112.0"
default_platform :ios
platform :ios do
#firim token
FirToken = "*"
#蒲同英
PgyerApiKey = "*"
PgyerUserKey = "*"
## Common
desc "发布新版本到AppStore"
lane :release do
#默认env文件
archiveRelease()
uploadRelease()
end
desc "上传新版本到AppStore"
lane :releaseupload do
#默认env文件
uploadRelease()
end
desc "发布One到AppStore"
lane :releaseA do
# actionRelease(name: ENV["Scheme_Name"], ipaDir: ENV["IpaDir_AppStore"])
sh "fastlane release --env targetA"
end
desc "发布到Fir"
lane :fir do
#默认env文件
archiveDevelopment()
uploadFir()
end
lane :firupload do
uploadFir()
end
desc "发布到pgyer"
lane :pgy do
#默认env文件
archiveDevelopment()
uploadPgyer()
end
desc "发布到pgyer"
lane :pgyupload do
#默认env文件
uploadPgyer()
end
desc "one发布到Fir"
lane :firA do
# actionFir(name: ENV["Scheme_name"], ipaDir: ENV["IpaDir_Development"])
sh "fastlane fir --env targetA"
end
desc "发布A到pgyer"
lane :pgyA do
#默认env文件
sh "fastlane pgy --env targetA"
end
desc "[通用]发布新版本到 AppStore"
def archiveRelease(name: ENV["Scheme_Name"], ipaDir: ENV["IpaDir_AppStore"])
clear_cache_files()
# cocoapods()
updateBuildVersion(showHash: false)
gym(
output_directory: ipaDir,
scheme: name,
export_method: 'app-store',
export_options: {
xcargs: "-allowProvisioningUpdates",
iCloudContainerEnvironment: 'Production'
}
)
end
desc "[通用]发布新版本到 AppStore"
def uploadRelease(name: ENV["Scheme_Name"], ipaDir: ENV["IpaDir_AppStore"])
deliver(force: true,
# ipa: "/Users/shang/ACS/access-admin-app-ios/ipa_appStore/AccessControlSystem.ipa",
ipa: "#{ipaDir}/#{name}.ipa",
metadata_path: ENV["Metadata_Path"],
screenshots_path: ENV["Screenshots_Path"],
)
# system "open #{ipaDir}"
handleDingTalk(name: name, ipaDir: ipaDir, appUrl: ENV["App_Store_Link"])
end
desc "[通用]发布新版本到 fir"
def archiveDevelopment(name: ENV["Scheme_Name"], ipaDir: ENV["IpaDir_Development"])
updateBuildVersion(showHash: true)
gym(
clean: true,
include_symbols: true,
output_directory: ipaDir,
scheme: name,
configuration: 'Debug',
export_method: 'development',
export_options: {iCloudContainerEnvironment: 'Development'}
)
end
desc "上传ipad 到 firim"
def uploadFir(name: ENV["Scheme_Name"], ipaDir: ENV["IpaDir_Development"], firToken: FirToken)
firim(firim_api_token: firToken, icon: ENV["App_Icon_Local"], ipa: "#{ipaDir}/#{name}.ipa")
handleDingTalk(name: name, ipaDir: ipaDir)
end
desc "上传ipad 到 Pgyer"
def uploadPgyer(name: ENV["Scheme_Name"], ipaDir: ENV["IpaDir_Development"], apiKey: PgyerApiKey, userKey: PgyerUserKey)
# uploadtime = Time.now.strftime("%Y%m%d%H%M")
uploadtime = Time.now.strftime("%Y-%m-%d %H:%M:%S")
pgyer(api_key: apiKey,
user_key: userKey,
# update_description: "fastlane自动打包上传测试 pgyer",
update_description: "#{uploadtime}",
password: "123456",
install_type: "2",
ipa: "#{ipaDir}/#{name}.ipa",
)
handleDingTalk(name: name, ipaDir: ipaDir, appUrl: ENV["Pgyer_Shortcut_Link"])
end
desc "更新BuildVersion"
def updateBuildVersion(name: ENV["Scheme_Name"], showHash: true)
plistDir = File.dirname(Dir.pwd)
puts "plist所在目录:_#{plistDir}_"
case name
when "IntelligentOfParkingOne"
plistFile = plist_from_path(path: "#{plistDir}/#{name}/#{name}-Info.plist")
else
plistFile = plist_from_path(path: "#{plistDir}/#{name}/*Info.plist")
end
puts "plistFile:_#{plistFile}_"
update_build({plist: plistFile, showHash: showHash})
end
desc "webhook 钉钉"
def handleDingTalk(name: ENV["Scheme_Name"], ipaDir: ENV["IpaDir_Development"], downloadUrl: ENV["Firim_Shortcut_Link"])
appPath = ipaDir + "/#{name}.ipa"
params = {appPath: appPath,
appIcon: ENV["App_Icon_Link"],
dingUrl: ENV["Dingtalk_Url"],
slogan: ENV["APP_Slogan"],
downloadUrl: downloadUrl
}
puts "---#{params.to_json}--"
dingdingtalk_robot(params)
end
desc "推送通知到slack"
def handleDingSlack(name: ENV["Scheme_Name"], ipaDir: ENV["IpaDir_Development"], downloadUrl: ENV["Firim_Shortcut_Link"])
appPath = ipaDir + "/#{name}.ipa"
params = {appPath: appPath,
appIcon: ENV["App_Icon_Link"],
slackUrl: ENV["Slack_Url"],
slogan: ENV["APP_Slogan"],
downloadUrl: downloadUrl
}
puts "---#{params.to_json}--"
dingslack_robot(params)
end
desc "测试"
lane :test do
handleDingSlack()
# handleDingTalk()
end
desc "one发布到Fir"
lane :testA do
# actionFir(name: ENV["Scheme_name"], ipaDir: ENV["IpaDir_Development"])
sh "fastlane test --env targetA"
end
# You can define as many lanes as you want
after_all do |lane|
end
error do |lane, exception|
end
end
dingdingtalk_robot.rb
module Fastlane
module Actions
module SharedValues
DINGDINGTALK_ROBOT_CUSTOM_VALUE = :DINGDINGTALK_ROBOT_CUSTOM_VALUE
end
class DingdingtalkRobotAction < Action
def self.run(params)
appPath = params[:appPath]
appIcon = params[:appIcon]
dingUrl = params[:dingUrl]
downloadUrl = params[:downloadUrl]
slogan = params[:slogan]
markdownText = params[:markdownText]
appName = other_action.get_ipa_info_plist_value(ipa: appPath, key: "CFBundleDisplayName")
bundleName = other_action.get_ipa_info_plist_value(ipa: appPath, key: "CFBundleBundleName")
appVersion = other_action.get_ipa_info_plist_value(ipa: appPath, key: "CFBundleShortVersionString")
appBuild = other_action.get_ipa_info_plist_value(ipa: appPath, key: "CFBundleVersion")
ipaName = other_action.get_ipa_info_plist_value(ipa: appPath, key: "CFBundleName")#备用
appName = appName.empty? == false ? appName : bundleName
platformInfo = "已更新至 #{downloadUrl.split(".")[1].capitalize} 啦!"
title = "iOS #{appName} #{appVersion} #{platformInfo}"
time = Time.new.strftime("%Y-%m-%d %H:%M:%S")
markdown ={
msgtype: "link",
link: {
title: title,
text: "版 本:#{appBuild}\n地 址:#{downloadUrl}\n时 间:#{time}",
picUrl: "#{appIcon}",
messageUrl: "#{downloadUrl}"
}
}
if markdownText
markdownText = "#{markdownText} \n - [Download](#{downloadUrl})"
markdown ={
"msgtype": "markdown",
"markdown": {"title": "#{title}",
"text": "### #{title}\n#{markdownText}",
}
}
end
##请求
uri = URI.parse(dingUrl)
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri)
request.add_field('Content-Type', 'application/json')
request.body = markdown.to_json
response = https.request(request)
puts "-----------#{uri.request_uri}-------------------"
puts "Response #{response.code} #{response.message}: #{response.body}"
end
#####################################################
# @!group Documentation
#####################################################
def self.description
"A short description with <= 80 characters of what this action does"
end
def self.details
# Optional:
# this is your chance to provide a more detailed description of this action
"You can use this action to do cool things..."
end
def self.available_options
[
FastlaneCore::ConfigItem.new(key: :appPath,
env_name: "GET_IPA",
description: "ipa文件所在的文件夹路径",
optional: false,
type: String),
FastlaneCore::ConfigItem.new(key: :downloadUrl,
description: "fir的ipa文件下载网址",
optional: false,
type: String),
FastlaneCore::ConfigItem.new(key: :appIcon,
description: "ipa图标网络地址",
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :dingUrl,
description: "钉钉机器人网络接口",
optional: false,
type: String),
FastlaneCore::ConfigItem.new(key: :markdownText,
description: "钉钉机器人 msgtype: markdown时的text",
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :slogan,
description: "slogan",
optional: true,
type: String),
]
end
def self.output
# Define the shared values you are going to provide
# Example
[
['DINGDINGTALK_ROBOT_CUSTOM_VALUE', 'A description of what this value contains']
]
end
def self.return_value
# If your method provides a return value, you can describe here what it does
end
def self.authors
# So no one will ever forget your contribution to fastlane :) You are awesome btw!
["Your GitHub/Twitter Name"]
end
def self.is_supported?(platform)
# you can do things like
#
# true
#
# platform == :ios
#
# [:ios, :mac].include?(platform)
#
platform == :ios
end
end
end
end
dingslack_robot.rb
module Fastlane
module Actions
module SharedValues
DINGSLACK_ROBOT_CUSTOM_VALUE = :DINGSLACK_ROBOT_CUSTOM_VALUE
end
class DingslackRobotAction < Action
def self.run(params)
appPath = params[:appPath]
downloadUrl = params[:downloadUrl]
appIcon = params[:appIcon]
slackUrl = params[:slackUrl]
slogan = params[:slogan]
appName = other_action.get_ipa_info_plist_value(ipa: appPath, key: "CFBundleDisplayName")
bundleName = other_action.get_ipa_info_plist_value(ipa: appPath, key: "CFBundleBundleName")
appVersion = other_action.get_ipa_info_plist_value(ipa: appPath, key: "CFBundleShortVersionString")
appBuild = other_action.get_ipa_info_plist_value(ipa: appPath, key: "CFBundleVersion")
ipaName = other_action.get_ipa_info_plist_value(ipa: appPath, key: "CFBundleName")#备用
appName = appName.empty? == false ? appName : bundleName
platformInfo = "已更新至 #{downloadUrl.split(".")[1].capitalize} 啦!"
message = "iOS #{appName} v#{appVersion} #{platformInfo}"
author = `git log -1 --pretty=format:"%ae"`
time = Time.new.strftime("%Y-%m-%d %H:%M:%S")
other_action.slack(
# message: "<项目名称> Successfully deployed new App Update.",
message: message,
slack_url: slackUrl,
# default_payloads: [:lane, :git_branch, :git_author, :last_git_commit],
default_payloads: [],
attachment_properties: {
thumb_url: appIcon,
author_name: author,
pretext: slogan,
fields: [
{
# title: "DownloadUrl",
value: "版本:#{appBuild}",
short: true
},
{
# title: "DownloadUrl",
value: "下载:#{downloadUrl}",
short: true
},
{
# title: "时间日期",
value: "时间:#{time}",
short: false
}]
}
)
end
#####################################################
# @!group Documentation
#####################################################
def self.description
"A short description with <= 80 characters of what this action does"
end
def self.details
# Optional:
# this is your chance to provide a more detailed description of this action
"You can use this action to do cool things..."
end
def self.available_options
[
FastlaneCore::ConfigItem.new(key: :appPath,
env_name: "GET_IPA",
description: "ipa文件所在的文件夹路径",
optional: false,
type: String),
FastlaneCore::ConfigItem.new(key: :downloadUrl,
description: "fir的ipa文件下载网址",
optional: false,
type: String),
FastlaneCore::ConfigItem.new(key: :appIcon,
description: "ipa图标网络地址",
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :slackUrl,
description: "slack webhook Url",
optional: false,
type: String),
FastlaneCore::ConfigItem.new(key: :slogan,
description: "slogan",
optional: true,
type: String),
]
end
def self.output
# Define the shared values you are going to provide
# Example
[
['DINGSLACK_ROBOT_CUSTOM_VALUE', 'A description of what this value contains']
]
end
def self.return_value
# If your method provides a return value, you can describe here what it does
end
def self.authors
# So no one will ever forget your contribution to fastlane :) You are awesome btw!
["Your GitHub/Twitter Name"]
end
def self.is_supported?(platform)
# you can do things like
#
# true
#
# platform == :ios
#
# [:ios, :mac].include?(platform)
#
platform == :ios
end
end
end
end