I am building an ionic/cordova project using the cordova-plugin-facebook4 plugin for Facebook authentication access. In config.xml
this looks like:
我正在使用cordova-plugin-facebook4插件构建一个离子/ cordova项目,用于Facebook身份验证访问。在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是针对开发应用程序,我们有一个单独的Facebook应用程序用于其他环境,如QA。
Is there any way to parameterize these variables in config.xml
and have them be replaced as part of a build step? Something like:
有没有办法在config.xml中参数化这些变量并将它们作为构建步骤的一部分进行替换?就像是:
<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文档中看到任何允许您这样做的内容。
4 个解决方案
#1
8
As you mentioned in the post, there is not much documentation about this in the official cordova documentation. After spending some time on this analysis, this is what I concluded:
正如您在帖子中提到的,在官方的cordova文档中没有太多关于此的文档。花了一些时间进行分析后,我得出结论:
There is some minimal help available ready-made to parameterize plugin variables available in config.xml
. This can be achieved through preference variables as mentioned in the official cordova link. But the problem with this approach is that its working depends on how on the plugin is coded.
现成的一些最小帮助可用于参数化config.xml中可用的插件变量。这可以通过官方cordova链接中提到的偏好变量来实现。但这种方法的问题在于它的工作取决于插件的编码方式。
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. 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. Hope it helps.
在facebook插件的情况下,如果你想参数化APP_ID变量,那么我猜钩子是继续进行的方式。即使是一个简单的Windows批处理文件来替换字符串匹配也应该没问题,并且可以在预构建操作上调用它来实现您的需求。希望能帮助到你。
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. 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. Hope it helps. Keep me posted.
由于时间有限,我能够拿出解决这个问题的cordova钩子。它可能是粗糙的方式,它也可以改进,但现在这种方法工作正常。已经将钩子作为示例应用程序发布在我的github页面中,并且README文件包含有关它的完整信息。希望能帮助到你。让我发布。
#2
7
@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. 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
. 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).
作为跨平台解决方案,您可以在cordova之上使用某种构建工具。对于我正在开发的项目,我们在子目录中有一个cordova项目,并且已经使用gulp来构建我们应用程序的其余部分,因此我们修改了我们的任务,将我们的cordova资产复制到构建目录以使其也执行搜索并在config.xml上替换。它从环境变量中提取替换,并使用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). Additionally, you can suffix the variable within config.xml with either _DEBUG
or _RELEASE
and it'll use those values instead as appropriate.
它将替换config.xml中以两个美元符号开头的任何变量,并且由字母数字字符和下划线组成,如果存在,则包含相应环境变量的值(如果不存在,则抛出错误)。此外,您可以使用_DEBUG或_RELEASE对config.xml中的变量进行后缀,并且它将根据需要使用这些值。
It assumes the following project structure:
它假设以下项目结构:
-
/
-
cordova
config.xml
- config.xml中
- ... (the rest of your cordova install)
- ...(你的其他电缆安装)
-
.env
(contains your environment variables) - .env(包含你的环境变量)
- cordova config.xml ...(你的cordova安装的其余部分).env(包含你的环境变量)
-
build
(the build directory and final output of the cordova app) - build(构建目录和cordova应用程序的最终输出)
-
- / cordova config.xml ...(您的cordova安装的其余部分).env(包含您的环境变量)build(构建目录和cordova应用程序的最终输出)
#3
4
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. For example, if NODE_ENV=prod
(production), then it would use the file environment.prod.json
:
我在src / environments /目录中有不同环境的文件,这些文件是根据我构建cordova时定义的NODE_ENV值选择的。例如,如果NODE_ENV = prod(生产),那么它将使用文件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.
请记住,您需要将自动cordova更改添加到模板(如添加插件),但这比在每个更改之前更改变量要好得多(并且在我的情况下,更少)尽管不是理想的,但是在不同环境下构建并且更不容易出错。
Update (2017-10-13)
Now when I add/remove plugins, the xml template file is also updated. I've just added the hooks described here.
现在,当我添加/删除插件时,xml模板文件也会更新。我刚刚添加了这里描述的钩子。
#4
0
In my practice, we just put two files name config.xml
and config.beta.xml
to separate variables.
在我的实践中,我们只是将两个文件命名为config.xml和config.beta.xml来分隔变量。
run shell mv config.beta.xml
before cordova platform add xxx
if building a beta apk.
如果构建beta版apk,请在cordova平台添加xxx之前运行shell mv config.beta.xml。
#1
8
As you mentioned in the post, there is not much documentation about this in the official cordova documentation. After spending some time on this analysis, this is what I concluded:
正如您在帖子中提到的,在官方的cordova文档中没有太多关于此的文档。花了一些时间进行分析后,我得出结论:
There is some minimal help available ready-made to parameterize plugin variables available in config.xml
. This can be achieved through preference variables as mentioned in the official cordova link. But the problem with this approach is that its working depends on how on the plugin is coded.
现成的一些最小帮助可用于参数化config.xml中可用的插件变量。这可以通过官方cordova链接中提到的偏好变量来实现。但这种方法的问题在于它的工作取决于插件的编码方式。
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. 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. Hope it helps.
在facebook插件的情况下,如果你想参数化APP_ID变量,那么我猜钩子是继续进行的方式。即使是一个简单的Windows批处理文件来替换字符串匹配也应该没问题,并且可以在预构建操作上调用它来实现您的需求。希望能帮助到你。
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. 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. Hope it helps. Keep me posted.
由于时间有限,我能够拿出解决这个问题的cordova钩子。它可能是粗糙的方式,它也可以改进,但现在这种方法工作正常。已经将钩子作为示例应用程序发布在我的github页面中,并且README文件包含有关它的完整信息。希望能帮助到你。让我发布。
#2
7
@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. 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
. 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).
作为跨平台解决方案,您可以在cordova之上使用某种构建工具。对于我正在开发的项目,我们在子目录中有一个cordova项目,并且已经使用gulp来构建我们应用程序的其余部分,因此我们修改了我们的任务,将我们的cordova资产复制到构建目录以使其也执行搜索并在config.xml上替换。它从环境变量中提取替换,并使用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). Additionally, you can suffix the variable within config.xml with either _DEBUG
or _RELEASE
and it'll use those values instead as appropriate.
它将替换config.xml中以两个美元符号开头的任何变量,并且由字母数字字符和下划线组成,如果存在,则包含相应环境变量的值(如果不存在,则抛出错误)。此外,您可以使用_DEBUG或_RELEASE对config.xml中的变量进行后缀,并且它将根据需要使用这些值。
It assumes the following project structure:
它假设以下项目结构:
-
/
-
cordova
config.xml
- config.xml中
- ... (the rest of your cordova install)
- ...(你的其他电缆安装)
-
.env
(contains your environment variables) - .env(包含你的环境变量)
- cordova config.xml ...(你的cordova安装的其余部分).env(包含你的环境变量)
-
build
(the build directory and final output of the cordova app) - build(构建目录和cordova应用程序的最终输出)
-
- / cordova config.xml ...(您的cordova安装的其余部分).env(包含您的环境变量)build(构建目录和cordova应用程序的最终输出)
#3
4
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. For example, if NODE_ENV=prod
(production), then it would use the file environment.prod.json
:
我在src / environments /目录中有不同环境的文件,这些文件是根据我构建cordova时定义的NODE_ENV值选择的。例如,如果NODE_ENV = prod(生产),那么它将使用文件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.
请记住,您需要将自动cordova更改添加到模板(如添加插件),但这比在每个更改之前更改变量要好得多(并且在我的情况下,更少)尽管不是理想的,但是在不同环境下构建并且更不容易出错。
Update (2017-10-13)
Now when I add/remove plugins, the xml template file is also updated. I've just added the hooks described here.
现在,当我添加/删除插件时,xml模板文件也会更新。我刚刚添加了这里描述的钩子。
#4
0
In my practice, we just put two files name config.xml
and config.beta.xml
to separate variables.
在我的实践中,我们只是将两个文件命名为config.xml和config.beta.xml来分隔变量。
run shell mv config.beta.xml
before cordova platform add xxx
if building a beta apk.
如果构建beta版apk,请在cordova平台添加xxx之前运行shell mv config.beta.xml。