codeplay-common 4.0.4 → 4.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -11,6 +11,20 @@ Make it to ionic project
|
|
|
11
11
|
Donate to get full code including many common functions
|
|
12
12
|
https://ko-fi.com/codeplay
|
|
13
13
|
|
|
14
|
+
|
|
15
|
+
Version 4.0.6
|
|
16
|
+
IAP related some automatic variable creation and validation
|
|
17
|
+
Fetch from vite.config.json file
|
|
18
|
+
'import.meta.env.VITE_APP_UNIQUE_ID': JSON.stringify(APP_UNIQUE_ID),
|
|
19
|
+
'import.meta.env.VITE_ANDROID_ANALYTICS_ENABLED': JSON.stringify(ANDROID_ANALYTICS_ENABLED),
|
|
20
|
+
'import.meta.env.VITE_IOS_ANALYTICS_ENABLED': JSON.stringify(IOS_ANALYTICS_ENABLED),
|
|
21
|
+
'import.meta.env.VITE_IAP_DESIGN': JSON.stringify(IAP_DESIGN),
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
Version 4.0.5
|
|
25
|
+
In "files\buildCodeplay\packageidBaseModification-1.4.js" SCHEDULE_EXACT_ALARM permission added for the app unique id 2 (resume generator app)
|
|
26
|
+
|
|
27
|
+
|
|
14
28
|
Version 4.0.4
|
|
15
29
|
patchFile(); method is disabled, Due to "@capacitor/android:8.4.2" this update. I think it is realted to safearea issue fixed in this latest version, file in "SystemBars.java"
|
|
16
30
|
|
|
@@ -272,16 +272,68 @@ function compareWithBeta(installedVersion, minVersion, isBeta) {
|
|
|
272
272
|
|
|
273
273
|
|
|
274
274
|
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
275
|
+
const ensureAnalyticsFlagsInConfig = (config) => {
|
|
276
|
+
const analyticsFlagKey = 'ANALYTICS_ENABLED';
|
|
277
|
+
const legacyAnalyticsFlagKey = ['ANALY', 'STICS_ENABLED'].join('');
|
|
278
|
+
let updated = false;
|
|
279
|
+
|
|
280
|
+
if (!config.android) {
|
|
281
|
+
config.android = {};
|
|
282
|
+
updated = true;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (!config.ios) {
|
|
286
|
+
config.ios = {};
|
|
287
|
+
updated = true;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const syncPlatformFlag = (platformName, platformConfig) => {
|
|
291
|
+
const existingValue = platformConfig[analyticsFlagKey];
|
|
292
|
+
const legacyValue = platformConfig[legacyAnalyticsFlagKey];
|
|
293
|
+
let nextValue = false;
|
|
294
|
+
|
|
295
|
+
if (typeof existingValue === 'boolean') {
|
|
296
|
+
nextValue = existingValue;
|
|
297
|
+
} else if (typeof legacyValue === 'boolean') {
|
|
298
|
+
nextValue = legacyValue;
|
|
299
|
+
} else if (existingValue !== undefined) {
|
|
300
|
+
console.warn(`⚠️ ${platformName}.ANALYTICS_ENABLED should be true or false. Automatically setting it to false.`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (platformConfig[analyticsFlagKey] !== nextValue) {
|
|
304
|
+
platformConfig[analyticsFlagKey] = nextValue;
|
|
305
|
+
updated = true;
|
|
306
|
+
console.warn(`⚠️ ${platformName}.ANALYTICS_ENABLED added/updated as ${nextValue}.`);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (legacyAnalyticsFlagKey in platformConfig) {
|
|
310
|
+
delete platformConfig[legacyAnalyticsFlagKey];
|
|
311
|
+
updated = true;
|
|
312
|
+
console.warn(`⚠️ ${platformName}.ANALYTICS_ENABLED spelling corrected.`);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (nextValue === false) {
|
|
316
|
+
console.warn(`⚠️ Google Analytics is disabled for ${platformName}. Mostly recommended to enable it when IAP is available.`);
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
syncPlatformFlag('android', config.android);
|
|
321
|
+
syncPlatformFlag('ios', config.ios);
|
|
322
|
+
|
|
323
|
+
return updated;
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
const checkAppUniqueId=()=>{
|
|
327
|
+
|
|
328
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
329
|
+
const analyticsFlagsUpdated = ensureAnalyticsFlagsInConfig(config);
|
|
330
|
+
|
|
331
|
+
const appUniqueId = config.android?.APP_UNIQUE_ID;
|
|
332
|
+
const RESIZEABLE_ACTIVITY = config.android?.RESIZEABLE_ACTIVITY;
|
|
333
|
+
const orientation = config.android?.ORIENTATION;
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
let logErrorMessage="";
|
|
285
337
|
|
|
286
338
|
// 1️⃣ Check if it’s missing
|
|
287
339
|
if (RESIZEABLE_ACTIVITY === undefined) {
|
|
@@ -309,22 +361,30 @@ const checkAppUniqueId=()=>{
|
|
|
309
361
|
logErrorMessage+='❌ APP_UNIQUE_ID is missing in capacitor.config.json.';
|
|
310
362
|
}
|
|
311
363
|
|
|
312
|
-
else if (!Number.isInteger(appUniqueId)) {
|
|
313
|
-
logErrorMessage+='❌ APP_UNIQUE_ID must be an integer. Example: 1, 2, 3, etc.';
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
364
|
+
else if (!Number.isInteger(appUniqueId)) {
|
|
365
|
+
logErrorMessage+='❌ APP_UNIQUE_ID must be an integer. Example: 1, 2, 3, etc.';
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if(logErrorMessage!="")
|
|
369
|
+
{
|
|
370
|
+
if (analyticsFlagsUpdated) {
|
|
371
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
372
|
+
console.log('✅ capacitor.config.json analytics flags synced.');
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
console.error(logErrorMessage);
|
|
376
|
+
process.exit(1)
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (analyticsFlagsUpdated) {
|
|
380
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
381
|
+
console.log('✅ capacitor.config.json analytics flags synced.');
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
console.log(`✅ APP_UNIQUE_ID is valid: ${appUniqueId}`);
|
|
386
|
+
|
|
387
|
+
}
|
|
328
388
|
|
|
329
389
|
checkAppUniqueId();
|
|
330
390
|
|
|
@@ -2456,7 +2516,7 @@ const checkAndupdateDropInViteConfig = () => {
|
|
|
2456
2516
|
console.log("✅ vite.config.(m)js Updated successfully.");
|
|
2457
2517
|
};
|
|
2458
2518
|
|
|
2459
|
-
const syncAdmobAliasInViteConfig = () => {
|
|
2519
|
+
const syncAdmobAliasInViteConfig = () => {
|
|
2460
2520
|
const possibleFiles = [
|
|
2461
2521
|
"vite.config.mjs",
|
|
2462
2522
|
"vite.config.js"
|
|
@@ -2517,15 +2577,607 @@ const syncAdmobAliasInViteConfig = () => {
|
|
|
2517
2577
|
viteContent = viteContent.replace(aliasLineRegex, nextGenAliasLine);
|
|
2518
2578
|
fs.writeFileSync(viteConfigPath, viteContent, "utf8");
|
|
2519
2579
|
console.log(`✅ @admob alias updated to ${nextGenRelativePath}`);
|
|
2520
|
-
};
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2580
|
+
};
|
|
2581
|
+
|
|
2582
|
+
|
|
2583
|
+
const getViteConfigPath = () => {
|
|
2584
|
+
const possibleFiles = [
|
|
2585
|
+
"vite.config.mjs",
|
|
2586
|
+
"vite.config.js"
|
|
2587
|
+
];
|
|
2588
|
+
|
|
2589
|
+
return possibleFiles
|
|
2590
|
+
.map(file => path.join(process.cwd(), file))
|
|
2591
|
+
.find(filePath => fs.existsSync(filePath));
|
|
2592
|
+
};
|
|
2593
|
+
|
|
2594
|
+
const getLatestIapDir = () => {
|
|
2595
|
+
const adsDir = path.join(process.cwd(), "src", "js", "Ads");
|
|
2596
|
+
|
|
2597
|
+
if (!fs.existsSync(adsDir)) return null;
|
|
2598
|
+
|
|
2599
|
+
const iapDirs = fs.readdirSync(adsDir, { withFileTypes: true })
|
|
2600
|
+
.filter(entry => entry.isDirectory() && /^IAP-\d+(\.\d+)*$/.test(entry.name))
|
|
2601
|
+
.map(entry => entry.name)
|
|
2602
|
+
.sort((a, b) => {
|
|
2603
|
+
const versionA = a.match(/(\d+(?:\.\d+)*)/)[1].split(".").map(Number);
|
|
2604
|
+
const versionB = b.match(/(\d+(?:\.\d+)*)/)[1].split(".").map(Number);
|
|
2605
|
+
|
|
2606
|
+
for (let i = 0; i < Math.max(versionA.length, versionB.length); i++) {
|
|
2607
|
+
const diff = (versionB[i] || 0) - (versionA[i] || 0);
|
|
2608
|
+
if (diff !== 0) return diff;
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2611
|
+
return 0;
|
|
2612
|
+
});
|
|
2613
|
+
|
|
2614
|
+
return iapDirs.length > 0 ? path.join(adsDir, iapDirs[0]) : null;
|
|
2615
|
+
};
|
|
2616
|
+
|
|
2617
|
+
const getAnalyticsConfig = () => {
|
|
2618
|
+
const config = fs.existsSync(configPath)
|
|
2619
|
+
? JSON.parse(fs.readFileSync(configPath, "utf8"))
|
|
2620
|
+
: {};
|
|
2621
|
+
|
|
2622
|
+
const analyticsFlagKey = "ANALYTICS_ENABLED";
|
|
2623
|
+
const androidEnabled = config.android?.[analyticsFlagKey] ?? false;
|
|
2624
|
+
const iosEnabled = config.ios?.[analyticsFlagKey] ?? false;
|
|
2625
|
+
|
|
2626
|
+
return {
|
|
2627
|
+
androidEnabled: androidEnabled === true,
|
|
2628
|
+
iosEnabled: iosEnabled === true,
|
|
2629
|
+
enabled: androidEnabled === true || iosEnabled === true
|
|
2630
|
+
};
|
|
2631
|
+
};
|
|
2632
|
+
|
|
2633
|
+
const isPackageAvailable = (packageName) => {
|
|
2634
|
+
if (!fs.existsSync(packageJsonPath)) return false;
|
|
2635
|
+
|
|
2636
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
2637
|
+
|
|
2638
|
+
return Boolean(
|
|
2639
|
+
packageJson.dependencies?.[packageName] ||
|
|
2640
|
+
packageJson.devDependencies?.[packageName] ||
|
|
2641
|
+
fs.existsSync(path.join(process.cwd(), "node_modules", packageName, "package.json"))
|
|
2642
|
+
);
|
|
2643
|
+
};
|
|
2644
|
+
|
|
2645
|
+
const sourceImportsPackage = (packageName, ignoredFilePath) => {
|
|
2646
|
+
const sourceDir = path.join(process.cwd(), "src");
|
|
2647
|
+
if (!fs.existsSync(sourceDir)) return false;
|
|
2648
|
+
|
|
2649
|
+
const escapedPackage = packageName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2650
|
+
const importRegex = new RegExp(`(?:from\\s*['"]${escapedPackage}(?:/[^'"]*)?['"]|import\\s*['"]${escapedPackage}(?:/[^'"]*)?['"]|import\\s*\\(\\s*['"]${escapedPackage}(?:/[^'"]*)?['"]\\s*\\)|require\\s*\\(\\s*['"]${escapedPackage}(?:/[^'"]*)?['"]\\s*\\))`);
|
|
2651
|
+
|
|
2652
|
+
const scan = (dir) => {
|
|
2653
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
2654
|
+
const fullPath = path.join(dir, entry.name);
|
|
2655
|
+
|
|
2656
|
+
if (ignoredFilePath && path.resolve(fullPath) === path.resolve(ignoredFilePath)) {
|
|
2657
|
+
continue;
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
if (entry.isDirectory()) {
|
|
2661
|
+
if (scan(fullPath)) return true;
|
|
2662
|
+
continue;
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
if (!/\.(js|mjs|cjs|ts|tsx|jsx|f7)$/.test(entry.name)) continue;
|
|
2666
|
+
|
|
2667
|
+
const content = fs.readFileSync(fullPath, "utf8");
|
|
2668
|
+
if (importRegex.test(content)) return true;
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
return false;
|
|
2672
|
+
};
|
|
2673
|
+
|
|
2674
|
+
return scan(sourceDir);
|
|
2675
|
+
};
|
|
2676
|
+
|
|
2677
|
+
const runNpmCommand = (command) => {
|
|
2678
|
+
console.log(`🚀 ${command}`);
|
|
2679
|
+
execSync(command, { stdio: "inherit" });
|
|
2680
|
+
};
|
|
2681
|
+
|
|
2682
|
+
const ensureFirebaseAnalyticsWrapper = (analyticsEnabled) => {
|
|
2683
|
+
const analyticsDir = getLatestIapDir();
|
|
2684
|
+
const legacyAnalyticsDir = path.join(process.cwd(), "src", "js", "analytics");
|
|
2685
|
+
const legacyAnalyticsFile = path.join(legacyAnalyticsDir, "firebase-analytics.js");
|
|
2686
|
+
|
|
2687
|
+
if (!analyticsDir) {
|
|
2688
|
+
console.warn("⚠️ No IAP-x.x folder found. Skipping Firebase analytics wrapper sync.");
|
|
2689
|
+
return null;
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2692
|
+
const analyticsFile = path.join(analyticsDir, "firebase-analytics.js");
|
|
2693
|
+
|
|
2694
|
+
if (!fs.existsSync(analyticsDir)) {
|
|
2695
|
+
fs.mkdirSync(analyticsDir, { recursive: true });
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2698
|
+
const activeWrapper = `import { Capacitor, registerPlugin } from '@capacitor/core';
|
|
2699
|
+
|
|
2700
|
+
const FirebaseAnalytics = registerPlugin('FirebaseAnalytics');
|
|
2701
|
+
|
|
2702
|
+
const isEnabledValue = (value) => value === true || value === 'true';
|
|
2703
|
+
|
|
2704
|
+
const canUseNativeAnalytics = () => {
|
|
2705
|
+
if (!Capacitor.isNativePlatform()) return false;
|
|
2706
|
+
|
|
2707
|
+
const platform = Capacitor.getPlatform();
|
|
2708
|
+
|
|
2709
|
+
if (platform === 'android') {
|
|
2710
|
+
return isEnabledValue(import.meta.env.VITE_ANDROID_ANALYTICS_ENABLED);
|
|
2711
|
+
}
|
|
2712
|
+
|
|
2713
|
+
if (platform === 'ios') {
|
|
2714
|
+
return isEnabledValue(import.meta.env.VITE_IOS_ANALYTICS_ENABLED);
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
return false;
|
|
2718
|
+
};
|
|
2719
|
+
|
|
2720
|
+
const cleanParams = (params = {}) => {
|
|
2721
|
+
return Object.entries(params).reduce((result, [key, value]) => {
|
|
2722
|
+
if (value === undefined || value === null || value === '') return result;
|
|
2723
|
+
if (typeof value === 'number' && Number.isNaN(value)) return result;
|
|
2724
|
+
|
|
2725
|
+
result[key] = value;
|
|
2726
|
+
return result;
|
|
2727
|
+
}, {});
|
|
2728
|
+
};
|
|
2729
|
+
|
|
2730
|
+
const trackEvent = async (name, params = {}) => {
|
|
2731
|
+
if (!canUseNativeAnalytics()) return;
|
|
2732
|
+
|
|
2733
|
+
try {
|
|
2734
|
+
await FirebaseAnalytics.logEvent({
|
|
2735
|
+
name,
|
|
2736
|
+
params: cleanParams(params),
|
|
2737
|
+
});
|
|
2738
|
+
} catch (err) {
|
|
2739
|
+
console.warn(\`Firebase analytics event failed: \${name}\`, err);
|
|
2740
|
+
}
|
|
2741
|
+
};
|
|
2742
|
+
|
|
2743
|
+
export const trackSubscriptionScreenViewed = (params) => {
|
|
2744
|
+
trackEvent('subscription_screen_view', params);
|
|
2745
|
+
};
|
|
2746
|
+
|
|
2747
|
+
export const trackSubscriptionCheckoutStarted = (params) => {
|
|
2748
|
+
trackEvent('subscription_checkout_start', params);
|
|
2749
|
+
};
|
|
2750
|
+
|
|
2751
|
+
export const trackSubscriptionPurchased = (params) => {
|
|
2752
|
+
trackEvent('subscription_purchase', params);
|
|
2753
|
+
};
|
|
2754
|
+
|
|
2755
|
+
export const trackConsumablePurchased = (params) => {
|
|
2756
|
+
trackEvent('consumable_purchase', params);
|
|
2757
|
+
};
|
|
2758
|
+
`;
|
|
2759
|
+
|
|
2760
|
+
const noopWrapper = `const trackEvent = () => {};
|
|
2761
|
+
|
|
2762
|
+
export const trackSubscriptionScreenViewed = trackEvent;
|
|
2763
|
+
export const trackSubscriptionCheckoutStarted = trackEvent;
|
|
2764
|
+
export const trackSubscriptionPurchased = trackEvent;
|
|
2765
|
+
export const trackConsumablePurchased = trackEvent;
|
|
2766
|
+
`;
|
|
2767
|
+
|
|
2768
|
+
const nextContent = analyticsEnabled ? activeWrapper : noopWrapper;
|
|
2769
|
+
const currentContent = fs.existsSync(analyticsFile) ? fs.readFileSync(analyticsFile, "utf8") : "";
|
|
2770
|
+
|
|
2771
|
+
if (currentContent !== nextContent) {
|
|
2772
|
+
fs.writeFileSync(analyticsFile, nextContent, "utf8");
|
|
2773
|
+
console.log(`✅ Firebase analytics wrapper ${analyticsEnabled ? "enabled" : "disabled"}: ${path.relative(process.cwd(), analyticsFile)}`);
|
|
2774
|
+
} else {
|
|
2775
|
+
console.log(`ℹ️ Firebase analytics wrapper already ${analyticsEnabled ? "enabled" : "disabled"}.`);
|
|
2776
|
+
}
|
|
2777
|
+
|
|
2778
|
+
if (fs.existsSync(legacyAnalyticsFile)) {
|
|
2779
|
+
fs.unlinkSync(legacyAnalyticsFile);
|
|
2780
|
+
console.log("✅ Removed old Firebase analytics wrapper: src/js/analytics/firebase-analytics.js");
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
if (fs.existsSync(legacyAnalyticsDir) && fs.readdirSync(legacyAnalyticsDir).length === 0) {
|
|
2784
|
+
fs.rmdirSync(legacyAnalyticsDir);
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
return analyticsFile;
|
|
2788
|
+
};
|
|
2789
|
+
|
|
2790
|
+
const syncFirebaseAnalyticsPackages = () => {
|
|
2791
|
+
const analyticsConfig = getAnalyticsConfig();
|
|
2792
|
+
|
|
2793
|
+
if (analyticsConfig.enabled) {
|
|
2794
|
+
if (!isPackageAvailable("@capacitor-firebase/analytics") || !isPackageAvailable("firebase")) {
|
|
2795
|
+
runNpmCommand("npm install @capacitor-firebase/analytics firebase");
|
|
2796
|
+
} else {
|
|
2797
|
+
console.log("ℹ️ Firebase Analytics packages already installed.");
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2800
|
+
ensureFirebaseAnalyticsWrapper(true);
|
|
2801
|
+
return;
|
|
2802
|
+
}
|
|
2803
|
+
|
|
2804
|
+
const analyticsFile = ensureFirebaseAnalyticsWrapper(false);
|
|
2805
|
+
|
|
2806
|
+
if (isPackageAvailable("@capacitor-firebase/analytics")) {
|
|
2807
|
+
runNpmCommand("npm uninstall @capacitor-firebase/analytics");
|
|
2808
|
+
} else {
|
|
2809
|
+
console.log("ℹ️ @capacitor-firebase/analytics is not installed.");
|
|
2810
|
+
}
|
|
2811
|
+
|
|
2812
|
+
if (isPackageAvailable("firebase")) {
|
|
2813
|
+
if (sourceImportsPackage("firebase", analyticsFile)) {
|
|
2814
|
+
console.log("ℹ️ Keeping firebase package because other source files import it.");
|
|
2815
|
+
} else {
|
|
2816
|
+
runNpmCommand("npm uninstall firebase");
|
|
2817
|
+
}
|
|
2818
|
+
}
|
|
2819
|
+
};
|
|
2820
|
+
|
|
2821
|
+
const syncFirebaseAnalyticsPodfile = () => {
|
|
2822
|
+
const podfilePath = path.join(process.cwd(), "ios", "App", "Podfile");
|
|
2823
|
+
if (!fs.existsSync(podfilePath)) return;
|
|
2824
|
+
|
|
2825
|
+
const { iosEnabled } = getAnalyticsConfig();
|
|
2826
|
+
const basePodLine = " pod 'CapacitorFirebaseAnalytics', :path => '../../node_modules/@capacitor-firebase/analytics'";
|
|
2827
|
+
const analyticsPodLine = " pod 'CapacitorFirebaseAnalytics/Analytics', :path => '../../node_modules/@capacitor-firebase/analytics'";
|
|
2828
|
+
|
|
2829
|
+
let content = fs.readFileSync(podfilePath, "utf8");
|
|
2830
|
+
let nextContent = content;
|
|
2831
|
+
|
|
2832
|
+
if (iosEnabled) {
|
|
2833
|
+
if (!nextContent.includes(basePodLine)) {
|
|
2834
|
+
nextContent = nextContent.replace(
|
|
2835
|
+
/(pod 'CapacitorCommunitySafeArea'[^\n]*\r?\n)/,
|
|
2836
|
+
`$1${basePodLine}\n`
|
|
2837
|
+
);
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
if (!nextContent.includes(analyticsPodLine)) {
|
|
2841
|
+
nextContent = nextContent.replace(
|
|
2842
|
+
/(# Add your Pods here\r?\n)/,
|
|
2843
|
+
`$1${analyticsPodLine}\n`
|
|
2844
|
+
);
|
|
2845
|
+
}
|
|
2846
|
+
} else {
|
|
2847
|
+
nextContent = nextContent
|
|
2848
|
+
.split(/\r?\n/)
|
|
2849
|
+
.filter(line => !line.includes("CapacitorFirebaseAnalytics"))
|
|
2850
|
+
.join("\n");
|
|
2851
|
+
}
|
|
2852
|
+
|
|
2853
|
+
if (nextContent !== content) {
|
|
2854
|
+
fs.writeFileSync(podfilePath, nextContent, "utf8");
|
|
2855
|
+
console.log(`✅ iOS Firebase Analytics Podfile entries ${iosEnabled ? "enabled" : "removed"}.`);
|
|
2856
|
+
} else {
|
|
2857
|
+
console.log(`ℹ️ iOS Firebase Analytics Podfile entries already ${iosEnabled ? "enabled" : "disabled"}.`);
|
|
2858
|
+
}
|
|
2859
|
+
};
|
|
2860
|
+
|
|
2861
|
+
const ensureImportOrRequire = (content, moduleName, esmLine, cjsLine) => {
|
|
2862
|
+
const escaped = moduleName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2863
|
+
if (new RegExp(`from\\s*['"]${escaped}['"]|require\\s*\\(\\s*['"]${escaped}['"]\\s*\\)`).test(content)) {
|
|
2864
|
+
return content;
|
|
2865
|
+
}
|
|
2866
|
+
|
|
2867
|
+
const isCommonJs = /module\.exports|require\s*\(/.test(content);
|
|
2868
|
+
const line = isCommonJs ? cjsLine : esmLine;
|
|
2869
|
+
|
|
2870
|
+
return `${line}\n${content}`;
|
|
2871
|
+
};
|
|
2872
|
+
|
|
2873
|
+
const ensureViteDefineEntry = (viteContent, key, valueExpression) => {
|
|
2874
|
+
const entry = ` '${key}': JSON.stringify(${valueExpression}),`;
|
|
2875
|
+
|
|
2876
|
+
if (viteContent.includes(`'${key}'`) || viteContent.includes(`"${key}"`)) {
|
|
2877
|
+
return viteContent;
|
|
2878
|
+
}
|
|
2879
|
+
|
|
2880
|
+
if (/define\s*:\s*{/.test(viteContent)) {
|
|
2881
|
+
return viteContent.replace(/define\s*:\s*{\s*/, match => `${match}\n${entry}\n`);
|
|
2882
|
+
}
|
|
2883
|
+
|
|
2884
|
+
const defineBlock = ` define: {
|
|
2885
|
+
'${key}': JSON.stringify(${valueExpression}),
|
|
2886
|
+
},`;
|
|
2887
|
+
|
|
2888
|
+
if (/\n\s*publicDir\s*:\s*[^,\n]+,?/.test(viteContent)) {
|
|
2889
|
+
return viteContent.replace(
|
|
2890
|
+
/(\n\s*publicDir\s*:\s*[^,\n]+,?)/,
|
|
2891
|
+
`$1\n${defineBlock}`
|
|
2892
|
+
);
|
|
2893
|
+
}
|
|
2894
|
+
|
|
2895
|
+
return viteContent.replace(
|
|
2896
|
+
/(return\s+{)/,
|
|
2897
|
+
`$1\n${defineBlock}`
|
|
2898
|
+
);
|
|
2899
|
+
};
|
|
2900
|
+
|
|
2901
|
+
const ensurePrivacyAndAnalyticsViteConfig = () => {
|
|
2902
|
+
const viteConfigPath = getViteConfigPath();
|
|
2903
|
+
|
|
2904
|
+
if (!viteConfigPath) {
|
|
2905
|
+
console.warn("⚠️ No vite config found. Skipping privacy/analytics Vite sync.");
|
|
2906
|
+
return;
|
|
2907
|
+
}
|
|
2908
|
+
|
|
2909
|
+
let viteContent = fs.readFileSync(viteConfigPath, "utf8");
|
|
2910
|
+
const originalContent = viteContent;
|
|
2911
|
+
|
|
2912
|
+
viteContent = ensureImportOrRequire(
|
|
2913
|
+
viteContent,
|
|
2914
|
+
"fs",
|
|
2915
|
+
"import fs from 'fs';",
|
|
2916
|
+
"const fs = require('fs');"
|
|
2917
|
+
);
|
|
2918
|
+
|
|
2919
|
+
viteContent = ensureImportOrRequire(
|
|
2920
|
+
viteContent,
|
|
2921
|
+
"path",
|
|
2922
|
+
"import path from 'path';",
|
|
2923
|
+
"const path = require('path');"
|
|
2924
|
+
);
|
|
2925
|
+
|
|
2926
|
+
if (!/\bcapacitorConfig\b/.test(viteContent)) {
|
|
2927
|
+
viteContent = viteContent.replace(
|
|
2928
|
+
/(\r?\nexport\s+default|\r?\nmodule\.exports)/,
|
|
2929
|
+
`\nconst capacitorConfig = JSON.parse(fs.readFileSync(path.resolve(__dirname, './capacitor.config.json'), 'utf8'));\n$1`
|
|
2930
|
+
);
|
|
2931
|
+
}
|
|
2932
|
+
|
|
2933
|
+
if (!/\bAPP_UNIQUE_ID\b/.test(viteContent)) {
|
|
2934
|
+
viteContent = viteContent.replace(
|
|
2935
|
+
/(const capacitorConfig = JSON\.parse\(fs\.readFileSync\(path\.resolve\(__dirname,\s*['"]\.\/capacitor\.config\.json['"]\),\s*['"]utf8['"]\)\);\r?\n)/,
|
|
2936
|
+
`$1const APP_UNIQUE_ID = capacitorConfig.android?.APP_UNIQUE_ID ?? '';\n`
|
|
2937
|
+
);
|
|
2938
|
+
}
|
|
2939
|
+
|
|
2940
|
+
if (!/\bANDROID_ANALYTICS_ENABLED\b/.test(viteContent)) {
|
|
2941
|
+
viteContent = viteContent.replace(
|
|
2942
|
+
/(const APP_UNIQUE_ID = capacitorConfig\.android\?\.APP_UNIQUE_ID \?\? ['"]['"];\r?\n)/,
|
|
2943
|
+
`$1const ANDROID_ANALYTICS_ENABLED = capacitorConfig.android?.ANALYTICS_ENABLED ?? false;\n`
|
|
2944
|
+
);
|
|
2945
|
+
}
|
|
2946
|
+
|
|
2947
|
+
if (!/\bIOS_ANALYTICS_ENABLED\b/.test(viteContent)) {
|
|
2948
|
+
viteContent = viteContent.replace(
|
|
2949
|
+
/(const ANDROID_ANALYTICS_ENABLED = capacitorConfig\.android\?\.ANALYTICS_ENABLED \?\? false;\r?\n)/,
|
|
2950
|
+
`$1const IOS_ANALYTICS_ENABLED = capacitorConfig.ios?.ANALYTICS_ENABLED ?? false;\n`
|
|
2951
|
+
);
|
|
2952
|
+
}
|
|
2953
|
+
|
|
2954
|
+
if (!/\bIAP_DESIGN\b/.test(viteContent)) {
|
|
2955
|
+
viteContent = viteContent.replace(
|
|
2956
|
+
/(const IOS_ANALYTICS_ENABLED = capacitorConfig\.ios\?\.ANALYTICS_ENABLED \?\? false;\r?\n)/,
|
|
2957
|
+
`$1const IAP_DESIGN = capacitorConfig["IAP-Design"] ?? 'default';\n`
|
|
2958
|
+
);
|
|
2959
|
+
}
|
|
2960
|
+
|
|
2961
|
+
viteContent = viteContent
|
|
2962
|
+
.replace(
|
|
2963
|
+
/const ANDROID_ANALYTICS_ENABLED = capacitorConfig\.android\?\.ANALY[ST]ICS_ENABLED \?\? capacitorConfig\.android\?\.ANALYTICS_ENABLED \?\? false;/g,
|
|
2964
|
+
"const ANDROID_ANALYTICS_ENABLED = capacitorConfig.android?.ANALYTICS_ENABLED ?? false;"
|
|
2965
|
+
)
|
|
2966
|
+
.replace(
|
|
2967
|
+
/const IOS_ANALYTICS_ENABLED = capacitorConfig\.ios\?\.ANALY[ST]ICS_ENABLED \?\? capacitorConfig\.ios\?\.ANALYTICS_ENABLED \?\? false;/g,
|
|
2968
|
+
"const IOS_ANALYTICS_ENABLED = capacitorConfig.ios?.ANALYTICS_ENABLED ?? false;"
|
|
2969
|
+
);
|
|
2970
|
+
|
|
2971
|
+
viteContent = ensureViteDefineEntry(viteContent, "import.meta.env.VITE_APP_UNIQUE_ID", "APP_UNIQUE_ID");
|
|
2972
|
+
viteContent = ensureViteDefineEntry(viteContent, "import.meta.env.VITE_ANDROID_ANALYTICS_ENABLED", "ANDROID_ANALYTICS_ENABLED");
|
|
2973
|
+
viteContent = ensureViteDefineEntry(viteContent, "import.meta.env.VITE_IOS_ANALYTICS_ENABLED", "IOS_ANALYTICS_ENABLED");
|
|
2974
|
+
viteContent = ensureViteDefineEntry(viteContent, "import.meta.env.VITE_IAP_DESIGN", "IAP_DESIGN");
|
|
2975
|
+
|
|
2976
|
+
if (viteContent !== originalContent) {
|
|
2977
|
+
fs.writeFileSync(viteConfigPath, viteContent, "utf8");
|
|
2978
|
+
console.log("✅ vite.config.(m)js privacy/analytics settings synced.");
|
|
2979
|
+
} else {
|
|
2980
|
+
console.log("ℹ️ vite.config.(m)js privacy/analytics settings already synced.");
|
|
2981
|
+
}
|
|
2982
|
+
};
|
|
2983
|
+
|
|
2984
|
+
const syncFirebaseAnalyticsSetup = () => {
|
|
2985
|
+
syncFirebaseAnalyticsPackages();
|
|
2986
|
+
syncFirebaseAnalyticsPodfile();
|
|
2987
|
+
ensurePrivacyAndAnalyticsViteConfig();
|
|
2988
|
+
};
|
|
2989
|
+
|
|
2990
|
+
const getAdmobIapConfigPath = () => {
|
|
2991
|
+
const possiblePaths = [
|
|
2992
|
+
path.join(process.cwd(), 'src', 'js', 'Ads', 'admob-ad-configuration-nextgen.json'),
|
|
2993
|
+
path.join(process.cwd(), 'src', 'js', 'Ads', 'admob-ad-configuration.json')
|
|
2994
|
+
];
|
|
2995
|
+
|
|
2996
|
+
return possiblePaths.find(fileExists);
|
|
2997
|
+
};
|
|
2998
|
+
|
|
2999
|
+
const getAdmobIapConfig = () => {
|
|
3000
|
+
const admobIapConfigPath = getAdmobIapConfigPath();
|
|
3001
|
+
|
|
3002
|
+
if (!admobIapConfigPath) {
|
|
3003
|
+
console.warn("⚠️ No AdMob configuration JSON found. Skipping RevenueCat IAP package sync.");
|
|
3004
|
+
return null;
|
|
3005
|
+
}
|
|
3006
|
+
|
|
3007
|
+
try {
|
|
3008
|
+
return JSON.parse(fs.readFileSync(admobIapConfigPath, "utf8"));
|
|
3009
|
+
} catch (err) {
|
|
3010
|
+
console.error(`❌ Failed to read ${path.relative(process.cwd(), admobIapConfigPath)}`, err);
|
|
3011
|
+
process.exit(1);
|
|
3012
|
+
}
|
|
3013
|
+
};
|
|
3014
|
+
|
|
3015
|
+
const isAnyIapStoreEnabled = (iapConfig) => {
|
|
3016
|
+
return Boolean(
|
|
3017
|
+
iapConfig?.playstore === true ||
|
|
3018
|
+
iapConfig?.samsung === true ||
|
|
3019
|
+
iapConfig?.amazon === true ||
|
|
3020
|
+
iapConfig?.ios === true
|
|
3021
|
+
);
|
|
3022
|
+
};
|
|
3023
|
+
|
|
3024
|
+
const ensureIapDesignInCapacitorConfig = (iapConfig) => {
|
|
3025
|
+
if (!isAnyIapStoreEnabled(iapConfig)) return;
|
|
3026
|
+
|
|
3027
|
+
if (!fs.existsSync(configPath)) {
|
|
3028
|
+
console.warn("⚠️ capacitor.config.json not found. Skipping IAP-Design sync.");
|
|
3029
|
+
return;
|
|
3030
|
+
}
|
|
3031
|
+
|
|
3032
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
3033
|
+
|
|
3034
|
+
if (Object.prototype.hasOwnProperty.call(config, "IAP-Design")) {
|
|
3035
|
+
console.log("ℹ️ capacitor.config.json IAP-Design already configured.");
|
|
3036
|
+
return;
|
|
3037
|
+
}
|
|
3038
|
+
|
|
3039
|
+
config["IAP-Design"] = "default";
|
|
3040
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
3041
|
+
console.log('✅ Added "IAP-Design": "default" to capacitor.config.json.');
|
|
3042
|
+
};
|
|
3043
|
+
|
|
3044
|
+
const getCurrentStoreId = () => {
|
|
3045
|
+
const envStoreId = Number(process.env.VITE_STORE_ID);
|
|
3046
|
+
if (Number.isInteger(envStoreId) && envStoreId > 0) return envStoreId;
|
|
3047
|
+
|
|
3048
|
+
const viteConfigPath = getViteConfigPath();
|
|
3049
|
+
if (!viteConfigPath) return 1;
|
|
3050
|
+
|
|
3051
|
+
const viteConfigContent = fs.readFileSync(viteConfigPath, "utf8");
|
|
3052
|
+
const commonAliasMatch = viteConfigContent.match(/['"]@common['"]:\s*path\.resolve\(__dirname,\s*['"]([^'"]+)['"]\)/);
|
|
3053
|
+
|
|
3054
|
+
if (!commonAliasMatch) return 1;
|
|
3055
|
+
|
|
3056
|
+
const commonFilePath = path.resolve(path.dirname(viteConfigPath), commonAliasMatch[1]);
|
|
3057
|
+
if (!fs.existsSync(commonFilePath)) return 1;
|
|
3058
|
+
|
|
3059
|
+
const commonFileContent = fs.readFileSync(commonFilePath, "utf8");
|
|
3060
|
+
const storeIdMatch = commonFileContent.match(/export\s+let\s+_storeid\s*=\s*import\.meta\.env\.VITE_STORE_ID\s*\|\|\s*(\d+)\s*;/);
|
|
3061
|
+
|
|
3062
|
+
return storeIdMatch ? Number(storeIdMatch[1]) : 1;
|
|
3063
|
+
};
|
|
3064
|
+
|
|
3065
|
+
const getRevenueCatStoreState = (iapConfig) => {
|
|
3066
|
+
const storeId = getCurrentStoreId();
|
|
3067
|
+
const configuration = iapConfig.configuration || {};
|
|
3068
|
+
const storeMap = {
|
|
3069
|
+
1: {
|
|
3070
|
+
name: "PlayStore",
|
|
3071
|
+
enabled: iapConfig.playstore === true,
|
|
3072
|
+
apiKeyName: "IAP.configuration.playstore",
|
|
3073
|
+
apiKey: configuration.playstore,
|
|
3074
|
+
usesGoogleBilling: true
|
|
3075
|
+
},
|
|
3076
|
+
6: {
|
|
3077
|
+
name: "iOSStore",
|
|
3078
|
+
enabled: iapConfig.ios === true,
|
|
3079
|
+
apiKeyName: "IAP.configuration.ios",
|
|
3080
|
+
apiKey: configuration.ios,
|
|
3081
|
+
usesGoogleBilling: false
|
|
3082
|
+
},
|
|
3083
|
+
7: {
|
|
3084
|
+
name: "AmazonStore",
|
|
3085
|
+
enabled: iapConfig.amazon === true,
|
|
3086
|
+
apiKeyName: "IAP.configuration.amazon",
|
|
3087
|
+
apiKey: configuration.amazon,
|
|
3088
|
+
usesGoogleBilling: false
|
|
3089
|
+
}
|
|
3090
|
+
};
|
|
3091
|
+
|
|
3092
|
+
return {
|
|
3093
|
+
storeId,
|
|
3094
|
+
store: storeMap[storeId] || null
|
|
3095
|
+
};
|
|
3096
|
+
};
|
|
3097
|
+
|
|
3098
|
+
const ensureAndroidPermission = (permission, enabled) => {
|
|
3099
|
+
if (!fs.existsSync(androidManifestPath)) return false;
|
|
3100
|
+
|
|
3101
|
+
let manifestContent = fs.readFileSync(androidManifestPath, "utf8");
|
|
3102
|
+
const permissionLine = ` <uses-permission android:name="${permission}" />`;
|
|
3103
|
+
const permissionRegex = new RegExp(`^\\s*<uses-permission\\s+android:name="${permission.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}"\\s*/?>\\s*\\r?\\n?`, "m");
|
|
3104
|
+
|
|
3105
|
+
if (enabled) {
|
|
3106
|
+
if (permissionRegex.test(manifestContent)) return false;
|
|
3107
|
+
|
|
3108
|
+
manifestContent = manifestContent.replace(
|
|
3109
|
+
/<\/manifest>\s*$/,
|
|
3110
|
+
`${permissionLine}\n</manifest>`
|
|
3111
|
+
);
|
|
3112
|
+
fs.writeFileSync(androidManifestPath, manifestContent, "utf8");
|
|
3113
|
+
console.log(`✅ Added Android permission: ${permission}`);
|
|
3114
|
+
return true;
|
|
3115
|
+
}
|
|
3116
|
+
|
|
3117
|
+
if (!permissionRegex.test(manifestContent)) return false;
|
|
3118
|
+
|
|
3119
|
+
manifestContent = manifestContent.replace(permissionRegex, "");
|
|
3120
|
+
fs.writeFileSync(androidManifestPath, manifestContent, "utf8");
|
|
3121
|
+
console.log(`✅ Removed Android permission: ${permission}`);
|
|
3122
|
+
return true;
|
|
3123
|
+
};
|
|
3124
|
+
|
|
3125
|
+
const syncRevenueCatIapSetup = () => {
|
|
3126
|
+
const admobConfig = getAdmobIapConfig();
|
|
3127
|
+
const iapConfig = admobConfig?.IAP;
|
|
3128
|
+
|
|
3129
|
+
if (!iapConfig) {
|
|
3130
|
+
console.log("ℹ️ IAP configuration not found. Skipping RevenueCat package sync.");
|
|
3131
|
+
return;
|
|
3132
|
+
}
|
|
3133
|
+
|
|
3134
|
+
ensureIapDesignInCapacitorConfig(iapConfig);
|
|
3135
|
+
|
|
3136
|
+
const revenueCatEnabled =
|
|
3137
|
+
iapConfig.playstore === true ||
|
|
3138
|
+
iapConfig.ios === true ||
|
|
3139
|
+
iapConfig.amazon === true;
|
|
3140
|
+
const { storeId, store } = getRevenueCatStoreState(iapConfig);
|
|
3141
|
+
const revenueCatEnabledForCurrentStore = store?.enabled === true;
|
|
3142
|
+
|
|
3143
|
+
if (revenueCatEnabledForCurrentStore && !store.apiKey) {
|
|
3144
|
+
console.error(`❌ RevenueCat IAP is enabled for ${store.name} but ${store.apiKeyName} is missing.`);
|
|
3145
|
+
process.exit(1);
|
|
3146
|
+
}
|
|
3147
|
+
|
|
3148
|
+
let packageChanged = false;
|
|
3149
|
+
|
|
3150
|
+
if (revenueCatEnabledForCurrentStore) {
|
|
3151
|
+
if (!isPackageAvailable("@revenuecat/purchases-capacitor")) {
|
|
3152
|
+
runNpmCommand("npm install @revenuecat/purchases-capacitor");
|
|
3153
|
+
packageChanged = true;
|
|
3154
|
+
} else {
|
|
3155
|
+
console.log(`ℹ️ RevenueCat package already installed for ${store.name}.`);
|
|
3156
|
+
}
|
|
3157
|
+
} else if (isPackageAvailable("@revenuecat/purchases-capacitor")) {
|
|
3158
|
+
runNpmCommand("npm uninstall @revenuecat/purchases-capacitor");
|
|
3159
|
+
packageChanged = true;
|
|
3160
|
+
} else {
|
|
3161
|
+
console.log(`ℹ️ RevenueCat package is not required for store id ${storeId}.`);
|
|
3162
|
+
}
|
|
3163
|
+
|
|
3164
|
+
ensureAndroidPermission("com.android.vending.BILLING", store?.usesGoogleBilling === true && revenueCatEnabledForCurrentStore);
|
|
3165
|
+
|
|
3166
|
+
if (iapConfig.samsung === true && revenueCatEnabled) {
|
|
3167
|
+
console.warn("⚠️ Samsung IAP uses cordova-plugin-samsungiap; PlayStore/Amazon/iOS use RevenueCat.");
|
|
3168
|
+
}
|
|
3169
|
+
|
|
3170
|
+
if (packageChanged) {
|
|
3171
|
+
runNpmCommand("npx cap sync");
|
|
3172
|
+
}
|
|
3173
|
+
};
|
|
3174
|
+
|
|
3175
|
+
|
|
3176
|
+
|
|
3177
|
+
|
|
3178
|
+
|
|
3179
|
+
|
|
3180
|
+
|
|
2529
3181
|
|
|
2530
3182
|
|
|
2531
3183
|
const compareVersion = (v1, v2) => {
|
|
@@ -2693,14 +3345,16 @@ ensureGitignoreEntry('buildCodeplay/');
|
|
|
2693
3345
|
|
|
2694
3346
|
// Run the validation
|
|
2695
3347
|
(async () => {
|
|
2696
|
-
|
|
2697
|
-
await loadPluginVersions(); // 🔥 NEW
|
|
2698
|
-
|
|
2699
|
-
await checkPlugins();
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
3348
|
+
|
|
3349
|
+
await loadPluginVersions(); // 🔥 NEW
|
|
3350
|
+
|
|
3351
|
+
await checkPlugins();
|
|
3352
|
+
syncRevenueCatIapSetup();
|
|
3353
|
+
syncFirebaseAnalyticsSetup();
|
|
3354
|
+
checkAndupdateDropInViteConfig();
|
|
3355
|
+
syncAdmobAliasInViteConfig();
|
|
3356
|
+
checkAdmobConfigurationProperty()
|
|
3357
|
+
})();
|
|
2704
3358
|
|
|
2705
3359
|
|
|
2706
3360
|
// ======================================================
|
|
@@ -326,6 +326,7 @@ if (!fs.existsSync(configPath)) {
|
|
|
326
326
|
const rawData = fs.readFileSync(configPath, 'utf8');
|
|
327
327
|
const config = JSON.parse(rawData);
|
|
328
328
|
const targetAppId=config.appId
|
|
329
|
+
const appUniqueId=config.android?.APP_UNIQUE_ID
|
|
329
330
|
|
|
330
331
|
|
|
331
332
|
|
|
@@ -394,6 +395,23 @@ function addPostNotificationPermissionIfNeeded() {
|
|
|
394
395
|
addPostNotificationPermissionIfNeeded();
|
|
395
396
|
|
|
396
397
|
|
|
398
|
+
function addExactAlarmPermissionIfNeeded() {
|
|
399
|
+
const permission =
|
|
400
|
+
'<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />';
|
|
401
|
+
|
|
402
|
+
if (Number(appUniqueId) !== 2) {
|
|
403
|
+
console.log('ℹ️ Skipping SCHEDULE_EXACT_ALARM permission for this APP_UNIQUE_ID.');
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
console.log('✅ Career reminders app detected. Ensuring SCHEDULE_EXACT_ALARM permission...');
|
|
408
|
+
addAndroidPermissions([permission]);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
addExactAlarmPermissionIfNeeded();
|
|
413
|
+
|
|
414
|
+
|
|
397
415
|
|
|
398
416
|
|
|
399
417
|
//console.log("TARGET APP ID IS : "+ targetAppId)
|
|
@@ -418,4 +436,4 @@ else if(targetAppId=="image.to.text.document")
|
|
|
418
436
|
];
|
|
419
437
|
}
|
|
420
438
|
|
|
421
|
-
addAndroidPermissions(permissions);
|
|
439
|
+
addAndroidPermissions(permissions);
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
{"name":"ffmpeg","pattern":"ffmpeg-(\\d+\\.\\d+)$","minVersion":"1.6","baseDir":"js","mandatoryUpdate":true,"isFolder":true},
|
|
18
18
|
{"name":"theme","pattern":"theme-(\\d+\\.\\d+)$","minVersion":"3.5","baseDir":"theme","destDir":"theme","mandatoryUpdate":true,"isFolder":true},
|
|
19
19
|
{"name":"certificatejs","pattern":"certificatejs-(\\d+\\.\\d+)$","minVersion":"1.9","baseDir":"certificate","destDir":"certificate","mandatoryUpdate":true,"isFolder":true},
|
|
20
|
-
{"name":"IAP","pattern":"IAP-(\\d+\\.\\d+)$","minVersion":"3.
|
|
20
|
+
{"name":"IAP","pattern":"IAP-(\\d+\\.\\d+)$","minVersion":"3.6","baseDir":"js/Ads","mandatoryUpdate":true,"isFolder":true},
|
|
21
21
|
{"name":"common-less","pattern":"common-(\\d+\\.\\d+)\\.less$","minVersion":"1.8","baseDir":"assets/css","mandatoryUpdate":true},
|
|
22
22
|
{"name":"localNotification_AppSettings","pattern":"localNotification_AppSettings-(\\d+\\.\\d+)\\.js$","minVersion":"1.0","baseDir":"js","mandatoryUpdate":true},
|
|
23
23
|
{"name":"localNotification","pattern":"localNotification-(\\d+\\.\\d+)\\.js$","minVersion":"2.2","baseDir":"js","mandatoryUpdate":true},
|