Closed jcleary98 closed 4 years ago
You are talking about cordova preferences and those don't support platform-specific values in cordova neither, so we won't implement this in Capacitor as it will make it different from Cordova behaviour.
For Capacitor configurations, some of them allow different values per platform.
Is it possible to have different values for android and ios in capacitor.config.json? I need to add APP_SECRET (used by AppCenter plugins), which has different values on each platform. When I add the following:
"cordova": { "preferences": { "APP_SECRET": "0000-0000-0000-0000-000000000000" } }
It will add this preference to the native config.xml files. If I manually add separate preference values to the config.xml files, they're cleared out when I run npx cap copy.
Alternatively, is there another way I can set these values in the native projects? Any help appreciated, thanks.
@jcleary98 did you find any solution for this?
@asangadev No, I haven't been able to integrate the App Center plugins as a result.
Hi @jcesarmobile , working with platform specific preferences always worked in cordova for me. This is also suggested by Microsoft in order to use the app center plugin for cordova:
As a complete example, for a Apache Cordova project that supports both Android and iOS targets, you'll have separate app project definitions in App Center, and therefore different app secret values for each target platform. The relevant section of the project's config.xml file will look like the following:
<platform name="android"> <preference name="APP_SECRET" value="0000-0000-0000-0000-000000000001" /> </platform> <platform name="ios"> <preference name="APP_SECRET" value="0000-0000-0000-0000-000000000002" /> </platform>
See here: https://docs.microsoft.com/en-us/appcenter/sdk/getting-started/cordova
I could not find any specifiy statement on the cordova docs, that this is supported but I it works to specify specific preferences in the platform tags. This also works with preferences of some common cordova plugins like cordova-plugin-statusbar or cordova-plugin-splashscreen. There is even a blog post on the offical corodva blog showing how to set the "WKWebViewOnly"-Preference specific for iOS.
<platform name="ios">
<preference name="WKWebViewOnly" value="true" />
<feature name="CDVWKWebViewEngine">
<param name="ios-package" value="CDVWKWebViewEngine" />
</feature>
<preference name="CordovaWebViewEngine" value="CDVWKWebViewEngine" />
</platform>
It would be great if you could reconsider this issue.
@asangadev and @jcleary98 As a temporary workaround I dont use the copy command of capacitor via the Capacitor CLI.
I wrote a little script that adds this functionality on top of the copy command. Please keep in mind this is just a REALLY dirty solution:
// task to copy only the web assets.
// uses capacitor infrastructure: https://github.com/ionic-team/capacitor/blob/master/cli/src/tasks/copy.ts
// added functionality to specify platform specific cordova settings
const Config = require('@capacitor/cli/dist/config');
const Copy = require('@capacitor/cli/dist/tasks/copy');
const replace = require('replace-in-file');
const path = require('path');
async function run() {
const config = new Config.Config(process.platform, process.cwd(), '../node_modules/@capacitor/cli/bin');
await copy(config, 'android');
await copy(config, 'ios');
// fixes google api key for uk.co.workingedge.phonegap.plugin.launchnavigator
await replace({
files: path.join(process.cwd(), '/android/**/*.*'),
from: "$GOOGLE_API_KEY_FOR_ANDROID",
to: "MYKEY"
});
};
async function copy(config, platform) {
let basePrefs;
if (config.app.extConfig && config.app.extConfig.cordova && config.app.extConfig.cordova[platform]) {
const platformPreferences = config.app.extConfig.cordova[platform].preferences;
if (platformPreferences) {
basePrefs = config.app.extConfig.cordova.preferences;
let combinedPrefs = {};
if (basePrefs) Object.assign(combinedPrefs, basePrefs);
Object.assign(combinedPrefs, platformPreferences);
config.app.extConfig.cordova.preferences = combinedPrefs;
}
}
await Copy.copyCommand(config, platform);
if (config.app.extConfig && config.app.extConfig.cordova) {
config.app.extConfig.cordova.preferences = basePrefs;
}
}
run();
Hope it can help you.
That's excellent @tntwist, I'll give it a try.
I found a little bug in this script that sets the "global" cordova preferences to undefined when the given platform has no own preferences here is the updated script:
// task to copy only the web assets.
// uses capacitor infrastructure: https://github.com/ionic-team/capacitor/blob/master/cli/src/tasks/copy.ts
// added functionality to specify platform specific cordova settings
const Config = require('@capacitor/cli/dist/config');
const Copy = require('@capacitor/cli/dist/tasks/copy');
const replace = require('replace-in-file');
const path = require('path');
async function run() {
const config = new Config.Config(process.platform, process.cwd(), '../node_modules/@capacitor/cli/bin');
await copy(config, 'android');
await copy(config, 'ios');
// fixes google api key for uk.co.workingedge.phonegap.plugin.launchnavigator
await replace({
files: path.join(process.cwd(), '/android/**/*.*'),
from: "$GOOGLE_API_KEY_FOR_ANDROID",
to: "MYKEY"
});
};
async function copy(config, platform) {
let basePrefs;
if (config.app.extConfig && config.app.extConfig.cordova) {
basePrefs = config.app.extConfig.cordova.preferences;
}
if (config.app.extConfig && config.app.extConfig.cordova && config.app.extConfig.cordova[platform]) {
const platformPreferences = config.app.extConfig.cordova[platform].preferences;
if (platformPreferences) {
let combinedPrefs = {};
if (basePrefs) Object.assign(combinedPrefs, basePrefs);
Object.assign(combinedPrefs, platformPreferences);
config.app.extConfig.cordova.preferences = combinedPrefs;
}
}
await Copy.copyCommand(config, platform);
if (config.app.extConfig && config.app.extConfig.cordova) {
config.app.extConfig.cordova.preferences = basePrefs;
}
}
run();
Hello, I'm just getting into Ionic (React). I cannot figure out how to apply preferences; the config.xml doesn't work and there's no guide for Ionic Capacity?
Hi @ollydixon , the config.xml from cordova does not work with capacitor. You need to use the capactitor.config.json.
Here are the docs: https://capacitorjs.com/docs/reference/config
If you want to apply platform specific preferences like in cordova you need to use the script I provided in this issue. Here is an example config:
{
"appId": "com.my.app",
"appName": "My app",
"bundledWebRuntime": false,
"npmClient": "npm",
"webDir": "www",
"plugins": {
"SplashScreen": {
"launchAutoHide": false,
"showSpinner": false,
"spinnerColor": "#2698f3",
"androidSplashResourceName": "splash_full"
}
},
"cordova": {
"android": {
"preferences": {
"APP_SECRET": "XXXDROID"
}
},
"ios": {
"preferences": {
"APP_SECRET": "XXXXIOS"
}
}
}
}
Have fun.
@tntwist thanks, I don't see the mention of 'preferences' anywhere on those docs? It's very confusing hehe.
@tntwist am looking to implement your work around solution but am having trouble figuring out where to place the running of the script to be executed. Are you able to provide some instructions around this please?
@KirstenStake the documentation really sucks and its totally incompleted.
If it helps here is how my project is stuctured and the config.
@KirstenStake I run this script when ever I would like to copy the web assets to the android or ios project. This is normaly the case after a Build of the Ionic project. I start the script like this:
node copyWebAssets.js
.
Here is an extract of my ci pipeline:
...
steps:
- task: UseNode@1
inputs:
version: '12.x'
displayName: 'Use node 12.x'
- task: Npm@1
inputs:
command: 'ci'
displayName: 'Install node packages'
- script: npx ionic build
displayName: 'Build ionic app'
- task: ArchiveFiles@2
inputs:
rootFolderOrFile: './www'
includeRootFolder: false
archiveType: 'zip'
archiveFile: '$(Build.ArtifactStagingDirectory)/www.zip'
replaceExistingArchive: true
displayName: 'Archive www assets to artifacts'
- script: node ./scripts/copyWebAssets.js
displayName: 'Copy web assets to native projects'
....
As you can see the script runs after the build of the ionic project.
I hope this helps you.
Hi @ollydixon , the config.xml from cordova does not work with capacitor. You need to use the capactitor.config.json.
Here are the docs: https://capacitorjs.com/docs/reference/config
If you want to apply platform specific preferences like in cordova you need to use the script I provided in this issue. Here is an example config:
{ "appId": "com.my.app", "appName": "My app", "bundledWebRuntime": false, "npmClient": "npm", "webDir": "www", "plugins": { "SplashScreen": { "launchAutoHide": false, "showSpinner": false, "spinnerColor": "#2698f3", "androidSplashResourceName": "splash_full" } }, "cordova": { "android": { "preferences": { "APP_SECRET": "XXXDROID" } }, "ios": { "preferences": { "APP_SECRET": "XXXXIOS" } } } }
Have fun.
Hi @tntwist ,
I tried this, but with no success, if I remove android
or ios
and have:
"cordova": {
"preferences": {
"APP_SECRET": "XXXDROID"
}
it works, but with the platform it doesn't.
Any idea how this could be solved?
@milkov85 thanks for the reply but we moved on from Cordova a long time ago to Flutter Web :-)
@milkov85 we didn't get this to work either so introduced a script to replace the template strings inside, based on which build command we used for the platform. The set up was tedious but now just works without us having to touch anything anymore.
Keep your capacitor.config.ts file as it is. Remove the platform specific object level from the cordova {} and only have preferences level {} with all your key/value pairs
Create a file capacitor.tpl.config.ts in the same root level where the original capacitor.config.ts lives. Copy the entire contents from capacitor.config.ts into the new file and change the values of the preference keys to template strings. E.g.
import { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'XYZ',
appName: ''XYZ'',
bundledWebRuntime: false,
webDir: 'www',
server: {
iosScheme: 'ionic'
},
plugins: {
SplashScreen: {
launchAutoHide: false,
launchShowDuration: 10000
}
},
cordova: {
preferences: {
'com.appboy.api_key': '${appboy}',
'APP_SECRET': '${appSecret}'
}
}
};
export default config;
Create a file that houses your platform specific key/values. You can get as fancy as you want here as we have folders like this: preferences > android file and ios file > each platform folder containing preferences.dev.json, preferences.stag.json, preferences.prod.json. In these files create your json object consisting of the key/values of the template strings used in file above.
Create your replacement script:
#!/usr/bin/env node
// Script to replace the template strings in capacitor.tpl.config.json based on environment and platform type
const fs = require('fs');
const path = require('path');
const compile = require('es6-template-strings/compile');
const resolveToString = require('es6-template-strings/resolve-to-string');
var ROOT_DIR = '';
var FILES = {
SRC: 'capacitor.tpl.config.ts',
DEST: 'capacitor.config.ts'
};
var env = 'dev';
if (process.env.npm_config_env) env = process.env.npm_config_env;
var platform = process.argv[2];
var envFile = 'preferences/' + platform + '/preferences.' + 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);
console.log('**~~Replacing template strings capacitor.json for env & platform:~~**', env, platform);
fs.writeFileSync(destFileFull, content);
5 Create your run scripts. We follow convention of env:platform. e.g. (this convention is followed in the script above, change accordingly). "prod:android": "npm run cap:template-strings --env=prod android {.....rest of the scripts here that you need to build}"
Hope that helps you at all. This was implemented a while back, not sure if there are better/easier ways now in Capacitor to do above. But once it's set up you pretty much don't need to touch it again
@KirstenStake thank you very much for the detailed explanation I will give it a try, hopefully it will work and I will not have to change the config each time I build different platform
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Capacitor, please create a new issue and ensure the template is fully filled out.
Is it possible to have different values for android and ios in capacitor.config.json? I need to add APP_SECRET (used by AppCenter plugins), which has different values on each platform. When I add the following:
"cordova": { "preferences": { "APP_SECRET": "0000-0000-0000-0000-000000000000" } }
It will add this preference to the native config.xml files. If I manually add separate preference values to the config.xml files, they're cleared out when I run npx cap copy.
Alternatively, is there another way I can set these values in the native projects? Any help appreciated, thanks.