codeplay-common 1.8.7 → 1.8.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.
@@ -1,722 +1,798 @@
1
- import { existsSync, readFileSync, readdirSync, promises, constants, writeFileSync, unlinkSync, mkdirSync, renameSync } from 'fs';
2
- import { join, resolve } from 'path';
3
- import { execSync } from 'child_process';
4
- import { createInterface } from 'readline';
5
-
6
- import { fileURLToPath } from 'url';
7
- import { dirname } from 'path';
8
-
9
- // Define a mapping between store IDs and store names
10
- const storeNames = {
11
- "1": "PlayStore",
12
- "2": "SamsungStore",
13
- "7": "AmazonStore"
14
- };
15
-
16
- let _appPackageId;
17
-
18
- let isAdmobFound = false;
19
-
20
- const amazonMinSdkVersion=23;
21
-
22
- const androidManifestPath = join("android", "app", "src", "main", "AndroidManifest.xml");
23
-
24
-
25
-
26
- const __filename = fileURLToPath(import.meta.url);
27
- const __dirname = dirname(__filename);
28
-
29
- function fileExists(filePath) {
30
- return existsSync(filePath);
31
- }
32
-
33
-
34
- const capacitorConfigPath = join(process.cwd(), 'capacitor.config.json');
35
-
36
- function getAdMobConfig() {
37
- if (!fileExists(capacitorConfigPath)) {
38
- throw new Error('❌ capacitor.config.json not found. Ensure this is a Capacitor project.');
39
- }
40
-
41
- const config = JSON.parse(readFileSync(capacitorConfigPath, 'utf8'));
42
- const admobConfig = config.plugins?.AdMob;
43
-
44
- _appPackageId=config.appId;
45
-
46
- if (!admobConfig) {
47
- throw new Error('❌ AdMob configuration is missing in capacitor.config.json.');
48
- }
49
-
50
- // Default to true if ADMOB_ENABLED is not specified
51
- const isEnabled = admobConfig.ADMOB_ENABLED !== false;
52
-
53
- if (!isEnabled) {
54
- return { ADMOB_ENABLED: false }; // Skip further validation
55
- }
56
-
57
- if (!admobConfig.APP_ID_ANDROID || !admobConfig.APP_ID_IOS) {
58
- throw new Error(' ❌ AdMob configuration is incomplete. Ensure APP_ID_ANDROID and APP_ID_IOS are defined.');
59
- }
60
-
61
- return {
62
- ADMOB_ENABLED: true,
63
- APP_ID_ANDROID: admobConfig.APP_ID_ANDROID,
64
- APP_ID_IOS: admobConfig.APP_ID_IOS,
65
- USE_LITE_ADS: admobConfig.USE_LITE_ADS === "lite",
66
- };
67
- }
68
-
69
-
70
-
71
- const _capacitorConfig = getAdMobConfig();
72
-
73
- const _isADMOB_ENABLED=_capacitorConfig.ADMOB_ENABLED;
74
-
75
- // Proceed only if ADMOB_ENABLED is true
76
- //if (_capacitorConfig.ADMOB_ENABLED)
77
-
78
-
79
- const admobConfigPath = join('src', 'js','Ads', 'admob-ad-configuration.json');
80
- let admobConfig;
81
-
82
- if (_isADMOB_ENABLED)
83
- {
84
- try
85
- {
86
- admobConfig = JSON.parse(readFileSync(admobConfigPath, 'utf8'));
87
- }
88
- catch (err)
89
- {
90
- console.error("❌ Failed to read admob-ad-configuration.json", err);
91
- process.exit(1);
92
- }
93
- }
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
- const checkCommonFileStoreId=()=>{
117
- const possibleConfigFiles = ['vite.config.mjs', 'vite.config.js'];
118
- let viteConfigPath;
119
- for (const configFile of possibleConfigFiles) {
120
- const fullPath = resolve( configFile);
121
- if (existsSync(fullPath)) {
122
- viteConfigPath = fullPath;
123
- break;
124
- }
125
- }
126
-
127
- if (!viteConfigPath) {
128
- console.error('Error: No vite.config.mjs or vite.config.js file found.');
129
- process.exit(1);
130
- }
131
-
132
- try {
133
- // Read vite config file
134
- const viteConfigContent = readFileSync(viteConfigPath, 'utf-8');
135
-
136
- // Extract @common alias path
137
- const aliasPattern = /'@common':\s*path\.resolve\(__dirname,\s*'(.+?)'\)/;
138
- const match = viteConfigContent.match(aliasPattern);
139
-
140
- if (!match) {
141
- console.error(`❌ Error: @common alias not found in ${viteConfigPath}`);
142
- process.exit(1);
143
- }
144
-
145
- const commonFilePath = match[1];
146
- const resolvedCommonPath = resolve(__dirname, commonFilePath);
147
-
148
- // Read the common file content
149
- if (!existsSync(resolvedCommonPath)) {
150
- console.error(`❌ Error: Resolved common file does not exist: ${resolvedCommonPath}`);
151
- process.exit(1);
152
- }
153
-
154
- const commonFileContent = readFileSync(resolvedCommonPath, 'utf-8');
155
-
156
- // Check for the _storeid export line
157
- const storeIdPattern = /export\s+let\s+_storeid\s*=\s*import\.meta\.env\.VITE_STORE_ID\s*\|\|\s*1\s*;/;
158
- if (!storeIdPattern.test(commonFileContent)) {
159
- console.error(`❌ Error: _storeid value is wrong in ${commonFilePath}`);
160
- process.exit(1);
161
- }
162
-
163
- console.log(commonFilePath,'Success - No problem found');
164
- } catch (error) {
165
- console.error('❌ Error:', error);
166
- process.exit(1);
167
- }
168
-
169
- }
170
-
171
- const checkIsTestingInAdmob=()=>{
172
-
173
- if (admobConfig.config && admobConfig.config.isTesting === true) {
174
- console.error(`❌ Problem found while generating the AAB file. Please change "isTesting: true" to "isTesting: false" in the "admob-ad-configuration.json" file.`);
175
- process.exit(1); // Exit with an error code to halt the process
176
- } else {
177
- console.log('✅ No problem found. "isTesting" is either already false or not defined.');
178
- }
179
- }
180
-
181
- const checkIsAdsDisableByReturnStatement=()=>{
182
-
183
-
184
- const adsFolder = join('src', 'js', 'Ads');
185
- const filePattern = /^admob-emi-(\d+\.)+\d+\.js$/;
186
-
187
- // Step 1: Find the admob file
188
- const files = readdirSync(adsFolder);
189
- const admobFile = files.find(f => filePattern.test(f));
190
-
191
- if (!admobFile) {
192
- console.log('❌ No Admob file found.');
193
- process.exit(1);
194
- }
195
-
196
- const filePath = join(adsFolder, admobFile);
197
- const content = readFileSync(filePath, 'utf-8');
198
-
199
- // Step 2: Extract the adsOnDeviceReady function body
200
- const functionRegex = /async\s+function\s+adsOnDeviceReady\s*\([^)]*\)\s*{([\s\S]*?)^}/m;
201
- const match = content.match(functionRegex);
202
-
203
- if (!match) {
204
- console.log(`❌ Function 'adsOnDeviceReady' not found in file: ${admobFile}`);
205
- process.exit(1);
206
- }
207
-
208
- const body = match[1];
209
- const lines = body.split('\n').map(line => line.trim());
210
-
211
- // Step 3: Skip blank lines and comments, get the first real code line
212
- let firstCodeLine = '';
213
- for (const line of lines) {
214
- if (line === '' || line.startsWith('//')) continue;
215
- firstCodeLine = line;
216
- break;
217
- }
218
-
219
- // Step 4: Block if it's any of the unwanted returns
220
- const badReturnPattern = /^return\s*(true|false)?\s*;?$/;
221
-
222
- if (badReturnPattern.test(firstCodeLine)) {
223
- console.log(`❌ BLOCKED in file '${admobFile}': First active line in 'adsOnDeviceReady' is '${firstCodeLine}'`);
224
- process.exit(2);
225
- } else {
226
- console.log(`✅ Safe: No early return (true/false) found in 'adsOnDeviceReady' of file '${admobFile}'.`);
227
- }
228
- }
229
-
230
-
231
-
232
- const addPermission_AD_ID=async()=>{
233
-
234
- const admobPluginXmlPath = join('node_modules', 'emi-indo-cordova-plugin-admob', 'plugin.xml');
235
-
236
-
237
- //let isAdmobFound = false;
238
- try {
239
- await promises.access(admobPluginXmlPath, constants.F_OK);
240
- isAdmobFound = true;
241
- } catch (err) {
242
- isAdmobFound = false;
243
- }
244
-
245
-
246
-
247
- if (isAdmobFound) {
248
- if (existsSync(androidManifestPath)) {
249
- let manifestContent = readFileSync(androidManifestPath, 'utf8');
250
- let modified = false;
251
-
252
- // --- Step 1: Ensure AD_ID permission exists ---
253
- const adIdPermission = '<uses-permission android:name="com.google.android.gms.permission.AD_ID" />';
254
- if (!manifestContent.includes(adIdPermission)) {
255
- console.log("📄 AD_ID permission not found. Adding to AndroidManifest.xml.");
256
- manifestContent = manifestContent.replace('</manifest>', ` ${adIdPermission}\n</manifest>`);
257
- console.log("✅ AD_ID permission added successfully.");
258
- modified = true;
259
- } else {
260
- console.log("ℹ️ AD_ID permission already exists in AndroidManifest.xml.");
261
- }
262
-
263
- // --- Step 2: Ensure OPTIMIZE_AD_LOADING meta-data exists ---
264
- const optimizeAdMeta = `<meta-data android:name="com.google.android.gms.ads.flag.OPTIMIZE_AD_LOADING" android:value="true" />`;
265
-
266
- if (!manifestContent.includes(optimizeAdMeta)) {
267
- console.log("📄 OPTIMIZE_AD_LOADING meta-data not found. Adding to AndroidManifest.xml.");
268
-
269
- const appTagPattern = /<application[^>]*>/;
270
- if (appTagPattern.test(manifestContent)) {
271
- manifestContent = manifestContent.replace(appTagPattern, match => `${match}\n ${optimizeAdMeta}`);
272
- console.log("✅ OPTIMIZE_AD_LOADING meta-data added successfully.");
273
- modified = true;
274
- } else {
275
- console.error("❌ <application> tag not found in AndroidManifest.xml.");
276
- }
277
- } else {
278
- console.log("ℹ️ OPTIMIZE_AD_LOADING meta-data already exists in AndroidManifest.xml.");
279
- }
280
-
281
- // --- Step 3: Write only if modified ---
282
- if (modified) {
283
- writeFileSync(androidManifestPath, manifestContent, 'utf8');
284
- console.log("💾 AndroidManifest.xml updated successfully.");
285
- } else {
286
- console.log("✅ No changes needed. AndroidManifest.xml is up to date.");
287
- }
288
-
289
- } else {
290
- console.error("❌ AndroidManifest.xml not found at the specified path.");
291
- }
292
- } else {
293
- console.log("\x1b[33m%s\x1b[0m", "⚠️ No AdMob found, so AD_ID permission and meta-data were not added");
294
- }
295
-
296
-
297
-
298
-
299
-
300
-
301
- }
302
-
303
-
304
-
305
-
306
-
307
-
308
-
309
-
310
-
311
-
312
-
313
- checkCommonFileStoreId();
314
-
315
-
316
-
317
- if (_isADMOB_ENABLED)
318
- {
319
- checkIsTestingInAdmob();
320
- checkIsAdsDisableByReturnStatement()
321
-
322
- await addPermission_AD_ID()
323
- }
324
-
325
-
326
-
327
-
328
-
329
-
330
- const { playstore, samsung, amazon } = (_isADMOB_ENABLED && admobConfig.IAP) ? admobConfig.IAP : { playstore: false, samsung: false, amazon: false };
331
- console.log(`ℹ️ IAP Configurations - PlayStore: ${playstore}, Samsung: ${samsung}, Amazon: ${amazon}`);
332
-
333
-
334
-
335
-
336
-
337
-
338
- // Get the store ID from the command line arguments
339
- const storeIdArg = process.argv[2]; // Get the store ID from the command line
340
- const storeIds = storeIdArg ? [storeIdArg] : ["1", "2", "7"]; // If a specific ID is provided, use it; otherwise, use all store IDs
341
-
342
- // Store the original minSdkVersion globally
343
- let originalMinSdkVersion;
344
-
345
- // Remove any existing AAB files before starting the build process
346
- const aabDirectory = join("android", "app", "build", "outputs", "bundle", "release");
347
- if (existsSync(aabDirectory)) {
348
- const files = readdirSync(aabDirectory).filter(file => file.endsWith('.aab'));
349
- files.forEach(file => {
350
- const filePath = join(aabDirectory, file);
351
- unlinkSync(filePath);
352
- console.log(`ℹ️ Deleted existing AAB file: ${file}`);
353
- });
354
- }
355
-
356
- const aabOutputDir = join("AAB");
357
- if (!existsSync(aabOutputDir)) {
358
- mkdirSync(aabOutputDir);
359
- console.log(`Created directory: ${aabOutputDir}`);
360
- }
361
-
362
- if (existsSync(aabOutputDir)) {
363
- const files = readdirSync(aabOutputDir).filter(file => file.endsWith('.aab'));
364
- files.forEach(file => {
365
- const filePath = join(aabOutputDir, file);
366
- unlinkSync(filePath);
367
- console.log(`Deleted existing AAB file: ${file}`);
368
- });
369
- }
370
-
371
-
372
- // Extract version code and version name from build.gradle
373
- const gradleFilePath = join("android", "app", "build.gradle");
374
- const gradleContent = readFileSync(gradleFilePath, 'utf8');
375
-
376
- const versionCodeMatch = gradleContent.match(/versionCode\s+(\d+)/);
377
- const versionNameMatch = gradleContent.match(/versionName\s+"([^"]+)"/);
378
-
379
- const versionCode = versionCodeMatch ? versionCodeMatch[1] : '';
380
- const versionName = versionNameMatch ? versionNameMatch[1] : '';
381
-
382
- // Display the current versionCode and versionName
383
- console.log(`Current versionCode: ${versionCode}`);
384
- console.log(`Current versionName: ${versionName}`);
385
-
386
- // Create an interface for user input
387
- const rl = createInterface({
388
- input: process.stdin,
389
- output: process.stdout
390
- });
391
-
392
- // Ask for new versionCode
393
- rl.question('Enter new versionCode (press enter to keep current): ', (newVersionCode) => {
394
- const finalVersionCode = newVersionCode || versionCode; // Use existing if no input
395
-
396
- // Ask for new versionName
397
- rl.question('Enter new versionName (press enter to keep current): ', (newVersionName) => {
398
- const finalVersionName = newVersionName || versionName; // Use existing if no input
399
-
400
- // Log the final version details
401
- console.log(`📦 Final versionCode: ${finalVersionCode}`);
402
- console.log(`📝 Final versionName: ${finalVersionName}`);
403
-
404
-
405
-
406
- // Update build.gradle with the new version details
407
- let updatedGradleContent = gradleContent
408
- .replace(/versionCode\s+\d+/, `versionCode ${finalVersionCode}`)
409
- .replace(/versionName\s+"[^"]+"/, `versionName "${finalVersionName}"`);
410
-
411
- // Check if resConfigs "en" already exists
412
- const resConfigsLine = ' resConfigs "en"';
413
- if (!updatedGradleContent.includes(resConfigsLine)) {
414
- // Add resConfigs "en" below versionName
415
- updatedGradleContent = updatedGradleContent.replace(/versionName\s+"[^"]+"/, `versionName "${finalVersionName}"\n${resConfigsLine}`);
416
- } else {
417
- console.log('ℹ️ resConfigs "en" already exists in build.gradle.');
418
- }
419
-
420
-
421
-
422
-
423
-
424
-
425
- if (/minifyEnabled\s+false/.test(updatedGradleContent)) {
426
- updatedGradleContent = updatedGradleContent.replace(/minifyEnabled\s+false/, 'minifyEnabled true');
427
- console.log('Replaced minifyEnabled false with true.');
428
- } else if (!/minifyEnabled\s+true/.test(updatedGradleContent)) {
429
- // Only insert if minifyEnabled (true or false) is NOT present
430
- if (/buildTypes\s*{[\s\S]*?release\s*{/.test(updatedGradleContent)) {
431
- updatedGradleContent = updatedGradleContent.replace(
432
- /(buildTypes\s*{[\s\S]*?release\s*{)/,
433
- '$1\n minifyEnabled true'
434
- );
435
- console.log('✅ Inserted minifyEnabled true into release block.');
436
- } else {
437
- console.log('⚠️ Warning: buildTypes > release block not found. minifyEnabled was not added.');
438
- }
439
- } else {
440
- console.log('ℹ️ minifyEnabled true already present. No change needed.');
441
- }
442
-
443
-
444
-
445
-
446
-
447
-
448
- // Write the updated gradle content back to build.gradle
449
- writeFileSync(gradleFilePath, updatedGradleContent, 'utf8');
450
- console.log(`✅ Updated build.gradle with versionCode: ${finalVersionCode}, versionName: ${finalVersionName}, resConfigs "en" and "minifyEnabled true"`);
451
-
452
- storeIds.forEach((id) => {
453
- console.log(`ℹ️ Building for Store ID ${id}`);
454
-
455
- // Set the environment variable for store ID
456
- process.env.VITE_STORE_ID = id;
457
-
458
- // Conditionally set the new file name
459
- let newFileName;
460
- let storeName = storeNames[id];
461
-
462
- managePackages(storeName);
463
-
464
- if (storeName === "SamsungStore") {
465
- // For SamsungStore, rename to versionCode value only
466
- newFileName = `${finalVersionCode}.aab`;
467
- } else {
468
- // For other stores, use the standard naming format
469
- newFileName = `app-release-signed-${storeName}-b${finalVersionCode}-v${finalVersionName}.aab`;
470
- }
471
-
472
- //storeName="amazon"
473
- const checkFullPath = join("AAB", newFileName); // Update to point to the new AAB directory
474
-
475
- // Modify minSdkVersion in variables.gradle for SamsungStore
476
- const variablesGradleFilePath = join("android", "variables.gradle");
477
- let variablesGradleContent = readFileSync(variablesGradleFilePath, 'utf8');
478
-
479
- // Extract the current minSdkVersion
480
- const minSdkVersionMatch = variablesGradleContent.match(/minSdkVersion\s*=\s*(\d+)/);
481
- const currentMinSdkVersion = minSdkVersionMatch ? parseInt(minSdkVersionMatch[1], 10) : null;
482
-
483
- // Store the original minSdkVersion (only on the first iteration)
484
- if (!originalMinSdkVersion) {
485
- originalMinSdkVersion = currentMinSdkVersion;
486
- }
487
- try {
488
- // Modify the minSdkVersion based on the store
489
-
490
-
491
- if(currentMinSdkVersion==23 || currentMinSdkVersion==24)
492
- {
493
- if (storeName === "SamsungStore" || storeName === "PlayStore" ||
494
- _appPackageId=="vfx.green.editor" || _appPackageId=="audio.music.sound.editor" || _appPackageId=="video.to.gif.maker") {
495
- if (currentMinSdkVersion !== 24) {
496
- variablesGradleContent = variablesGradleContent.replace(/minSdkVersion\s*=\s*\d+/, 'minSdkVersion = 24');
497
- console.log('minSdkVersion updated to 24 for SamsungStore & PlayStore');
498
- writeFileSync(variablesGradleFilePath, variablesGradleContent);
499
- }
500
- } else {
501
- // For PlayStore and AmazonStore, ensure minSdkVersion is originalMinSdkVersion
502
- //if (currentMinSdkVersion !== originalMinSdkVersion) {
503
- variablesGradleContent = variablesGradleContent.replace(/minSdkVersion\s*=\s*\d+/, `minSdkVersion = ${amazonMinSdkVersion}`);
504
- console.log(`minSdkVersion reverted to ${amazonMinSdkVersion} for ${storeName}`);
505
- writeFileSync(variablesGradleFilePath, variablesGradleContent);
506
- //}
507
- }
508
- }
509
-
510
-
511
- // Run the Node.js script to modify plugin.xml
512
- if (isAdmobFound) {
513
- execSync('node buildCodeplay/modify-plugin-xml.js', { stdio: 'inherit' });
514
- } else {
515
- console.log("\x1b[33m%s\x1b[0m", "Seems to Pro Version [No ads found]");
516
- }
517
-
518
- // Run the Vite build
519
- execSync(`npm run build:storeid${id}`, { stdio: 'inherit' });
520
-
521
-
522
-
523
- // Copy the built files to the appropriate folder
524
- const src = join("www", "*");
525
- const dest = join("android", "app", "src", "main", "assets", "public");
526
-
527
- // Use 'xcopy' command for Windows
528
- execSync(`xcopy ${src} ${dest} /E /I /Y`, { stdio: 'inherit' });
529
-
530
- // Build Android AAB file
531
- //child_process.execSync('cd android && ./gradlew bundleRelease', { stdio: 'inherit' });
532
-
533
-
534
- // Build Android AAB file with Capacitor
535
- execSync('npx cap sync android', { stdio: 'inherit' });
536
- execSync('npx cap build android --androidreleasetype=AAB', { stdio: 'inherit' });
537
-
538
-
539
-
540
- variablesGradleContent = variablesGradleContent.replace(/minSdkVersion\s*=\s*\d+/, 'minSdkVersion = 24');
541
- console.log('minSdkVersion revert to 24 (default)');
542
- writeFileSync(variablesGradleFilePath, variablesGradleContent);
543
-
544
-
545
- // Rename the output AAB file
546
- const oldFilePath = join(aabDirectory, "app-release-signed.aab");
547
- if (existsSync(oldFilePath)) {
548
- renameSync(oldFilePath, checkFullPath);
549
- console.log(`✅ Renamed output AAB file to: ${newFileName}`);
550
- } else {
551
- console.error("❌ AAB file not found after build.");
552
- }
553
-
554
- } catch (error) {
555
- console.error(`❌ Error during build for Store ID ${id}:`, error);
556
- process.exit(1);
557
- }
558
- });
559
-
560
- rl.close(); // Close the readline interface after all operations
561
- });
562
- });
563
-
564
-
565
-
566
-
567
-
568
- function managePackages(store) {
569
- console.log(`IAP Configurations - PlayStore: ${playstore}, Samsung: ${samsung}, Amazon: ${amazon}`);
570
-
571
- let install = "";
572
- let uninstall = "";
573
-
574
-
575
-
576
- let manifestContent = readFileSync(androidManifestPath, 'utf-8');
577
-
578
- const permissionsToRemove = [
579
- 'com.android.vending.BILLING',
580
- 'com.samsung.android.iap.permission.BILLING'
581
- ];
582
-
583
-
584
- permissionsToRemove.forEach(permission => {
585
- const permissionRegex = new RegExp(`^\\s*<uses-permission\\s+android:name="${permission}"\\s*/?>\\s*[\r\n]?`, 'm');
586
- if (permissionRegex.test(manifestContent)) {
587
- manifestContent = manifestContent.replace(permissionRegex, '');
588
- console.log(`✅ Removed <uses-permission android:name="${permission}" /> from AndroidManifest.xml`);
589
- }
590
- });
591
-
592
- // Write the updated content back to the file
593
- writeFileSync(androidManifestPath, manifestContent, 'utf-8');
594
-
595
-
596
-
597
- if ((playstore && store === "PlayStore") || (amazon && store === "AmazonStore")) {
598
- install = '@revenuecat/purchases-capacitor';
599
- uninstall = 'cordova-plugin-samsungiap';
600
-
601
- // Update AndroidManifest.xml for PlayStore
602
- if(playstore)
603
- updateAndroidManifest(store,
604
- '<uses-permission android:name="com.android.vending.BILLING" />');
605
-
606
- } else if (samsung && store === "SamsungStore") {
607
- install = 'cordova-plugin-samsungiap';
608
- uninstall = '@revenuecat/purchases-capacitor';
609
-
610
- // Update AndroidManifest.xml for SamsungStore
611
- updateAndroidManifest(store,
612
- '<uses-permission android:name="com.samsung.android.iap.permission.BILLING" />');
613
-
614
- } else {
615
- console.log("No valid store specified or no configurations found. Both plugins will be uninstalled.");
616
- try {
617
- execSync(`npm uninstall cordova-plugin-samsungiap`, { stdio: 'inherit' });
618
- execSync(`npm uninstall @revenuecat/purchases-capacitor`, { stdio: 'inherit' });
619
- console.log(`✅ Both plugins uninstalled successfully.`);
620
- } catch (err) {
621
- console.error("❌ Error uninstalling plugins:", err);
622
- }
623
- return;
624
- }
625
-
626
- console.log(`⚠️ Installing ${install} and uninstalling ${uninstall} for ${store}...`);
627
- try {
628
- if (install) {
629
- execSync(`npm install ${install}`, { stdio: 'inherit' });
630
- }
631
- if (uninstall) {
632
- execSync(`npm uninstall ${uninstall}`, { stdio: 'inherit' });
633
- }
634
- console.log(`✅ ${install} installed and ${uninstall} uninstalled successfully.`);
635
- } catch (err) {
636
- console.error(`❌ Error managing packages for ${store}:`, err);
637
- }
638
- }
639
-
640
-
641
-
642
- function updateAndroidManifest(store, addPermission) {
643
- try {
644
- if (!existsSync(androidManifestPath)) {
645
- console.error("❌ AndroidManifest.xml file not found!");
646
- return;
647
- }
648
-
649
- // Read the content of the AndroidManifest.xml
650
- let manifestContent = readFileSync(androidManifestPath, 'utf-8');
651
-
652
- // Normalize line endings to `\n` for consistent processing
653
- manifestContent = manifestContent.replace(/\r\n/g, '\n');
654
-
655
- // Check if the permission is already present
656
- if (manifestContent.includes(addPermission.trim())) {
657
- console.log(`${addPermission} is already in the AndroidManifest.xml. Skipping addition.`);
658
- return; // Skip if the permission is already present
659
- }
660
-
661
- // Insert the permission before the closing </manifest> tag
662
- const closingTag = '</manifest>';
663
- const formattedPermission = ` ${addPermission.trim()}\n`;
664
- if (manifestContent.includes(closingTag)) {
665
- manifestContent = manifestContent.replace(
666
- closingTag,
667
- `${formattedPermission}${closingTag}`
668
- );
669
- console.log(`✅ Added ${addPermission} before </manifest> tag.`);
670
- } else {
671
- console.warn(`⚠️ </manifest> tag not found. Adding ${addPermission} at the end of the file.`);
672
- manifestContent += `\n${formattedPermission}`;
673
- }
674
-
675
- // Normalize line endings back to `\r\n` and write the updated content
676
- manifestContent = manifestContent.replace(/\n/g, '\r\n');
677
- writeFileSync(androidManifestPath, manifestContent, 'utf-8');
678
- console.log(`✅ AndroidManifest.xml updated successfully for ${store}`);
679
- } catch (err) {
680
- console.error(`❌ Error updating AndroidManifest.xml for ${store}:`, err);
681
- }
682
- }
683
-
684
-
685
-
686
- /* function updateAndroidManifest1(store, addPermission) {
687
- try {
688
- if (!fs.existsSync(androidManifestPath)) {
689
- console.error("AndroidManifest.xml file not found!");
690
- return;
691
- }
692
-
693
- let manifestContent = fs.readFileSync(androidManifestPath, 'utf-8');
694
-
695
-
696
-
697
- // Add the required permission if not already present
698
- if (!manifestContent.includes(addPermission)) {
699
- const manifestLines = manifestContent.split('\n');
700
- const insertIndex = manifestLines.findIndex(line => line.trim().startsWith('<application'));
701
- if (insertIndex > -1) {
702
- manifestLines.splice(insertIndex, 0, ` ${addPermission}`);
703
- manifestContent = manifestLines.join('\n');
704
- console.log(`Added ${addPermission} to AndroidManifest.xml`);
705
- }
706
- }
707
-
708
- // Write the updated content back to the file
709
- fs.writeFileSync(androidManifestPath, manifestContent, 'utf-8');
710
- console.log(`AndroidManifest.xml updated successfully for ${store}`);
711
- } catch (err) {
712
- console.error(`Error updating AndroidManifest.xml for ${store}:`, err);
713
- }
714
- } */
715
-
716
-
717
-
718
-
719
-
720
-
721
-
722
-
1
+ /*
2
+ Can be run like
3
+ node finalrelease
4
+ node finalrelease 1
5
+ node finalrelease "1,2,7"
6
+ */
7
+
8
+ import { existsSync, readFileSync, readdirSync, promises, constants, writeFileSync, unlinkSync, mkdirSync, renameSync } from 'fs';
9
+ import { join, resolve } from 'path';
10
+ import { execSync } from 'child_process';
11
+ import { createInterface } from 'readline';
12
+
13
+ import { fileURLToPath } from 'url';
14
+ import { dirname } from 'path';
15
+
16
+ /* const path = require('path');
17
+ const fs = require('fs'); */
18
+
19
+ import fs from 'fs';
20
+ import path from 'path';
21
+
22
+ // Define a mapping between store IDs and store names
23
+ /* const storeNames = {
24
+ "1": "PlayStore",
25
+ "2": "SamsungStore",
26
+ "7": "AmazonStore"
27
+ }; */
28
+
29
+ const storeNames = {
30
+ "1": "PlayStore",
31
+ "2": "SamsungStore",
32
+ "7": "AmazonStore",
33
+
34
+ "3": "MiStore",
35
+ "4": "HuaweiStore",
36
+ "5": "OppoStore",
37
+ //"6": "iOSStore",
38
+ "8": "VivoStore"
39
+ };
40
+
41
+
42
+ //1=> PlayStore 2=> SamsungStore 3=>MiStore 4=>HuaweiStore 5=>OppoStore 6=>iOSStore 7=> AmazonStore 8=> VivoStore
43
+
44
+
45
+
46
+
47
+
48
+ let isAdmobFound = false;
49
+
50
+ const amazonMinSdkVersion=23;
51
+
52
+ const androidManifestPath = join("android", "app", "src", "main", "AndroidManifest.xml");
53
+
54
+
55
+ const configPath = path.join(process.cwd(), 'capacitor.config.json');
56
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
57
+
58
+ const _appUniqueId = config.android?.APP_UNIQUE_ID;
59
+ const _appName=config.appName;
60
+ const _appPackageId=config.appId;
61
+
62
+
63
+
64
+ const __filename = fileURLToPath(import.meta.url);
65
+ const __dirname = dirname(__filename);
66
+
67
+ function fileExists(filePath) {
68
+ return existsSync(filePath);
69
+ }
70
+
71
+
72
+ const capacitorConfigPath = join(process.cwd(), 'capacitor.config.json');
73
+
74
+ function getAdMobConfig() {
75
+ if (!fileExists(capacitorConfigPath)) {
76
+ throw new Error('❌ capacitor.config.json not found. Ensure this is a Capacitor project.');
77
+ }
78
+
79
+ const config = JSON.parse(readFileSync(capacitorConfigPath, 'utf8'));
80
+ const admobConfig = config.plugins?.AdMob;
81
+
82
+ //_appPackageId=config.appId;
83
+
84
+ if (!admobConfig) {
85
+ throw new Error('❌ AdMob configuration is missing in capacitor.config.json.');
86
+ }
87
+
88
+ // Default to true if ADMOB_ENABLED is not specified
89
+ const isEnabled = admobConfig.ADMOB_ENABLED !== false;
90
+
91
+ if (!isEnabled) {
92
+ return { ADMOB_ENABLED: false }; // Skip further validation
93
+ }
94
+
95
+ if (!admobConfig.APP_ID_ANDROID || !admobConfig.APP_ID_IOS) {
96
+ throw new Error(' ❌ AdMob configuration is incomplete. Ensure APP_ID_ANDROID and APP_ID_IOS are defined.');
97
+ }
98
+
99
+ return {
100
+ ADMOB_ENABLED: true,
101
+ APP_ID_ANDROID: admobConfig.APP_ID_ANDROID,
102
+ APP_ID_IOS: admobConfig.APP_ID_IOS,
103
+ USE_LITE_ADS: admobConfig.USE_LITE_ADS === "lite",
104
+ };
105
+ }
106
+
107
+
108
+
109
+ const _capacitorConfig = getAdMobConfig();
110
+
111
+ const _isADMOB_ENABLED=_capacitorConfig.ADMOB_ENABLED;
112
+
113
+ // Proceed only if ADMOB_ENABLED is true
114
+ //if (_capacitorConfig.ADMOB_ENABLED)
115
+
116
+
117
+ const admobConfigPath = join('src', 'js','Ads', 'admob-ad-configuration.json');
118
+ let admobConfig;
119
+
120
+ if (_isADMOB_ENABLED)
121
+ {
122
+ try
123
+ {
124
+ admobConfig = JSON.parse(readFileSync(admobConfigPath, 'utf8'));
125
+ }
126
+ catch (err)
127
+ {
128
+ console.error("Failed to read admob-ad-configuration.json", err);
129
+ process.exit(1);
130
+ }
131
+ }
132
+
133
+
134
+
135
+
136
+
137
+
138
+
139
+
140
+
141
+
142
+
143
+
144
+
145
+
146
+
147
+
148
+
149
+
150
+
151
+
152
+
153
+
154
+ const checkCommonFileStoreId=()=>{
155
+ const possibleConfigFiles = ['vite.config.mjs', 'vite.config.js'];
156
+ let viteConfigPath;
157
+ for (const configFile of possibleConfigFiles) {
158
+ const fullPath = resolve( configFile);
159
+ if (existsSync(fullPath)) {
160
+ viteConfigPath = fullPath;
161
+ break;
162
+ }
163
+ }
164
+
165
+ if (!viteConfigPath) {
166
+ console.error('❌ Error: No vite.config.mjs or vite.config.js file found.');
167
+ process.exit(1);
168
+ }
169
+
170
+ try {
171
+ // Read vite config file
172
+ const viteConfigContent = readFileSync(viteConfigPath, 'utf-8');
173
+
174
+ // Extract @common alias path
175
+ const aliasPattern = /'@common':\s*path\.resolve\(__dirname,\s*'(.+?)'\)/;
176
+ const match = viteConfigContent.match(aliasPattern);
177
+
178
+ if (!match) {
179
+ console.error(`❌ Error: @common alias not found in ${viteConfigPath}`);
180
+ process.exit(1);
181
+ }
182
+
183
+ const commonFilePath = match[1];
184
+ const resolvedCommonPath = resolve(__dirname, commonFilePath);
185
+
186
+ // Read the common file content
187
+ if (!existsSync(resolvedCommonPath)) {
188
+ console.error(`❌ Error: Resolved common file does not exist: ${resolvedCommonPath}`);
189
+ process.exit(1);
190
+ }
191
+
192
+ const commonFileContent = readFileSync(resolvedCommonPath, 'utf-8');
193
+
194
+ // Check for the _storeid export line
195
+ const storeIdPattern = /export\s+let\s+_storeid\s*=\s*import\.meta\.env\.VITE_STORE_ID\s*\|\|\s*1\s*;/;
196
+ if (!storeIdPattern.test(commonFileContent)) {
197
+ console.error(`❌ Error: _storeid value is wrong in ${commonFilePath}`);
198
+ process.exit(1);
199
+ }
200
+
201
+ console.log(commonFilePath,'Success - No problem found');
202
+ } catch (error) {
203
+ console.error('❌ Error:', error);
204
+ process.exit(1);
205
+ }
206
+
207
+ }
208
+
209
+ const checkIsTestingInAdmob=()=>{
210
+
211
+ if (admobConfig.config && admobConfig.config.isTesting === true) {
212
+ console.error(`❌ Problem found while generating the AAB file. Please change "isTesting: true" to "isTesting: false" in the "admob-ad-configuration.json" file.`);
213
+ process.exit(1); // Exit with an error code to halt the process
214
+ } else {
215
+ console.log('✅ No problem found. "isTesting" is either already false or not defined.');
216
+ }
217
+ }
218
+
219
+ const checkIsAdsDisableByReturnStatement=()=>{
220
+
221
+
222
+ const adsFolder = join('src', 'js', 'Ads');
223
+ const filePattern = /^admob-emi-(\d+\.)+\d+\.js$/;
224
+
225
+ // Step 1: Find the admob file
226
+ const files = readdirSync(adsFolder);
227
+ const admobFile = files.find(f => filePattern.test(f));
228
+
229
+ if (!admobFile) {
230
+ console.log('❌ No Admob file found.');
231
+ process.exit(1);
232
+ }
233
+
234
+ const filePath = join(adsFolder, admobFile);
235
+ const content = readFileSync(filePath, 'utf-8');
236
+
237
+ // Step 2: Extract the adsOnDeviceReady function body
238
+ const functionRegex = /async\s+function\s+adsOnDeviceReady\s*\([^)]*\)\s*{([\s\S]*?)^}/m;
239
+ const match = content.match(functionRegex);
240
+
241
+ if (!match) {
242
+ console.log(`❌ Function 'adsOnDeviceReady' not found in file: ${admobFile}`);
243
+ process.exit(1);
244
+ }
245
+
246
+ const body = match[1];
247
+ const lines = body.split('\n').map(line => line.trim());
248
+
249
+ // Step 3: Skip blank lines and comments, get the first real code line
250
+ let firstCodeLine = '';
251
+ for (const line of lines) {
252
+ if (line === '' || line.startsWith('//')) continue;
253
+ firstCodeLine = line;
254
+ break;
255
+ }
256
+
257
+ // Step 4: Block if it's any of the unwanted returns
258
+ const badReturnPattern = /^return\s*(true|false)?\s*;?$/;
259
+
260
+ if (badReturnPattern.test(firstCodeLine)) {
261
+ console.log(`❌ BLOCKED in file '${admobFile}': First active line in 'adsOnDeviceReady' is '${firstCodeLine}'`);
262
+ process.exit(2);
263
+ } else {
264
+ console.log(`✅ Safe: No early return (true/false) found in 'adsOnDeviceReady' of file '${admobFile}'.`);
265
+ }
266
+ }
267
+
268
+
269
+
270
+ const addPermission_AD_ID=async()=>{
271
+
272
+ const admobPluginXmlPath = join('node_modules', 'emi-indo-cordova-plugin-admob', 'plugin.xml');
273
+
274
+
275
+ //let isAdmobFound = false;
276
+ try {
277
+ await promises.access(admobPluginXmlPath, constants.F_OK);
278
+ isAdmobFound = true;
279
+ } catch (err) {
280
+ isAdmobFound = false;
281
+ }
282
+
283
+
284
+
285
+ if (isAdmobFound) {
286
+ if (existsSync(androidManifestPath)) {
287
+ let manifestContent = readFileSync(androidManifestPath, 'utf8');
288
+ let modified = false;
289
+
290
+ // --- Step 1: Ensure AD_ID permission exists ---
291
+ const adIdPermission = '<uses-permission android:name="com.google.android.gms.permission.AD_ID" />';
292
+ if (!manifestContent.includes(adIdPermission)) {
293
+ console.log("📄 AD_ID permission not found. Adding to AndroidManifest.xml.");
294
+ manifestContent = manifestContent.replace('</manifest>', ` ${adIdPermission}\n</manifest>`);
295
+ console.log("✅ AD_ID permission added successfully.");
296
+ modified = true;
297
+ } else {
298
+ console.log("ℹ️ AD_ID permission already exists in AndroidManifest.xml.");
299
+ }
300
+
301
+ // --- Step 2: Ensure OPTIMIZE_AD_LOADING meta-data exists ---
302
+ const optimizeAdMeta = `<meta-data android:name="com.google.android.gms.ads.flag.OPTIMIZE_AD_LOADING" android:value="true" />`;
303
+
304
+ if (!manifestContent.includes(optimizeAdMeta)) {
305
+ console.log("📄 OPTIMIZE_AD_LOADING meta-data not found. Adding to AndroidManifest.xml.");
306
+
307
+ const appTagPattern = /<application[^>]*>/;
308
+ if (appTagPattern.test(manifestContent)) {
309
+ manifestContent = manifestContent.replace(appTagPattern, match => `${match}\n ${optimizeAdMeta}`);
310
+ console.log("✅ OPTIMIZE_AD_LOADING meta-data added successfully.");
311
+ modified = true;
312
+ } else {
313
+ console.error("❌ <application> tag not found in AndroidManifest.xml.");
314
+ }
315
+ } else {
316
+ console.log("ℹ️ OPTIMIZE_AD_LOADING meta-data already exists in AndroidManifest.xml.");
317
+ }
318
+
319
+ // --- Step 3: Write only if modified ---
320
+ if (modified) {
321
+ writeFileSync(androidManifestPath, manifestContent, 'utf8');
322
+ console.log("💾 AndroidManifest.xml updated successfully.");
323
+ } else {
324
+ console.log("✅ No changes needed. AndroidManifest.xml is up to date.");
325
+ }
326
+
327
+ } else {
328
+ console.error("❌ AndroidManifest.xml not found at the specified path.");
329
+ }
330
+ } else {
331
+ console.log("\x1b[33m%s\x1b[0m", "⚠️ No AdMob found, so AD_ID permission and meta-data were not added");
332
+ }
333
+
334
+
335
+
336
+
337
+
338
+
339
+ }
340
+
341
+
342
+
343
+
344
+
345
+
346
+
347
+
348
+
349
+
350
+
351
+ checkCommonFileStoreId();
352
+
353
+
354
+
355
+ if (_isADMOB_ENABLED)
356
+ {
357
+ checkIsTestingInAdmob();
358
+ checkIsAdsDisableByReturnStatement()
359
+
360
+ await addPermission_AD_ID()
361
+ }
362
+
363
+
364
+
365
+
366
+
367
+
368
+ const { playstore, samsung, amazon } = (_isADMOB_ENABLED && admobConfig.IAP) ? admobConfig.IAP : { playstore: false, samsung: false, amazon: false };
369
+ console.log(`ℹ️ IAP Configurations - PlayStore: ${playstore}, Samsung: ${samsung}, Amazon: ${amazon}`);
370
+
371
+
372
+
373
+
374
+
375
+
376
+ // Get the store ID from the command line arguments
377
+ /* const storeIdArg = ["2","3"]//process.argv[2]; // Get the store ID from the command line
378
+ const storeIds = storeIdArg ? storeIdArg : Object.keys(storeNames);//["1", "2", "7"]; // If a specific ID is provided, use it; otherwise, use all store IDs
379
+
380
+ debugger; */
381
+
382
+ let storeIdArg = process.argv[2]; // command-line argument
383
+ let storeIds;
384
+
385
+ if (storeIdArg) {
386
+ try {
387
+ // Try parsing as JSON array first
388
+ const parsed = JSON.parse(storeIdArg);
389
+ if (Array.isArray(parsed)) {
390
+ storeIds = parsed.map(String); // ensure strings
391
+ } else {
392
+ storeIds = [parsed.toString()];
393
+ }
394
+ } catch (e) {
395
+ // Not JSON, assume comma-separated string
396
+ storeIds = storeIdArg.split(",").map(s => s.trim());
397
+ }
398
+ } else {
399
+ // No argument, use all store IDs
400
+ storeIds = Object.keys(storeNames);
401
+ }
402
+
403
+
404
+ // Store the original minSdkVersion globally
405
+ let originalMinSdkVersion;
406
+
407
+ // Remove any existing AAB files before starting the build process
408
+ const aabDirectory = join("android", "app", "build", "outputs", "bundle", "release");
409
+ if (existsSync(aabDirectory)) {
410
+ const files = readdirSync(aabDirectory).filter(file => file.endsWith('.aab'));
411
+ files.forEach(file => {
412
+ const filePath = join(aabDirectory, file);
413
+ unlinkSync(filePath);
414
+ console.log(`ℹ️ Deleted existing AAB file: ${file}`);
415
+ });
416
+ }
417
+
418
+ const aabOutputDir = join("AAB");
419
+ if (!existsSync(aabOutputDir)) {
420
+ mkdirSync(aabOutputDir);
421
+ console.log(`Created directory: ${aabOutputDir}`);
422
+ }
423
+
424
+ if (existsSync(aabOutputDir)) {
425
+ const files = readdirSync(aabOutputDir).filter(file => file.endsWith('.aab'));
426
+ files.forEach(file => {
427
+ const filePath = join(aabOutputDir, file);
428
+ unlinkSync(filePath);
429
+ console.log(`Deleted existing AAB file: ${file}`);
430
+ });
431
+ }
432
+
433
+
434
+ // Extract version code and version name from build.gradle
435
+ const gradleFilePath = join("android", "app", "build.gradle");
436
+ const gradleContent = readFileSync(gradleFilePath, 'utf8');
437
+
438
+ const versionCodeMatch = gradleContent.match(/versionCode\s+(\d+)/);
439
+ const versionNameMatch = gradleContent.match(/versionName\s+"([^"]+)"/);
440
+
441
+ const versionCode = versionCodeMatch ? versionCodeMatch[1] : '';
442
+ const versionName = versionNameMatch ? versionNameMatch[1] : '';
443
+
444
+ // Display the current versionCode and versionName
445
+ console.log(`Current versionCode: ${versionCode}`);
446
+ console.log(`Current versionName: ${versionName}`);
447
+
448
+ // Create an interface for user input
449
+ const rl = createInterface({
450
+ input: process.stdin,
451
+ output: process.stdout
452
+ });
453
+
454
+ // Ask for new versionCode
455
+ rl.question('Enter new versionCode (press enter to keep current): ', (newVersionCode) => {
456
+ const finalVersionCode = newVersionCode || versionCode; // Use existing if no input
457
+
458
+ // Ask for new versionName
459
+ rl.question('Enter new versionName (press enter to keep current): ', (newVersionName) => {
460
+ const finalVersionName = newVersionName || versionName; // Use existing if no input
461
+
462
+ // Log the final version details
463
+ console.log(`📦 Final versionCode: ${finalVersionCode}`);
464
+ console.log(`📝 Final versionName: ${finalVersionName}`);
465
+
466
+
467
+
468
+ // Update build.gradle with the new version details
469
+ let updatedGradleContent = gradleContent
470
+ .replace(/versionCode\s+\d+/, `versionCode ${finalVersionCode}`)
471
+ .replace(/versionName\s+"[^"]+"/, `versionName "${finalVersionName}"`);
472
+
473
+ // Check if resConfigs "en" already exists
474
+ const resConfigsLine = ' resConfigs "en"';
475
+ if (!updatedGradleContent.includes(resConfigsLine)) {
476
+ // Add resConfigs "en" below versionName
477
+ updatedGradleContent = updatedGradleContent.replace(/versionName\s+"[^"]+"/, `versionName "${finalVersionName}"\n${resConfigsLine}`);
478
+ } else {
479
+ console.log('ℹ️ resConfigs "en" already exists in build.gradle.');
480
+ }
481
+
482
+
483
+
484
+
485
+
486
+
487
+ if (/minifyEnabled\s+false/.test(updatedGradleContent)) {
488
+ updatedGradleContent = updatedGradleContent.replace(/minifyEnabled\s+false/, 'minifyEnabled true');
489
+ console.log('Replaced minifyEnabled false with true.');
490
+ } else if (!/minifyEnabled\s+true/.test(updatedGradleContent)) {
491
+ // Only insert if minifyEnabled (true or false) is NOT present
492
+ if (/buildTypes\s*{[\s\S]*?release\s*{/.test(updatedGradleContent)) {
493
+ updatedGradleContent = updatedGradleContent.replace(
494
+ /(buildTypes\s*{[\s\S]*?release\s*{)/,
495
+ '$1\n minifyEnabled true'
496
+ );
497
+ console.log(' Inserted minifyEnabled true into release block.');
498
+ } else {
499
+ console.log('⚠️ Warning: buildTypes > release block not found. minifyEnabled was not added.');
500
+ }
501
+ } else {
502
+ console.log('ℹ️ minifyEnabled true already present. No change needed.');
503
+ }
504
+
505
+
506
+
507
+
508
+
509
+
510
+ // Write the updated gradle content back to build.gradle
511
+ writeFileSync(gradleFilePath, updatedGradleContent, 'utf8');
512
+ console.log(`✅ Updated build.gradle with versionCode: ${finalVersionCode}, versionName: ${finalVersionName}, resConfigs "en" and "minifyEnabled true"`);
513
+
514
+ storeIds.forEach((id) => {
515
+ console.log(`ℹ️ Building for Store ID ${id}`);
516
+
517
+ // Set the environment variable for store ID
518
+ process.env.VITE_STORE_ID = id;
519
+
520
+ // Conditionally set the new file name
521
+ let newFileName;
522
+ let storeName = storeNames[id];
523
+
524
+ debugger;
525
+
526
+
527
+ managePackages(storeName);
528
+
529
+ if (storeName === "SamsungStore") {
530
+ // For SamsungStore, rename to versionCode value only
531
+ //newFileName = `${finalVersionCode}.aab`;
532
+ newFileName=`${_appUniqueId}_${_appName.replaceAll(" ","_")}-${(storeName.toUpperCase()).replace("STORE","")}-b${finalVersionCode}-v${finalVersionName.replace(/\./g,'_')}.aab`
533
+ } else {
534
+ // For other stores, use the standard naming format
535
+ //newFileName = `app-release-signed-${storeName}-b${finalVersionCode}-v${finalVersionName}.aab`;
536
+
537
+ newFileName=`${_appUniqueId}_${_appName.replaceAll(" ","_")}-${(storeName.toUpperCase()).replace("STORE","")}-b${finalVersionCode}-v${finalVersionName}.aab`
538
+
539
+
540
+ /*
541
+ const _appUniqueId = config.android?.APP_UNIQUE_ID;
542
+ const _appName=config.appName;
543
+ const _appPackageId=config.appId;
544
+ */
545
+
546
+ }
547
+
548
+ //storeName="amazon"
549
+ const checkFullPath = join("AAB", newFileName); // Update to point to the new AAB directory
550
+
551
+ // Modify minSdkVersion in variables.gradle for SamsungStore
552
+ const variablesGradleFilePath = join("android", "variables.gradle");
553
+ let variablesGradleContent = readFileSync(variablesGradleFilePath, 'utf8');
554
+
555
+ // Extract the current minSdkVersion
556
+ const minSdkVersionMatch = variablesGradleContent.match(/minSdkVersion\s*=\s*(\d+)/);
557
+ const currentMinSdkVersion = minSdkVersionMatch ? parseInt(minSdkVersionMatch[1], 10) : null;
558
+
559
+ // Store the original minSdkVersion (only on the first iteration)
560
+ if (!originalMinSdkVersion) {
561
+ originalMinSdkVersion = currentMinSdkVersion;
562
+ }
563
+ try {
564
+ // Modify the minSdkVersion based on the store
565
+
566
+
567
+ if(currentMinSdkVersion==23 || currentMinSdkVersion==24)
568
+ {
569
+ if (storeName === "SamsungStore" || storeName === "PlayStore" ||
570
+ _appPackageId=="vfx.green.editor" || _appPackageId=="audio.music.sound.editor" || _appPackageId=="video.to.gif.maker") {
571
+ if (currentMinSdkVersion !== 24) {
572
+ variablesGradleContent = variablesGradleContent.replace(/minSdkVersion\s*=\s*\d+/, 'minSdkVersion = 24');
573
+ console.log('minSdkVersion updated to 24 for SamsungStore & PlayStore');
574
+ writeFileSync(variablesGradleFilePath, variablesGradleContent);
575
+ }
576
+ } else {
577
+ // For PlayStore and AmazonStore, ensure minSdkVersion is originalMinSdkVersion
578
+ //if (currentMinSdkVersion !== originalMinSdkVersion) {
579
+ variablesGradleContent = variablesGradleContent.replace(/minSdkVersion\s*=\s*\d+/, `minSdkVersion = ${amazonMinSdkVersion}`);
580
+ console.log(`minSdkVersion reverted to ${amazonMinSdkVersion} for ${storeName}`);
581
+ writeFileSync(variablesGradleFilePath, variablesGradleContent);
582
+ //}
583
+ }
584
+ }
585
+
586
+
587
+ // Run the Node.js script to modify plugin.xml
588
+ if (isAdmobFound) {
589
+ execSync('node buildCodeplay/modify-plugin-xml.js', { stdio: 'inherit' });
590
+ } else {
591
+ console.log("\x1b[33m%s\x1b[0m", "Seems to Pro Version [No ads found]");
592
+ }
593
+
594
+ // Run the Vite build
595
+ execSync(`npm run build:storeid${id}`, { stdio: 'inherit' });
596
+
597
+
598
+
599
+ // Copy the built files to the appropriate folder
600
+ const src = join("www", "*");
601
+ const dest = join("android", "app", "src", "main", "assets", "public");
602
+
603
+ // Use 'xcopy' command for Windows
604
+ execSync(`xcopy ${src} ${dest} /E /I /Y`, { stdio: 'inherit' });
605
+
606
+ // Build Android AAB file
607
+ //child_process.execSync('cd android && ./gradlew bundleRelease', { stdio: 'inherit' });
608
+
609
+
610
+ // Build Android AAB file with Capacitor
611
+ execSync('npx cap sync android', { stdio: 'inherit' });
612
+ execSync('npx cap build android --androidreleasetype=AAB', { stdio: 'inherit' });
613
+
614
+
615
+
616
+ variablesGradleContent = variablesGradleContent.replace(/minSdkVersion\s*=\s*\d+/, 'minSdkVersion = 24');
617
+ console.log('minSdkVersion revert to 24 (default)');
618
+ writeFileSync(variablesGradleFilePath, variablesGradleContent);
619
+
620
+
621
+ // Rename the output AAB file
622
+ const oldFilePath = join(aabDirectory, "app-release-signed.aab");
623
+ if (existsSync(oldFilePath)) {
624
+ renameSync(oldFilePath, checkFullPath);
625
+ console.log(`✅ Renamed output AAB file to: ${newFileName}`);
626
+ } else {
627
+ console.error("❌ AAB file not found after build.");
628
+ }
629
+
630
+ } catch (error) {
631
+ console.error(`❌ Error during build for Store ID ${id}:`, error);
632
+ process.exit(1);
633
+ }
634
+ });
635
+
636
+ rl.close(); // Close the readline interface after all operations
637
+ });
638
+ });
639
+
640
+
641
+
642
+
643
+
644
+ function managePackages(store) {
645
+ console.log(`IAP Configurations - PlayStore: ${playstore}, Samsung: ${samsung}, Amazon: ${amazon}`);
646
+
647
+ let install = "";
648
+ let uninstall = "";
649
+
650
+
651
+
652
+ let manifestContent = readFileSync(androidManifestPath, 'utf-8');
653
+
654
+ const permissionsToRemove = [
655
+ 'com.android.vending.BILLING',
656
+ 'com.samsung.android.iap.permission.BILLING'
657
+ ];
658
+
659
+
660
+ permissionsToRemove.forEach(permission => {
661
+ const permissionRegex = new RegExp(`^\\s*<uses-permission\\s+android:name="${permission}"\\s*/?>\\s*[\r\n]?`, 'm');
662
+ if (permissionRegex.test(manifestContent)) {
663
+ manifestContent = manifestContent.replace(permissionRegex, '');
664
+ console.log(`✅ Removed <uses-permission android:name="${permission}" /> from AndroidManifest.xml`);
665
+ }
666
+ });
667
+
668
+ // Write the updated content back to the file
669
+ writeFileSync(androidManifestPath, manifestContent, 'utf-8');
670
+
671
+
672
+
673
+ if ((playstore && store === "PlayStore") || (amazon && store === "AmazonStore")) {
674
+ install = '@revenuecat/purchases-capacitor';
675
+ uninstall = 'cordova-plugin-samsungiap';
676
+
677
+ // Update AndroidManifest.xml for PlayStore
678
+ if(playstore)
679
+ updateAndroidManifest(store,
680
+ '<uses-permission android:name="com.android.vending.BILLING" />');
681
+
682
+ } else if (samsung && store === "SamsungStore") {
683
+ install = 'cordova-plugin-samsungiap';
684
+ uninstall = '@revenuecat/purchases-capacitor';
685
+
686
+ // Update AndroidManifest.xml for SamsungStore
687
+ updateAndroidManifest(store,
688
+ '<uses-permission android:name="com.samsung.android.iap.permission.BILLING" />');
689
+
690
+ } else {
691
+ console.log("No valid store specified or no configurations found. Both plugins will be uninstalled.");
692
+ try {
693
+ execSync(`npm uninstall cordova-plugin-samsungiap`, { stdio: 'inherit' });
694
+ execSync(`npm uninstall @revenuecat/purchases-capacitor`, { stdio: 'inherit' });
695
+ console.log(`✅ Both plugins uninstalled successfully.`);
696
+ } catch (err) {
697
+ console.error("❌ Error uninstalling plugins:", err);
698
+ }
699
+ return;
700
+ }
701
+
702
+ console.log(`⚠️ Installing ${install} and uninstalling ${uninstall} for ${store}...`);
703
+ try {
704
+ if (install) {
705
+ execSync(`npm install ${install}`, { stdio: 'inherit' });
706
+ }
707
+ if (uninstall) {
708
+ execSync(`npm uninstall ${uninstall}`, { stdio: 'inherit' });
709
+ }
710
+ console.log(`✅ ${install} installed and ${uninstall} uninstalled successfully.`);
711
+ } catch (err) {
712
+ console.error(`❌ Error managing packages for ${store}:`, err);
713
+ }
714
+ }
715
+
716
+
717
+
718
+ function updateAndroidManifest(store, addPermission) {
719
+ try {
720
+ if (!existsSync(androidManifestPath)) {
721
+ console.error("❌ AndroidManifest.xml file not found!");
722
+ return;
723
+ }
724
+
725
+ // Read the content of the AndroidManifest.xml
726
+ let manifestContent = readFileSync(androidManifestPath, 'utf-8');
727
+
728
+ // Normalize line endings to `\n` for consistent processing
729
+ manifestContent = manifestContent.replace(/\r\n/g, '\n');
730
+
731
+ // Check if the permission is already present
732
+ if (manifestContent.includes(addPermission.trim())) {
733
+ console.log(`${addPermission} is already in the AndroidManifest.xml. Skipping addition.`);
734
+ return; // Skip if the permission is already present
735
+ }
736
+
737
+ // Insert the permission before the closing </manifest> tag
738
+ const closingTag = '</manifest>';
739
+ const formattedPermission = ` ${addPermission.trim()}\n`;
740
+ if (manifestContent.includes(closingTag)) {
741
+ manifestContent = manifestContent.replace(
742
+ closingTag,
743
+ `${formattedPermission}${closingTag}`
744
+ );
745
+ console.log(`✅ Added ${addPermission} before </manifest> tag.`);
746
+ } else {
747
+ console.warn(`⚠️ </manifest> tag not found. Adding ${addPermission} at the end of the file.`);
748
+ manifestContent += `\n${formattedPermission}`;
749
+ }
750
+
751
+ // Normalize line endings back to `\r\n` and write the updated content
752
+ manifestContent = manifestContent.replace(/\n/g, '\r\n');
753
+ writeFileSync(androidManifestPath, manifestContent, 'utf-8');
754
+ console.log(`✅ AndroidManifest.xml updated successfully for ${store}`);
755
+ } catch (err) {
756
+ console.error(`❌ Error updating AndroidManifest.xml for ${store}:`, err);
757
+ }
758
+ }
759
+
760
+
761
+
762
+ /* function updateAndroidManifest1(store, addPermission) {
763
+ try {
764
+ if (!fs.existsSync(androidManifestPath)) {
765
+ console.error("AndroidManifest.xml file not found!");
766
+ return;
767
+ }
768
+
769
+ let manifestContent = fs.readFileSync(androidManifestPath, 'utf-8');
770
+
771
+
772
+
773
+ // Add the required permission if not already present
774
+ if (!manifestContent.includes(addPermission)) {
775
+ const manifestLines = manifestContent.split('\n');
776
+ const insertIndex = manifestLines.findIndex(line => line.trim().startsWith('<application'));
777
+ if (insertIndex > -1) {
778
+ manifestLines.splice(insertIndex, 0, ` ${addPermission}`);
779
+ manifestContent = manifestLines.join('\n');
780
+ console.log(`Added ${addPermission} to AndroidManifest.xml`);
781
+ }
782
+ }
783
+
784
+ // Write the updated content back to the file
785
+ fs.writeFileSync(androidManifestPath, manifestContent, 'utf-8');
786
+ console.log(`AndroidManifest.xml updated successfully for ${store}`);
787
+ } catch (err) {
788
+ console.error(`Error updating AndroidManifest.xml for ${store}:`, err);
789
+ }
790
+ } */
791
+
792
+
793
+
794
+
795
+
796
+
797
+
798
+