Flutter: Solving iOS .xcodeproj merge conflicts with XcodeGen

JT Liew
4 min readApr 5, 2021

--

Have you encountered merge requests like the image below when you were trying to integrate iOS code changes from your team members?

This merge conflict occurs whenever there are any changes to the .xcodeproj file. Such as:

  1. Changes to file(s) locations
  2. Changes to build settings
  3. Changes to build phases
  4. Changes to build configurations
  5. Changes to schemes

The example above looks okay and manageable. However, if there are many changes made to the XCode project, do enjoy solving the merge conflict in a 2000+ lines .xcodeproj file!

XCodeGen

https://github.com/yonaskolb/XcodeGen

XcodeGen is an Xcode project generator via a YAML config file. It can generate Xcode projects, .xcodeproj file can be added into the .gitignore later on. One of the examples for its usage is Google’s Filament repository. To install XcodeGen, you can use brew to install it via the command.

brew install xcodegen

XcodeGen & Flutter

XCodeGen benefits Flutter developers who have to deal with a lot of development with Swift and XCode where merge conflicts can be annoying or even disruptive to your day to day development tasks. The below shows the steps to use XCodeGen to generate XCode projects for your Flutter apps.

Anatomy of Runner XCode project

To create the project.yml file to be used by XcodeGen. It is important to understand the project structure of a simple Flutter Xcode project. You can use flutter create <Project Name> to create a Flutter project. Open the Xcode Project in <Project Name>/ios/<Project Name>.xcodeproj to see the project file structures seen below.

Here are a few things to take notice of in the project structures:

  1. There is a Flutter directory that contains:
    - Debug.xcconfig
    - Release.xcconfig
    - Generated.xcconfig
    - AppFrameworkInfo.plist
  2. The name of ‘Runner’
    - The .xcconfig files contain entries to point to .../Pods-Runner...xcconfig
    - Podfile points to Runner project and target
    - Runner-Bridging-Header.h
    - Runner directory that contains the storyboards, Info.plist, AppDelegate.swift and the bridging header file
  3. Custom Build Phases of Run Script and Thin Binary. Create two shell files and copy the script into
Run Script Build Phase
Thin Binary Build Phase

Creating the project.yml file

With the knowledge above. We can create a project.yml configuration file at the root of the <PROJECT_ROOT>/ios.

1} Add the below in the project.yml file. The entry of name is the name of the .xcodeproj, which it generates.

name: Runner
fileGroups: # Optional
- project.yml # fileGroups is for including files without targets

2} Add options entry. Here are the minimum settings to run XCode.

options: 
bundleIdPrefix: com.yourcompany
createIntermediateGroups: true
deploymentTarget:
iOS: "13.0"

3} Add Runner to targets entry. Within Runner target. There are several settings to be added. First are the config files under the Flutter directory group in your ios project.

targets:
Runner:
configFiles:
Debug: Flutter/Debug.xcconfig
Release: Flutter/Release.xcconfig

3.1} Add bridging headers to settings to settings. The bridging header is for bridging Objective C code to Swift.
Note: To find out the key to the Build Settings, you can check the document/website.

    settings:
base:
SWIFT_OBJC_BRIDGING_HEADER:
- Runner/Runner-Bridging-Header.h

3.2} Create two files. run_scripts.sh and thin_binary.sh

3.2.1} phase_scripts/run_scripts.sh

/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build

3.2.2} phase_scripts/thin_binary.sh

/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed_and_thin

3.3} Update the preBuildScripts and postBuildScripts entries with the below

    preBuildScripts:
- path: phase_scripts/run_scripts.sh
name: Run Script
postBuildScripts:
- path: phase_scripts/thin_binary.sh
name: Thin Binary

3.4} Add attributes, platforms and type in the Runner. To find out the Development Team ID that works for your project, you can follow the StackOverflow entry steps.

    attributes:
DevelopmentTeam: DEVELOPMENT_TEAM_ID
platform: iOS
type: application

3.5} Add sources entry. This assigns the individual files or directory to the target Runner.

   sources: 
- Runner/
- Flutter/AppFrameworkInfo.plist
- Flutter/Generated.xcconfig
- Flutter/Debug.xcconfig
- Flutter/Release.xcconfig

Here how the final project.yml looks like.

name: Runner
fileGroups:
- project.yml
options:
bundleIdPrefix: com.netvirta
createIntermediateGroups: true
deploymentTarget:
iOS: "13.0"
targets:
Runner:
configFiles:
Debug: Flutter/Debug.xcconfig
Release: Flutter/Release.xcconfig
settings:
base:
SWIFT_OBJC_BRIDGING_HEADER:
- Runner/Runner-Bridging-Header.h
preBuildScripts:
- path: phase_scripts/run_scripts.sh
name: Run Script
postBuildScripts:
- path: phase_scripts/thin_binary.sh
name: Thin Binary
attributes:
DevelopmentTeam: DEVELOPMENT_TEAM_ID
platform: iOS
type: application
sources:
- Runner/
- Flutter/AppFrameworkInfo.plist
- Flutter/Generated.xcconfig
- Flutter/Debug.xcconfig
- Flutter/Release.xcconfig

Running XcodeGen

  1. In Terminal, navigate to <Project Root>/ios
  2. Run xcodegen to generate Runner.xcproj
  3. If there are any third-party dependencies. Run pod install . If not, you can skip to the next step
  4. flutter run to run your flutter app

Final step

Delete Runner.xcworkspace and Runner.xcproj . Add these entries into .gitignore

By following the steps above, you can say goodbye to the crazy merge conflicts you’ll face if you are working on native iOS code frequently on an iOS project.

Closing

In my quest to find out how to use XcodeGen to create Flutter’s Xcode project. I understand the minimum setup and settings to create an iOS Flutter project, which is not too complicated and quite easy to set up.

P.S.

  1. NetVirta just released Verifyt to Google Play Store and Apple AppStore. Do check them out!
  2. Looking for a working opportunity in Singapore’s leading company that deals with 3D body scanning technology? Join us via the link here.

Reference

  1. https://github.com/yonaskolb/XcodeGen
  2. https://github.com/google/filament/tree/main/ios/samples/hello-ar

--

--

JT Liew
JT Liew

Written by JT Liew

Mobile developer; Netvirta; Android; Flutter; Gradle; Kotlin

Responses (1)