Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] How i can use a test and production environment? #3504

Closed
approached opened this issue Apr 20, 2020 · 20 comments
Closed

[Question] How i can use a test and production environment? #3504

approached opened this issue Apr 20, 2020 · 20 comments
Labels
Type: Question Type: Stale Issue has become stale - automatically added by Stale bot

Comments

@approached
Copy link

Hi @ all,

How i can use a test and production environment?

I have one codebase which is managed with git.
I use follow modules: firestore, authentication, analytics, crashlytics and storage. Firestore and storage is most important.

Has anybody a idea?

@mikehardy
Copy link
Collaborator

I think there is some commentary about this in older issues if you search, we should probably put a FAQ or guide up

There are a couple ways to do it but they all start with the same idea: you have multiple firebase projects in the cloud, one for each environment you want to support.

Then for Android I think the best thing is to use build flavors, and maintain the google json file in for example android/app/src/environment name/google-services.json - one for each environment. So I have:

mike@isabela:~/work/Kullki/ksocialscore/packages/public-app (rebranding *) % find . | grep google-services.json
./android/app/src/qa/google-services.json
./android/app/src/staging/google-services.json
./android/app/src/prod/google-services.json
./android/app/src/dev/google-services.json

I use product flavors (google up the Android docs for them) - which are a separate axis from "release" vs "debug" so that each environment get's a unique application Id and I can have all of the environments installed on the same device at the same time.

So my android/app/build.gradle has this chunk in it:

    flavorDimensions "release_streams"
    productFlavors {
        dev {
            applicationIdSuffix ".dev"
            versionNameSuffix applicationIdSuffix
        }
        qa {
            applicationIdSuffix ".test"
            versionNameSuffix applicationIdSuffix
        }
        staging {
            applicationIdSuffix ".staging"
            versionNameSuffix applicationIdSuffix
        }
        prod {

        }
    }

For iOS I use Targets in Xcode as the build separation (they work like flavors in Android's gradle build system - make one per backend Firebase project/environment), and I made a sub-directory for each GoogleService-Info.plist. Then for each environment Target in Xcode I select the correct plist file and select that it should be a member of the target

So I have

mike@isabela:~/work/Kullki/ksocialscore/packages/public-app (rebranding *) % find . |grep GoogleService-Info.plist
./ios/KScoreApp/Prod/GoogleService-Info.plist
./ios/KScoreApp/Dev/GoogleService-Info.plist
./ios/KScoreApp/Staging/GoogleService-Info.plist
./ios/KScoreApp/Test/GoogleService-Info.plist

And each of those targets gets a separate bundleId (prod is 'com.kompai.kscore', dev is 'com.kompai.kscore.dev' etc for me) for the same reason as the android flavors above - I can have each environment installed on the same device at the same time. I do have to manage each as a separate product in Apple Developer Connection which is a pain in the butt, but that is mostly one time setup, then they all TestFlight happily.

To make them easy to tell apart I have different icons for the non-prod environments, and I do a bit of work in the app to tell (based on bundleId or applicationId) what flavor is executing so I can enable or disable different features but nothing too fancy.

That's it. All the files are in source control, the firebase descriptor files don't get copied around (that's another way to do it but I don't like "clobber this file with this other file..." as a build step) and I have 4 fully separate apps so they aren't fighting each other for your devices and emulators.

A fair bit of initial infrastructure to build but it's worked great for almost 2 years after getting it going. Hope this helps.

@andersonaddo
Copy link
Contributor

This sounds like solid advice, this should definitely be added to or linked to in the docs

@mikehardy
Copy link
Collaborator

I unfortunately no longer really have perspective on it nor remember all the steps 🤣 - but if you try it and keep track of the steps then propose a docs PR about one person every couple of days (my guess based on support traffic) would probably read it and praise your name...

@andersonaddo
Copy link
Contributor

andersonaddo commented Apr 21, 2020

I think I'll do just that.
If I run into problems I'll dm you on discord.

EDIT: There already seems to be a pretty solid guide right here actually.

@approached
Copy link
Author

approached commented Apr 22, 2020

@mikehardy thank you so much. Your post help me a lot. Your solution works great but i'am a single developer so i have other easy solution.

Android:
I use just debug (dev) and release (prod). This blog post help me:
https://firebase.googleblog.com/2016/08/organizing-your-firebase-enabled-android-app-builds.html

File structure:

./android/app/src/debug/google-services.json
./android/app/src/release/google-services.json

./android/app/build.gradle

buildTypes {
  debug {
    signingConfig signingConfigs.debug
    applicationIdSuffix ".debug" // <- added
  }

For IOS i will try tomorrow

@Salakar
Copy link
Member

Salakar commented Apr 22, 2020

As @approached suggested, on Android the Google Services plugin does support reading from specific build 'type' directory by default, e.g. you can place the json file in a android/app/src/{build_type} folder if you are using multiple build types.

Source: https://developers.google.com/android/guides/google-services-plugin#troubleshooting

@mikehardy
Copy link
Collaborator

@approached that does seem like it would work, but realize that you won't be properly testing prior to prod, in that release builds typically go through minimizing and obfuscation, which can lead to a whole class of bugs on both platforms. If you don't have a test environment where you test release type builds you may endure some surprises along the way. I think that's a low risk - possible worth it in your situation - but something to keep in mind.

@stale
Copy link

stale bot commented May 20, 2020

Hello 👋, to help manage issues we automatically close stale issues.
This issue has been automatically marked as stale because it has not had activity for quite some time. Has this issue been fixed, or does it still require the community's attention?

This issue will be closed in 15 days if no further activity occurs.
Thank you for your contributions.

@stale stale bot added the Type: Stale Issue has become stale - automatically added by Stale bot label May 20, 2020
@FRizzonelli
Copy link

@mikehardy thank you so much. Your post help me a lot. Your solution works great but i'am a single developer so i have other easy solution.

Android:
I use just debug (dev) and release (prod). This blog post help me:
https://firebase.googleblog.com/2016/08/organizing-your-firebase-enabled-android-app-builds.html

File structure:

./android/app/src/debug/google-services.json
./android/app/src/release/google-services.json

./android/app/build.gradle

buildTypes {
  debug {
    signingConfig signingConfigs.debug
    applicationIdSuffix ".debug" // <- added
  }

For IOS i will try tomorrow

Did you find out how to setup it for iOS?

@mikehardy
Copy link
Collaborator

@FRizzonelli I use schemes for iOS. I have one scheme per back-end firebase project. I have one google plist file for each of those firebase projects (naturally). In my Xcode project definition I have associated each particular firebase backend google plist file with the correct scheme via the Xcode "file ownership" feature that lets you associate a specific file with specific scheme(s).

Then when I build for iOS I just choose the correct scheme and I get connected to the correct project.

@afilp
Copy link

afilp commented Feb 22, 2021

@mikehardy Do you use the same name for GoogleService-Info.plist for each variant? (scheme?)
Not sure what "file ownership" is and how it works, I searched in Google and I could not fine something related for XCode.
Do you have any resource where we can read about this?

Thanks!

@mikehardy
Copy link
Collaborator

@afilp no, the variants get suffixes tacked on them for android, so they have different package names. This is critical as it is what allows you to have each variant installed at the same time on the same simulator / real device. Would not be that useful otherwise?

Do you have any resource where we can read about this?

No, sorry. But a simple search turns things up for me? https://stackoverflow.com/questions/14147640/what-is-my-target-and-how-do-i-add-a-file-to-it-for-unit-testing

@rcidt
Copy link

rcidt commented Sep 14, 2022

@mikehardy I know this is a bit old, but I am trying to follow your recommendation for Android.

For me, adding the suffix to the package name, produces the following crash on app start:

java.lang.RuntimeException: Unable to instantiate application com.my.app.adhoc.MainApplication package com.my.app.adhoc: java.lang.ClassNotFoundException: Didn't find class "com.my.app.adhoc.MainApplication" on path: Dex
PathList[[zip file "/data/app/~~cZDyy8K6SOKCxrS3z8Tp4w==/com.my.app.adhoc-wJ2yIcTHXrxufN7F3hmqng==/base.apk"],nativeLibraryDirectories=[/data/app/~~cZDyy8K6SOKCxrS3z8Tp4w==/com.my.app.adhoc-wJ2yIcTHXrxufN7F3hmqng==/lib/arm64, /data/app/~~cZDyy8K6SOKCxrS3z8Tp4w==/com.my.app.adhoc-wJ2yIcTHXrxufN7F3hmqng==/base.apk!/lib/arm64-v8a, /system/lib64, /system_ext/lib64]]

Does this mean I need to change the java source path from android/app/src/main/java/com/my/app/ to android/app/src/main/java/com/my/app/adhoc/ just to support this?

Thanks in advanced!

@mikehardy
Copy link
Collaborator

Hey - I think this guide has all the stuff I had to do for Android, it was just the build flavors that changed, and then running the build flavor ? https://medium.com/@ywongcode/building-multiple-versions-of-a-react-native-app-4361252ddde5

@rcidt
Copy link

rcidt commented Sep 15, 2022

@mikehardy thank you for sharing! That did the trick :D

@blwinters
Copy link

blwinters commented Jun 2, 2023

This was a very helpful guide, thanks @mikehardy. I now have a separate iOS target/bundleId for each environment. As such, I had to adjust my Podfile to handle these new targets, and found this example helpful for that.

Edit: Actually, I think I'm going to use the abstract_target approach since I don't need to specify many actual pods for my project.

@blwinters
Copy link

I'll also mention that when you are adding the GoogleService-Info.plist files to the Xcode project, make sure you select "Create groups" and not "Create folder references". If you use folder references then the folder reference will manage the target membership, which resulted in Firebase not finding the plist, causing a crash for me on launch. You want to have /dev, /staging, /prod as groups so that you can select the target membership on the files directly.

Screenshot 2023-06-02 at 11 18 10 AM

@blwinters
Copy link

blwinters commented Jun 2, 2023

Also note that you'll need to include the appIdSuffix argument when running the Android variants. So my scripts now look like this (using react-native-config for the .env files):

"android": "ENVFILE=.env.development react-native run-android --mode=devDebug --appIdSuffix dev",
"android:staging": "ENVFILE=.env.staging react-native run-android --mode=stagingDebug --appIdSuffix staging",
"android:prod": "ENVFILE=.env.production react-native run-android --mode=prodDebug",

https://stackoverflow.com/a/48340408/4139760

@Simon-44
Copy link

Is it still the right way for handling different envs? I read somewhere that now, you should have only one Firebase project and create an application for each env so in the end you have only one google-services.json that handles dev / staging / prod for example.

@jsimonassi
Copy link

@Simon-44 Did you find a new way to solve this problem? I've been trying to update my app from RN 68.5 to RN 0.73, but with the new gradle version i need to set a namespace for my app (Removing from manifest). The namespace is different from my aplicationId and i cant resolve this so far keeping the same firebase project. Do you have some tips?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Question Type: Stale Issue has become stale - automatically added by Stale bot
Projects
None yet
Development

No branches or pull requests