自动化打包实战 — Fastlane

刚到一个新公司,项目框架处于初步阶段,于是鄙人准备做一些事情,把这个项目该完善的模块尽量都一一完善。
第一步便是从自动化打包开始,自动化打包属于一个多人协作开发、测试流程中不可或缺的东西,不仅节约开发者不必要的打包时间,也可免除来自打包过程中的意外(证书配置错误、接口问题等低级错误)。实际来说,作为一个开发者应该有懒得去做重复耗时的事的心态,所以自动化打包、持续集成(CI)等应运而生。
后面我也会写一篇Jenkins的集成实战。
2018年11月12日更新,已完成:自动化打包实战 — Jenkins

一、安装Fastlane

使用命令行安装,有两种。
1、使用 gem 安装:sudo gem install fastlane
2、使用 homebrew 安装:brew cask install fastlane(需先安装homebrew,这个应该是开发者标配了吧...)
我这里使用 gem 安装的是2.107.0版本(2018年10月17日最新)。

二、开始使用Fastlane

初始化Fastlane

1、cd 到你的项目根目录
2、执行fastlane init命令

image.png

3、这个时候会有4个选项可供选择,这里我选择的是3,会让你输入你的Apple ID和密码,输入完成会让你选择是否下载metadata之类的,输入Y同意即可。

Fastlane目录结构

在上面步骤初始化完毕之后,会在你的项目根目录下多出一个fastlane文件夹,文件夹下有以下文件:
image.png

其中metadata和screenshots分别对应App元数据和商店应用截图。

Appfile主要存放App的apple_id team_id app_identifier等信息。
image.png
Deliverfile中为发布的配置信息,一般情况用不到。

Fastfile是我们最应该考虑的文件,里面的内容决定了我们执行什么操作。
(懒人直接去复制粘贴文件内容吧☺)

以下为FastFile示例文件,差不多满足基本需求
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
#     https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
#     https://docs.fastlane.tools/plugins/available-plugins
#

# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane

default_platform(:ios)

platform :ios do
  ipapath = './fastlane/ipa/'
  scheme = '你的工程名称'
  bundleId = "工程的bundleId"

  desc "Push a new release build to the App Store"

#打包
#编译一个adhoc ipa包
  lane :build_adhoc_ipa do 
    #sync_code_signing(
     # type: 'adhoc',
      #readonly: true
      #)
    build_app(
      clean: true,
      configuration: "Release",
      export_method: "ad-hoc", 
      output_directory: ipapath,
      output_name: scheme + "_adhoc.ipa",
      export_options: {
        #指定描述文件
        provisioningProfiles: {
          bundleId => "iOSDistributionAdHoc(这是我的描述文件名称,你自己选你自己的)"
        }
      }
      )
  end

#编译一个dev的包
  lane :build_development_ipa do
    #sync_code_signing(
      #type: development,
      #readonly: true
      #)
    build_app(
      clean: true,
      configuration: "debug",
      export_method: "development", 
      output_directory: ipapath,
      output_name: scheme + "_development.ipa",
      export_options: {
        #指定描述文件
        provisioningProfiles: {
          bundleId => "iOS_wildcard_development(这是我的描述文件名称,你自己选你自己的"
        }
      }
      )
  end

  #编译一个appstore的包
  lane :build_appstore_ipa do
    #sync_code_signing(
      #type: appstore,
      #readonly: true
      #)
    build_app(
      clean: true,
      configuration: "release",
      export_method: "app-store", 
      output_directory: ipapath,
      output_name: scheme + "_appstore.ipa",
      export_options: {
        #指定描述文件
        provisioningProfiles: {
          bundleId => "iOSDistribution20180930(这是我的描述文件名称,你自己选你自己的"
        }
      }
      )
  end


  #上传指定路径的包到蒲公英
  lane :uploadToPgyer do |op|
      #蒲公英取本地文件路径上传
      path = op[:path]
        pgyer(api_key: "你的蒲公英账号的appkey", user_key: "你的蒲公英账号的userkey", ipa: path, password:"想设置密码就加这个键值对", install_type:"2", update_description:"update by fastlane test(更新描述)")
  end

  #上传已存在的adhoc包到蒲公英
  lane :upload_exist_adhoc_ToPgyer do
    uploadToPgyer(path: ipapath + scheme + '_adhoc.ipa')
  end


  #编译一个adhoc 包并上传蒲公英
  lane :build_adhoc_uploadToPgyer do
    build_adhoc_ipa
    uploadToPgyer(path: ipapath + scheme + '_adhoc.ipa')
  end

#编译一个beta包并上传TestFlight
#upload_to_testflight

  #编译一个AppStore包并上传到ITC
  lane :build_appstroe_uploadToITC do
    build_appstore_ipa
    upload_to_app_store(
      ipa: ipapath + "/" + scheme + "_appstore.ipa"
      )
  end
end
注意点:

这里我没有使用xcode的自动证书管理,因为如果使用自动管理会有坑,有时会自动选择错证书,需要去额外设置解决,既然麻烦那就直接手动管理好了。

Fastlane的使用

cd到项目根目录之后,执行命令fastlane action,这个action就是上面FastFile里面每个lane xxxxxxx doxxxxxxx,比如我想打一个adhoc的包,就执行fastlane build_adhoc_ipa即可。
fastlane还有很多其他的操作,例如'fastlane actions'查看所有的操作。
另外在FastFile中还有match等相关操作,match是一种全新的证书同步管理机制,例如

  lane :match_appstore do 
    match(type: "appstore", force_for_new_devices: true)
  end

  lane :match_adhoc do 
    match(type: "adhoc", force_for_new_devices: true)
  end  

  lane :match_development do 
    match(type: "development", force_for_new_devices: true)
  end

这里就不展开讲了,有兴趣的可以去官网看看。

最后贴一张Fastlane的整个信息图,开始你的挖坑之旅吧。
fastlanePDF.png

如果有遇到问题报错之类的,一般错误信息后面都会带有GitHub的issue链接,可以进去看看,也可以在文章地下评论,我会及时回复。
fastlane的集成使用相对比较简单,之后会再补上一篇Jenkins的集成。

更新:--------应测试需求,新增自动打包结束后发送邮件通知他们-----------

思路

Fastlane目前好像还没有一键发邮件的功能,于是只能自己写脚本,然后通过Fastlane运行该脚本来达到发送邮件目的。
首先我们需要登录自己的邮箱,然后再给对方发送邮件;登录自己的邮箱需要设置SMTP或者EXCHANGE服务(当然还有其他,这两个主流),于是开始撸Py脚本。

SMTP服务的邮箱

话不多说,直接先上脚本代码,这里以126邮箱为例(163、QQ等都一样)。

#coding:utf-8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
import smtplib
from smtplib import SMTP
from email.mime.text import MIMEText
from email.header import Header
 
#构造纯文本邮件内容
msg = MIMEText('Fastlane自动打包成功\n\n下载地址:http://www.pgyer.com/xxxxxx  \n\n密码:xxxxxxx  \n\n使用iPhone扫描二维码即可下载\n\n\n\n有问题随时联系开发','plain','utf-8')
msg['From'] = 'wodeyouxaing@126.com'
msg['To'] = '测试组'
subject = 'iOS自动打包成功'
msg['Subject'] = Header(subject,'utf-8')

#发送者邮箱
sender = 'wodeyouxiang@126.com'
 
#发送者的登陆用户名和密码
user = 'wodeyouxiang@126.com'
password = 'wodemima'#记住,这里不是你的登录密码,而是你在126邮箱那里设置中开通SMTP服务后,自己设置的授权码!!!(qq会自动生成一段授权码,126邮箱会让你自己设置一个)
 
#发送者邮箱的SMTP服务器地址
smtpserver = 'smtp.126.com'
 
#接收者的邮箱地址
receiver = ['wodeqq@qq.com']
 
smtp = smtplib.SMTP() #实例化SMTP对象
smtp.connect(smtpserver,25) #端口25
smtp.login(user,password) #登陆smtp服务器
smtp.sendmail(sender,receiver,msg.as_string())

smtp.quit()

以上脚本写好之后,直接先打开终端自己本地跑一遍,执行python xxxxx.py

常见报错:

1smtplib.SMTPDataError: (554, b'DT:SPM 163 smtp10,DsCowAA3h9_QbgZXI9_fCQ--.713S2 1460039376,please see http://mail.163.com/help/help_
参照126官网的错误提示可知原因是:•554 DT:SPM 发送的邮件内容包含了未被许可的信息,或被系统识别为垃圾邮件。请检查是否有用户发送病毒或者垃圾邮件。
翻译过来就是你的主题中不能包含test等字眼,另外msg['From'] = 'wodeyouxaing@126.com'这里面的值需要和你的sender = 'wodeyouxiang@126.com'保持一致,否则一样会报错554,参考链接:https://blog.csdn.net/wangming520liwei/article/details/53900269

2、出现各种Timeout,此时要考虑
(1)SMTP地址是否和你的邮箱对应好,比如'smtp.126.com'对应的是126邮箱,'smtp.qq.com'对应的是QQ邮箱等。
(2)你的邮箱是否已经开启了SMTP服务。

SMTP设置.png

3、出现smtplib.SMTPAuthenticationError: (535, '5.7.3 Authentication unsuccessful'),说明账户密码不对,慢慢重试吧。

Exchange服务的邮箱

为什么还要玩Exchange邮箱呢?因为我司的工作邮箱不支持SMTP服务,不让用....那没办法,只能开撸Exchange服务,后来发现,利用exchangelib去发邮件简直不能太简单了。。。来吧,开干!
先上exchangelib的官网:https://pypi.org/project/exchangelib/

前提

安装exchangelib,在终端中执行pip install exchangelib,有的人会出现找不到pip指令,pip是python的包管理工具,在Python2.7的安装包中,easy_install.py是默认安装的,而pip需要我们手动安装,
那就先执行sudo easy_install pip安装上pip,后再执行前面的exchangelib的安装吧。
在安装exchangelib的时候有的人会遇到报错:Could not install packages due to an EnvironmentError: [Errno 13] Permission denied: '/Library/Python/2.7/site-packages/lxml-4.2.5.dist-info' Consider using the --user option or check the permissions.
原因可能是Python版本的问题,而不是sudo权限,所以用homebrew执行brew install python3之后,再安装pip,再安装exchangelib。
这里涉及到如何把系统的python2.7换成默认使用你自己用brew安装的python3.7,参考链接:https://blog.csdn.net/NancyLiu0/article/details/81781809,同理,pip也需要软指向到/user/local/bin下,具体可Google。

image.png

使用exchangelib
from exchangelib import DELEGATE, Account, Credentials, Message, Mailbox, HTMLBody

def Email(to, subject, body):
    creds = Credentials(
        username='nidezhanghao',
        password='nidemima'
    )
    account = Account(
        primary_smtp_address='nideyouxaing@xxx.com',
        credentials=creds,
        autodiscover=True,
        access_type=DELEGATE
    )
    m = Message(
        account=account,
        subject=subject,
        body=HTMLBody(body),
        to_recipients = [Mailbox(email_address=to)]
    )
    m.send()

Email("目的地邮箱@qq.com", "abc", "def")
常见错误:

1exchangelib.errors.AutoDiscoverFailed: All steps in the autodiscover protocol failed,这个是因为你本机的exchangelib版本和你的服务器exchangelib的版本不一致导致的,用pip search exchangelib查询本机的版本号,然后再去问问你们的IT支持吧,找他要服务器的版本相关信息。

Fastlane配置自动发送邮件

执行脚本成功之后,需要在Fastlane里面去做这个 自动执行脚本 操作,于是来到我们熟悉的Fastfile.
1、把写好的py脚本文件copy到以下目录:你的项目/fastlane
2、在Fastfile中添加以下代码块:

# 发送邮件提醒下载测试
  lane :sendEmail_SMTPToTest do
    path =  Dir::pwd + '/sendEmailPY_SMTP.py'#这里是你的脚本文件名
    cmd = 'python ' + path 
    sh cmd
  end

然后在之前写过的编译adhoc包并且发送蒲公英那个lane里面,加上这个新写的发送邮件的lane就大功告成啦!


  #编译一个adhoc 包并上传蒲公英 并且给测试人员发送邮件
  lane :build_adhoc_uploadToPgyer_SendEmail do
    build_adhoc_ipa
    uploadToPgyer(path: ipapath + scheme + '_adhoc.ipa')
    sendEmail_SMTPToTest
  end
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容