Unity Cloud Build Fastlane for Android

I’m currently building an app that targets both Android and iOS, and using Unity Cloud Build as a CI manager. Currently, I have one build profile each set up for iOS and Android, and in the iOS profile there’s a field for specifying a custom fastfile configuration, since Unity relies on fastlane to deploy to AppStoreConnect.

However, the Fastlane API suggests it also works with the Android platform and deploying to the Google Play Console, but there is no such option for it in the Android version of the Unity Cloud Build profile. It still builds the apps correctly which can be downloaded and uploaded to the Console manually, but I (and likely many others) would like the process to be automated as well.

Is this a feature that is planned for a future release of Unity Cloud Build, and if so, when?

Failing that, the best workaround I can think of is calling a shell script in the post-build script field, which in turn calls on Fastlane to run the lanes I want. How feasible is this? Is fastlane only installed in the iOS image of the cloud builder? Would I need the shell script to install/verify the existence of fastlane in order to execute the lanes I want to run?

1 Like

I’ve been messing with this for a while. Used to have a ridiculously complicated bash script for this, until I realized that fastlane is installed, and you can easily use it in a bash script in the post build event. Now it’s literally a 4 line script (minus comments), here it is:

#!/bin/bash

# Passed in as environment variables from CI, you must get this from Google and put
# it in the environment variable PLAYSTORE_KEY in the Unity build config.
# $PLAYSTORE_KEY - The JSON file with the credentials for the Google Developer account

# You can also just hardcode your package name, e.g. com.candycrush.game or whatever here...
PACKAGE_NAME=$(cat "$WORKSPACE/build.json" | jq -j '.[].bundleid')

# Unity environment variables replace the "\n" signs from the private key with spaces for some reason,
# so we replaces spaces with "\n" signs again so it works properly.
KEY_WITH_NEWLINES=$(echo $PLAYSTORE_KEY | jq '.private_key |= sub(" (?!PRIVATE|KEY)"; "\n"; "g")' -c -j)

# You could also use shorter argument names here, but DO NOT use -e for --release-status, there's some error there where
# fastlane thinks -e should mean the -env option and fails.
# Also, you could put the "draft" and "internal" into environment variables if you want to never have to modify the script
# again and just control it with environment variables.
fastlane supply --package_name "$PACKAGE_NAME" --aab "$UNITY_PLAYER_PATH"  --json_key_data "$KEY_WITH_NEWLINES" --release-status draft --track internal

So just put that in a “upload.sh” file, add it as the post build file in the build config. Get your google key in json format and put it in as the env variable “PLAYSTORE_KEY”. No additional fastlane configuration is needed, which was a pleasant surprise, it actually works with just the right parameters passed in.

Hope this helps :slight_smile:

10 Likes

Thanks so much for sharing that script @raudas ! We had been using firebase, but wanted to switch over to Google Play Console… this script worked right out of the box for that!

1 Like

Great, happy to hear it helped :slight_smile:

Hi,

Thanks for this. Trying it out myself but getting this error:

7683: Executing Post-Build Script at scripts/upload.sh
7684: [07:03:12]: [33mSeems like launching fastlane takes a while - please run[0m
7685: [07:03:12]:
7686: [07:03:12]: [36m$ [sudo] gem cleanup[0m
7687: [07:03:12]:
7688: [07:03:12]: [33mto uninstall outdated gems and make fastlane launch faster[0m
7689: [07:03:12]: [33mAlternatively it's recommended to start using a Gemfile to lock your dependencies[0m
7690: [07:03:12]: [33mTo get started with a Gemfile, run[0m
7691: [07:03:12]:
7692: [07:03:12]: [36m$ bundle init[0m
7693: [07:03:12]: [36m$ echo 'gem "fastlane"' >> Gemfile[0m
7694: [07:03:12]: [36m$ bundle install[0m
7695: [07:03:12]:
7696: [07:03:12]: [33mAfter creating the Gemfile and Gemfile.lock, commit those files into version control[0m
7697: [07:03:12]: [33mGet started using a Gemfile for fastlane https://docs.fastlane.tools/getting-started/ios/setup/#use-a-gemfile[0m
7698: [07:03:26]: Sending anonymous analytics information
7699: [07:03:26]: Learn more at https://docs.fastlane.tools/#metrics
7700: [07:03:26]: No personal or sensitive data is sent.
7701: [07:03:26]: You can disable this by adding `opt_out_usage` at the top of your Fastfile
7702: [07:03:26]: [31mError setting value 'BUILD_PATH/p/.build/last/default-android/Default Android.apk' for option 'aab'[0m
7703: [31m
7704: [!] aab file is not an aab[0m
7705: #######################################################################
7706: # fastlane 2.204.3 is available. You are on 2.182.0.
7707: # You should use the latest version.
7708: # Please update using `gem install fastlane`.
7709: #######################################################################
7710: [32m2.204.3 Improvements[0m
7711: * [trainer][scan] identify skipped tests in `xcresult` and export to Junit format and output in scan (#19957) via Igor Makarov
7712: * [Fastlane.Swift] Swift fastlane upgrader #18933 (#19914) via Enrique Garcia
7713: * [pem][spaceship] update development push certificate type ID (#19879) via Igor Makarov
7714: * [snapshot] fix compile error on macCatalyst (#19917) via Philipp Arndt
7715: * [Fastlane.Swift] readPodspec: return map of [String: Any] (#19953) via Hais Deakin
7716: * [match] update :force_for_new_certificates option description (#19938) via Wolfgang Lutz
7717: [32m2.204.2 App Store Connect API is fixed - reverts local filtering[0m
7718: * Revert "[spaceship][deliver][pilot] temporarily fix finding app by filtering by bundle id locally (#19900)" (#19906) via Josh Holtz (@joshdholtz)
7719: Version `2.204.1` will be removed from RubyGems as the temporary fix is no longer needed
7720: [32m2.204.1 Temporary App Store Connect Fix[0m
7721: * [spaceship][deliver][pilot] temporarily fix finding app by filtering by bundle id locally (#19900) via Josh Holtz (@joshdholtz)
7722: [32mTo see all new releases, open https://github.com/fastlane/fastlane/releases[0m
7723: [32mPlease update using `gem install fastlane`[0m
7724: ! build of 'default-android' failed. Post-Build script exited with status 1. Aborting.
7725: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/bvr-3.8.7.2.4.2/lib/bvr/build/build_handler.rb:104:in `compile'
7726: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/bvr-3.8.7.2.4.2/lib/bvr/project.rb:129:in `call'
7727: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/bvr-3.8.7.2.4.2/lib/bvr/project.rb:129:in `build_chain'
7728: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/bvr-3.8.7.2.4.2/lib/bvr/project.rb:80:in `build'
7729: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/bvr-3.8.7.2.4.2/lib/bvr/thor/tasks/project.rb:288:in `call'
7730: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/bvr-3.8.7.2.4.2/lib/bvr/thor/tasks/project.rb:288:in `build_steps'
7731: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/bvr-3.8.7.2.4.2/lib/bvr/thor/tasks/project.rb:117:in `build'
7732: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/command.rb:27:in `run'
7733: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/invocation.rb:126:in `invoke_command'
7734: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor.rb:369:in `dispatch'
7735: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/base.rb:444:in `start'
7736: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/runner.rb:44:in `method_missing'
7737: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/bvr-3.8.7.2.4.2/lib/bvr/thor/runner.rb:25:in `block in method_missing'
7738: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/bvr-3.8.7.2.4.2/lib/bvr/timing.rb:10:in `wrap'
7739: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/bvr-3.8.7.2.4.2/lib/bvr/thor/runner.rb:24:in `method_missing'
7740: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/command.rb:29:in `run'
7741: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/command.rb:126:in `run'
7742: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/invocation.rb:126:in `invoke_command'
7743: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor.rb:369:in `dispatch'
7744: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/base.rb:444:in `start'
7745: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/bvr-3.8.7.2.4.2/lib/bvr/thor/tasks/buildjobs.rb:120:in `buildscript'
7746: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/command.rb:27:in `run'
7747: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/invocation.rb:126:in `invoke_command'
7748: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor.rb:369:in `dispatch'
7749: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/base.rb:444:in `start'
7750: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/runner.rb:44:in `method_missing'
7751: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/bvr-3.8.7.2.4.2/lib/bvr/thor/runner.rb:25:in `block in method_missing'
7752: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/bvr-3.8.7.2.4.2/lib/bvr/timing.rb:10:in `wrap'
7753: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/bvr-3.8.7.2.4.2/lib/bvr/thor/runner.rb:24:in `method_missing'
7754: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/command.rb:29:in `run'
7755: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/command.rb:126:in `run'
7756: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/invocation.rb:126:in `invoke_command'
7757: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor.rb:369:in `dispatch'
7758: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/thor-0.19.4/lib/thor/base.rb:444:in `start'
7759: /home/buildbot/.rvm/gems/ruby-2.4.2/gems/bvr-3.8.7.2.4.2/bin/bvr_runner:11:in `<main>'
7760: Publishing build 2 of 16767722914694/167929e7-f8c5-4349-b265-cffd612f9fd6 for target 'default-android'...
7761: Uploading extra_data/artifacts/icon.png
7762:   ...done
7763: Uploading extra_data/build_report/files.json
7764:   ...done
7765: Uploading extra_data/build_report/files.reflected.json  ...done
7766: Uploading extra_data/build_report/steps.reflected.json  ...done
7767: Uploading extra_data/build_report/strippingInfo.json
7768:   ...done
7769: Uploading extra_data/build_report/summary.json
7770:   ...done
7771: Uploading extra_data/build_report/summary.reflected.json
7772:   ...done
7773: Uploading extra_data/build_report/v2.steps.json
7774:   ...done
7775: Uploading Default Android.apk
7776:   ...done
7777: Zipping cache files from Library
7778: done.
7779: publishing finished successfully.
7780: Build failed. Please check the log for further details.
7781: Using /home/buildbot/.rvm/gems/ruby-2.4.2
7782: postbuildsteps finished successfully
7783: postbuildstatus finished successfully.
7784: Attempting to return legacy license
7785: No legacy license to return. Exiting
7786: Finished: FAILURE

Hi everyone, I’m trying this solution but I got this error:

Google Api Error: forbidden: The caller does not have permission - The caller does not have permission

Tried a lot of things but didn’t work. I hope anyone can help me

1 Like

Where do you guys get what to put into the PLAYSTORE_KEY environment variable from?
Is it from here?

i try to find solution for the same question) where i can find this “PLAYSTORE_KEY”?

ok, i find where i can get this key - https://docs.fastlane.tools/getting-started/android/setup/

but i have a new problem -
The Android App Bundle was signed with the wrong key. Found: SHA1: bla-bla-bla, expected: not bla-bla-bla

could anyone post the iOS version of this so we upload to the appstore?

Another +1 @raudas , thanks for this tip with fastlane and jq.

One more thing I would add to the above post is disabling xtrace and verbose mode for it:

set +x
set +v
# the script
set -x
set -v

Without this, at least in the current incarnation of UCB, all of your raw secrets will be printed in plain text to the build log when xtrace mode prints them out after expansion.

For testflight, I haven’t experimented with fastlane, but we are able to use the xcode command line pretty easily for uploads:

if xcrun altool --upload-app -f $UNITY_PLAYER_PATH -u $APPLE_USERID -p $APPLE_PASSWORD --type ios; then
echo "Uploading to Testflight successful"
else
echo "Failed to upload to testflight"
fi```
Where the apple userid and password env vars are set to whichever appstoreconnect account you want to upload with.

Fastlane supply is only for google play. Fastlane has the deliver/appstore/upload_to_app_store action for testflight:
https://docs.fastlane.tools/actions/upload_to_app_store/

Correct, but none of the deliver/appstore/upload_to_app_store aliases actually work for me…

see here: https://github.com/fastlane/fastlane/issues/20387
and here: https://discussions.unity.com/t/819944/12

The following just doesn’t authenticate…

#!/bin/bash

build_folder_path="$WORKSPACE/.build/last/$TARGET_NAME"
ipa_path="$build_folder_path/build.ipa"

echo "###############################################"
echo "Uploading app to TestFlight..."
echo "-----------------------------------------------"
pwd
echo "-----------------------------------------------"
env
echo "-----------------------------------------------"
ls -a .
echo "-----------------------------------------------"
echo "build.json"
cat build.json
echo "-----------------------------------------------"

exit_code=0
if fastlane upload_to_testflight --api_key_path "fastlane/api_key_info.json" --ipa "$ipa_path" ; then
    echo "======== Upload IPA to Appstore Connect finished with success"
    # end without error
    exit_code=0
else
    echo "======== ERROR! Upload IPA to Appstore Connect failed"
    echo "-------- Current Folder Content"
    ls -a .
    echo "-----------------------------------------------"
    bundle exec fastlane env
    echo "-----------------------------------------------"
    # end with error
    exit_code=1
fi

echo "###############################################"
exit $exit_code

I used this documentation to create my fast lane folder but I don’t know how to start upload operation. Is there any example script for that?

Have you found the solution? I have the same issue.

I’ve almost got things working, but I’m still getting stuck at:
“No local metadata, apks, aab, or track to promote were found, make sure to run fastlane supply init to setup supply”

When I try to put fastlane supply init in front of fastlane supply I get:
“[!] No authentication parameters were specified. These must be provided in order to authenticate with Google”

Looking at the fastlane docs it says that you have to run fastlane supply init from [your_project_folder]? Does anyone know how to do this in the UCB environment?

Didn’t you @raudas have to do something similar? Or did you work around this?

UPDATE
had a woopsie in my fastlane supply call. I had ‘-aab’ instead of ‘–aab’. This solved it for me :slight_smile:
And thanks for the script!

For anyone still trying to find what to do with the PLAYSTORE_KEY, I found this post very helpful: Automated Release From Unity Cloud Build To Google Play | by Emre SOLAK | Dream Harvesters Team | Medium.
Eventually you get a .json file. Copy everything inside the file. In Cloud Build Config > Advanced Settings > Environment Variables > Add variable > Key = PLAYSTORE_KEY, Value = [paste entire .json content]

hello
it’s seems not working for me … with all configurated, i’ve got an UCB error build when executing the bash file
[error] [!] Google Api Error: Invalid request - Invalid package name: null.

So why the script (bash file) can’t achieve to get the PACKAGE_NAME ?
PACKAGE_NAME=$(cat “$WORKSPACE/build.json” | jq -j ‘.[ ].bundleid’)

have you got the same issue in 2024 ?

Do u solve it? Im with same problem here