Skip to content
This repository was archived by the owner on Apr 4, 2023. It is now read-only.

Commit 1ff72da

Browse files
committed
Support separate firebase dev and prod environments
1 parent f3492de commit 1ff72da

File tree

2 files changed

+198
-11
lines changed

2 files changed

+198
-11
lines changed

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ Open your Firebase project at the Google console and click 'Add app' to add an i
3737

3838
* Android: `google-services.json` which you'll add to your NativeScript project at `app/App_Resources/Android/google-services.json`
3939

40+
Note: for using separate versions of these files for dev/prod environments see [this section](#separation-of-environments)
41+
4042
## Installation
4143
If you rather watch a (slightly outdated) video explaining the steps then check out this step-by-step guide - you'll also learn how to
4244
add iOS and Android support to the Firebase console and how to integrate anonymous authentication:
@@ -268,3 +270,28 @@ android {
268270
```
269271

270272
Where `"15.0.0"` is best set to the same value as the `googlePlayServicesVersion` value in [this file](https://github.com/EddyVerbruggen/nativescript-plugin-firebase/blob/48a99ccd2a0f590c37080b1a252173ea9b996e9f/publish/scripts/installer.js#L540).
273+
274+
## Separation of Environments
275+
276+
It is possible to use different development and production environments by using multiple `GoogleService-Info.plist` and `google-services.json` files.
277+
278+
### Setup
279+
1. Create two separate Firebase projects (e.g. `myproject` and `myproject-dev`) and configure them with the same package name
280+
2. Download the `plist` and `json` files for both projects and put them in the relevant directories with either `.dev` or `.prod` appended to the file names, so you have the following files in place:
281+
282+
* iOS
283+
* `app/App_Resources/iOS/GoogleService-Info.plist.dev`
284+
* `app/App_Resources/iOS/GoogleService-Info.plist.prod`
285+
* Android
286+
* `app/App_Resources/Android/google-services.json.dev`
287+
* `app/App_Resources/Android/google-services.json.prod`
288+
289+
Note: if you currently have the `storageBucket` property in the `firebase.init()` then remove it (not mandatory anymore as of version `6.5.0` of this plugin), so it will be taken automatically from the relevant google services `plist` and `json` files.
290+
291+
### Build
292+
The after-prepare hook of this plugin will now choose either the `dev` or the `prod` version of your google services `plist` and `json` files depending on how you run your build:
293+
294+
* `prod` will be selected if you run with either the `--release`, `--env.prod` or `--env.production` flags
295+
* `dev` will be selected if you do not run with the above flags
296+
297+
Note: if you do not have both `dev` and `prod` files in place, the regular `GoogleService-Info.plist` and `google-services.json` files will be used.

src/scripts/postinstall.js

Lines changed: 171 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3407,22 +3407,68 @@ apply plugin: "com.google.gms.google-services"
34073407

34083408
/**
34093409
* Installs an after-prepare build hook to copy the app/App_Resources/Android/google-services.json to platform/android on build.
3410+
* Installs before-checkForChange build hook to detect changes in environment and copy GoogleServices.plist on build
34103411
*/
34113412
function writeGoogleServiceCopyHook() {
3412-
console.log("Install google-service.json copy hook.");
3413+
3414+
/*
3415+
Install after-prepare hook
3416+
*/
3417+
3418+
console.log("Install google-service.json after-prepare copy hook.");
34133419
try {
3414-
var scriptContent =
3420+
var afterPrepareScriptContent =
34153421
`
34163422
var path = require("path");
34173423
var fs = require("fs");
34183424
34193425
module.exports = function($logger, $projectData, hookArgs) {
34203426
3421-
return new Promise(function(resolve, reject) {
3427+
return new Promise(function(resolve, reject) {
3428+
3429+
/* Decide whether to prepare for dev or prod environment */
3430+
3431+
var isReleaseBuild = (hookArgs.appFilesUpdaterOptions && hookArgs.appFilesUpdaterOptions.release) ? true : false;
3432+
var validProdEnvs = ['prod','production'];
3433+
var isProdEnv = false; // building with --env.prod or --env.production flag
3434+
3435+
if (hookArgs.platformSpecificData.env) {
3436+
Object.keys(hookArgs.platformSpecificData.env).forEach((key) => {
3437+
if (validProdEnvs.indexOf(key)>-1) { isProdEnv=true; }
3438+
});
3439+
}
3440+
3441+
var buildType = isReleaseBuild || isProdEnv ? 'production' : 'development';
3442+
3443+
/* Create info file in platforms dir so we can detect changes in environment and force prepare if needed */
3444+
3445+
var npfInfoPath = path.join($projectData.platformsDir, hookArgs.platform.toLowerCase(), ".pluginfirebaseinfo");
3446+
var npfInfo = {
3447+
buildType: buildType,
3448+
};
3449+
3450+
try { fs.writeFileSync(npfInfoPath, JSON.stringify(npfInfo)); }
3451+
catch (err) {
3452+
$logger.info('nativescript-plugin-firebase: unable to create '+npfInfoPath+', prepare will be forced next time!');
3453+
}
3454+
3455+
3456+
/* Handle preparing of Google Services files */
3457+
34223458
if (hookArgs.platform.toLowerCase() === 'android') {
3423-
var sourceGoogleJson = path.join($projectData.appResourcesDirectoryPath, "Android", "google-services.json");
34243459
var destinationGoogleJson = path.join($projectData.platformsDir, "android", "app", "google-services.json");
34253460
var destinationGoogleJsonAlt = path.join($projectData.platformsDir, "android", "google-services.json");
3461+
var sourceGoogleJson = path.join($projectData.appResourcesDirectoryPath, "Android", "google-services.json");
3462+
var sourceGoogleJsonProd = path.join($projectData.appResourcesDirectoryPath, "Android", "google-services.json.prod");
3463+
var sourceGoogleJsonDev = path.join($projectData.appResourcesDirectoryPath, "Android", "google-services.json.dev");
3464+
3465+
// ensure we have both dev/prod versions so we never overwrite singlular google-services.json
3466+
if (fs.existsSync(sourceGoogleJsonProd) && fs.existsSync(sourceGoogleJsonDev)) {
3467+
if (buildType==='production') { sourceGoogleJson = sourceGoogleJsonProd; } // use prod version
3468+
else { sourceGoogleJson = sourceGoogleJsonDev; } // use dev version
3469+
}
3470+
3471+
// copy correct version to destination
34263472
if (fs.existsSync(sourceGoogleJson) && fs.existsSync(path.dirname(destinationGoogleJson))) {
34273473
$logger.out("Copy " + sourceGoogleJson + " to " + destinationGoogleJson + ".");
34283474
fs.writeFileSync(destinationGoogleJson, fs.readFileSync(sourceGoogleJson));
@@ -3437,11 +3483,16 @@ module.exports = function($logger, $projectData, hookArgs) {
34373483
reject();
34383484
}
34393485
} else if (hookArgs.platform.toLowerCase() === 'ios') {
3440-
var sourceGooglePlist = path.join($projectData.appResourcesDirectoryPath, "iOS", "GoogleService-Info.plist");
3441-
if (!fs.existsSync(sourceGooglePlist)) {
3442-
$logger.warn(sourceGooglePlist + " does not exist. Please follow the installation instructions from the documentation");
3443-
return reject();
3444-
} else {
3486+
// we have copied our GoogleService-Info.plist during before-checkForChanges hook, here we delete it to avoid changes in git
3487+
var destinationGooglePlist = path.join($projectData.appResourcesDirectoryPath, "iOS", "GoogleService-Info.plist");
3488+
var sourceGooglePlistProd = path.join($projectData.appResourcesDirectoryPath, "iOS", "GoogleService-Info.plist.prod");
3489+
var sourceGooglePlistDev = path.join($projectData.appResourcesDirectoryPath, "iOS", "GoogleService-Info.plist.dev");
3490+
3491+
// if we have both dev/prod versions, let's remove GoogleService-Info.plist in destination dir
3492+
if (fs.existsSync(sourceGooglePlistProd) && fs.existsSync(sourceGooglePlistDev)) {
3493+
if (fs.existsSync(destinationGooglePlist)) { fs.unlinkSync(destinationGooglePlist); }
3494+
resolve();
3495+
} else { // single GoogleService-Info.plist modus
34453496
resolve();
34463497
}
34473498
} else {
@@ -3459,9 +3510,118 @@ module.exports = function($logger, $projectData, hookArgs) {
34593510
}
34603511
fs.mkdirSync(afterPrepareDirPath);
34613512
}
3462-
fs.writeFileSync(scriptPath, scriptContent);
3513+
fs.writeFileSync(scriptPath, afterPrepareScriptContent);
3514+
} catch(e) {
3515+
console.log("Failed to install google-service.json after-prepare copy hook.");
3516+
console.log(e);
3517+
}
3518+
3519+
/*
3520+
Install before-checkForChanges hook
3521+
*/
3522+
3523+
console.log("Install google-service.json before-checkForChanges copy hook.");
3524+
try {
3525+
var beforeCheckForChangesContent =
3526+
`
3527+
var path = require("path");
3528+
var fs = require("fs");
3529+
3530+
module.exports = function($logger, $projectData, hookArgs) {
3531+
return new Promise(function(resolve, reject) {
3532+
3533+
/* Decide whether to prepare for dev or prod environment */
3534+
3535+
var isReleaseBuild = hookArgs['checkForChangesOpts']['projectData']['$options']['argv']['release'] || false;
3536+
var validProdEnvs = ['prod','production'];
3537+
var isProdEnv = false; // building with --env.prod or --env.production flag
3538+
3539+
var env = hookArgs['checkForChangesOpts']['projectData']['$options']['argv']['env'];
3540+
if (env) {
3541+
Object.keys(env).forEach((key) => {
3542+
if (validProdEnvs.indexOf(key)>-1) { isProdEnv=true; }
3543+
});
3544+
}
3545+
3546+
var buildType = isReleaseBuild || isProdEnv ? 'production' : 'development';
3547+
3548+
/*
3549+
Detect if we have nativescript-plugin-firebase temp file created during after-prepare hook, so we know
3550+
for which environment {development|prod} the project was prepared. If needed, we delete the NS .nsprepareinfo
3551+
file so we force a new prepare
3552+
*/
3553+
var platform = hookArgs['checkForChangesOpts']['platform'].toLowerCase(); // ios | android
3554+
var platformsDir = hookArgs['checkForChangesOpts']['projectData']['platformsDir'];
3555+
var appResourcesDirectoryPath = hookArgs['checkForChangesOpts']['projectData']['appResourcesDirectoryPath'];
3556+
var forcePrepare = true; // whether to force NS to run prepare
3557+
var npfInfoPath = path.join(platformsDir, platform, ".pluginfirebaseinfo");
3558+
var nsPrepareInfoPath = path.join(platformsDir, platform, ".nsprepareinfo");
3559+
var copyPlistOpts = { platform, appResourcesDirectoryPath, buildType, $logger }
3560+
3561+
if (fs.existsSync(npfInfoPath)) {
3562+
var npfInfo = undefined;
3563+
try { npfInfo = JSON.parse(fs.readFileSync(npfInfoPath, 'utf8')); }
3564+
catch (e) { $logger.info('nativescript-plugin-firebase: error reading '+npfInfoPath); }
3565+
3566+
if (npfInfo && npfInfo.hasOwnProperty('buildType') && npfInfo.buildType===buildType) {
3567+
$logger.info('nativescript-plugin-firebase: building for same environment, not forcing prepare.');
3568+
forcePrepare=false;
3569+
}
3570+
} else { $logger.info('nativescript-plugin-firebase: '+npfInfoPath+' not found, forcing prepare!'); }
3571+
3572+
if (forcePrepare && fs.existsSync(nsPrepareInfoPath)) {
3573+
$logger.info('nativescript-plugin-firebase: running release build or change in environment detected, forcing prepare!');
3574+
3575+
if (fs.existsSync(npfInfoPath)) { fs.unlinkSync(npfInfoPath); }
3576+
fs.unlinkSync(nsPrepareInfoPath);
3577+
3578+
if (copyPlist(copyPlistOpts)) { resolve(); } else { reject(); }
3579+
} else { if (copyPlist(copyPlistOpts)) { resolve(); } else { reject(); } }
3580+
});
3581+
};
3582+
3583+
/*
3584+
Handle preparing of Google Services files for iOS
3585+
*/
3586+
var copyPlist = function(copyPlistOpts) {
3587+
if (copyPlistOpts.platform === 'android') { return true; }
3588+
else if (copyPlistOpts.platform === 'ios') {
3589+
var sourceGooglePlistProd = path.join(copyPlistOpts.appResourcesDirectoryPath, "iOS", "GoogleService-Info.plist.prod");
3590+
var sourceGooglePlistDev = path.join(copyPlistOpts.appResourcesDirectoryPath, "iOS", "GoogleService-Info.plist.dev");
3591+
var destinationGooglePlist = path.join(copyPlistOpts.appResourcesDirectoryPath, "iOS", "GoogleService-Info.plist");
3592+
3593+
// if we have both dev/prod versions, we copy (or overwrite) GoogleService-Info.plist in destination dir
3594+
if (fs.existsSync(sourceGooglePlistProd) && fs.existsSync(sourceGooglePlistDev)) {
3595+
if (copyPlistOpts.buildType==='production') { // use prod version
3596+
copyPlistOpts.$logger.out("nativescript-plugin-firebase: copy " + sourceGooglePlistProd + " to " + destinationGooglePlist + ".");
3597+
fs.writeFileSync(destinationGooglePlist, fs.readFileSync(sourceGooglePlistProd));
3598+
return true;
3599+
} else { // use dev version
3600+
copyPlistOpts.$logger.out("nativescript-plugin-firebase: copy " + sourceGooglePlistDev + " to " + destinationGooglePlist + ".");
3601+
fs.writeFileSync(destinationGooglePlist, fs.readFileSync(sourceGooglePlistDev));
3602+
return true;
3603+
}
3604+
} else if (!fs.existsSync(sourceGooglePlist)) { // single GoogleService-Info.plist modus but missing
3605+
copyPlistOpts.$logger.warn("nativescript-plugin-firebase: " + sourceGooglePlist + " does not exist. Please follow the installation instructions from the documentation");
3606+
return false;
3607+
} else {
3608+
return true; // single GoogleService-Info.plist modus
3609+
}
3610+
} else { return true; }
3611+
}
3612+
`;
3613+
var scriptPath = path.join(appRoot, "hooks", "before-checkForChanges", "firebase-copy-google-services.js");
3614+
var afterPrepareDirPath = path.dirname(scriptPath);
3615+
var hooksDirPath = path.dirname(afterPrepareDirPath);
3616+
if (!fs.existsSync(afterPrepareDirPath)) {
3617+
if (!fs.existsSync(hooksDirPath)) {
3618+
fs.mkdirSync(hooksDirPath);
3619+
}
3620+
fs.mkdirSync(afterPrepareDirPath);
3621+
}
3622+
fs.writeFileSync(scriptPath, beforeCheckForChangesContent);
34633623
} catch(e) {
3464-
console.log("Failed to install google-service.json copy hook.");
3624+
console.log("Failed to install google-service.json before-checkForChanges copy hook.");
34653625
console.log(e);
34663626
}
34673627
}

0 commit comments

Comments
 (0)