Переменные среды Cordova config.xml

Сценарий:

Я Ionic3 приложение Ionic3, и в моем Ionic3 config.xml есть некоторые данные, которые я хочу изменить в соответствии со своей средой (например, я хочу, чтобы идентификатор приложения Facebook имел разные значения для разработки, подготовки и производства).

Я добился этого before_prepare создания шаблона config.xml (файл config.tpl.xml) и before_prepare cordova для замены переменных в шаблоне на правильные значения и сохранения сгенерированного содержимого в config.xml.

cordova крючок использует npm пакет es6-template-strings:

npm install es6-template-strings --save-dev

Крюк это:

#!/usr/bin/env node
var fs = require('fs');
var path = require('path');
var compile = require('es6-template-strings/compile');
var resolveToString = require('es6-template-strings/resolve-to-string');

var ROOT_DIR = process.argv[2];
var FILES = {
    SRC: "config.tpl.xml",
    DEST: "config.xml"
};

var env = process.env.NODE_ENV || 'dev';
var envFile = 'src/environments/environment.' + env + '.json';

var srcFileFull = path.join(ROOT_DIR, FILES.SRC);
var destFileFull = path.join(ROOT_DIR, FILES.DEST);
var configFileFull = path.join(ROOT_DIR, envFile);

var templateData = fs.readFileSync(srcFileFull, 'utf8');

var configData = fs.readFileSync(configFileFull, 'utf8');
var config = JSON.parse(configData);

var compiled = compile(templateData);
var content = resolveToString(compiled, config);

fs.writeFileSync(destFileFull, content);

У меня есть файлы в каталоге src/environments/ для разных сред, которые выбираются на NODE_ENV значения NODE_ENV, которое определяется при сборке cordova. Например, если NODE_ENV=prod (production), он будет использовать файл environment.prod.json:

{
    ...
    "FACEBOOK_APP_ID": "11111111",
    "FACEBOOK_APP_NAME": "My Facebook App Name",
    ...
    "PUSH_SENDER_ID": "22222222",
    ...
}

Когда ловушка выполнена, эта часть в cordova.tpl.xml:

<plugin name="cordova-plugin-facebook4" spec="~1.7.4">
    <variable name="APP_ID" value="${FACEBOOK_APP_ID}" />
    <variable name="APP_NAME" value="${FACEBOOK_APP_NAME}" />
</plugin>
<plugin name="phonegap-plugin-push" spec="~1.9.2">
    <variable name="SENDER_ID" value="${PUSH_SENDER_ID}" />
</plugin>

становится как:

<plugin name="cordova-plugin-facebook4" spec="~1.7.4">
    <variable name="APP_ID" value="11111111" />
    <variable name="APP_NAME" value="My Facebook App Name" />
</plugin>
<plugin name="phonegap-plugin-push" spec="~1.9.2">
    <variable name="SENDER_ID" value="22222222" />
</plugin>

Эта проблема:

Все идет нормально. Проблема заключается в том, что когда некоторые автоматические изменения вносятся в config.xml (например, добавление плагинов), это не отражается в cordova.tpl.xml, поэтому я должен помнить, чтобы вносить изменения вручную.

Хотя способ сделать это сейчас намного лучше, чем добавлять каждую переменную среды, как раньше (это был кошмар обслуживания и подвержен ошибкам), мне все равно приходится каждый раз менять шаблон при добавлении/изменении/удалении плагина ( не так часто и легко обнаружить проблему, когда я ее забываю, но все же далеко от идеала).

Мой вопрос:

Я хотел бы знать, есть ли способ избежать этих ручных изменений, но продолжайте использовать переменные среды, как я делаю сейчас.

Это может быть достигнуто --save внесения автоматических изменений в config.xml которые будут сделаны вместо этого в config.tpl.xml (например, при добавлении плагина с --save), если это возможно, но я не нашел ни cordova варианта cordova по этому поводу.

Или используя config.xml в качестве шаблона и отправьте его в другое место с определенными переменными (например, в www/config.xml), и используйте config.xml в другом месте, которое будет использоваться для сборки приложения (не в config.xml в корне, т.е. шаблон). Я бы изменил только файлы src и dest в моем хуке (на config.xml и www/config.xml соответственно). Но я также не нашел способ достичь этого.

Есть мысли по этому поводу?

(Это не должно быть специфическим решением Ionic.)

Обновление (2017-10-13)

Основываясь на ответе Бобби, я достиг того, чего хотел, как при установке, так и при удалении плагина. Я создал 4 хука: after_plugin_add, after_plugin_rm, before_plugin_add, before_plugin_rm.

Перехватчики before копируют шаблон (config.tpl.xml) в файл config.xml а перехватчики after делают обратное.

before_plugin_add и before_plugin_rm:

#!/usr/bin/env node
var fs = require('fs');
var path = require('path');

var ROOT_DIR = process.argv[2];
var FILES = {
    SRC: 'config.tpl.xml',
    DEST: 'config.xml'
};

var srcFileFull = path.join(ROOT_DIR, FILES.SRC);
var destFileFull = path.join(ROOT_DIR, FILES.DEST);

var templateData = fs.readFileSync(srcFileFull, 'utf8');
fs.writeFileSync(destFileFull, templateData);

after_plugin_add и after_plugin_rm практически идентичны, просто FILES.SRC значения FILES.SRC и FILES.DEST.

Ответ 1

Одним из решений может быть создание перехватов для before_plugin_install и after_plugin_install.

On before_plugin_install copy the cordova.tpl.xml to cordova.xml.
... Plugin is installed ...
On after_plugin_install copy cordova.xml to cordova.tpl.xml

Ответ 2

gulpfile.js

    const gulp = require('gulp');
const Config = require('cordova-config');
var fs = require('fs');
var argv = require('yargs').argv;

gulp.task('config', function () {

    let data;
    let env = argv.channelTag;
    if (!env || env === 'dev') {
        data = fs.readFileSync('src/environments/environment.ts', 'utf-8');
    } else {
        data = fs.readFileSync('src/environments/environment.' + env + '.ts', 'utf-8');
    }

    let startIndex = data.indexOf("{");
    let lastIndex = (data.indexOf("}")) + 1;

    let configEnv = JSON.parse(data.substring(startIndex, lastIndex));
    console.log(configEnv);

    const configXml = new Config('config.xml');

    configXml.setID(configEnv.appId);
    configXml.setName(configEnv.appName);
    configXml.setVersion(configEnv.version);
    configXml.setAndroidVersionCode(configEnv.versionCode);


    // Write the config file
    configXml.writeSync();
});

environment.ts

    export const environment = {
  "production": false,
  "appId": "in.xyz.abcDev",
  "appName": "MyApp Dev",
  "version": "0.0.1",
  "versionCode": "1000"
};