美文网首页IOS个人开发深入学习iOS常用技术收集
手把手教你给一个iOS app配置多个环境变量

手把手教你给一个iOS app配置多个环境变量

作者: 一缕殇流化隐半边冰霜 | 来源:发表于2016-08-11 09:01 被阅读38773次

    前言

    谈到多环境,相信现在大多公司都至少有2-3个app环境了,比如Test环境,UAT(User Acceptance Test)用户验收测试环境,Release环境等等。当需要开发打多个包的时候,一般常见做法就是直接代码里面修改环境变量,改完之后Archive一下就打包了。当然这种做法很正确,只不过不是很优雅很高效。如果搭建好了Jenkins(搭建教程),我们利用它来优雅的打包。如果利用Jenkins来打包,我们就需要来给app来配置一下多个环境变量了。之后Jenkins分别再不同环境下自动集成即可。接下来,我们来谈谈常见的2种做法。

    目录

    • 1.利用Build Configuration来配置多环境
    • 2.利用xcconfig文件来配置多环境
    • 3.利用Targets来配置多环境

    一.利用Build Configuration来配置多环境

    前言里面我们先谈到了需求,由于需要配置多个环境,并且多个环境都需要安装到手机上,那么可以配置Build Configuration来完成这个任务。如果Build Configuration还不熟悉的,可以先温习一下官方文档新版文档链接在这里Build settings reference

    1. 新建Build Configuration

    先点击Project里面找到Configuration,然后选择添加,这里新加一个Configuration。系统默认是2个,一个Debug,一个Release。这里我们需要选择是复制一个Debug还是Release。Release和Debug的区别是,Release是不能调试程序,因为默认是屏蔽了可调试的一些参数,具体可以看BuildSetting里面的区别,而且Release编译时有做编译优化,会比用Debug打包出来的体积更小一点。

    这里我们选择一个Duplicate “Debug” Configuration,因为我们新的环境需要debug,添加完了之后就会多了一套Configuration了,这一套其实是包含了一些编译参数的配置集合。如果此时项目里面有cocopods的话,打开Configuration Set就会发现是如下的样子:

    在我们自己的项目里面用了Pod,打开配置是会看到如下信息


    注意:刚刚新建完Build Configuration之后,这时如果有pod,请立即执行一下

    
    pod install  
    

    pod安装完成之后会自动生成xcconfig文件,如果你手动新建这个xcconfig,然后把原来的debug和release对应的pod xcconfig文件内容复制进来,这样做是无效的,需要pod自己去生成xcconfig文件才能被识别到。

    新建完Build Configuration,这个时候需要新建pod里面对应的Build Configuration,要不然一会编译会报错。如果没用pod,可以忽略一下这一段。

    如下图新建一个对应之前Porject里面新建的Build Configuration


    2. 新建Scheme

    接下来我们要为新的Configuration新建一个编译Scheme。


    新建完成之后,我们就可以编辑刚刚新建的Scheme,这里可以把Run模式和Archive都改成新建Scheme。如下图:

    注意:如果是使用了Git这些协同工具的同学这里还需要把刚刚新建的Scheme共享出去,否则其他人看不到这个Scheme。选择“Manage Schemes”

    3. 新建User-defined Build Settings

    再次回到Project的Build Settings里面来,Add User-Defined Setting。


    我们这里新加入2个参数,CustomAppBundleld是为了之后打包可以分开打成多个包,这里需要3个不同的Id,建议是直接在原来的Bundleld加上Scheme的名字即可。

    CustomProductName是为了app安装到手机上之后,手机上显示的名字,这里可以按照对应的环境给予描述,比如测试服,UAT,等等。如下图。

    这里值得提到的一点是,下面Pods的Build_DIR这些目录其实是Pods自己生成好的,之前执行过Pod install 之后,这里默认都是配置好的,不需要再改动了。

    4. 修改info.plist文件 和 Images.xcassets

    先来修改一下info.plist文件。

    由于我们新添加了2个CustomAppBundleld 和 CustomProductName,这里我们需要把info.plist里面的Bundle display name修改成我们自定义的这个字典。编译过程中,编译器会根据我们设置好的Scheme去自己选择Debug,Release,TestRelease分别对应的ProductName。

    我们还需要在Images.xcassets里面新添加2个New iOS App Icon,名字最好和scheme的名字相同,这样好区分。

    新建完AppIcon之后,再在Build Setting里面找到Asset Catalog Compiler里面,然后把这几种模式下的App Icon set
    Name分别设置上对应的图标。如上图。

    既然我们已经新建了这几个scheme,那接下来怎么把他们都打包成app呢??这里有一份官方的文档Troubleshooting Application Archiving in Xcode这里面详细记录了我们平时点击了Archive之后是怎么打包的。

    这里分享一下我分好这些环境的心得。一切切记,每个环境都要设置好Debug 和 Release!千万别认为线上的版本只设置Release就好,哪天需要调试线上版本,没有设置Debug就无从下手了。也千万别认为测试环境的版本只要设置Debug就好,万一哪天要发布一个测试环境需要发Release包,那又无从下手了。我的建议就是每个环境都配置Debug 和 Release,即使以后不用,也提前设置好,以防万一。合理的设置应该如下图这样。

    | -------------------------- |------------------|
    |           Scheme           |   Configurations |  
    | -------------------------- |------------------| 
    |      XXXXProjectTest       |      Debug       | 
    |                            |------------------|
    |                            |      Release     | 
    | -------------------------- |------------------|
    |      XXXXProjectAppStore   |      Debug       | 
    |                            |------------------|
    |                            |      Release     | 
    | -------------------------- |------------------|
    |      XXXXProjectUAT        |      Debug       | 
    |                            |------------------|
    |                            |      Release     | 
    | -------------------------- |------------------|
    
    

    注意这里一定要把Scheme的名字和编译方式区分开,选择了一个Scheme,只是相当于选择了一个环境,并不是代表这Debug还是Release。

    我建议Scheme只配置环境,而进来的Run和Archive来配置Debug和Release,我建议每个Scheme都按照上图来,Run对应的Debug,Archive对应的Release。

    配置好上述之后,就可以选择不同环境运行app了。可以在手机上生成不同的环境的app,可以同时安装。如下图。

    5. 配置和获取环境变量

    接下来讲几种动态配置环境变量的方法

    1. 使用GCC预编译头参数GCC_PREPROCESSOR_DEFINITIONS

    我们进入到Build Settings里面,可以找到Apple LLVM Preprocessing,这里我们可以找到Preprocessor Macros在这里,我们是可以加一些环境变量的宏定义来标识符。Preprocessor Macros可以根据不同的环境预先制定不同定义的宏。


    如上图,圈出来的地方其实就是一个标识符。

    有了这些我们预先设置的标识符之后,我们就可以在代码里面写入如下的代码了。

    
    #ifdef DEVELOP
    #define searchURL @"http://www.baidu.com"
    #define sociaURL  @"weibo.com"
    #elif UAT
    #define searchURL @"http://www.bing.com"
    #define sociaURL  @"twitter.com"
    #else
    #define searchURL @"http://www.google.com"
    #define sociaURL  @"facebook.com"
    #endif
    
    
    2. 使用plist文件动态配置环境变量

    我们先来新建3个名字一样的plist作为3个环境的配置文件。


    这里名字一样的好处是写代码方便,因为就只需要去读取“Configuration.plist”就可以了,如果名字不一样,还要分别去把对应环境的plist名字拼接出来才能读取。

    众所周知,在一个文件夹里面新建2个相同名字的文件,Mac 系统都会提示我们名字相同,不允许我们新建。那我们怎么新建3个相同名字的文件呢?这其实很简单,分别放在3个不同文件夹下面即可。如下图:

    我就是这样放置的,大家可以根据自己习惯去放置文件。

    接下来我们要做的是在编译的时候,运行app前,动态的copy Configuration.plist到app里面,这里需要设置一个copy脚本。


    进入到我们的Target里面,找到Build Phases,我们新建一个New Copy Files Phase,并且重命名为Copy Configuration Files

    
    echo "CONFIGURATION -> ${CONFIGURATION}"
    RESOURCE_PATH=${SRCROOT}/${PRODUCT_NAME}/config/${CONFIGURATION}
    
    BUILD_APP_DIR=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app
    
    echo "Copying all files under ${RESOURCE_PATH} to ${BUILD_APP_DIR}"
    cp -v "${RESOURCE_PATH}/"* "${BUILD_APP_DIR}/"
    
    

    这一段脚本就能保证我们的Configuration.plist 文件可以在编译的时候,选择其中一个打包进我们的app。

    再写代码每次读取这个plist里面的信息就可以做到动态化了。

    
    - (NSString *) readValueFromConfigurationFile {
        NSBundle *bundle = [NSBundle mainBundle];
        NSString *path = [bundle pathForResource:@"Configuration" ofType:@"plist"];
        NSDictionary *config = [NSDictionary dictionaryWithContentsOfFile:path];
        return config[@"serverURL"];
    }
    
    

    这里我假设plist文件里面预设置了一个serverURL的字符串,用这种方式就可以读取出来了。当然在plist里面也可以设置数组,字典,相应的把返回值和Key值改一下就可以了。

    3. 使用单例来处理环境切换

    当然使用一个单例也可以做到环境切换。新建一个单例,然后可以在设置菜单里面加入一个列表,里面列出所有的环境,然后用户选择以后,单例就初始化用户所选的环境。和上面几种方式不同的是,这种方式就是在一个app里面切换多种环境。看大家的需求,任取所需。

    二.利用文件来配置多环境

    说道xcconfig,这个官方文档上面也提到的不是很详细,在网上寻找了一下,倒是找到了另外一份详细非官方文档。The Unofficial Guide to xcconfig files

    提到xcconfig,就要先说说几个概念。

    1. 区分几个概念

    先来区分一下Xcode Workspace、Xcode Scheme、Xcode Project、Xcode Target、Build Settings 这5者的关系。这5者的关系在苹果官方文档上其实都已经说明的很清楚了。详情见文档Xcode Concepts

    我来简单来解读一下文档。

    Xcode Workspace

    A workspace is an Xcode document that groups projects and other documents so you can work on them together. A workspace can contain any number of Xcode projects, plus any other files you want to include. In addition to organizing all the files in each Xcode project, a workspace provides implicit and explicit relationships among the included projects and their targets.

    workspace这个概念大家应该都很清楚了。它可以包含多个Project和其他文档文件。

    ** Xcode Project**

    An Xcode project is a repository for all the files, resources, and information required to build one or more software products. A project contains all the elements used to build your products and maintains the relationships between those elements. It contains one or more targets, which specify how to build products. A project defines default build settings for all the targets in the project (each target can also specify its own build settings, which override the project build settings).

    project就是一个个的仓库,里面会包含属于这个项目的所有文件,资源,以及生成一个或者多个软件产品的信息。每一个project会包含一个或者多个 targets,而每一个 target 告诉我们如何生产 products。project 会为所有 targets 定义了默认的 build settings,每一个 target 也能自定义自己的 build settings,且 target 的 build settings 会重写 project 的 build settings。

    最后这句话比较重要,下面设置xcconfig的时候就会用到这一点。

    Xcode Project 文件会包含以下信息,对资源文件的引用(源码.h和.m文件,frame,资源文件plist,bundle文件等,图片文件image.xcassets还有Interface Builder(nib),storyboard文件)、文件结构导航中用来组织源文件的组、Project-level build configurations(Debug\Release)、Targets、可执行环境,该环境用于调试或者测试程序。

    ** Xcode Target**

    A target specifies a product to build and contains the instructions for building the product from a set of files in a project or workspace. A target defines a single product; it organizes the inputs into the build system—the source files and instructions for processing those source files—required to build that product. Projects can contain one or more targets, each of which produces one product.

    target 会有且唯一生成一个 product, 它将构建该 product 所需的文件和处理这些文件所需的指令集整合进 build system 中。Projects 会包含一个或者多个 targets,每一个 target 将会产出一个 product。

    这里值得说明的是,每个target 中的 build setting 参数继承自 project 的 build settings, 一旦你在 target 中修改任意 settings 来重写 project settings,那么最终生效的 settings 参数以在 target 中设置的为准. Project 可以包含多个 target, 但是在同一时刻,只会有一个 target 生效,可用 Xcode 的 scheme 来指定是哪一个 target 生效。

    ** Build Settings**

    A build setting is a variable that contains information about how a particular aspect of a product’s build process should be performed. For example, the information in a build setting can specify which options Xcode passes to the compiler.

    build setting 中包含了 product 生成过程中所需的参数信息。project的build settings会对于整个project 中的所有targets生效,而target的build settings是重写了Project的build settings,重写的配置以target为准。

    一个 build configaration 指定了一套 build settings 用于生成某一 target 的 product,例如Debug和Release就属于build configaration。

    ** Xcode Scheme**

    An Xcode scheme defines a collection of targets to build, a configuration to use when building, and a collection of tests to execute.

    一个Scheme就包含了一套targets(这些targets之间可能有依赖关系),一个configuration,一套待执行的tests。

    这5者的关系,举个可能不恰当的例子,
    Xcode Workspace就如同工厂,Xcode Project如同车间,每个车间可以独立于工厂来生产产品(project可独立于workspace存在),但是各个车间组合起来就需要工厂来组织(如果用了cocopods,就需要用workspace)。Xcode Target是一条条的流水线,一条流水线上面只生产一种产品。Build Settings是生产产品的秘方,如果是生产汽水,Build Settings就是其中各个原料的配方。Xcode Scheme是生产方案,包含了流水线生产,秘方,还包含生产完成之后的质检(test)。

    2. 来创建一个xcconfig文件

    然后创建好了这个文件,我们在project里面设置一下。

    在这些地方把配置文件换成我们刚刚新建的文件。

    接下来就要编写我们的xcconfig文件了。这个文件里面可以写的东西挺多的。细心的同学就会发现,其实我们一直使用的cocopods就是用这个文件来配置编译参数的。我们随便看一个简单的cocopods的xcconfig文件,就是下图这样子:

    
    GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
    HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Forms"
    OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/Forms"
    OTHER_LDFLAGS = $(inherited) -ObjC -l"Forms"
    PODS_ROOT = ${SRCROOT}/Pods
    

    我们由于需要配置网络环境,那可以这样写

    //网络请求baseurl
    REQUESTBASE_URL = @"http:\\/\\/10.20.100.1"
    

    当然也可以写成cocopods那样

    GCC_PREPROCESSOR_DEFINITIONS = $(inherited) WEBSERVICE_URL='$(REQUESTBASE_URL)' MESSAGE_SYSTEM_URL='$(MESSAGE_SYSTEM_URL)'
    
    

    这里利用了一个GCC_PREPROCESSOR_DEFINITIONS编译参数。

    Space-separated list of option specifications. Specifies preprocessor macros in the form foo (for a simple #define) or foo=1 (for a value definition). This list is passed to the compiler through the gcc -D option when compiling precompiled headers and implementation files.

    GCC_PREPROCESSOR_DEFINITIONS 是 GCC 预编译头参数,通常我们可以在 Project 文件下的 Build Settings 对预编译宏定义进行默认赋值。

    它就是在Build Settings里面的 Apple LLVM 7.X - Preprocessing - Preprocessor Macros 这里。


    Preprocessor Macros 其实是按照 Configuration 选项进行默认配置的, 它是可以根据不同的环境预先制定不同定义的宏,或者为不同环境下的相同变量定义不同的值。

    xcconfig 我们可以写入不同的 Configuration 选项配置不同的文件。每一个 xcconfig 可以配置 Build Settings 里的属性值, 其实实质就是通过 xcconfig 去修改 GCC_PREPROCESSOR_DEFINITIONS 的值,这样我们就可以做到动态配置环境的需求了。

    最后还需要提的一点是,这个配置文件的level的问题。现在本地有这么多配置,到底哪一个最终生效呢?打开Build 里面的level,我们来看一个例子。

    我们目前可以看到有5个配置,他们是有优先级的。优先级是从左往右,依次降低的。Resolved = target-level > project-level > 自定义配置文件 > iOS 默认配置。左边第一列永远显示的是当前生效的最终配置结果。

    知道了这个优先级之后,我们可以更加灵活的配置我们的app了。

    最后关于xcconfig配置,基本使用就这些了。但是这里面的学问不仅仅这些。

    还能利用xcconfig动态配置Build Settings里面的很多参数。这其实类似于cocopods的做法。但是有一个大神的做法很优雅。值得大家感兴趣的人去学习学习。iOS大神Justin Spahr-Summers的开源库xcconfigs提供了一个类权威的模板, 这是一个很好的学习使用xcconfig的库,强烈推荐。

    最后这里有一个Demo,配置了Cocopods,配置了xcconfig文件,还有Build Configuration的,大家可以看看,请多多指教,Demo

    三.利用Targets来配置多环境

    配置一个多环境其实一个Scheme和xcconfig已经完全够用了,为什么还要有这个第三点呢?虽说仅仅为了配置一个多环境这点“小事”,但是利用多个Targets也能实现需求,只不过有点“兴师动众”了。

    关于构建Targets这个技术,我也是在2年前的公司实践过。当时的需求是做一个OEM的产品。自己公司有主要产品,也帮其他公司做OEM。一说到OEM,大家应该就知道Targets用到这里的妙用了。利用Targets可以瞬间大批量产生大量的app。

    2013年巧哥也发过关于Targets的文章,猿题库iOS客户端的技术细节(一):使用多target来构建大量相似App,我原来公司在2014年也实现了这种功能。

    仅仅只用一套代码,就可以生产出7个app。7个app的证书都是不同的,配置也都不同,但是代码只需要维护一套代码,就可以完成维护7个app的目标。

    下面我们来看看怎么新建Targets,有2种方法。

    一种方法是完全新建一个Targets,另外一种方法是复制原有的Targets。

    其实第一种方法建立出Targets,之后看你需求是怎么样的。如果也想是做OEM这种,可以把新建出来的project删掉,本地还是维护一套代码,然后在新建的Targets 的Build Phases里面去把本地现有代码加上,参数自己可以随意配置。这样也是一套代码维护多个app。

    第二种方法就是复制一个原有的Targets,这种做法只用自己去改参数就可以了。

    再来说说Targets的参数。

    由于我们新建了Targets,相当于新建了一个app了。所以里面的所有的文件全部都可以更改。包括info.plist,源码引用,Build Settings……所有参数都可以改,这样就不仅仅局限于修改Scheme和xcconfig,所以之前说仅仅配置一个多环境用Targets有点兴师动众,但是它确实能完成目的。根据第二章里面我们也提到了,Targets相当于流水线,仅次于Project的地位,可以想象,有了Targets,我们没有什么不能修改的。

    PS.最后关于Targets还有一点想说的,如果大家有多个app,并且这几个app之间有超过80%的代码都是完全一样的,或者说仅仅只是个别界面显示不同,逻辑都完全相同,建议大家用Targets来做,这样只需要维护一套代码就可以了。维护多套相同的代码,实在太没有效率了。一个bug需要在多套代码上面来回改动,费时费力。

    这时候可能有人会问了,如果维护一套代码,以后这些app如果需求有不同怎么办??比如要进入不同界面,跳转不同界面,页面也显示不同怎么办??这个问题其实很简单。在Targets里面的Compile Sources里面是可以给每个不同的Targets添加不同的编译代码的。只需要在每个不同的Targets里面加入不同界面的代码进行编译就可以了,在跳转的那个界面加上宏,来控制不同的app跳转到相应界面。这样本地还是维护的一套代码,只不过每个Targets编译的代码就是这套代码的子集了。这样维护起来还是很方便。也实现了不同app不同界面,不同需求了。

    最后

    其实这篇文章的需求源自于上篇Jenkins自动化持续集成,有一个需求是能打不同环境的包。之前没有Jenkins的时候就改改URL运行一遍就好,虽说做法不够优雅,但是也不麻烦。现在想持续集成,只好把环境都分好,参数配置正确,这样Jenkins可以一次性多个环境的包一起打。真正做到多环境的持续集成。

    最后就可以打出不同环境的包了。请大家多多指教。

    相关文章

      网友评论

      • 孙掌门:有一个问题,为什么release模式,app的名字不会改变,求指教
      • 李有钱灬:受用了!Ps:这个比喻真的是吊!
      • iOS_渔翁:是我太菜了, 感觉好复杂, 之前看一个写好的脚本, 配置到plist文件, 直接运行脚本就行了
      • ab930aaf4440:您好,看了这篇文字,有个问题想请教一下,这三种多环境变量配置,有何优缺点吗?我目前感觉第三种更为简单一点。。。其它两张好像稍微复杂,又容易出错。。
        hahand:多configure是对应多环境的,比如开发环境,测试环境,即使上线了可能根据客户不同也可以配置不同的环境,不同节日也可以使用这个换肤做节日版本。 用途是 一个app -> 多个后台(或者版本)
        多target是对应多app的,比如开发一个系统有多种成员参与需要使用不同app,例如医生-病人,老板-求职者,店家-消费者,但是此时app的大体UI资源和功能代码是可以复用的,就可以用多target。 此时每个target都对应自己的debug,test版本,可以理解为不同的app。
      • 6b4e3ff4ef5d:我看有种多环境打包方式是不会在手机端生成多个不同环境的,而是一个包。然后在系统设置里面,找到App,点到App里面会有一个选择环境的list。选择后重新启动app就会切换好相应的模式,你知道怎么做吗
        口袋海贼王_:Settings.Bundle

        了解下
      • 031f5cfa82d0:霜神您好, 清明终于这篇啃完了, 中间有不明白的问题也结合其他的文章梳理通了. 但还是有一个问题没有解决, 就是每次 pod install 都会把 xcconfig 里自定义的环境信息比如
        「REQUESTBASE_URL = @"http:\\/\\/10.20.100.1"
        GCC_PREPROCESSOR_DEFINITIONS = $(inherited) WEBSERVICE_URL='$(REQUESTBASE_URL)' MESSAGE_SYSTEM_URL='$(MESSAGE_SYSTEM_URL)'」覆写掉, 又需要手动的粘贴一次.
        请问该怎么解决呢?
        雪中夜归人:在podfile文件中写上如下代码
        post_install do |installer|
        installer.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
        if config == 'Debug'
        config.build_settings['GCC_PREPROCESSOR_DEFINITIONS']='$(inherited) DEBUG=1 kBossManager=1'
        else
        config.build_settings['GCC_PREPROCESSOR_DEFINITIONS']='$(inherited) COCOAPODS=1 kBossManager=1'
        end
        end
        end
        end
        https://guides.cocoapods.org/syntax/podfile.html#post_install
      • me_shane:请问应用名称国际化怎么做
      • me_shane:请问第一种方法怎么区分不同appgroups ?
      • SealShile:Preprocessor Macros这里,除了系统的DEBUG变量,其他自定义的变量无法读取。有空check一下。
      • 程序员不务正业:非常赞的一篇文章
      • Ali2016:楼主你给的demo地址不是git阿, clone不下来。。。
      • liyaoyao:你好,在用第一种方法 生成不同的scheme 后,然后配置测试环境,运行pod ,但是如果pod 下来的库有用到 DEBUG 这个宏 ,此时这个DEBUG 是无效的 ,请问这个有办法解决么
      • NAN先生的喵:看完后,我其实没有太懂如何自由的切换环境。。。我现在的项目是用在PCH文件定义宏。每次切换环境打包很麻烦,我希望在APP端提供一个接口,测试点击的时候可以切换环境,这样就可以更改URL,可是宏发生在预编译时期,所以,楼主可以告诉我,配置xcconfig后可以做到这种需求吗?
      • 左左4143:可以在不修改boundID的情况下在一个设备上同时安装不同环境的几个APP吗?因为很多第三方是绑定boundID的
      • 乌鸦菌:求教:
        文中提到
        ```
        我建议Scheme只配置环境,而进来的Run和Archive来配置Debug和Release,我建议每个Scheme都按照上图来,Run对应的Debug,Archive对应的Release。
        ```
        但是下文『5.配置和获取环境变量』的「方法1.」与「方法2.」都还是依据Configuration来改变环境变量的。
        也就是说,Scheme1、Scheme2、Scheme3的Debug模式实际上均为同一套环境变量。
        不知道我哪里理解偏差了,如何才能让环境变量的配置跟着Scheme走,而不是跟着Configuration(Debug/Release)走?
        求大神解答~
      • 鬼崇祟:作者有没有试过xcode9.1 使用GCC预编译头参数在打包的时候似乎会有问题,报参数未声明什么的错
        manajay:我也是这个问题, xcode10 beta 版就没这个问题.
        不过我 xcode 直接build 也会报错, 你怎么解决的???
      • 小巷深深:需要国际化的时候,多配置如何能显示不同的应用名?
        我知道国际化应用名称的时候,新建一个Info.String文件,然后在其中添加CFBundleDisplayName来显示应用名称。
        如果我还想同时区分测试版和企业版,要怎么实现呢
      • sjeffery:xcode 9 add user_defined setting 没有出来CustomAppBundleld和CustomProductName。
        请问这个要怎么弄。
        一缕殇流化隐半边冰霜:@sjeffery 你看看我文章中给的一个demo的例子
      • nasy_iOS:| -------------------------- |------------------|
        | Scheme | Configurations |
        | -------------------------- |------------------|
        | XXXXProjectTest | Debug |
        | |------------------|
        | | Release |
        | -------------------------- |------------------|
        | XXXXProjectAppStore | Debug |
        | |------------------|
        | | Release |
        | -------------------------- |------------------|
        | XXXXProjectUAT | Debug |
        | |------------------|
        | | Release |
        | -------------------------- |------------------|
        能不能详细说说这个怎么配置??我这里出了问题 ,切换scheme中的Configuration 却改变了bundle id 导致打的包不是需要的包,求解。。。。
        一缕殇流化隐半边冰霜:@nasy_iOS 我这里当时做的时候并不是切换scheme去改变Debug 和 Release 的,选择 edit scheme - 左边栏选择 Archive - Build Configuration 这里面选择你想要的环境。
      • Comedy_G:大神厉害,要把iOS吃透真的好难~
        一缕殇流化隐半边冰霜:@Comedy_G 静下心来花点时间吧
      • 十一岁的加重:那么问题来了,打一个包,如何在不重新打包的情况下,在三个环境里自由切换
        一缕殇流化隐半边冰霜:@十一岁的加重 不显示很简单,你让改环境的这个藏在一个地方。就算生产环境也可以弄出来,不过一般用户并不知道。然后再是锁环境的问题,这个Xcode里面有一个宏变量可以判断当前是什么环境,如果当前是生产环境就不允许切换,这样就好啦:stuck_out_tongue_winking_eye::stuck_out_tongue_winking_eye::stuck_out_tongue_winking_eye:
        十一岁的加重:@一缕殇流化隐半边冰霜 测试环境可以用,但生产环境怎么让这个setting不显示啊并且锁死在生产的地址啊
        一缕殇流化隐半边冰霜:@十一岁的加重 可以在setting里面设置一些环境变量,在app里面可以切换这些环境变量。你就在setting里面改就可以了。。不过这是同一个app里面更换环境。
      • 十一岁的加重:最近一直在思考这个问题,关于环境切换,请问有没有,打包给测试之后,测试可以自由在手机上切换环境的做法啊,毕竟打包三个ipa跟自由切换好像不是一个概念,个人觉得自由切换是一个ipa装手机上,自由切换三四种环境
        一缕殇流化隐半边冰霜:@十一岁的加重 昨天好像回复过你了,这里就不回复了哈。
      • singlestep:"如果Build Configuration还不熟悉的,可以先温习一下官方文档" 这句话引入的 "官方文档" 链接应该是地址变更了,能更新参阅下吗?
        一缕殇流化隐半边冰霜:@singlestep 我更新了。。你再刷新一下原文就可以看到了。
      • 大爱丶ALi:echo "CONFIGURATION -> ${CONFIGURATION}"
        RESOURCE_PATH=${SRCROOT}/${PRODUCT_NAME}/config/${CONFIGURATION}

        BUILD_APP_DIR=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app

        echo "Copying all files under ${RESOURCE_PATH} to ${BUILD_APP_DIR}"
        cp -v "${RESOURCE_PATH}/"* "${BUILD_APP_DIR}/"
        这段脚本往哪写啊,我怎么没找到地方加它啊
        一缕殇流化隐半边冰霜:@大爱丶ALi 下面哪两种??
        大爱丶ALi:@一缕殇流化隐半边冰霜 嗯,原来得先得部署Jenkins 啊,自动化打包上传,我用的别人写Python 脚本。下边两种方式需要部署Jenkins 吗
        一缕殇流化隐半边冰霜:@大爱丶ALi 编译完成以后,Jenkins里面可以允许执行一段脚本,你把这段脚本放到那里去执行。
      • RyanLou24:弱弱的問一句做OC Swift必須用Mac嗎😅😅😅
        一缕殇流化隐半边冰霜:@RyanLou24 最好用Mac,window装虚拟机或者黑苹果也可以。。不过很蛋疼。
      • 鬼崇祟:大神 xcconfig中的参数怎么使用呢
        一缕殇流化隐半边冰霜:@鬼崇祟 OK,解决了就好,还有问题可以随时探讨哈
        鬼崇祟:@一缕殇流化隐半边冰霜 已经解决了:grin:
        一缕殇流化隐半边冰霜:@鬼崇祟 具体指的是哪一个??
      • 鬼崇祟:有点晕,如果每一个Scheme都最好有debug和release的话,那我3个Scheme就应该用共有6个Configurations,每一个都对应一对debug和release,是这样理解吗
        鬼崇祟:@一缕殇流化隐半边冰霜 缕清了:joy: 谢楼主的文章:+1:
        鬼崇祟:@一缕殇流化隐半边冰霜 那如果是这样的话 新建User-defined Build Settings设置app名和bundle id 就有些怪了,就成了每一个debug都能打三个不同名字的ipa包,三个环境9个包了
        一缕殇流化隐半边冰霜:@鬼崇祟 是的,是这么理解的
      • 码农甲:大神 你怎么保证 多个job 同时打包的
        一缕殇流化隐半边冰霜:@一只名叫心蓝的猫 你说的是分布式的Jenkins吧???
      • Doliant_H:作者写的很用心,学习了
        一缕殇流化隐半边冰霜:@左岸听雨 一起学习:kissing_heart:
      • _Boring:MARK
      • AndyLiu:我们是一套代码打多个app包,但是还想每个app能打多个环境的包,怎么办?1,3结合?
        一缕殇流化隐半边冰霜:@AndyLiu 建立target应该都没有啥问题,建立多个scheme的时候,如果有啥问题,可以看我文章里面放的那个demo,我那个是配置好的。可以给你参考一下。:kissing_heart:
        AndyLiu:@一缕殇流化隐半边冰霜 谢谢,我试试:+1:
        一缕殇流化隐半边冰霜:@AndyLiu 嗯,建立多个target和多个scheme
      • 一抹相思泪成雨:想问下,配置好这几个环境以后,然后用脚本打包,为啥打出的IPA包,是开发环境,不是release环境的包?这样还要添加uuid。。
        一缕殇流化隐半边冰霜:@Hoolink 一直用脚本打包的呀,有两套脚本呀,develop和release的。
        一抹相思泪成雨:@一缕殇流化隐半边冰霜 你用过脚本打包吗??脚本执行的只是某个环境变量,但是证书签名好像是除了release都是开发证书签名的。。你遇到过没有??
        一缕殇流化隐半边冰霜:@Hoolink 你是有针对每个不同环境,对应的脚本都有配置吧??
      • ibingewin:请问大神,3种环境对应3个不同的bundle ID,公司级账号,难道还要创建3个appID、3套描述文件吗,要不然怎么能够装在一个手机上
        一缕殇流化隐半边冰霜:@ibingewin 这个是为了测试多个环境,这种方式并不需要3个appid,在编译过程中会生成不同的bundle ID。Appid是为了上线用的。
      • Autotestplat::+1:
        一缕殇流化隐半边冰霜:@测试开发 :kissing_heart::kissing_heart:一起学习
      • Hengry:感觉好复杂啊,我自己弄了一套:打一个包,可以手动切换 测试,线上,以及审核版本:smile:
        Hengry:@DevHank 只需一个包,让测试慢慢玩去
      • 星期六下午火锅:早点看到你的文章就好了,你有研究xcodebuild自动化打包不
        一缕殇流化隐半边冰霜:@尼卡多尔拉斯 我的脚本就是Jenkins那篇文章里面的脚本呀。。
        星期六下午火锅:@一缕殇流化隐半边冰霜 我也写了一个脚本,只是简单的我们可以互相换着看看不
        一缕殇流化隐半边冰霜:@尼卡多尔拉斯 有研究呀。。你看我Jenkins的那篇文章。。
      • 星期六下午火锅:厉害,我前段时间自己研究,和你第一段配置一样,但是在提交的时候archive配置的都是开发模式,提交审核居然过了。把我坑惨了,开发模式的外网是请求不到的,它居然审核通过了:joy:
        一缕殇流化隐半边冰霜:@尼卡多尔拉斯 这也可以啊。。。看来苹果的审核也有漏网之鱼啊。。。
      • DarrenK://网络请求baseurl
        REQUESTBASE_URL = @"http:\\/\\/10.20.100.1"

        OC中这样写有问题:sweat:

        我在OC中是这样写的
        //网络请求baseurl
        REQUESTBASE_URL = @\"http:\/\/10.20.100.1\"

        然后在Preprocessor Macros中配置的SERVICE_HOST=${REQUESTBASE_URL}
      • 李大戮:大神,配置好之后,从Debug改为Release之后,BundleId和Bundle Name都变了,但Profile文件没有变化。打包之后Profile文件却是正确的
        李大戮:@一缕殇流化隐半边冰霜 我的锅,已搞定。谢谢大神:+1:
        一缕殇流化隐半边冰霜:@李大戮 这是一个问题还是??
      • DrunkenMouse:最近公司也要求持续打包了,还就是jenkins,过来取取经:grin: 不过xcode8好像有些配置文件都改了,找不到对应位置了,从 新建User-defined Build Settings之后的plist文件修改创建开始有点懵。。
      • Jack猫:在Build Settings下面Add User-Defined String来为不同环境设置不同的bundle,这样可以在同一台设备上同时安装不同环境的包。但问题来了,不同环境的bundle不同,会导致推送服务无法工作,第三方服务入分享也会无法工作
        一缕殇流化隐半边冰霜:@simaiox 嗯,我们debug环境没有推送,就UAT和证书是有推送和分享那些的。:kissing_heart::stuck_out_tongue_winking_eye::stuck_out_tongue_winking_eye:
        Jack猫:@一缕殇流化隐半边冰霜 这样做好费事儿,还是每次修改build configuration来切换环境省事儿些,毕竟如果业务需要添加一个环境,所有工作都要重复一遍。另外创建微信应用还需要审核周期。所以还是看公司业务来决定使用哪种方式来切换
        一缕殇流化隐半边冰霜:@simaiox 如果要测试分享和推送,需要按照不同的bundle建立不同的证书和申请不同的分享ID
      • 矫炎圻:如果是多个相似的APP,但是又有区别的话,极不推荐使用前两种方法,导入多个配置文件和bundle id不符合,即使能解决,archive的时候还会有各种问题,建议用target.
        一缕殇流化隐半边冰霜:@矫炎圻 :+1::+1::+1:感受到了!!确实用target做会好一点。
        矫炎圻:@一缕殇流化隐半边冰霜 是的 不同证书不分target的话问题太多:sweat:
        一缕殇流化隐半边冰霜:@矫炎圻 我目前也用target啦。。
      • 小巷深深:我的项目中用Build Configuration创建了三个scheme:debug,release,inHouse。
        release是提交appstore用的,debug是自己开发时用的,不会去打包,inHouse是打包内测使用。

        然后在非release版本中我都添加了一个切换环境的功能:点击一个按钮,弹出一个环境列表,测试人员点一下就可以切换了,非常方便。在切换环境的时候,如果业务比较复杂,也可以把这个功能做得复杂一些,比如添加几个复选框,来选择是否清除缓存,是否重置为新版本等等。切换完环境直接杀掉app。 而且还可以添加升级提醒功能,方便测试去更新版本。

        按我这种方法只需要打一个内测版分发就可以了,切换环境的功能都放到app里了。
        大神觉得这个方案怎么样。
        iStig:感觉你这种方法跟文章中描述的方法有一个差异就是同一个手机你无法安装多个app 因为你的bounld id都是一致的
        灵儿菇凉:请问你这个方法适用于环境变量写在pch中的情况么?
        一缕殇流化隐半边冰霜:@小巷深深 可以的,只要你切换环境的时候一些初始化的变量能初始化完,就没事。我之前公司里面必须要杀掉app才行,因为一个环境变量是在appdelegate里面初始化的。
      • 煜寒了:有个地方有点看晕了,霜神指点一下
        在一/3. 这个位置

        ```
        我建议Scheme只配置环境,而进来的Run和Archive来配置Debug和Release,我建议每个Scheme都按照上图来,Run对应的Debug,Archive对应的Release。

        配置好上述之后,就可以选择不同环境运行app了。可以在手机上生成不同的环境的app,可以同时安装。如下图。
        ```

        那如果Archive 对应的都使用Release 的配置的话,不管使用哪一个Scheme 打出来的包,如果不是企业分发账户,这种只能用来提交appstore 吧? 测试也就不能安装。测试设备只能安装Debug 归档的安装包,包括测试的推送和发布的推送也是互不相通的。

        我们这边后台测试服和发布是完全独立的,测试配置的测试推送证书,发布配置的是发布推送证书,如果想在同一部手机上共存,首先bundleid 必须不同,其次就是推送证书。当然这些都是可以解决的,但是这些问题应该是不可避免的吧?

        不知道我的理解是不是有问题。
      • 9a38c23476d7:先收藏了,留着慢慢看!很实用的,谢谢!
      • 一世长安近欢喜:你好,我在Preprocessor Macros配置环境变量的时候定义UAT=1 ,但是在项目中获取不到这个值
        着魔的毛豆:我也遇到了,请问解决了吗
      • 闭眼看天空:进入到我们的Target里面,找到Build Phases,我们新建一个New Copy Files Phase,并且重命名为Copy Configuration Files。 请问这句话 我创建了 New Copy Files Phase 怎么弄脚本进去 我创建Run Script才能放进去
        一缕殇流化隐半边冰霜:@闭眼看天空 暂时没有错先不管,我也不是很清楚加这个的含义,等出错了再看问题:kissing_heart::kissing_heart:
        闭眼看天空:@一缕殇流化隐半边冰霜 已经弄好了 非常感谢 不过选择的时候创建New Copy Files Phase 貌似不是这个 是Run Script 不知道对不对
        一缕殇流化隐半边冰霜:@闭眼看天空 直接粘贴呀
      • MrFire_:我们需要打几十个类似的包,功能大体相同,appicon图标和名字不一样,目测可以实现,先收藏再研读,谢谢!
        MrFire_:@一缕殇流化隐半边冰霜 :clap: thank you!
        一缕殇流化隐半边冰霜:@hungryBoy 嗯啊。。可以实现的。。看看配置就可以了。。我文章里面有一个做好的例子,你看看就知道怎么弄了。。
      • ynot16:请问下,第一个方法,新建完scheme,你提到“新建完成之后,我们就可以编辑刚刚新建的Scheme,这里可以把Run模式和Archive都改成新建Scheme”,不过最后又提到 “而进来的Run和Archive来配置Debug和Release,我建议每个Scheme都按照上图来,Run对应的Debug,Archive对应的Release。”,到底是怎么样?把run,和archive都改成新建scheme可以打不同环境的包,但是所有scheme的run对应Debug,archive对应Release,不同scheme打得包之间不就会相互替换,不能共存么?
        一缕殇流化隐半边冰霜:@ynotcc 能不能在手机上共存是由那个boundID决定的,只要ID不同,都可以安装的
        一缕殇流化隐半边冰霜:@ynotcc 你疑惑的是不能共存,你看看我文章给了一个demo,那个是我做好的一个例子
        一缕殇流化隐半边冰霜:@ynotcc 不同的scheme之间是可以替换的,你更改编译参数就可以了,我文章里面说都可以编辑,但是我建议还是按照run就是debug这种默认的方式来,因为新人不是很明白我们的改动。所以建议的做法是,有几个环境就有几个scheme,每个scheme都有和其对应的debug和release
      • ec200686b10b:很详细。谢谢分享
      • 言子玉:问一下 应用设置不同的bundle identifier,若想应用应用具备推送功能的话,岂不是再在开发者网站上创建不同环境的应用标示? 你们是怎么解决的
        一缕殇流化隐半边冰霜:@zPaul 描述文件不变。。还是你原来用的那个,只不过把你原来项目里面的icon和app的名字,都变成了一个“数组”了,里面包含多个环境,然后根据你的配置,编译的时候就只会填入“数组”里面的一个配置,这样就可以做到多环境了。
        言子玉:@一缕殇流化隐半边冰霜 我的问题 不知道你看明白没有。 换一种方式问你吧,为了使不同环境的ipa包可以同时出现在一台手机上,你针对不同环境改变了应用的bundle identifier,那么你在不同环境打包时,采用的是什么描述文件(Provisioning Profile) ?
        一缕殇流化隐半边冰霜:@zPaul 不需要的。。我文章有一个demo,你下下来看看。。标识和图标本地做就可以
      • 宝贝嘛嘛爱你:古
        一缕殇流化隐半边冰霜:@宝贝嘛嘛爱你 :kissing_heart: 一起学习
      • wokenshin:楼主你好,我现在xcode里面遇到一个问题,就是在我的scheme里面 只有release没有debug了,而我的code signing里面也是只有release的选项没有debug的选项了。直接导致我无法选择对应的开发环境的证书了。我当前的xocde是xcode8.。。。本来想借助你的这篇文章来添加变量解决的,可是奇葩的是 我在 Configuration地方点击加号的时候 居然也只有release一个选项。。。。。请问知道咋整不?困扰我一天了 哎 :scream:
        一缕殇流化隐半边冰霜:@wokenshin :+1::+1::+1:厉害!!!
        wokenshin:@一缕殇流化隐半边冰霜 我解决了。在project-->Configuration 中点击加号重新添加的。点击加号的时候也只有release。。。。我直接重命名的。。。。 只有其中一个项目是这样,其他的项目都正常。 Xcode8 还有很多坑。。。。
        一缕殇流化隐半边冰霜:@wokenshin 还有这么奇葩的问题??Xcode8??
      • 方圆几度:你用的是哪个版本的Xcode?我做了遍,user -defined 与你讲的有些出入,没有Cocoapods的内容
        一缕殇流化隐半边冰霜:@请喊我船长 文章里面有一个我做好的demo,你看看
        一缕殇流化隐半边冰霜:@请喊我船长 哪个版本都有的。。。那个cocoapod在它自己的pro设置里面
      • 方圆几度:学习ing
        一缕殇流化隐半边冰霜:@请喊我船长 一起学习:smile::smile:
      • Jackson同学:看了你的两篇文章都是干货,极客精神追求不平庸
        一缕殇流化隐半边冰霜:@张国兵 一起学习:kissing_heart::kissing_heart::kissing_heart:一起进步:stuck_out_tongue_winking_eye::stuck_out_tongue_winking_eye:
      • Jackson同学:很有必要的一种集成模式 赞必须要学习不能再用之前那么low的办法了
        一缕殇流化隐半边冰霜:@张国兵 :kissing_heart::kissing_heart::kissing_heart:一起学习!!!
      • 五蕴盛:很强势
      • 元呢:小白菜表示看不懂。。。。
      • butcheryl:@一缕殇流化隐半边冰霜 在更改主工程的build config 后,执行 pod install,pod工程会根据主工程的设置,自动生成build config 。其中Debug 和 Release,使用对应的Debug和Release配置, 但是其他config如果不手动指定,默认使用 Release 环境。

        如果要手动指定,需要在 podfile 文件中指定对应config在自动生成时所需要的环境
        project 'TestProject', 'Mac App Store' => :release, 'Test' => :debug

        如果创建一个根据 Debug copy 出来的config,如果不进行上述操作,断点到pod里的库时,因为是Release环境所以没法去调试。

        官方文档:
        https://guides.cocoapods.org/syntax/podfile.html#project
        一缕殇流化隐半边冰霜:@Butcher_ :+1::+1::+1:谢谢大神提醒!!我更新一下文章。。那个我们其余的环境没有调试,所以还没有发现这个问题,谢谢大神指点!!
      • liyaoyao:请问我用.xcconfig 修改PRODUCT_NAME ,但实际的PRODUCT_NAME 还是target的名字,这是怎么回事?
        一缕殇流化隐半边冰霜:@41847721a65f 你把这个写死了??
        liyaoyao:@一缕殇流化隐半边冰霜 系统package 中的 PRODUCT_NAME = $(TARGET_NAME),我改成PRODUCT_NAME = dddddd ,package 那边需要怎样改?
        一缕殇流化隐半边冰霜:@41847721a65f parkaging属性里面还要再改一下名字
      • Joker_C:你会后悔
      • 混不吝丶:把hostURL动态改一下就好了啊
        一缕殇流化隐半边冰霜:@混不吝丶 截取么??
        混不吝丶:@一缕殇流化隐半边冰霜 我的做法是在hostURL后面加一个!号 ,以!切割 ,动态修改hostURL
        一缕殇流化隐半边冰霜:@混不吝丶 可以的。。不过我是想持续集成。集成过程中能动态改么??求指点
      • NdzRA4:新建的是 copy file phase? 应该是 run shell script吧~~
        一缕殇流化隐半边冰霜:我当时确实用的是copy file phase
        一缕殇流化隐半边冰霜:@周二可 我当时确实用的是copy file phase
        周二可:同问~~
      • dongwenbo:学习了,非常有用。。。
      • hext123:Mark, Targets 用来同时装几个环境的app不错
        一缕殇流化隐半边冰霜:@Emperor鈿 是的。。Targets的做法是可以实现任何配置,不过就是这种做法比较大,如果只是单纯的分个环境,弄个Scheme就好啦。。Targets,我觉得更多的是用来做OEM的。
      • A_sura:很不错,学习了!谢谢作者分享....
        一缕殇流化隐半边冰霜:@A_sura 一起学习:stuck_out_tongue_winking_eye::stuck_out_tongue_winking_eye:
      • jianshu_wl:搞这么复杂, 目的也就是先写好多个环境的代码文件, 然后需要更改环境的时候, 只用鼠标去点击切换. 个人觉得还是单例要简单一点. :joy:
        灵儿菇凉:请问用单列实现的思路是什么呢?环境变量写在pch中了,能做到吗?
        灵儿菇凉:@一缕殇流化隐半边冰霜 您好,请问用单例怎么实现呢?我这边的话环境变量都是写在pch中了,感觉后续没有办法再变了,大神有什么好意见吗?就是不管是程序一开始让用户选择环境还是说已经运行了通过某个动作触发去切换环境?
        一缕殇流化隐半边冰霜:@jianshu_wl 恩。。单例是简单,不过我们公司环境有点蛋疼,数据结构不一样,你切换环境的时候用单例初始化没用,必须在程序运行开始初始化,这个时候用单例就没用了。单例切换的时候程序已经在运行中了。老板还要求多个环境让我打不同的包都安装在手机上,用单例,多个环境的数据就都在本地了。我们代码里面多个环境这样混在一起会出bug。。所以我就只能分开环境了。。
      • wg689:#if DEBUG//develop 调试开发环境
        //测试阿里云服务器9月最新的 需要type
        #define REQUEST_URL @"http://112.74.208.243:113/api"
        #define REQUEST_URL_root @"http://112.74.208.243:113"
        #define isNeedType 1


        //测试服务器 需要type后台电脑
        //#define REQUEST_URL @"http://192.168.0.106:1111/api"
        //#define REQUEST_URL_root @"http://192.168.0.106:1111"
        //#define isNeedType 1


        //阿里云服务器 需要type--1.5appstore在用,正式用户环境-确保其他的没打开
        //#define REQUEST_URL @"http://api.123.com:1111/api"
        //#define REQUEST_URL_root @"http://api.123.com:1111"
        //#define isNeedType 1



        #else //生产环境 永久打开,发布就直接来到这个环境
        //测试阿里云服务器 需要type--1.5appstore在用,正式用户环境-确保其他的没打开
        #define REQUEST_URL @"http://api.123.com:1111/api"
        #define REQUEST_URL_root @"http://api.123.com:1111"
        #define isNeedType 1

        #endif
        我们公司这样的是不是low 有啥缺点
        wg689:@一缕殇流化隐半边冰霜 为啥一次要打那么多包,改完了代码就测试,测试一切好了,就切换到正式发布
        一缕殇流化隐半边冰霜:@wg_hjl 嗯嗯。。。我们原来是这样做的。这样做是可以的,不过你要是持续集成的话,这样子就比较麻烦,你这样子无法一次性打多个不同的包了。。。
        wg689:@wg_hjl 欢饮指教.ps 服务器地址瞎写的 只是demo
      • 4990145ebbf7:我现在用的就是最基本的方式,向大神学习了!!!
        翀鹰精灵:@一缕殇流化隐半边冰霜 你好 ,大神 能加下QQ吗,配置Jenkins(搭建教程)的时候好多问题哦😂😂😂
        一缕殇流化隐半边冰霜:@夕夏如是说 额。。。。我还算不上大神。。。一起学习,一起进步啦。。。 :stuck_out_tongue_winking_eye: :fist:
      • wg689:为啥这么复杂啊,不就直接切换服务器地址
        一缕殇流化隐半边冰霜:@一只名叫心蓝的猫 你说的是分布式的Jenkins吧???
        码农甲:@一缕殇流化隐半边冰霜 大神 你怎么保证 多个job 同时打包的
        一缕殇流化隐半边冰霜:@wg_hjl 也可以直接切换服务器地址。。但是需要更改代码。。我是想实现多个环境的持续集成,所以这样做的。。有没有什么其他的办法能保证这几个环境同时持续集成呢??请多多指点
      • Lol刀妹:可以,很强势
        一缕殇流化隐半边冰霜:@丶秋月白 强哥??是谁??
        秋月白Moon:活捉强哥:sunglasses:
      • 我叫阿水: :joy: 大神你工作几年了。。。看你还谦虚的自称菜鸟,让我们这些真菜鸟情何以堪 :sob:
        一缕殇流化隐半边冰霜:@YioMidd 当然是现成的然后自己改的。。我前端知识不多,还没有那么牛。。
        我叫阿水:@一缕殇流化隐半边冰霜 对了,你的博客主题是自己开发的吗,还是用现成自己修改的??:joy:昨天心血来潮用hexo搭了一个
        一缕殇流化隐半边冰霜:@YioMidd 我也才工作3年。。。还不是大神呢。。。 :sweat:
      • twinkle_孟:写得很好
        一缕殇流化隐半边冰霜:@孟凡君 谢谢支持!!!:v::v:
      • LaiYoung_:我们公司也是用的这个模式。要好好啃一下才行
        一缕殇流化隐半边冰霜:@LaiYoung :stuck_out_tongue_winking_eye: 有啥问题,还请你多多指点哈~~
      • HenryCheng:冰霜强势啊,先马后看
        一缕殇流化隐半边冰霜:@HenryCheng 额。。程神也好快!!你看看,有没有什么问题,多指点指点我!!:stuck_out_tongue_winking_eye::stuck_out_tongue_winking_eye:

      本文标题:手把手教你给一个iOS app配置多个环境变量

      本文链接:https://www.haomeiwen.com/subject/ybulsttx.html