codeplay-common 4.0.7 → 4.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +2 -2
- package/LICENSE +21 -21
- package/README.md +60 -45
- package/files/buildCodeplay/codeplayBeforeBuild-6.2.js +747 -713
- package/files/buildCodeplay/versions.json +1 -1
- package/files/finalrelease +937 -937
- package/files/iap-install-2.js +145 -145
- package/files/ionic.config.json +6 -6
- package/files/scripts/setup-baseline-profile.js +241 -241
- package/package.json +16 -16
- package/scripts/sync-files.js +105 -105
- package/scripts/uninstall.js +104 -104
|
@@ -272,68 +272,68 @@ function compareWithBeta(installedVersion, minVersion, isBeta) {
|
|
|
272
272
|
|
|
273
273
|
|
|
274
274
|
|
|
275
|
-
const ensureAnalyticsFlagsInConfig = (config) => {
|
|
276
|
-
const analyticsFlagKey = 'ANALYTICS_ENABLED';
|
|
277
|
-
const legacyAnalyticsFlagKey = ['ANALY', 'STICS_ENABLED'].join('');
|
|
278
|
-
let updated = false;
|
|
279
|
-
|
|
280
|
-
if (!config.android) {
|
|
281
|
-
config.android = {};
|
|
282
|
-
updated = true;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (!config.ios) {
|
|
286
|
-
config.ios = {};
|
|
287
|
-
updated = true;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
const syncPlatformFlag = (platformName, platformConfig) => {
|
|
291
|
-
const existingValue = platformConfig[analyticsFlagKey];
|
|
292
|
-
const legacyValue = platformConfig[legacyAnalyticsFlagKey];
|
|
293
|
-
let nextValue = false;
|
|
294
|
-
|
|
295
|
-
if (typeof existingValue === 'boolean') {
|
|
296
|
-
nextValue = existingValue;
|
|
297
|
-
} else if (typeof legacyValue === 'boolean') {
|
|
298
|
-
nextValue = legacyValue;
|
|
299
|
-
} else if (existingValue !== undefined) {
|
|
300
|
-
console.warn(`⚠️ ${platformName}.ANALYTICS_ENABLED should be true or false. Automatically setting it to false.`);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (platformConfig[analyticsFlagKey] !== nextValue) {
|
|
304
|
-
platformConfig[analyticsFlagKey] = nextValue;
|
|
305
|
-
updated = true;
|
|
306
|
-
console.warn(`⚠️ ${platformName}.ANALYTICS_ENABLED added/updated as ${nextValue}.`);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if (legacyAnalyticsFlagKey in platformConfig) {
|
|
310
|
-
delete platformConfig[legacyAnalyticsFlagKey];
|
|
311
|
-
updated = true;
|
|
312
|
-
console.warn(`⚠️ ${platformName}.ANALYTICS_ENABLED spelling corrected.`);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
if (nextValue === false) {
|
|
316
|
-
console.warn(`⚠️ Google Analytics is disabled for ${platformName}. Mostly recommended to enable it when IAP is available.`);
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
syncPlatformFlag('android', config.android);
|
|
321
|
-
syncPlatformFlag('ios', config.ios);
|
|
322
|
-
|
|
323
|
-
return updated;
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
const checkAppUniqueId=()=>{
|
|
327
|
-
|
|
328
|
-
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
329
|
-
const analyticsFlagsUpdated = ensureAnalyticsFlagsInConfig(config);
|
|
330
|
-
|
|
331
|
-
const appUniqueId = config.android?.APP_UNIQUE_ID;
|
|
332
|
-
const RESIZEABLE_ACTIVITY = config.android?.RESIZEABLE_ACTIVITY;
|
|
333
|
-
const orientation = config.android?.ORIENTATION;
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
let logErrorMessage="";
|
|
275
|
+
const ensureAnalyticsFlagsInConfig = (config) => {
|
|
276
|
+
const analyticsFlagKey = 'ANALYTICS_ENABLED';
|
|
277
|
+
const legacyAnalyticsFlagKey = ['ANALY', 'STICS_ENABLED'].join('');
|
|
278
|
+
let updated = false;
|
|
279
|
+
|
|
280
|
+
if (!config.android) {
|
|
281
|
+
config.android = {};
|
|
282
|
+
updated = true;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (!config.ios) {
|
|
286
|
+
config.ios = {};
|
|
287
|
+
updated = true;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const syncPlatformFlag = (platformName, platformConfig) => {
|
|
291
|
+
const existingValue = platformConfig[analyticsFlagKey];
|
|
292
|
+
const legacyValue = platformConfig[legacyAnalyticsFlagKey];
|
|
293
|
+
let nextValue = false;
|
|
294
|
+
|
|
295
|
+
if (typeof existingValue === 'boolean') {
|
|
296
|
+
nextValue = existingValue;
|
|
297
|
+
} else if (typeof legacyValue === 'boolean') {
|
|
298
|
+
nextValue = legacyValue;
|
|
299
|
+
} else if (existingValue !== undefined) {
|
|
300
|
+
console.warn(`⚠️ ${platformName}.ANALYTICS_ENABLED should be true or false. Automatically setting it to false.`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (platformConfig[analyticsFlagKey] !== nextValue) {
|
|
304
|
+
platformConfig[analyticsFlagKey] = nextValue;
|
|
305
|
+
updated = true;
|
|
306
|
+
console.warn(`⚠️ ${platformName}.ANALYTICS_ENABLED added/updated as ${nextValue}.`);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (legacyAnalyticsFlagKey in platformConfig) {
|
|
310
|
+
delete platformConfig[legacyAnalyticsFlagKey];
|
|
311
|
+
updated = true;
|
|
312
|
+
console.warn(`⚠️ ${platformName}.ANALYTICS_ENABLED spelling corrected.`);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (nextValue === false) {
|
|
316
|
+
console.warn(`⚠️ Google Analytics is disabled for ${platformName}. Mostly recommended to enable it when IAP is available.`);
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
syncPlatformFlag('android', config.android);
|
|
321
|
+
syncPlatformFlag('ios', config.ios);
|
|
322
|
+
|
|
323
|
+
return updated;
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
const checkAppUniqueId=()=>{
|
|
327
|
+
|
|
328
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
329
|
+
const analyticsFlagsUpdated = ensureAnalyticsFlagsInConfig(config);
|
|
330
|
+
|
|
331
|
+
const appUniqueId = config.android?.APP_UNIQUE_ID;
|
|
332
|
+
const RESIZEABLE_ACTIVITY = config.android?.RESIZEABLE_ACTIVITY;
|
|
333
|
+
const orientation = config.android?.ORIENTATION;
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
let logErrorMessage="";
|
|
337
337
|
|
|
338
338
|
// 1️⃣ Check if it’s missing
|
|
339
339
|
if (RESIZEABLE_ACTIVITY === undefined) {
|
|
@@ -361,30 +361,30 @@ const checkAppUniqueId=()=>{
|
|
|
361
361
|
logErrorMessage+='❌ APP_UNIQUE_ID is missing in capacitor.config.json.';
|
|
362
362
|
}
|
|
363
363
|
|
|
364
|
-
else if (!Number.isInteger(appUniqueId)) {
|
|
365
|
-
logErrorMessage+='❌ APP_UNIQUE_ID must be an integer. Example: 1, 2, 3, etc.';
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
if(logErrorMessage!="")
|
|
369
|
-
{
|
|
370
|
-
if (analyticsFlagsUpdated) {
|
|
371
|
-
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
372
|
-
console.log('✅ capacitor.config.json analytics flags synced.');
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
console.error(logErrorMessage);
|
|
376
|
-
process.exit(1)
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
if (analyticsFlagsUpdated) {
|
|
380
|
-
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
381
|
-
console.log('✅ capacitor.config.json analytics flags synced.');
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
console.log(`✅ APP_UNIQUE_ID is valid: ${appUniqueId}`);
|
|
386
|
-
|
|
387
|
-
}
|
|
364
|
+
else if (!Number.isInteger(appUniqueId)) {
|
|
365
|
+
logErrorMessage+='❌ APP_UNIQUE_ID must be an integer. Example: 1, 2, 3, etc.';
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if(logErrorMessage!="")
|
|
369
|
+
{
|
|
370
|
+
if (analyticsFlagsUpdated) {
|
|
371
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
372
|
+
console.log('✅ capacitor.config.json analytics flags synced.');
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
console.error(logErrorMessage);
|
|
376
|
+
process.exit(1)
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (analyticsFlagsUpdated) {
|
|
380
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
381
|
+
console.log('✅ capacitor.config.json analytics flags synced.');
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
console.log(`✅ APP_UNIQUE_ID is valid: ${appUniqueId}`);
|
|
386
|
+
|
|
387
|
+
}
|
|
388
388
|
|
|
389
389
|
checkAppUniqueId();
|
|
390
390
|
|
|
@@ -2516,7 +2516,7 @@ const checkAndupdateDropInViteConfig = () => {
|
|
|
2516
2516
|
console.log("✅ vite.config.(m)js Updated successfully.");
|
|
2517
2517
|
};
|
|
2518
2518
|
|
|
2519
|
-
const syncAdmobAliasInViteConfig = () => {
|
|
2519
|
+
const syncAdmobAliasInViteConfig = () => {
|
|
2520
2520
|
const possibleFiles = [
|
|
2521
2521
|
"vite.config.mjs",
|
|
2522
2522
|
"vite.config.js"
|
|
@@ -2577,607 +2577,632 @@ const syncAdmobAliasInViteConfig = () => {
|
|
|
2577
2577
|
viteContent = viteContent.replace(aliasLineRegex, nextGenAliasLine);
|
|
2578
2578
|
fs.writeFileSync(viteConfigPath, viteContent, "utf8");
|
|
2579
2579
|
console.log(`✅ @admob alias updated to ${nextGenRelativePath}`);
|
|
2580
|
-
};
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
const getViteConfigPath = () => {
|
|
2584
|
-
const possibleFiles = [
|
|
2585
|
-
"vite.config.mjs",
|
|
2586
|
-
"vite.config.js"
|
|
2587
|
-
];
|
|
2588
|
-
|
|
2589
|
-
return possibleFiles
|
|
2590
|
-
.map(file => path.join(process.cwd(), file))
|
|
2591
|
-
.find(filePath => fs.existsSync(filePath));
|
|
2592
|
-
};
|
|
2593
|
-
|
|
2594
|
-
const getLatestIapDir = () => {
|
|
2595
|
-
const adsDir = path.join(process.cwd(), "src", "js", "Ads");
|
|
2596
|
-
|
|
2597
|
-
if (!fs.existsSync(adsDir)) return null;
|
|
2598
|
-
|
|
2599
|
-
const iapDirs = fs.readdirSync(adsDir, { withFileTypes: true })
|
|
2600
|
-
.filter(entry => entry.isDirectory() && /^IAP-\d+(\.\d+)*$/.test(entry.name))
|
|
2601
|
-
.map(entry => entry.name)
|
|
2602
|
-
.sort((a, b) => {
|
|
2603
|
-
const versionA = a.match(/(\d+(?:\.\d+)*)/)[1].split(".").map(Number);
|
|
2604
|
-
const versionB = b.match(/(\d+(?:\.\d+)*)/)[1].split(".").map(Number);
|
|
2605
|
-
|
|
2606
|
-
for (let i = 0; i < Math.max(versionA.length, versionB.length); i++) {
|
|
2607
|
-
const diff = (versionB[i] || 0) - (versionA[i] || 0);
|
|
2608
|
-
if (diff !== 0) return diff;
|
|
2609
|
-
}
|
|
2610
|
-
|
|
2611
|
-
return 0;
|
|
2612
|
-
});
|
|
2613
|
-
|
|
2614
|
-
return iapDirs.length > 0 ? path.join(adsDir, iapDirs[0]) : null;
|
|
2615
|
-
};
|
|
2616
|
-
|
|
2617
|
-
const getAnalyticsConfig = () => {
|
|
2618
|
-
const config = fs.existsSync(configPath)
|
|
2619
|
-
? JSON.parse(fs.readFileSync(configPath, "utf8"))
|
|
2620
|
-
: {};
|
|
2621
|
-
|
|
2622
|
-
const analyticsFlagKey = "ANALYTICS_ENABLED";
|
|
2623
|
-
const androidEnabled = config.android?.[analyticsFlagKey] ?? false;
|
|
2624
|
-
const iosEnabled = config.ios?.[analyticsFlagKey] ?? false;
|
|
2625
|
-
|
|
2626
|
-
return {
|
|
2627
|
-
androidEnabled: androidEnabled === true,
|
|
2628
|
-
iosEnabled: iosEnabled === true,
|
|
2629
|
-
enabled: androidEnabled === true || iosEnabled === true
|
|
2630
|
-
};
|
|
2631
|
-
};
|
|
2632
|
-
|
|
2633
|
-
const isPackageAvailable = (packageName) => {
|
|
2634
|
-
if (!fs.existsSync(packageJsonPath)) return false;
|
|
2635
|
-
|
|
2636
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
2637
|
-
|
|
2638
|
-
return Boolean(
|
|
2639
|
-
packageJson.dependencies?.[packageName] ||
|
|
2640
|
-
packageJson.devDependencies?.[packageName] ||
|
|
2641
|
-
fs.existsSync(path.join(process.cwd(), "node_modules", packageName, "package.json"))
|
|
2642
|
-
);
|
|
2643
|
-
};
|
|
2644
|
-
|
|
2645
|
-
const sourceImportsPackage = (packageName, ignoredFilePath) => {
|
|
2646
|
-
const sourceDir = path.join(process.cwd(), "src");
|
|
2647
|
-
if (!fs.existsSync(sourceDir)) return false;
|
|
2648
|
-
|
|
2649
|
-
const escapedPackage = packageName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2650
|
-
const importRegex = new RegExp(`(?:from\\s*['"]${escapedPackage}(?:/[^'"]*)?['"]|import\\s*['"]${escapedPackage}(?:/[^'"]*)?['"]|import\\s*\\(\\s*['"]${escapedPackage}(?:/[^'"]*)?['"]\\s*\\)|require\\s*\\(\\s*['"]${escapedPackage}(?:/[^'"]*)?['"]\\s*\\))`);
|
|
2651
|
-
|
|
2652
|
-
const scan = (dir) => {
|
|
2653
|
-
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
2654
|
-
const fullPath = path.join(dir, entry.name);
|
|
2655
|
-
|
|
2656
|
-
if (ignoredFilePath && path.resolve(fullPath) === path.resolve(ignoredFilePath)) {
|
|
2657
|
-
continue;
|
|
2658
|
-
}
|
|
2659
|
-
|
|
2660
|
-
if (entry.isDirectory()) {
|
|
2661
|
-
if (scan(fullPath)) return true;
|
|
2662
|
-
continue;
|
|
2663
|
-
}
|
|
2664
|
-
|
|
2665
|
-
if (!/\.(js|mjs|cjs|ts|tsx|jsx|f7)$/.test(entry.name)) continue;
|
|
2666
|
-
|
|
2667
|
-
const content = fs.readFileSync(fullPath, "utf8");
|
|
2668
|
-
if (importRegex.test(content)) return true;
|
|
2669
|
-
}
|
|
2670
|
-
|
|
2671
|
-
return false;
|
|
2672
|
-
};
|
|
2673
|
-
|
|
2674
|
-
return scan(sourceDir);
|
|
2675
|
-
};
|
|
2676
|
-
|
|
2580
|
+
};
|
|
2581
|
+
|
|
2582
|
+
|
|
2583
|
+
const getViteConfigPath = () => {
|
|
2584
|
+
const possibleFiles = [
|
|
2585
|
+
"vite.config.mjs",
|
|
2586
|
+
"vite.config.js"
|
|
2587
|
+
];
|
|
2588
|
+
|
|
2589
|
+
return possibleFiles
|
|
2590
|
+
.map(file => path.join(process.cwd(), file))
|
|
2591
|
+
.find(filePath => fs.existsSync(filePath));
|
|
2592
|
+
};
|
|
2593
|
+
|
|
2594
|
+
const getLatestIapDir = () => {
|
|
2595
|
+
const adsDir = path.join(process.cwd(), "src", "js", "Ads");
|
|
2596
|
+
|
|
2597
|
+
if (!fs.existsSync(adsDir)) return null;
|
|
2598
|
+
|
|
2599
|
+
const iapDirs = fs.readdirSync(adsDir, { withFileTypes: true })
|
|
2600
|
+
.filter(entry => entry.isDirectory() && /^IAP-\d+(\.\d+)*$/.test(entry.name))
|
|
2601
|
+
.map(entry => entry.name)
|
|
2602
|
+
.sort((a, b) => {
|
|
2603
|
+
const versionA = a.match(/(\d+(?:\.\d+)*)/)[1].split(".").map(Number);
|
|
2604
|
+
const versionB = b.match(/(\d+(?:\.\d+)*)/)[1].split(".").map(Number);
|
|
2605
|
+
|
|
2606
|
+
for (let i = 0; i < Math.max(versionA.length, versionB.length); i++) {
|
|
2607
|
+
const diff = (versionB[i] || 0) - (versionA[i] || 0);
|
|
2608
|
+
if (diff !== 0) return diff;
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2611
|
+
return 0;
|
|
2612
|
+
});
|
|
2613
|
+
|
|
2614
|
+
return iapDirs.length > 0 ? path.join(adsDir, iapDirs[0]) : null;
|
|
2615
|
+
};
|
|
2616
|
+
|
|
2617
|
+
const getAnalyticsConfig = () => {
|
|
2618
|
+
const config = fs.existsSync(configPath)
|
|
2619
|
+
? JSON.parse(fs.readFileSync(configPath, "utf8"))
|
|
2620
|
+
: {};
|
|
2621
|
+
|
|
2622
|
+
const analyticsFlagKey = "ANALYTICS_ENABLED";
|
|
2623
|
+
const androidEnabled = config.android?.[analyticsFlagKey] ?? false;
|
|
2624
|
+
const iosEnabled = config.ios?.[analyticsFlagKey] ?? false;
|
|
2625
|
+
|
|
2626
|
+
return {
|
|
2627
|
+
androidEnabled: androidEnabled === true,
|
|
2628
|
+
iosEnabled: iosEnabled === true,
|
|
2629
|
+
enabled: androidEnabled === true || iosEnabled === true
|
|
2630
|
+
};
|
|
2631
|
+
};
|
|
2632
|
+
|
|
2633
|
+
const isPackageAvailable = (packageName) => {
|
|
2634
|
+
if (!fs.existsSync(packageJsonPath)) return false;
|
|
2635
|
+
|
|
2636
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
2637
|
+
|
|
2638
|
+
return Boolean(
|
|
2639
|
+
packageJson.dependencies?.[packageName] ||
|
|
2640
|
+
packageJson.devDependencies?.[packageName] ||
|
|
2641
|
+
fs.existsSync(path.join(process.cwd(), "node_modules", packageName, "package.json"))
|
|
2642
|
+
);
|
|
2643
|
+
};
|
|
2644
|
+
|
|
2645
|
+
const sourceImportsPackage = (packageName, ignoredFilePath) => {
|
|
2646
|
+
const sourceDir = path.join(process.cwd(), "src");
|
|
2647
|
+
if (!fs.existsSync(sourceDir)) return false;
|
|
2648
|
+
|
|
2649
|
+
const escapedPackage = packageName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2650
|
+
const importRegex = new RegExp(`(?:from\\s*['"]${escapedPackage}(?:/[^'"]*)?['"]|import\\s*['"]${escapedPackage}(?:/[^'"]*)?['"]|import\\s*\\(\\s*['"]${escapedPackage}(?:/[^'"]*)?['"]\\s*\\)|require\\s*\\(\\s*['"]${escapedPackage}(?:/[^'"]*)?['"]\\s*\\))`);
|
|
2651
|
+
|
|
2652
|
+
const scan = (dir) => {
|
|
2653
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
2654
|
+
const fullPath = path.join(dir, entry.name);
|
|
2655
|
+
|
|
2656
|
+
if (ignoredFilePath && path.resolve(fullPath) === path.resolve(ignoredFilePath)) {
|
|
2657
|
+
continue;
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
if (entry.isDirectory()) {
|
|
2661
|
+
if (scan(fullPath)) return true;
|
|
2662
|
+
continue;
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
if (!/\.(js|mjs|cjs|ts|tsx|jsx|f7)$/.test(entry.name)) continue;
|
|
2666
|
+
|
|
2667
|
+
const content = fs.readFileSync(fullPath, "utf8");
|
|
2668
|
+
if (importRegex.test(content)) return true;
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
return false;
|
|
2672
|
+
};
|
|
2673
|
+
|
|
2674
|
+
return scan(sourceDir);
|
|
2675
|
+
};
|
|
2676
|
+
|
|
2677
2677
|
const runNpmCommand = (command) => {
|
|
2678
2678
|
console.log(`🚀 ${command}`);
|
|
2679
2679
|
execSync(command, { stdio: "inherit" });
|
|
2680
2680
|
};
|
|
2681
2681
|
|
|
2682
|
-
const
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
const legacyAnalyticsFile = path.join(legacyAnalyticsDir, "firebase-analytics.js");
|
|
2686
|
-
|
|
2687
|
-
if (!analyticsDir) {
|
|
2688
|
-
console.warn("⚠️ No IAP-x.x folder found. Skipping Firebase analytics wrapper sync.");
|
|
2689
|
-
return null;
|
|
2690
|
-
}
|
|
2691
|
-
|
|
2692
|
-
const analyticsFile = path.join(analyticsDir, "firebase-analytics.js");
|
|
2693
|
-
|
|
2694
|
-
if (!fs.existsSync(analyticsDir)) {
|
|
2695
|
-
fs.mkdirSync(analyticsDir, { recursive: true });
|
|
2696
|
-
}
|
|
2697
|
-
|
|
2698
|
-
const activeWrapper = `import { Capacitor, registerPlugin } from '@capacitor/core';
|
|
2699
|
-
|
|
2700
|
-
const FirebaseAnalytics = registerPlugin('FirebaseAnalytics');
|
|
2701
|
-
|
|
2702
|
-
const isEnabledValue = (value) => value === true || value === 'true';
|
|
2703
|
-
|
|
2704
|
-
const canUseNativeAnalytics = () => {
|
|
2705
|
-
if (!Capacitor.isNativePlatform()) return false;
|
|
2706
|
-
|
|
2707
|
-
const platform = Capacitor.getPlatform();
|
|
2708
|
-
|
|
2709
|
-
if (platform === 'android') {
|
|
2710
|
-
return isEnabledValue(import.meta.env.VITE_ANDROID_ANALYTICS_ENABLED);
|
|
2711
|
-
}
|
|
2712
|
-
|
|
2713
|
-
if (platform === 'ios') {
|
|
2714
|
-
return isEnabledValue(import.meta.env.VITE_IOS_ANALYTICS_ENABLED);
|
|
2715
|
-
}
|
|
2716
|
-
|
|
2717
|
-
return false;
|
|
2718
|
-
};
|
|
2719
|
-
|
|
2720
|
-
const cleanParams = (params = {}) => {
|
|
2721
|
-
return Object.entries(params).reduce((result, [key, value]) => {
|
|
2722
|
-
if (value === undefined || value === null || value === '') return result;
|
|
2723
|
-
if (typeof value === 'number' && Number.isNaN(value)) return result;
|
|
2724
|
-
|
|
2725
|
-
result[key] = value;
|
|
2726
|
-
return result;
|
|
2727
|
-
}, {});
|
|
2728
|
-
};
|
|
2729
|
-
|
|
2730
|
-
const trackEvent = async (name, params = {}) => {
|
|
2731
|
-
if (!canUseNativeAnalytics()) return;
|
|
2732
|
-
|
|
2733
|
-
try {
|
|
2734
|
-
await FirebaseAnalytics.logEvent({
|
|
2735
|
-
name,
|
|
2736
|
-
params: cleanParams(params),
|
|
2737
|
-
});
|
|
2738
|
-
} catch (err) {
|
|
2739
|
-
console.warn(\`Firebase analytics event failed: \${name}\`, err);
|
|
2740
|
-
}
|
|
2741
|
-
};
|
|
2742
|
-
|
|
2743
|
-
export const trackSubscriptionScreenViewed = (params) => {
|
|
2744
|
-
trackEvent('subscription_screen_view', params);
|
|
2745
|
-
};
|
|
2746
|
-
|
|
2747
|
-
export const trackSubscriptionCheckoutStarted = (params) => {
|
|
2748
|
-
trackEvent('subscription_checkout_start', params);
|
|
2749
|
-
};
|
|
2750
|
-
|
|
2751
|
-
export const trackSubscriptionPurchased = (params) => {
|
|
2752
|
-
trackEvent('subscription_purchase', params);
|
|
2753
|
-
};
|
|
2754
|
-
|
|
2755
|
-
export const trackConsumablePurchased = (params) => {
|
|
2756
|
-
trackEvent('consumable_purchase', params);
|
|
2757
|
-
};
|
|
2758
|
-
`;
|
|
2759
|
-
|
|
2760
|
-
const noopWrapper = `const trackEvent = () => {};
|
|
2761
|
-
|
|
2762
|
-
export const trackSubscriptionScreenViewed = trackEvent;
|
|
2763
|
-
export const trackSubscriptionCheckoutStarted = trackEvent;
|
|
2764
|
-
export const trackSubscriptionPurchased = trackEvent;
|
|
2765
|
-
export const trackConsumablePurchased = trackEvent;
|
|
2766
|
-
`;
|
|
2767
|
-
|
|
2768
|
-
const nextContent = analyticsEnabled ? activeWrapper : noopWrapper;
|
|
2769
|
-
const currentContent = fs.existsSync(analyticsFile) ? fs.readFileSync(analyticsFile, "utf8") : "";
|
|
2770
|
-
|
|
2771
|
-
if (currentContent !== nextContent) {
|
|
2772
|
-
fs.writeFileSync(analyticsFile, nextContent, "utf8");
|
|
2773
|
-
console.log(`✅ Firebase analytics wrapper ${analyticsEnabled ? "enabled" : "disabled"}: ${path.relative(process.cwd(), analyticsFile)}`);
|
|
2774
|
-
} else {
|
|
2775
|
-
console.log(`ℹ️ Firebase analytics wrapper already ${analyticsEnabled ? "enabled" : "disabled"}.`);
|
|
2776
|
-
}
|
|
2777
|
-
|
|
2778
|
-
if (fs.existsSync(legacyAnalyticsFile)) {
|
|
2779
|
-
fs.unlinkSync(legacyAnalyticsFile);
|
|
2780
|
-
console.log("✅ Removed old Firebase analytics wrapper: src/js/analytics/firebase-analytics.js");
|
|
2781
|
-
}
|
|
2782
|
-
|
|
2783
|
-
if (fs.existsSync(legacyAnalyticsDir) && fs.readdirSync(legacyAnalyticsDir).length === 0) {
|
|
2784
|
-
fs.rmdirSync(legacyAnalyticsDir);
|
|
2785
|
-
}
|
|
2786
|
-
|
|
2787
|
-
return analyticsFile;
|
|
2788
|
-
};
|
|
2789
|
-
|
|
2790
|
-
const syncFirebaseAnalyticsPackages = () => {
|
|
2791
|
-
const analyticsConfig = getAnalyticsConfig();
|
|
2792
|
-
|
|
2793
|
-
if (analyticsConfig.enabled) {
|
|
2794
|
-
if (!isPackageAvailable("@capacitor-firebase/analytics") || !isPackageAvailable("firebase")) {
|
|
2795
|
-
runNpmCommand("npm install @capacitor-firebase/analytics firebase");
|
|
2796
|
-
} else {
|
|
2797
|
-
console.log("ℹ️ Firebase Analytics packages already installed.");
|
|
2798
|
-
}
|
|
2799
|
-
|
|
2800
|
-
ensureFirebaseAnalyticsWrapper(true);
|
|
2801
|
-
return;
|
|
2802
|
-
}
|
|
2803
|
-
|
|
2804
|
-
const analyticsFile = ensureFirebaseAnalyticsWrapper(false);
|
|
2805
|
-
|
|
2806
|
-
if (isPackageAvailable("@capacitor-firebase/analytics")) {
|
|
2807
|
-
runNpmCommand("npm uninstall @capacitor-firebase/analytics");
|
|
2808
|
-
} else {
|
|
2809
|
-
console.log("ℹ️ @capacitor-firebase/analytics is not installed.");
|
|
2810
|
-
}
|
|
2811
|
-
|
|
2812
|
-
if (isPackageAvailable("firebase")) {
|
|
2813
|
-
if (sourceImportsPackage("firebase", analyticsFile)) {
|
|
2814
|
-
console.log("ℹ️ Keeping firebase package because other source files import it.");
|
|
2815
|
-
} else {
|
|
2816
|
-
runNpmCommand("npm uninstall firebase");
|
|
2817
|
-
}
|
|
2818
|
-
}
|
|
2819
|
-
};
|
|
2820
|
-
|
|
2821
|
-
const syncFirebaseAnalyticsPodfile = () => {
|
|
2822
|
-
const podfilePath = path.join(process.cwd(), "ios", "App", "Podfile");
|
|
2823
|
-
if (!fs.existsSync(podfilePath)) return;
|
|
2824
|
-
|
|
2825
|
-
const { iosEnabled } = getAnalyticsConfig();
|
|
2826
|
-
const basePodLine = " pod 'CapacitorFirebaseAnalytics', :path => '../../node_modules/@capacitor-firebase/analytics'";
|
|
2827
|
-
const analyticsPodLine = " pod 'CapacitorFirebaseAnalytics/Analytics', :path => '../../node_modules/@capacitor-firebase/analytics'";
|
|
2828
|
-
|
|
2829
|
-
let content = fs.readFileSync(podfilePath, "utf8");
|
|
2830
|
-
let nextContent = content;
|
|
2831
|
-
|
|
2832
|
-
if (iosEnabled) {
|
|
2833
|
-
if (!nextContent.includes(basePodLine)) {
|
|
2834
|
-
nextContent = nextContent.replace(
|
|
2835
|
-
/(pod 'CapacitorCommunitySafeArea'[^\n]*\r?\n)/,
|
|
2836
|
-
`$1${basePodLine}\n`
|
|
2837
|
-
);
|
|
2838
|
-
}
|
|
2839
|
-
|
|
2840
|
-
if (!nextContent.includes(analyticsPodLine)) {
|
|
2841
|
-
nextContent = nextContent.replace(
|
|
2842
|
-
/(# Add your Pods here\r?\n)/,
|
|
2843
|
-
`$1${analyticsPodLine}\n`
|
|
2844
|
-
);
|
|
2845
|
-
}
|
|
2846
|
-
} else {
|
|
2847
|
-
nextContent = nextContent
|
|
2848
|
-
.split(/\r?\n/)
|
|
2849
|
-
.filter(line => !line.includes("CapacitorFirebaseAnalytics"))
|
|
2850
|
-
.join("\n");
|
|
2851
|
-
}
|
|
2852
|
-
|
|
2853
|
-
if (nextContent !== content) {
|
|
2854
|
-
fs.writeFileSync(podfilePath, nextContent, "utf8");
|
|
2855
|
-
console.log(`✅ iOS Firebase Analytics Podfile entries ${iosEnabled ? "enabled" : "removed"}.`);
|
|
2682
|
+
const syncSystemBarsSafeAreaMigration = () => {
|
|
2683
|
+
if (isPackageAvailable("@capacitor-community/safe-area")) {
|
|
2684
|
+
runNpmCommand("npm uninstall @capacitor-community/safe-area");
|
|
2856
2685
|
} else {
|
|
2857
|
-
console.log(
|
|
2858
|
-
}
|
|
2859
|
-
};
|
|
2860
|
-
|
|
2861
|
-
const ensureImportOrRequire = (content, moduleName, esmLine, cjsLine) => {
|
|
2862
|
-
const escaped = moduleName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2863
|
-
if (new RegExp(`from\\s*['"]${escaped}['"]|require\\s*\\(\\s*['"]${escaped}['"]\\s*\\)`).test(content)) {
|
|
2864
|
-
return content;
|
|
2865
|
-
}
|
|
2866
|
-
|
|
2867
|
-
const isCommonJs = /module\.exports|require\s*\(/.test(content);
|
|
2868
|
-
const line = isCommonJs ? cjsLine : esmLine;
|
|
2869
|
-
|
|
2870
|
-
return `${line}\n${content}`;
|
|
2871
|
-
};
|
|
2872
|
-
|
|
2873
|
-
const ensureViteDefineEntry = (viteContent, key, valueExpression) => {
|
|
2874
|
-
const entry = ` '${key}': JSON.stringify(${valueExpression}),`;
|
|
2875
|
-
|
|
2876
|
-
if (viteContent.includes(`'${key}'`) || viteContent.includes(`"${key}"`)) {
|
|
2877
|
-
return viteContent;
|
|
2878
|
-
}
|
|
2879
|
-
|
|
2880
|
-
if (/define\s*:\s*{/.test(viteContent)) {
|
|
2881
|
-
return viteContent.replace(/define\s*:\s*{\s*/, match => `${match}\n${entry}\n`);
|
|
2882
|
-
}
|
|
2883
|
-
|
|
2884
|
-
const defineBlock = ` define: {
|
|
2885
|
-
'${key}': JSON.stringify(${valueExpression}),
|
|
2886
|
-
},`;
|
|
2887
|
-
|
|
2888
|
-
if (/\n\s*publicDir\s*:\s*[^,\n]+,?/.test(viteContent)) {
|
|
2889
|
-
return viteContent.replace(
|
|
2890
|
-
/(\n\s*publicDir\s*:\s*[^,\n]+,?)/,
|
|
2891
|
-
`$1\n${defineBlock}`
|
|
2892
|
-
);
|
|
2686
|
+
console.log("ℹ️ @capacitor-community/safe-area is not installed.");
|
|
2893
2687
|
}
|
|
2894
2688
|
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
`$1\n${defineBlock}`
|
|
2898
|
-
);
|
|
2899
|
-
};
|
|
2900
|
-
|
|
2901
|
-
const ensurePrivacyAndAnalyticsViteConfig = () => {
|
|
2902
|
-
const viteConfigPath = getViteConfigPath();
|
|
2903
|
-
|
|
2904
|
-
if (!viteConfigPath) {
|
|
2905
|
-
console.warn("⚠️ No vite config found. Skipping privacy/analytics Vite sync.");
|
|
2689
|
+
if (!fs.existsSync(configPath)) {
|
|
2690
|
+
console.warn("⚠️ capacitor.config.json not found. Skipping SystemBars config sync.");
|
|
2906
2691
|
return;
|
|
2907
2692
|
}
|
|
2908
2693
|
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
viteContent = ensureImportOrRequire(
|
|
2913
|
-
viteContent,
|
|
2914
|
-
"fs",
|
|
2915
|
-
"import fs from 'fs';",
|
|
2916
|
-
"const fs = require('fs');"
|
|
2917
|
-
);
|
|
2918
|
-
|
|
2919
|
-
viteContent = ensureImportOrRequire(
|
|
2920
|
-
viteContent,
|
|
2921
|
-
"path",
|
|
2922
|
-
"import path from 'path';",
|
|
2923
|
-
"const path = require('path');"
|
|
2924
|
-
);
|
|
2925
|
-
|
|
2926
|
-
if (!/\bcapacitorConfig\b/.test(viteContent)) {
|
|
2927
|
-
viteContent = viteContent.replace(
|
|
2928
|
-
/(\r?\nexport\s+default|\r?\nmodule\.exports)/,
|
|
2929
|
-
`\nconst capacitorConfig = JSON.parse(fs.readFileSync(path.resolve(__dirname, './capacitor.config.json'), 'utf8'));\n$1`
|
|
2930
|
-
);
|
|
2931
|
-
}
|
|
2932
|
-
|
|
2933
|
-
if (!/\bAPP_UNIQUE_ID\b/.test(viteContent)) {
|
|
2934
|
-
viteContent = viteContent.replace(
|
|
2935
|
-
/(const capacitorConfig = JSON\.parse\(fs\.readFileSync\(path\.resolve\(__dirname,\s*['"]\.\/capacitor\.config\.json['"]\),\s*['"]utf8['"]\)\);\r?\n)/,
|
|
2936
|
-
`$1const APP_UNIQUE_ID = capacitorConfig.android?.APP_UNIQUE_ID ?? '';\n`
|
|
2937
|
-
);
|
|
2938
|
-
}
|
|
2939
|
-
|
|
2940
|
-
if (!/\bANDROID_ANALYTICS_ENABLED\b/.test(viteContent)) {
|
|
2941
|
-
viteContent = viteContent.replace(
|
|
2942
|
-
/(const APP_UNIQUE_ID = capacitorConfig\.android\?\.APP_UNIQUE_ID \?\? ['"]['"];\r?\n)/,
|
|
2943
|
-
`$1const ANDROID_ANALYTICS_ENABLED = capacitorConfig.android?.ANALYTICS_ENABLED ?? false;\n`
|
|
2944
|
-
);
|
|
2945
|
-
}
|
|
2946
|
-
|
|
2947
|
-
if (!/\bIOS_ANALYTICS_ENABLED\b/.test(viteContent)) {
|
|
2948
|
-
viteContent = viteContent.replace(
|
|
2949
|
-
/(const ANDROID_ANALYTICS_ENABLED = capacitorConfig\.android\?\.ANALYTICS_ENABLED \?\? false;\r?\n)/,
|
|
2950
|
-
`$1const IOS_ANALYTICS_ENABLED = capacitorConfig.ios?.ANALYTICS_ENABLED ?? false;\n`
|
|
2951
|
-
);
|
|
2952
|
-
}
|
|
2953
|
-
|
|
2954
|
-
if (!/\bIAP_DESIGN\b/.test(viteContent)) {
|
|
2955
|
-
viteContent = viteContent.replace(
|
|
2956
|
-
/(const IOS_ANALYTICS_ENABLED = capacitorConfig\.ios\?\.ANALYTICS_ENABLED \?\? false;\r?\n)/,
|
|
2957
|
-
`$1const IAP_DESIGN = capacitorConfig["IAP-Design"] ?? 'default';\n`
|
|
2958
|
-
);
|
|
2959
|
-
}
|
|
2960
|
-
|
|
2961
|
-
viteContent = viteContent
|
|
2962
|
-
.replace(
|
|
2963
|
-
/const ANDROID_ANALYTICS_ENABLED = capacitorConfig\.android\?\.ANALY[ST]ICS_ENABLED \?\? capacitorConfig\.android\?\.ANALYTICS_ENABLED \?\? false;/g,
|
|
2964
|
-
"const ANDROID_ANALYTICS_ENABLED = capacitorConfig.android?.ANALYTICS_ENABLED ?? false;"
|
|
2965
|
-
)
|
|
2966
|
-
.replace(
|
|
2967
|
-
/const IOS_ANALYTICS_ENABLED = capacitorConfig\.ios\?\.ANALY[ST]ICS_ENABLED \?\? capacitorConfig\.ios\?\.ANALYTICS_ENABLED \?\? false;/g,
|
|
2968
|
-
"const IOS_ANALYTICS_ENABLED = capacitorConfig.ios?.ANALYTICS_ENABLED ?? false;"
|
|
2969
|
-
);
|
|
2970
|
-
|
|
2971
|
-
viteContent = ensureViteDefineEntry(viteContent, "import.meta.env.VITE_APP_UNIQUE_ID", "APP_UNIQUE_ID");
|
|
2972
|
-
viteContent = ensureViteDefineEntry(viteContent, "import.meta.env.VITE_ANDROID_ANALYTICS_ENABLED", "ANDROID_ANALYTICS_ENABLED");
|
|
2973
|
-
viteContent = ensureViteDefineEntry(viteContent, "import.meta.env.VITE_IOS_ANALYTICS_ENABLED", "IOS_ANALYTICS_ENABLED");
|
|
2974
|
-
viteContent = ensureViteDefineEntry(viteContent, "import.meta.env.VITE_IAP_DESIGN", "IAP_DESIGN");
|
|
2694
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
2695
|
+
if (!config.plugins) config.plugins = {};
|
|
2696
|
+
if (!config.plugins.SystemBars) config.plugins.SystemBars = {};
|
|
2975
2697
|
|
|
2976
|
-
if (
|
|
2977
|
-
|
|
2978
|
-
|
|
2698
|
+
if (config.plugins.SystemBars.insetsHandling !== "css") {
|
|
2699
|
+
config.plugins.SystemBars.insetsHandling = "css";
|
|
2700
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
2701
|
+
console.log('✅ capacitor.config.json SystemBars.insetsHandling set to "css".');
|
|
2979
2702
|
} else {
|
|
2980
|
-
console.log(
|
|
2703
|
+
console.log('ℹ️ capacitor.config.json SystemBars.insetsHandling already "css".');
|
|
2981
2704
|
}
|
|
2982
2705
|
};
|
|
2983
2706
|
|
|
2984
|
-
const
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
};
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
const
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
}
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
}
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
}
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
const
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
},
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
);
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
const
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
}
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
}
|
|
3173
|
-
};
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
2707
|
+
const ensureFirebaseAnalyticsWrapper = (analyticsEnabled) => {
|
|
2708
|
+
const analyticsDir = getLatestIapDir();
|
|
2709
|
+
const legacyAnalyticsDir = path.join(process.cwd(), "src", "js", "analytics");
|
|
2710
|
+
const legacyAnalyticsFile = path.join(legacyAnalyticsDir, "firebase-analytics.js");
|
|
2711
|
+
|
|
2712
|
+
if (!analyticsDir) {
|
|
2713
|
+
console.warn("⚠️ No IAP-x.x folder found. Skipping Firebase analytics wrapper sync.");
|
|
2714
|
+
return null;
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
const analyticsFile = path.join(analyticsDir, "firebase-analytics.js");
|
|
2718
|
+
|
|
2719
|
+
if (!fs.existsSync(analyticsDir)) {
|
|
2720
|
+
fs.mkdirSync(analyticsDir, { recursive: true });
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
const activeWrapper = `import { Capacitor, registerPlugin } from '@capacitor/core';
|
|
2724
|
+
|
|
2725
|
+
const FirebaseAnalytics = registerPlugin('FirebaseAnalytics');
|
|
2726
|
+
|
|
2727
|
+
const isEnabledValue = (value) => value === true || value === 'true';
|
|
2728
|
+
|
|
2729
|
+
const canUseNativeAnalytics = () => {
|
|
2730
|
+
if (!Capacitor.isNativePlatform()) return false;
|
|
2731
|
+
|
|
2732
|
+
const platform = Capacitor.getPlatform();
|
|
2733
|
+
|
|
2734
|
+
if (platform === 'android') {
|
|
2735
|
+
return isEnabledValue(import.meta.env.VITE_ANDROID_ANALYTICS_ENABLED);
|
|
2736
|
+
}
|
|
2737
|
+
|
|
2738
|
+
if (platform === 'ios') {
|
|
2739
|
+
return isEnabledValue(import.meta.env.VITE_IOS_ANALYTICS_ENABLED);
|
|
2740
|
+
}
|
|
2741
|
+
|
|
2742
|
+
return false;
|
|
2743
|
+
};
|
|
2744
|
+
|
|
2745
|
+
const cleanParams = (params = {}) => {
|
|
2746
|
+
return Object.entries(params).reduce((result, [key, value]) => {
|
|
2747
|
+
if (value === undefined || value === null || value === '') return result;
|
|
2748
|
+
if (typeof value === 'number' && Number.isNaN(value)) return result;
|
|
2749
|
+
|
|
2750
|
+
result[key] = value;
|
|
2751
|
+
return result;
|
|
2752
|
+
}, {});
|
|
2753
|
+
};
|
|
2754
|
+
|
|
2755
|
+
const trackEvent = async (name, params = {}) => {
|
|
2756
|
+
if (!canUseNativeAnalytics()) return;
|
|
2757
|
+
|
|
2758
|
+
try {
|
|
2759
|
+
await FirebaseAnalytics.logEvent({
|
|
2760
|
+
name,
|
|
2761
|
+
params: cleanParams(params),
|
|
2762
|
+
});
|
|
2763
|
+
} catch (err) {
|
|
2764
|
+
console.warn(\`Firebase analytics event failed: \${name}\`, err);
|
|
2765
|
+
}
|
|
2766
|
+
};
|
|
2767
|
+
|
|
2768
|
+
export const trackSubscriptionScreenViewed = (params) => {
|
|
2769
|
+
trackEvent('subscription_screen_view', params);
|
|
2770
|
+
};
|
|
2771
|
+
|
|
2772
|
+
export const trackSubscriptionCheckoutStarted = (params) => {
|
|
2773
|
+
trackEvent('subscription_checkout_start', params);
|
|
2774
|
+
};
|
|
2775
|
+
|
|
2776
|
+
export const trackSubscriptionPurchased = (params) => {
|
|
2777
|
+
trackEvent('subscription_purchase', params);
|
|
2778
|
+
};
|
|
2779
|
+
|
|
2780
|
+
export const trackConsumablePurchased = (params) => {
|
|
2781
|
+
trackEvent('consumable_purchase', params);
|
|
2782
|
+
};
|
|
2783
|
+
`;
|
|
2784
|
+
|
|
2785
|
+
const noopWrapper = `const trackEvent = () => {};
|
|
2786
|
+
|
|
2787
|
+
export const trackSubscriptionScreenViewed = trackEvent;
|
|
2788
|
+
export const trackSubscriptionCheckoutStarted = trackEvent;
|
|
2789
|
+
export const trackSubscriptionPurchased = trackEvent;
|
|
2790
|
+
export const trackConsumablePurchased = trackEvent;
|
|
2791
|
+
`;
|
|
2792
|
+
|
|
2793
|
+
const nextContent = analyticsEnabled ? activeWrapper : noopWrapper;
|
|
2794
|
+
const currentContent = fs.existsSync(analyticsFile) ? fs.readFileSync(analyticsFile, "utf8") : "";
|
|
2795
|
+
|
|
2796
|
+
if (currentContent !== nextContent) {
|
|
2797
|
+
fs.writeFileSync(analyticsFile, nextContent, "utf8");
|
|
2798
|
+
console.log(`✅ Firebase analytics wrapper ${analyticsEnabled ? "enabled" : "disabled"}: ${path.relative(process.cwd(), analyticsFile)}`);
|
|
2799
|
+
} else {
|
|
2800
|
+
console.log(`ℹ️ Firebase analytics wrapper already ${analyticsEnabled ? "enabled" : "disabled"}.`);
|
|
2801
|
+
}
|
|
2802
|
+
|
|
2803
|
+
if (fs.existsSync(legacyAnalyticsFile)) {
|
|
2804
|
+
fs.unlinkSync(legacyAnalyticsFile);
|
|
2805
|
+
console.log("✅ Removed old Firebase analytics wrapper: src/js/analytics/firebase-analytics.js");
|
|
2806
|
+
}
|
|
2807
|
+
|
|
2808
|
+
if (fs.existsSync(legacyAnalyticsDir) && fs.readdirSync(legacyAnalyticsDir).length === 0) {
|
|
2809
|
+
fs.rmdirSync(legacyAnalyticsDir);
|
|
2810
|
+
}
|
|
2811
|
+
|
|
2812
|
+
return analyticsFile;
|
|
2813
|
+
};
|
|
2814
|
+
|
|
2815
|
+
const syncFirebaseAnalyticsPackages = () => {
|
|
2816
|
+
const analyticsConfig = getAnalyticsConfig();
|
|
2817
|
+
|
|
2818
|
+
if (analyticsConfig.enabled) {
|
|
2819
|
+
if (!isPackageAvailable("@capacitor-firebase/analytics") || !isPackageAvailable("firebase")) {
|
|
2820
|
+
runNpmCommand("npm install @capacitor-firebase/analytics firebase");
|
|
2821
|
+
} else {
|
|
2822
|
+
console.log("ℹ️ Firebase Analytics packages already installed.");
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2825
|
+
ensureFirebaseAnalyticsWrapper(true);
|
|
2826
|
+
return;
|
|
2827
|
+
}
|
|
2828
|
+
|
|
2829
|
+
const analyticsFile = ensureFirebaseAnalyticsWrapper(false);
|
|
2830
|
+
|
|
2831
|
+
if (isPackageAvailable("@capacitor-firebase/analytics")) {
|
|
2832
|
+
runNpmCommand("npm uninstall @capacitor-firebase/analytics");
|
|
2833
|
+
} else {
|
|
2834
|
+
console.log("ℹ️ @capacitor-firebase/analytics is not installed.");
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2837
|
+
if (isPackageAvailable("firebase")) {
|
|
2838
|
+
if (sourceImportsPackage("firebase", analyticsFile)) {
|
|
2839
|
+
console.log("ℹ️ Keeping firebase package because other source files import it.");
|
|
2840
|
+
} else {
|
|
2841
|
+
runNpmCommand("npm uninstall firebase");
|
|
2842
|
+
}
|
|
2843
|
+
}
|
|
2844
|
+
};
|
|
2845
|
+
|
|
2846
|
+
const syncFirebaseAnalyticsPodfile = () => {
|
|
2847
|
+
const podfilePath = path.join(process.cwd(), "ios", "App", "Podfile");
|
|
2848
|
+
if (!fs.existsSync(podfilePath)) return;
|
|
2849
|
+
|
|
2850
|
+
const { iosEnabled } = getAnalyticsConfig();
|
|
2851
|
+
const basePodLine = " pod 'CapacitorFirebaseAnalytics', :path => '../../node_modules/@capacitor-firebase/analytics'";
|
|
2852
|
+
const analyticsPodLine = " pod 'CapacitorFirebaseAnalytics/Analytics', :path => '../../node_modules/@capacitor-firebase/analytics'";
|
|
2853
|
+
|
|
2854
|
+
let content = fs.readFileSync(podfilePath, "utf8");
|
|
2855
|
+
let nextContent = content;
|
|
2856
|
+
|
|
2857
|
+
if (iosEnabled) {
|
|
2858
|
+
if (!nextContent.includes(basePodLine)) {
|
|
2859
|
+
nextContent = nextContent.replace(
|
|
2860
|
+
/(pod 'CapacitorCommunitySafeArea'[^\n]*\r?\n)/,
|
|
2861
|
+
`$1${basePodLine}\n`
|
|
2862
|
+
);
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2865
|
+
if (!nextContent.includes(analyticsPodLine)) {
|
|
2866
|
+
nextContent = nextContent.replace(
|
|
2867
|
+
/(# Add your Pods here\r?\n)/,
|
|
2868
|
+
`$1${analyticsPodLine}\n`
|
|
2869
|
+
);
|
|
2870
|
+
}
|
|
2871
|
+
} else {
|
|
2872
|
+
nextContent = nextContent
|
|
2873
|
+
.split(/\r?\n/)
|
|
2874
|
+
.filter(line => !line.includes("CapacitorFirebaseAnalytics"))
|
|
2875
|
+
.join("\n");
|
|
2876
|
+
}
|
|
2877
|
+
|
|
2878
|
+
if (nextContent !== content) {
|
|
2879
|
+
fs.writeFileSync(podfilePath, nextContent, "utf8");
|
|
2880
|
+
console.log(`✅ iOS Firebase Analytics Podfile entries ${iosEnabled ? "enabled" : "removed"}.`);
|
|
2881
|
+
} else {
|
|
2882
|
+
console.log(`ℹ️ iOS Firebase Analytics Podfile entries already ${iosEnabled ? "enabled" : "disabled"}.`);
|
|
2883
|
+
}
|
|
2884
|
+
};
|
|
2885
|
+
|
|
2886
|
+
const ensureImportOrRequire = (content, moduleName, esmLine, cjsLine) => {
|
|
2887
|
+
const escaped = moduleName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2888
|
+
if (new RegExp(`from\\s*['"]${escaped}['"]|require\\s*\\(\\s*['"]${escaped}['"]\\s*\\)`).test(content)) {
|
|
2889
|
+
return content;
|
|
2890
|
+
}
|
|
2891
|
+
|
|
2892
|
+
const isCommonJs = /module\.exports|require\s*\(/.test(content);
|
|
2893
|
+
const line = isCommonJs ? cjsLine : esmLine;
|
|
2894
|
+
|
|
2895
|
+
return `${line}\n${content}`;
|
|
2896
|
+
};
|
|
2897
|
+
|
|
2898
|
+
const ensureViteDefineEntry = (viteContent, key, valueExpression) => {
|
|
2899
|
+
const entry = ` '${key}': JSON.stringify(${valueExpression}),`;
|
|
2900
|
+
|
|
2901
|
+
if (viteContent.includes(`'${key}'`) || viteContent.includes(`"${key}"`)) {
|
|
2902
|
+
return viteContent;
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2905
|
+
if (/define\s*:\s*{/.test(viteContent)) {
|
|
2906
|
+
return viteContent.replace(/define\s*:\s*{\s*/, match => `${match}\n${entry}\n`);
|
|
2907
|
+
}
|
|
2908
|
+
|
|
2909
|
+
const defineBlock = ` define: {
|
|
2910
|
+
'${key}': JSON.stringify(${valueExpression}),
|
|
2911
|
+
},`;
|
|
2912
|
+
|
|
2913
|
+
if (/\n\s*publicDir\s*:\s*[^,\n]+,?/.test(viteContent)) {
|
|
2914
|
+
return viteContent.replace(
|
|
2915
|
+
/(\n\s*publicDir\s*:\s*[^,\n]+,?)/,
|
|
2916
|
+
`$1\n${defineBlock}`
|
|
2917
|
+
);
|
|
2918
|
+
}
|
|
2919
|
+
|
|
2920
|
+
return viteContent.replace(
|
|
2921
|
+
/(return\s+{)/,
|
|
2922
|
+
`$1\n${defineBlock}`
|
|
2923
|
+
);
|
|
2924
|
+
};
|
|
2925
|
+
|
|
2926
|
+
const ensurePrivacyAndAnalyticsViteConfig = () => {
|
|
2927
|
+
const viteConfigPath = getViteConfigPath();
|
|
2928
|
+
|
|
2929
|
+
if (!viteConfigPath) {
|
|
2930
|
+
console.warn("⚠️ No vite config found. Skipping privacy/analytics Vite sync.");
|
|
2931
|
+
return;
|
|
2932
|
+
}
|
|
2933
|
+
|
|
2934
|
+
let viteContent = fs.readFileSync(viteConfigPath, "utf8");
|
|
2935
|
+
const originalContent = viteContent;
|
|
2936
|
+
|
|
2937
|
+
viteContent = ensureImportOrRequire(
|
|
2938
|
+
viteContent,
|
|
2939
|
+
"fs",
|
|
2940
|
+
"import fs from 'fs';",
|
|
2941
|
+
"const fs = require('fs');"
|
|
2942
|
+
);
|
|
2943
|
+
|
|
2944
|
+
viteContent = ensureImportOrRequire(
|
|
2945
|
+
viteContent,
|
|
2946
|
+
"path",
|
|
2947
|
+
"import path from 'path';",
|
|
2948
|
+
"const path = require('path');"
|
|
2949
|
+
);
|
|
2950
|
+
|
|
2951
|
+
if (!/\bcapacitorConfig\b/.test(viteContent)) {
|
|
2952
|
+
viteContent = viteContent.replace(
|
|
2953
|
+
/(\r?\nexport\s+default|\r?\nmodule\.exports)/,
|
|
2954
|
+
`\nconst capacitorConfig = JSON.parse(fs.readFileSync(path.resolve(__dirname, './capacitor.config.json'), 'utf8'));\n$1`
|
|
2955
|
+
);
|
|
2956
|
+
}
|
|
2957
|
+
|
|
2958
|
+
if (!/\bAPP_UNIQUE_ID\b/.test(viteContent)) {
|
|
2959
|
+
viteContent = viteContent.replace(
|
|
2960
|
+
/(const capacitorConfig = JSON\.parse\(fs\.readFileSync\(path\.resolve\(__dirname,\s*['"]\.\/capacitor\.config\.json['"]\),\s*['"]utf8['"]\)\);\r?\n)/,
|
|
2961
|
+
`$1const APP_UNIQUE_ID = capacitorConfig.android?.APP_UNIQUE_ID ?? '';\n`
|
|
2962
|
+
);
|
|
2963
|
+
}
|
|
2964
|
+
|
|
2965
|
+
if (!/\bANDROID_ANALYTICS_ENABLED\b/.test(viteContent)) {
|
|
2966
|
+
viteContent = viteContent.replace(
|
|
2967
|
+
/(const APP_UNIQUE_ID = capacitorConfig\.android\?\.APP_UNIQUE_ID \?\? ['"]['"];\r?\n)/,
|
|
2968
|
+
`$1const ANDROID_ANALYTICS_ENABLED = capacitorConfig.android?.ANALYTICS_ENABLED ?? false;\n`
|
|
2969
|
+
);
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
if (!/\bIOS_ANALYTICS_ENABLED\b/.test(viteContent)) {
|
|
2973
|
+
viteContent = viteContent.replace(
|
|
2974
|
+
/(const ANDROID_ANALYTICS_ENABLED = capacitorConfig\.android\?\.ANALYTICS_ENABLED \?\? false;\r?\n)/,
|
|
2975
|
+
`$1const IOS_ANALYTICS_ENABLED = capacitorConfig.ios?.ANALYTICS_ENABLED ?? false;\n`
|
|
2976
|
+
);
|
|
2977
|
+
}
|
|
2978
|
+
|
|
2979
|
+
if (!/\bIAP_DESIGN\b/.test(viteContent)) {
|
|
2980
|
+
viteContent = viteContent.replace(
|
|
2981
|
+
/(const IOS_ANALYTICS_ENABLED = capacitorConfig\.ios\?\.ANALYTICS_ENABLED \?\? false;\r?\n)/,
|
|
2982
|
+
`$1const IAP_DESIGN = capacitorConfig["IAP-Design"] ?? 'default';\n`
|
|
2983
|
+
);
|
|
2984
|
+
}
|
|
2985
|
+
|
|
2986
|
+
viteContent = viteContent
|
|
2987
|
+
.replace(
|
|
2988
|
+
/const ANDROID_ANALYTICS_ENABLED = capacitorConfig\.android\?\.ANALY[ST]ICS_ENABLED \?\? capacitorConfig\.android\?\.ANALYTICS_ENABLED \?\? false;/g,
|
|
2989
|
+
"const ANDROID_ANALYTICS_ENABLED = capacitorConfig.android?.ANALYTICS_ENABLED ?? false;"
|
|
2990
|
+
)
|
|
2991
|
+
.replace(
|
|
2992
|
+
/const IOS_ANALYTICS_ENABLED = capacitorConfig\.ios\?\.ANALY[ST]ICS_ENABLED \?\? capacitorConfig\.ios\?\.ANALYTICS_ENABLED \?\? false;/g,
|
|
2993
|
+
"const IOS_ANALYTICS_ENABLED = capacitorConfig.ios?.ANALYTICS_ENABLED ?? false;"
|
|
2994
|
+
);
|
|
2995
|
+
|
|
2996
|
+
viteContent = ensureViteDefineEntry(viteContent, "import.meta.env.VITE_APP_UNIQUE_ID", "APP_UNIQUE_ID");
|
|
2997
|
+
viteContent = ensureViteDefineEntry(viteContent, "import.meta.env.VITE_ANDROID_ANALYTICS_ENABLED", "ANDROID_ANALYTICS_ENABLED");
|
|
2998
|
+
viteContent = ensureViteDefineEntry(viteContent, "import.meta.env.VITE_IOS_ANALYTICS_ENABLED", "IOS_ANALYTICS_ENABLED");
|
|
2999
|
+
viteContent = ensureViteDefineEntry(viteContent, "import.meta.env.VITE_IAP_DESIGN", "IAP_DESIGN");
|
|
3000
|
+
|
|
3001
|
+
if (viteContent !== originalContent) {
|
|
3002
|
+
fs.writeFileSync(viteConfigPath, viteContent, "utf8");
|
|
3003
|
+
console.log("✅ vite.config.(m)js privacy/analytics settings synced.");
|
|
3004
|
+
} else {
|
|
3005
|
+
console.log("ℹ️ vite.config.(m)js privacy/analytics settings already synced.");
|
|
3006
|
+
}
|
|
3007
|
+
};
|
|
3008
|
+
|
|
3009
|
+
const syncFirebaseAnalyticsSetup = () => {
|
|
3010
|
+
syncFirebaseAnalyticsPackages();
|
|
3011
|
+
syncFirebaseAnalyticsPodfile();
|
|
3012
|
+
ensurePrivacyAndAnalyticsViteConfig();
|
|
3013
|
+
};
|
|
3014
|
+
|
|
3015
|
+
const getAdmobIapConfigPath = () => {
|
|
3016
|
+
const possiblePaths = [
|
|
3017
|
+
path.join(process.cwd(), 'src', 'js', 'Ads', 'admob-ad-configuration-nextgen.json'),
|
|
3018
|
+
path.join(process.cwd(), 'src', 'js', 'Ads', 'admob-ad-configuration.json')
|
|
3019
|
+
];
|
|
3020
|
+
|
|
3021
|
+
return possiblePaths.find(fileExists);
|
|
3022
|
+
};
|
|
3023
|
+
|
|
3024
|
+
const getAdmobIapConfig = () => {
|
|
3025
|
+
const admobIapConfigPath = getAdmobIapConfigPath();
|
|
3026
|
+
|
|
3027
|
+
if (!admobIapConfigPath) {
|
|
3028
|
+
console.warn("⚠️ No AdMob configuration JSON found. Skipping RevenueCat IAP package sync.");
|
|
3029
|
+
return null;
|
|
3030
|
+
}
|
|
3031
|
+
|
|
3032
|
+
try {
|
|
3033
|
+
return JSON.parse(fs.readFileSync(admobIapConfigPath, "utf8"));
|
|
3034
|
+
} catch (err) {
|
|
3035
|
+
console.error(`❌ Failed to read ${path.relative(process.cwd(), admobIapConfigPath)}`, err);
|
|
3036
|
+
process.exit(1);
|
|
3037
|
+
}
|
|
3038
|
+
};
|
|
3039
|
+
|
|
3040
|
+
const isAnyIapStoreEnabled = (iapConfig) => {
|
|
3041
|
+
return Boolean(
|
|
3042
|
+
iapConfig?.playstore === true ||
|
|
3043
|
+
iapConfig?.samsung === true ||
|
|
3044
|
+
iapConfig?.amazon === true ||
|
|
3045
|
+
iapConfig?.ios === true
|
|
3046
|
+
);
|
|
3047
|
+
};
|
|
3048
|
+
|
|
3049
|
+
const ensureIapDesignInCapacitorConfig = (iapConfig) => {
|
|
3050
|
+
if (!isAnyIapStoreEnabled(iapConfig)) return;
|
|
3051
|
+
|
|
3052
|
+
if (!fs.existsSync(configPath)) {
|
|
3053
|
+
console.warn("⚠️ capacitor.config.json not found. Skipping IAP-Design sync.");
|
|
3054
|
+
return;
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
3058
|
+
|
|
3059
|
+
if (Object.prototype.hasOwnProperty.call(config, "IAP-Design")) {
|
|
3060
|
+
console.log("ℹ️ capacitor.config.json IAP-Design already configured.");
|
|
3061
|
+
return;
|
|
3062
|
+
}
|
|
3063
|
+
|
|
3064
|
+
config["IAP-Design"] = "default";
|
|
3065
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
3066
|
+
console.log('✅ Added "IAP-Design": "default" to capacitor.config.json.');
|
|
3067
|
+
};
|
|
3068
|
+
|
|
3069
|
+
const getCurrentStoreId = () => {
|
|
3070
|
+
const envStoreId = Number(process.env.VITE_STORE_ID);
|
|
3071
|
+
if (Number.isInteger(envStoreId) && envStoreId > 0) return envStoreId;
|
|
3072
|
+
|
|
3073
|
+
const viteConfigPath = getViteConfigPath();
|
|
3074
|
+
if (!viteConfigPath) return 1;
|
|
3075
|
+
|
|
3076
|
+
const viteConfigContent = fs.readFileSync(viteConfigPath, "utf8");
|
|
3077
|
+
const commonAliasMatch = viteConfigContent.match(/['"]@common['"]:\s*path\.resolve\(__dirname,\s*['"]([^'"]+)['"]\)/);
|
|
3078
|
+
|
|
3079
|
+
if (!commonAliasMatch) return 1;
|
|
3080
|
+
|
|
3081
|
+
const commonFilePath = path.resolve(path.dirname(viteConfigPath), commonAliasMatch[1]);
|
|
3082
|
+
if (!fs.existsSync(commonFilePath)) return 1;
|
|
3083
|
+
|
|
3084
|
+
const commonFileContent = fs.readFileSync(commonFilePath, "utf8");
|
|
3085
|
+
const storeIdMatch = commonFileContent.match(/export\s+let\s+_storeid\s*=\s*import\.meta\.env\.VITE_STORE_ID\s*\|\|\s*(\d+)\s*;/);
|
|
3086
|
+
|
|
3087
|
+
return storeIdMatch ? Number(storeIdMatch[1]) : 1;
|
|
3088
|
+
};
|
|
3089
|
+
|
|
3090
|
+
const getRevenueCatStoreState = (iapConfig) => {
|
|
3091
|
+
const storeId = getCurrentStoreId();
|
|
3092
|
+
const configuration = iapConfig.configuration || {};
|
|
3093
|
+
const storeMap = {
|
|
3094
|
+
1: {
|
|
3095
|
+
name: "PlayStore",
|
|
3096
|
+
enabled: iapConfig.playstore === true,
|
|
3097
|
+
apiKeyName: "IAP.configuration.playstore",
|
|
3098
|
+
apiKey: configuration.playstore,
|
|
3099
|
+
usesGoogleBilling: true
|
|
3100
|
+
},
|
|
3101
|
+
6: {
|
|
3102
|
+
name: "iOSStore",
|
|
3103
|
+
enabled: iapConfig.ios === true,
|
|
3104
|
+
apiKeyName: "IAP.configuration.ios",
|
|
3105
|
+
apiKey: configuration.ios,
|
|
3106
|
+
usesGoogleBilling: false
|
|
3107
|
+
},
|
|
3108
|
+
7: {
|
|
3109
|
+
name: "AmazonStore",
|
|
3110
|
+
enabled: iapConfig.amazon === true,
|
|
3111
|
+
apiKeyName: "IAP.configuration.amazon",
|
|
3112
|
+
apiKey: configuration.amazon,
|
|
3113
|
+
usesGoogleBilling: false
|
|
3114
|
+
}
|
|
3115
|
+
};
|
|
3116
|
+
|
|
3117
|
+
return {
|
|
3118
|
+
storeId,
|
|
3119
|
+
store: storeMap[storeId] || null
|
|
3120
|
+
};
|
|
3121
|
+
};
|
|
3122
|
+
|
|
3123
|
+
const ensureAndroidPermission = (permission, enabled) => {
|
|
3124
|
+
if (!fs.existsSync(androidManifestPath)) return false;
|
|
3125
|
+
|
|
3126
|
+
let manifestContent = fs.readFileSync(androidManifestPath, "utf8");
|
|
3127
|
+
const permissionLine = ` <uses-permission android:name="${permission}" />`;
|
|
3128
|
+
const permissionRegex = new RegExp(`^\\s*<uses-permission\\s+android:name="${permission.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}"\\s*/?>\\s*\\r?\\n?`, "m");
|
|
3129
|
+
|
|
3130
|
+
if (enabled) {
|
|
3131
|
+
if (permissionRegex.test(manifestContent)) return false;
|
|
3132
|
+
|
|
3133
|
+
manifestContent = manifestContent.replace(
|
|
3134
|
+
/<\/manifest>\s*$/,
|
|
3135
|
+
`${permissionLine}\n</manifest>`
|
|
3136
|
+
);
|
|
3137
|
+
fs.writeFileSync(androidManifestPath, manifestContent, "utf8");
|
|
3138
|
+
console.log(`✅ Added Android permission: ${permission}`);
|
|
3139
|
+
return true;
|
|
3140
|
+
}
|
|
3141
|
+
|
|
3142
|
+
if (!permissionRegex.test(manifestContent)) return false;
|
|
3143
|
+
|
|
3144
|
+
manifestContent = manifestContent.replace(permissionRegex, "");
|
|
3145
|
+
fs.writeFileSync(androidManifestPath, manifestContent, "utf8");
|
|
3146
|
+
console.log(`✅ Removed Android permission: ${permission}`);
|
|
3147
|
+
return true;
|
|
3148
|
+
};
|
|
3149
|
+
|
|
3150
|
+
const syncRevenueCatIapSetup = () => {
|
|
3151
|
+
const admobConfig = getAdmobIapConfig();
|
|
3152
|
+
const iapConfig = admobConfig?.IAP;
|
|
3153
|
+
|
|
3154
|
+
if (!iapConfig) {
|
|
3155
|
+
console.log("ℹ️ IAP configuration not found. Skipping RevenueCat package sync.");
|
|
3156
|
+
return;
|
|
3157
|
+
}
|
|
3158
|
+
|
|
3159
|
+
ensureIapDesignInCapacitorConfig(iapConfig);
|
|
3160
|
+
|
|
3161
|
+
const revenueCatEnabled =
|
|
3162
|
+
iapConfig.playstore === true ||
|
|
3163
|
+
iapConfig.ios === true ||
|
|
3164
|
+
iapConfig.amazon === true;
|
|
3165
|
+
const { storeId, store } = getRevenueCatStoreState(iapConfig);
|
|
3166
|
+
const revenueCatEnabledForCurrentStore = store?.enabled === true;
|
|
3167
|
+
|
|
3168
|
+
if (revenueCatEnabledForCurrentStore && !store.apiKey) {
|
|
3169
|
+
console.error(`❌ RevenueCat IAP is enabled for ${store.name} but ${store.apiKeyName} is missing.`);
|
|
3170
|
+
process.exit(1);
|
|
3171
|
+
}
|
|
3172
|
+
|
|
3173
|
+
let packageChanged = false;
|
|
3174
|
+
|
|
3175
|
+
if (revenueCatEnabledForCurrentStore) {
|
|
3176
|
+
if (!isPackageAvailable("@revenuecat/purchases-capacitor")) {
|
|
3177
|
+
runNpmCommand("npm install @revenuecat/purchases-capacitor");
|
|
3178
|
+
packageChanged = true;
|
|
3179
|
+
} else {
|
|
3180
|
+
console.log(`ℹ️ RevenueCat package already installed for ${store.name}.`);
|
|
3181
|
+
}
|
|
3182
|
+
} else if (isPackageAvailable("@revenuecat/purchases-capacitor")) {
|
|
3183
|
+
runNpmCommand("npm uninstall @revenuecat/purchases-capacitor");
|
|
3184
|
+
packageChanged = true;
|
|
3185
|
+
} else {
|
|
3186
|
+
console.log(`ℹ️ RevenueCat package is not required for store id ${storeId}.`);
|
|
3187
|
+
}
|
|
3188
|
+
|
|
3189
|
+
ensureAndroidPermission("com.android.vending.BILLING", store?.usesGoogleBilling === true && revenueCatEnabledForCurrentStore);
|
|
3190
|
+
|
|
3191
|
+
if (iapConfig.samsung === true && revenueCatEnabled) {
|
|
3192
|
+
console.warn("⚠️ Samsung IAP uses cordova-plugin-samsungiap; PlayStore/Amazon/iOS use RevenueCat.");
|
|
3193
|
+
}
|
|
3194
|
+
|
|
3195
|
+
if (packageChanged) {
|
|
3196
|
+
runNpmCommand("npx cap sync");
|
|
3197
|
+
}
|
|
3198
|
+
};
|
|
3199
|
+
|
|
3200
|
+
|
|
3201
|
+
|
|
3202
|
+
|
|
3203
|
+
|
|
3204
|
+
|
|
3205
|
+
|
|
3181
3206
|
|
|
3182
3207
|
|
|
3183
3208
|
const compareVersion = (v1, v2) => {
|
|
@@ -3344,17 +3369,18 @@ ensureGitignoreEntry('buildCodeplay/');
|
|
|
3344
3369
|
|
|
3345
3370
|
|
|
3346
3371
|
// Run the validation
|
|
3347
|
-
(async () => {
|
|
3372
|
+
(async () => {
|
|
3348
3373
|
|
|
3349
3374
|
await loadPluginVersions(); // 🔥 NEW
|
|
3350
3375
|
|
|
3376
|
+
syncSystemBarsSafeAreaMigration();
|
|
3351
3377
|
await checkPlugins();
|
|
3352
3378
|
syncRevenueCatIapSetup();
|
|
3353
3379
|
syncFirebaseAnalyticsSetup();
|
|
3354
|
-
checkAndupdateDropInViteConfig();
|
|
3355
|
-
syncAdmobAliasInViteConfig();
|
|
3356
|
-
checkAdmobConfigurationProperty()
|
|
3357
|
-
})();
|
|
3380
|
+
checkAndupdateDropInViteConfig();
|
|
3381
|
+
syncAdmobAliasInViteConfig();
|
|
3382
|
+
checkAdmobConfigurationProperty()
|
|
3383
|
+
})();
|
|
3358
3384
|
|
|
3359
3385
|
|
|
3360
3386
|
// ======================================================
|
|
@@ -3444,45 +3470,45 @@ const filePath = path.join(
|
|
|
3444
3470
|
"../node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java"
|
|
3445
3471
|
);
|
|
3446
3472
|
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3473
|
+
const SYSTEM_BARS_PATCH_MARKER = "CODEPLAY_KEYBOARD_INSET_FIX";
|
|
3474
|
+
|
|
3475
|
+
function getSystemBarsPatchedBlock(originalBlock, content) {
|
|
3476
|
+
const isCapacitor842OrNewer = content.includes("private String insetsHandling = INSETS_HANDLING_CSS;");
|
|
3477
|
+
const safeAreaCondition = isCapacitor842OrNewer
|
|
3478
|
+
? "INSETS_HANDLING_CSS.equals(insetsHandling)"
|
|
3479
|
+
: "Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && hasViewportCover && insetHandlingEnabled";
|
|
3480
|
+
|
|
3481
|
+
return `if (shouldPassthroughInsets) {
|
|
3482
|
+
/* ${SYSTEM_BARS_PATCH_MARKER}
|
|
3483
|
+
${originalBlock.split("\n").map(line => " " + line).join("\n")}
|
|
3484
|
+
*/
|
|
3485
|
+
|
|
3486
|
+
// Codeplay fix: avoid adding IME height as WebView parent padding.
|
|
3487
|
+
v.setPadding(0, 0, 0, 0);
|
|
3451
3488
|
|
|
3452
|
-
if (
|
|
3489
|
+
if (${safeAreaCondition}) {
|
|
3453
3490
|
Insets safeAreaInsets = calcSafeAreaInsets(insets);
|
|
3454
3491
|
injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
|
|
3455
3492
|
}
|
|
3456
3493
|
|
|
3457
|
-
return
|
|
3458
|
-
.setInsets(
|
|
3459
|
-
WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(),
|
|
3460
|
-
Insets.of(
|
|
3461
|
-
systemBarsInsets.left,
|
|
3462
|
-
systemBarsInsets.top,
|
|
3463
|
-
systemBarsInsets.right,
|
|
3464
|
-
getBottomInset(systemBarsInsets, keyboardVisible)
|
|
3465
|
-
)
|
|
3466
|
-
)
|
|
3467
|
-
.build();
|
|
3494
|
+
return insets; // WebView handles keyboard and safe-area sizing.
|
|
3468
3495
|
}`;
|
|
3496
|
+
}
|
|
3469
3497
|
|
|
3470
|
-
|
|
3471
|
-
const
|
|
3472
|
-
|
|
3473
|
-
${OLD_BLOCK.split("\n").map(line => " " + line).join("\n")}
|
|
3474
|
-
*/
|
|
3475
|
-
|
|
3476
|
-
// ✅ NEW LOGIC (CUSTOM FIX)
|
|
3477
|
-
v.setPadding(0, 0, 0, 0);
|
|
3498
|
+
function findShouldPassthroughInsetsBlock(content) {
|
|
3499
|
+
const start = content.indexOf(" if (shouldPassthroughInsets) {");
|
|
3500
|
+
if (start === -1) return null;
|
|
3478
3501
|
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
}
|
|
3502
|
+
const endMarker = "\n\n if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)";
|
|
3503
|
+
const end = content.indexOf(endMarker, start);
|
|
3504
|
+
if (end === -1) return null;
|
|
3483
3505
|
|
|
3484
|
-
|
|
3485
|
-
|
|
3506
|
+
return {
|
|
3507
|
+
start,
|
|
3508
|
+
end,
|
|
3509
|
+
text: content.slice(start, end)
|
|
3510
|
+
};
|
|
3511
|
+
}
|
|
3486
3512
|
|
|
3487
3513
|
// 🚨 ERROR MESSAGE
|
|
3488
3514
|
const ERROR_MSG = `
|
|
@@ -3511,30 +3537,38 @@ function patchFile() {
|
|
|
3511
3537
|
process.exit(1);
|
|
3512
3538
|
}
|
|
3513
3539
|
|
|
3540
|
+
const capacitorConfig = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
3541
|
+
if (capacitorConfig.plugins?.SystemBars?.insetsHandling === "disable") {
|
|
3542
|
+
console.log('ℹ️ SystemBars.insetsHandling is "disable"; skipping SystemBars.java keyboard inset patch.');
|
|
3543
|
+
return;
|
|
3544
|
+
}
|
|
3545
|
+
|
|
3514
3546
|
let content = fs.readFileSync(filePath, "utf8");
|
|
3515
3547
|
|
|
3516
3548
|
// ✅ Already patched?
|
|
3517
|
-
if (content.includes("🔴 ORIGINAL CODE (COMMENTED FOR SAFETY)")) {
|
|
3549
|
+
if (content.includes(SYSTEM_BARS_PATCH_MARKER) || content.includes("🔴 ORIGINAL CODE (COMMENTED FOR SAFETY)")) {
|
|
3518
3550
|
console.log("✅ Already SystemBars.java patched. Skipping...");
|
|
3519
3551
|
return;
|
|
3520
3552
|
}
|
|
3521
3553
|
|
|
3522
|
-
|
|
3523
|
-
if (!
|
|
3554
|
+
const block = findShouldPassthroughInsetsBlock(content);
|
|
3555
|
+
if (!block) {
|
|
3524
3556
|
console.error(ERROR_MSG);
|
|
3525
3557
|
process.exit(1);
|
|
3526
3558
|
}
|
|
3527
3559
|
|
|
3528
3560
|
// 🔁 Replace
|
|
3529
|
-
const updated =
|
|
3561
|
+
const updated =
|
|
3562
|
+
content.slice(0, block.start) +
|
|
3563
|
+
getSystemBarsPatchedBlock(block.text, content) +
|
|
3564
|
+
content.slice(block.end);
|
|
3530
3565
|
|
|
3531
3566
|
fs.writeFileSync(filePath, updated, "utf8");
|
|
3532
3567
|
|
|
3533
|
-
console.log("✅ SystemBars.java patched
|
|
3568
|
+
console.log("✅ SystemBars.java patched with Codeplay keyboard inset fix!");
|
|
3534
3569
|
}
|
|
3535
3570
|
|
|
3536
3571
|
//patchFile();
|
|
3537
|
-
//console.log("SystemBars.java Not Patched, due to upgrade from @capacitor/android:8.4.2. We need to validate if any problem related to the systembar issue. Note: For this we have disable the 'patchFile()' method");
|
|
3538
3572
|
|
|
3539
3573
|
//################################## SystemBars.java update for "@capacitor/android": "^8.3.0" plugin END ###############################
|
|
3540
3574
|
|