codeplay-common 1.6.3 → 1.6.4

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