iosjenkinsbuildbranding

MultiBranding the same source code without using xcode


I have an app and I’d like to brand it as 3 different apps with different UI.

I don’t want to do using Xcode directly.

So far I found so many solutions that says create different targets and drag and drop the image like that

But I intend to do this branding work outside of Xcode



Help me out !


Solution

  • Now we can build the code without opening the Xcode

    Branding (UI,Build settings and functional)

    Using Terminal

    Branding.sh

       #Author: Durai Amuthan(h.duraiamuthan@gmail.com)
    #This is to achieve multiple branding of an iOS app by configuring the variables below
    
    #************ Configuring the brand starts ************
    
    #Directory path where .xcworkspace or .xcodeproj exists
    PathOfProjectDirectory=/Users/Shared/Jenkins/Documents/JenkinsTestNuu/New/
    
    #Path where info.plist exists
    PathOfInfoPlist=$PathOfProjectDirectory/XxYyZz
    
    #Path to icons where new iTunesArtwork and application icon exixts
    #Note: Make sure proper naming conventions of file has been followed
    PathOfNewIcons=/Users/Shared/Jenkins/Documents/icons-two
    
    #Path to asset resource where you have kept your application icon.
    PathOfAppIconSet=$PathOfProjectDirectory/XxYyZz/Icon.xcassets/AppIcon.appiconset
    
    #Path where do you want the .app file has to be kept
    PathToApp=/Users/Shared/Jenkins/Documents/JenkinsTestNuu/app
    
    #Path where do you want the .ipa file has to kept
    PathToIpa=/Users/Shared/Jenkins/Documents/JenkinsTestNuu/ipa
    
    #Cocoapods project or project that involves more than one modules are scheme based
    isWorkspaceBased=true
    
    #Path of the Project (.xcodeproj) - applicable for workspace(.xcworkspace) based project
    PathofProjectFile=$PathOfProjectDirectory/XxYyZz.xcodeproj
    
    #Path of the Workspace (.xcworkspace)
    PathofWorkspaceFile=$PathOfProjectDirectory/XxYyZz.xcworkspace
    
    #Name of the target - applicable only for non-workspace(.xcodeproj)  based projects
    Target=XxYyZz
    
    #Scheme of the iOS app
    Scheme=XxYyZz
    
    #To ascertain Cocoapods has been used or not
    isCocoaPodsBased=true
    
    #Configuration of the app (Debug -(Development) or Release(Adhoc or Distribution))
    Config=Release
    
    #For giving access to signing idetity found in KeyChain
    LoginKeychainPath=/Users/Shared/Jenkins/Library/Keychains/login.keychain
    LoginKeyChainPassword=xxyyzz
    
    #Name of the code signing identity.You can find the name in Keychain or xcode build setting
    CodeSigningIdentity='iPhone Distribution: Xx Yy Zz Limited (3Z5MHUYJ2L)'
    
    #Path of the provisioning profile
    PathToMobileProvision=/Users/Shared/Jenkins/Desktop/BrandingTest.mobileprovision
    
    #UUID value found inside Provisioning profile has to be given
    #Do not forget to install provisiong profile in the system
    ProvisioningProfileIdentity=6e6506e9-8233-4886-9084-zf21e8f8bbae
    
    #Bundle identifier of the app
    BundleIdentifier=com.xxyy.zz
    
    #AppVersion of the app
    AppVersion=2.2.2
    
    #App Name
    Appname=Two
    
    #************ Configuring the brand ends ************
    
    #** Creatting the build based on configuration starts **
    
    cd $PathOfInfoPlist
    echo "****************** Setting App Name ******************"
    /usr/libexec/PlistBuddy -c "Set :CFBundleName $Appname" info.plist
    /usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $Appname" info.plist
    echo "app name has been set as $Appname"
    
    cd $PathOfProjectDirectory
    echo "****************** Setting AppVersion ******************"
    /usr/bin/agvtool new-marketing-AppVersion $AppVersion
    /usr/bin/agvtool new-AppVersion -all $AppVersion
    
    echo "****************** Changing app icons & iTunes Artwork ******************"
    cp -R $PathOfNewIcons/*.png $PathOfAppIconSet
    echo "App icons has been changed at $PathOfNewIcons"
    cp -R $PathOfNewIcons/iTunesArtwork@2x $PathOfProjectDirectory/XxYyZz
    cp -R $PathOfNewIcons/iTunesArtwork $PathOfProjectDirectory/XxYyZz
    echo "iTunesArtwork has been changed at $PathOfProjectDirectory"
    
    #Unlock login keychain
    security unlock-keychain -p $LoginKeyChainPassword $LoginKeychainPath
    if $isCocoaPodsBased == 'true'
    then
    echo "****************** Installing Cocoapods **********************"
    /usr/local/bin/pod install
    echo "Cocoapods has been installed"
    fi
    
    echo "****************** Creating .app ******************"
    if $isWorkspaceBased == 'true'
    then
    /usr/bin/xcodebuild -scheme $Scheme -workspace $PathofWorkspaceFile -configuration $Config clean build CONFIGURATION_BUILD_DIR=$PathToApp "CODE_SIGN_IDENTITY=$CodeSigningIdentity" "PRODUCT_BUNDLE_IDENTIFIER=$BundleIdentifier" "PROVISIONING_PROFILE=$ProvisioningProfileIdentity"
    else
    /usr/bin/xcodebuild -target $Target -project $PathofProjectFile -configuration $Config clean build CONFIGURATION_BUILD_DIR=$PathToApp "CODE_SIGN_IDENTITY=$CodeSigningIdentity" "PRODUCT_BUNDLE_IDENTIFIER=$BundleIdentifier" "PROVISIONING_PROFILE=$ProvisioningProfileIdentity"
    fi
    echo ".app has been generated at $PathToApp"
    
    echo "****************** Creating .ipa *******************"
    /usr/bin/xcrun -sdk iphoneos PackageApplication -v $PathToApp/XxYyZz.app -o $PathToIpa/$Appname.ipa --embed $PathToMobileProvision --sign "$CodeSigningIdentity"
    echo "$Appname.ipa has been generated at $PathToIpa"
    
    #** Creatting the build based on configuration ends **
    

    The file is self-descriptive you can understand easily. Just configure the values of variable in the file and call it like below

    sh Branding.sh
    

    FYI:

    If you want some other icons also to be changed besides App Icon and iTunesArtwork use cp command e.g

    cp path/to/source path/to/destination
    

    To know more info do cp man

    With the above file you can do Branding for UI and Build Settings.

    For functional branding , you have to keep

    in a separate plist file so that this things also can be changed according to respective brand while building the app

    Plist file

    In coding side you can customise your application to read the values from plist like this

    Function defintion:

    func getPlistFile()->Dictionary<String,AnyObject>? {
            var dictPlistFile:Dictionary<String,AnyObject>?
            if let path = NSBundle.mainBundle().pathForResource("plistfile", ofType: "plist") {
                if let dictValue = NSDictionary(contentsOfFile: path) as? Dictionary<String, AnyObject> {
                    dictPlistFile=dictValue
                }
            }
            return dictPlistFile
        }
    

    Function calling:

    var Value=getPlistFile()?["Key"]
    

    You can change the values of the key according to brand using the PlistBuddy while building the app

    Here is the syntax

    /usr/libexec/PlistBuddy -c "Set :Key Value" plistfile.plist
    

    Using Jenkins

    We can effectively re-use the shell script here in jenkins

    1.You have to parameterise all the variables in shell script in jenkins using Add Parameter... like in the below screenshot I have done for one variable like that you have to do it for all others

    Paramterization

    2.Choose Execute shell in the Build Step

    Build Step

    3.Copy the script that is there in between Creating the build based on configuration starts and Creating the build based on configuration ends and paste it in Execute Shell Execute Shell

    Note:

    xcode_fix_PackageApplicationResourceRules.sh

    #!/bin/sh
    # A script to patch xcrun PackageInstallation so that it doesn't use the deprecated --resource-rules
    # See "Do not use the --resource-rules flag or ResourceRules.plist. They have been obsoleted and will be rejected."
    #   under https://developer.apple.com/library/mac/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG205
    # Reported as Apple bug #19384243
    # 
    # should be run as a user who can modify the PackageApplication file
    
    xcodedir=$1
    
    function usage {
            # FIXME we cannot parse args properly because 2 are optional...
            echo "USAGE: $0 xcodedir"
            echo "  xcodedir: an install dir like /Application/Xcode6.1.1.app"
    }
    
    if [[ $# -ne 1 ]]; then
            echo "ERROR: invalid number of arguments"
            usage
            exit -1 
    fi
    
    pi="$xcodedir/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/PackageApplication"
    piorig="$piOrig"
    
    if [[ ! -f "$pi" ]]; then
        echo "$pi file not found. Invalid argument ?"
        usage
        exit -1
    fi
    
    grep resource-rules "$pi" 
    if [[ $? -ne 0 ]]; then
        echo "PackageApplication doesn't use resource-rules. Skipping"
        exit 0
    fi
    
    if [[ -f "$piorig" ]]; then
        echo "Backup file $piorig already exist. Aborting"
        exit -1
    fi
    
    perl  -p -i'Orig' -e 'BEGIN{undef $/;} s/,resource-rules(.*sign}).*ResourceRules.plist"/$1/smg' "$pi" 
    echo $?
    

    I hope this helps you