简体   繁体   English

使用环境变量/参数化config.xml

[英]Using environment variables / parameterizing config.xml

I am building an ionic/cordova project using the cordova-plugin-facebook4 plugin for Facebook authentication access. 我正在使用cordova-plugin-facebook4插件构建一个离子/ cordova项目,用于Facebook身份验证访问。 In config.xml this looks like: config.xml这看起来像:

<plugin name="cordova-plugin-facebook4" spec="~1.7.1">
  <variable name="APP_ID" value="1234567890123456"/>
  <variable name="APP_NAME" value="My_Appy_App"/>
</plugin>

This works okay, but the APP_ID we are using is for the dev app and we have a separate facebook app for other environments such as QA. APP_ID ,但我们使用的APP_ID是针对开发应用程序,我们有一个单独的Facebook应用程序用于其他环境,如QA。

Is there any way to parameterize these variables in config.xml and have them be replaced as part of a build step? 有没有办法在config.xml参数化这些变量并将它们作为构建步骤的一部分进行替换? Something like: 就像是:

<plugin name="foo" spec="~0.0.0">
  <variable name="bar" value="${env.APP_ID}"/>
</plugin>

... and then run APP_ID=baz ionic build android or something like that. ...然后运行APP_ID=baz ionic build android或类似的东西。

I don't see anything in the cordova documentation that allows you to do this. 我没有在cordova文档中看到任何允许您这样做的内容。

@Ghandi's solution using cordova hooks is a good example of how this can be accomplished, though it's specifically windows only since it utilizes a batch file and PowerShell for the hook script. @Ghandi使用cordova钩子的解决方案就是如何实现这一点的一个很好的例子,尽管它只是专门用于Windows,因为它使用批处理文件和PowerShell作为钩子脚本。

As a cross-platform solution, you can utilize some sort of build tool on top of cordova. 作为跨平台解决方案,您可以在cordova之上使用某种构建工具。 For the project I'm working on, we have a cordova project in a subdirectory and were already using gulp to build the rest of our app so we modified our task that copies our cordova assets to a build directory to make it also perform a search and replace on config.xml . 对于我正在进行的项目,我们在子目录中有一个cordova项目,并且已经使用gulp来构建我们应用程序的其余部分,因此我们修改了我们的任务,将我们的cordova资产复制到构建目录以使其也执行搜索并在config.xml替换。 It pulls replacements from environment variables and uses a dotenv library to load environment from a .env file (which is not checked into the repository). 它从环境变量中提取替换,并使用dotenv库从.env文件(未检入存储库)加载环境。

var gulp = require('gulp'),
  replace = require('gulp-replace'),
  gutil = require('gulp-util'),
  filter = require('gulp-filter'),
  path = require('path'),
  dotenv = require('dotenv'),

  argv = require('yargs').argv,
  isRelease = !!(typeof argv.release !== 'undefined' ? argv.release : (typeof argv.r !== 'undefined' ? argv.r : false));

gulp.task('cordova_assets', ['clean', 'templates'], function() {
  dotenv.config({path: path.join(__dirname, 'cordova', '.env'), silent: true});
  var f = filter(['cordova/config.xml'], {restore: true});

  return gulp.src(['cordova/**/*'], {base: './'})
    .pipe(f)
    .pipe(replace(/\$\$([A-Z0-9_]+)/gi, function(substr, varname) {
      var repl = '';
      if(!isRelease && typeof process.env[varname + '_DEBUG'] !== 'undefined')
        repl = process.env[varname + '_DEBUG'];
      else if(isRelease && typeof process.env[varname + '_RELEASE'] !== 'undefined')
        repl = process.env[varname + '_RELEASE'];
      else if(typeof process.env[varname] !== 'undefined')
        repl = process.env[varname];
      else {
        throw new gutil.PluginError('cordova_config', {
          message: 'expected but could not find the environment variables "' + varname +
          '" or "' + varname + '_' + (isRelease ? 'RELEASE' : 'DEBUG') + '" which is used in cordova/config.xml. ' +
          'Add it to cordova/.env or specify them explicitly when running the build command.'
        });
      }

      console.log('replacing "%s" with "%s"', substr, repl);
      return repl;
    }))
    .pipe(f.restore)
    .pipe(gulp.dest('build'));
});

It will replace any variables in config.xml that begin with two dollar signs and consist of alphanumeric characters and underscores with the value of the corresponding environment variable if it exists (and throws an error if it doesn't). 它将替换config.xml中以两个美元符号开头的任何变量,并且由字母数字字符和下划线组成,如果存在,则包含相应环境变量的值(如果不存在,则抛出错误)。 Additionally, you can suffix the variable within config.xml with either _DEBUG or _RELEASE and it'll use those values instead as appropriate. 此外,您可以使用_DEBUG_RELEASE config.xml中的变量进行后缀,并且它将根据需要使用这些值。

It assumes the following project structure: 它假定以下项目结构:

  • /
    • cordova
      • config.xml
      • ... (the rest of your cordova install) ...(你的其他电缆安装)
      • .env (contains your environment variables) .env (包含您的环境变量)
    • build (the build directory and final output of the cordova app) build (构建目录和cordova应用程序的最终输出)

I've achieved that creating a template config.xml (the file is config.tpl.xml ) and a before_prepare cordova hook to replace the variables in the template with the correct values and save the generated content in config.xml . 我已经实现了创建模板config.xml (文件是config.tpl.xml )和before_prepare cordova挂钩,用正确的值替换模板中的变量,并将生成的内容保存在config.xml

The cordova hook uses the npm package es6-template-strings : cordova钩子使用npm包es6-template-strings

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

The hook is: 钩子是:

#!/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);

I have files in the src/environments/ directory for different environments, that are chosen based on the NODE_ENV value that is defined when I build cordova. 我在src/environments/目录中有不同环境的文件,这些文件是根据我构建cordova时定义的NODE_ENV值选择的。 For example, if NODE_ENV=prod (production), then it would use the file environment.prod.json : 例如,如果NODE_ENV=prod (production),那么它将使用文件environment.prod.json

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

When the hook is executed, this part in the cordova.tpl.xml : 当钩子被执行时,这部分在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>

becomes like: 变得像:

<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>

Just have in mind that you need to add the automatic cordova changes to config.xml to the template (like adding a plugin), but that is much better (and, in my case, less frequent) than having to change the variables before each build with different environments and much less error prone, although it is not ideal. 只是有一点,你需要添加自动科尔多瓦更改config.xml的模板(如添加一个插件),但要好得多(和,在我的情况,那么频繁)不是各自之前改变变量尽管不是理想的,但是在不同环境下构建并且更不容易出错。

Update (2017-10-13) 更新(2017-10-13)

Now when I add/remove plugins, the xml template file is also updated. 现在,当我添加/删除插件时,xml模板文件也会更新。 I've just added the hooks described here . 我刚刚添加了这里描述的钩子。

As you mentioned in the post, there is not much documentation about this in the official cordova documentation. 正如您在帖子中提到的,在官方的cordova文档中没有太多关于此的文档。 After spending some time on this analysis, this is what I concluded: 花了一些时间进行分析后,我得出结论:

There is some minimal help available ready-made to parameterize plugin variables available in config.xml . 现成的一些最小帮助可用于参数化config.xml可用的插件变量。 This can be achieved through preference variables as mentioned in the official cordova link . 这可以通过官方cordova链接中提到的偏好变量来实现。 But the problem with this approach is that its working depends on how on the plugin is coded. 但这种方法的问题在于它的工作取决于插件的编码方式。

I tried this approach with the facebook plugin, but it didn't work :( I tried as below: 我用facebook插件尝试了这种方法,但它没有用:(我试过如下:

<preference name="MY_CUSTOM_STRING" default="12345678901234567" />
    <plugin name="cordova-plugin-facebook4" spec="~1.7.1">
        <variable name="APP_ID">$MY_CUSTOM_STRING</variable>
        <variable name="APP_NAME" value="My_Appy_App"/>
    </plugin>

Tried out the same approach for google maps plugin and it worked :) I tried as below: 试过谷歌地图插件的相同方法,它工作:)我尝试如下:

<preference name="MY_CUSTOM_STRING" default="12345678901234567" />
<plugin name="cordova-plugin-googlemaps" spec="~1.3.9">
    <variable name="API_KEY_FOR_ANDROID">$MY_CUSTOM_STRING</variable>
</plugin>

So all I could conclude is that the parameterizing approach is dependent on the core plugin code. 所以我可以得出结论,参数化方法依赖于核心插件代码。

In the case of the facebook plugin, if you want to parameterize the APP_ID variable, then I guess hooks are the way to proceed. 在facebook插件的情况下,如果你想参数化APP_ID变量,那么我猜钩子是继续进行的方式。 Even a simple windows batch file to replace a string match should be fine and it can be invoked on pre build action to achieve what you require. 即使是一个简单的Windows批处理文件来替换字符串匹配也应该没问题,并且可以在预构建操作上调用它来实现您的需求。 Hope it helps. 希望能帮助到你。

UPDATE: 更新:

I do agree with Brandon's comments. 我同意布兰登的评论。

With the limited time i had, I was able to come up with the cordova hook that resolves this issue. 由于时间有限,我能够拿出解决这个问题的cordova钩子。 It may be a crude way and it can be refined too but for now this approach works fine. 它可能是粗糙的方式,它也可以改进,但现在这种方法工作正常。 Have posted the hook as a sample app in my github page and the README file has complete info about it. 已经将钩子作为示例应用程序发布在我的github页面中 ,并且README文件包含有关它的完整信息。 Hope it helps. 希望能帮助到你。 Keep me posted. 让我发布。

In my practice, we just put two files name config.xml and config.beta.xml to separate variables. 在我的实践中,我们只是将两个文件命名为config.xmlconfig.beta.xml来分隔变量。

run shell mv config.beta.xml before cordova platform add xxx if building a beta apk. 如果构建beta版apk,请在cordova platform add xxx之前运行shell mv config.beta.xml

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM