codeplay-common 4.7.8 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +2 -2
- package/LICENSE +21 -21
- package/README.md +154 -154
- package/files/buildCodeplay/apk-store-builder.js +10 -4
- package/files/buildCodeplay/codeplayBeforeBuild-6.4.js +405 -354
- package/files/buildCodeplay/ios-emi-admob-modification.js +25 -25
- package/files/buildCodeplay/manifestModification.js +12 -12
- package/files/buildCodeplay/newly added.txt +89 -89
- package/files/buildCodeplay/release-sync.config.json +4 -4
- package/files/buildCodeplay/remove-force-kotlin-disable.js +43 -43
- package/files/buildCodeplay/setSplashAnimation-1.4.js +70 -70
- package/files/buildCodeplay/versions.json +4 -4
- package/files/finalrelease +49 -49
- package/files/generate-ai-promo-video.js +23 -23
- package/files/iap-install-2.js +145 -145
- package/files/ionic.config.json +6 -6
- package/files/scripts/setup-baseline-profile.js +265 -265
- package/files/scripts-screenshot/screenshot/background-decorations.js +120 -120
- package/files/scripts-screenshot/screenshot/frame-samples.js +117 -117
- package/files/scripts-screenshot/screenshot/screenshot-copy.json +44 -44
- package/files/scripts-screenshot/screenshot/screenshot-info.json +1737 -1737
- package/files/take-screen-image.js +3949 -3949
- package/files/take-screen-video.js +644 -644
- package/package.json +15 -15
- package/scripts/sync-files.js +104 -104
- package/scripts/uninstall.js +109 -109
|
@@ -44,15 +44,15 @@ const ONESIGNAL_PLUGIN_NAME = "onesignal-cordova-plugin";
|
|
|
44
44
|
const ADMOB_NEXTGEN_PLUGIN_NAME = "admob-emi-nextgen";
|
|
45
45
|
const ADMOB_NEXTGEN_FILE_PATTERN = new RegExp(`^${ADMOB_NEXTGEN_PLUGIN_NAME}-\\d+(?:\\.\\d+)*\\.js$`);
|
|
46
46
|
const ADMOB_NEXTGEN_CONFIG = "admob-ad-configuration-nextgen.json";
|
|
47
|
-
const ADMOB_OLD_CONFIG = "admob-ad-configuration.json";
|
|
48
|
-
const AGENT_INSTRUCTIONS_VERSION_KEY = "agents";
|
|
49
|
-
const AGENT_INSTRUCTIONS_ZIP_PREFIX = "agents";
|
|
50
|
-
const AGENT_INSTRUCTIONS_FILE = "AGENTS.md";
|
|
51
|
-
const AGENT_INSTRUCTIONS_DIR = "AGENTS";
|
|
47
|
+
const ADMOB_OLD_CONFIG = "admob-ad-configuration.json";
|
|
48
|
+
const AGENT_INSTRUCTIONS_VERSION_KEY = "agents";
|
|
49
|
+
const AGENT_INSTRUCTIONS_ZIP_PREFIX = "agents";
|
|
50
|
+
const AGENT_INSTRUCTIONS_FILE = "AGENTS.md";
|
|
51
|
+
const AGENT_INSTRUCTIONS_DIR = "AGENTS";
|
|
52
52
|
const AGENT_INSTRUCTIONS_VERSION_FILE = ".codeplay-version";
|
|
53
53
|
|
|
54
54
|
// Remove the retired plugin before any validation, patching or package updates.
|
|
55
|
-
removeOneSignalPlugin();
|
|
55
|
+
removeOneSignalPlugin();
|
|
56
56
|
|
|
57
57
|
const parseVersionParts = (version) => String(version || "0")
|
|
58
58
|
.trim()
|
|
@@ -531,107 +531,107 @@ checkAppUniqueId();
|
|
|
531
531
|
|
|
532
532
|
|
|
533
533
|
|
|
534
|
-
// ======================================================
|
|
535
|
-
// ENSURE IAP STARTS FROM THE HOME PAGE
|
|
536
|
-
// ======================================================
|
|
537
|
-
|
|
538
|
-
const getHomePagePath = () => {
|
|
539
|
-
const pagesDir = path.join(ROOT_DIR, "pages");
|
|
540
|
-
if (!fs.existsSync(pagesDir)) return null;
|
|
541
|
-
|
|
542
|
-
const exactHomePath = path.join(pagesDir, "home.f7");
|
|
543
|
-
if (fs.existsSync(exactHomePath)) return exactHomePath;
|
|
544
|
-
|
|
545
|
-
const pageFiles = fs.readdirSync(pagesDir)
|
|
546
|
-
.filter(fileName => fileName.endsWith(".f7"));
|
|
547
|
-
|
|
548
|
-
return pageFiles
|
|
549
|
-
.map(fileName => path.join(pagesDir, fileName))
|
|
550
|
-
.find(filePath => /data-name\s*=\s*['"]home['"]/.test(fs.readFileSync(filePath, "utf8"))) || null;
|
|
551
|
-
};
|
|
552
|
-
|
|
553
|
-
const getRelativeModuleImport = (sourceFile, targetFile) => {
|
|
554
|
-
let relativePath = path.relative(path.dirname(sourceFile), targetFile).replace(/\\/g, "/");
|
|
555
|
-
if (!relativePath.startsWith(".")) relativePath = `./${relativePath}`;
|
|
556
|
-
return relativePath;
|
|
557
|
-
};
|
|
558
|
-
|
|
559
|
-
const addInitIapToExistingImport = (content) => {
|
|
560
|
-
const iapImportRegex = /import\s*\{([^}]*)\}\s*from\s*(['"])([^'"]*\/IAP-\d+(?:\.\d+)*\/IAP-check-And-LoadAd\.js)\2\s*;?/;
|
|
561
|
-
const match = content.match(iapImportRegex);
|
|
562
|
-
if (!match || /\binitIAP\b/.test(match[1])) return content;
|
|
563
|
-
|
|
564
|
-
const importNames = match[1].trim();
|
|
565
|
-
const nextImportNames = importNames ? `initIAP, ${importNames}` : "initIAP";
|
|
566
|
-
return content.replace(iapImportRegex, `import { ${nextImportNames} } from ${match[2]}${match[3]}${match[2]};`);
|
|
567
|
-
};
|
|
568
|
-
|
|
569
|
-
const addInitIapCall = (content) => {
|
|
570
|
-
if (/\binitIAP\s*\(/.test(content)) return content;
|
|
571
|
-
|
|
572
|
-
const pageInitRegex = /(\$on\(\s*(['"])pageInit\2\s*,\s*(?:async\s*)?\(\)\s*=>\s*\{\s*\r?\n)/;
|
|
573
|
-
if (pageInitRegex.test(content)) {
|
|
574
|
-
return content.replace(pageInitRegex, "$1 initIAP();\n");
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
const componentStartRegex = /(export\s+default\s*\([^)]*\)\s*=>\s*\{\s*\r?\n)/;
|
|
578
|
-
if (componentStartRegex.test(content)) {
|
|
579
|
-
return content.replace(componentStartRegex, "$1 initIAP();\n");
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
throw new Error("Unable to find a Framework7 component or pageInit lifecycle for IAP startup.");
|
|
583
|
-
};
|
|
584
|
-
|
|
585
|
-
const ensureIapStartupOnHomePage = () => {
|
|
586
|
-
const iapConfig = getAdmobIapConfig()?.IAP;
|
|
587
|
-
if (!isAnyIapStoreEnabled(iapConfig)) {
|
|
588
|
-
console.log("ℹ️ IAP is disabled for every store. AdMob will use direct startup.");
|
|
589
|
-
return;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
const latestIapDir = getLatestIapDir();
|
|
593
|
-
if (!latestIapDir) {
|
|
594
|
-
throw new Error("IAP is enabled but no IAP-x.x folder was found.");
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
const homePagePath = getHomePagePath();
|
|
598
|
-
if (!homePagePath) {
|
|
599
|
-
throw new Error("IAP is enabled but a Framework7 Home page could not be found in src/pages.");
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
const iapModulePath = path.join(latestIapDir, "IAP-check-And-LoadAd.js");
|
|
603
|
-
if (!fs.existsSync(iapModulePath)) {
|
|
604
|
-
throw new Error(`IAP startup module is missing: ${iapModulePath}`);
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
let content = fs.readFileSync(homePagePath, "utf8");
|
|
608
|
-
const originalContent = content;
|
|
609
|
-
const staticInitImportRegex = /import\s*\{[^}]*\binitIAP\b[^}]*\}\s*from\s*['"][^'"]*\/IAP-\d+(?:\.\d+)*\/IAP-check-And-LoadAd\.js['"]\s*;?/;
|
|
610
|
-
|
|
611
|
-
content = addInitIapToExistingImport(content);
|
|
612
|
-
|
|
613
|
-
if (!staticInitImportRegex.test(content)) {
|
|
614
|
-
const relativeImport = getRelativeModuleImport(homePagePath, iapModulePath);
|
|
615
|
-
const scriptStartRegex = /<script>\s*\r?\n/;
|
|
616
|
-
if (!scriptStartRegex.test(content)) {
|
|
617
|
-
throw new Error(`Unable to find the script block in ${homePagePath}`);
|
|
618
|
-
}
|
|
619
|
-
content = content.replace(scriptStartRegex, `$&import { initIAP } from '${relativeImport}';\n`);
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
content = addInitIapCall(content);
|
|
623
|
-
|
|
624
|
-
if (content !== originalContent) {
|
|
625
|
-
fs.writeFileSync(homePagePath, content, "utf8");
|
|
626
|
-
console.log(`✅ Added direct IAP startup to ${path.relative(process.cwd(), homePagePath)}.`);
|
|
627
|
-
} else {
|
|
628
|
-
console.log(`ℹ️ Direct IAP startup already configured in ${path.relative(process.cwd(), homePagePath)}.`);
|
|
629
|
-
}
|
|
630
|
-
};
|
|
631
|
-
|
|
632
|
-
// ======================================================
|
|
633
|
-
// ENSURE IAP STARTS FROM THE HOME PAGE END
|
|
634
|
-
// ======================================================
|
|
534
|
+
// ======================================================
|
|
535
|
+
// ENSURE IAP STARTS FROM THE HOME PAGE
|
|
536
|
+
// ======================================================
|
|
537
|
+
|
|
538
|
+
const getHomePagePath = () => {
|
|
539
|
+
const pagesDir = path.join(ROOT_DIR, "pages");
|
|
540
|
+
if (!fs.existsSync(pagesDir)) return null;
|
|
541
|
+
|
|
542
|
+
const exactHomePath = path.join(pagesDir, "home.f7");
|
|
543
|
+
if (fs.existsSync(exactHomePath)) return exactHomePath;
|
|
544
|
+
|
|
545
|
+
const pageFiles = fs.readdirSync(pagesDir)
|
|
546
|
+
.filter(fileName => fileName.endsWith(".f7"));
|
|
547
|
+
|
|
548
|
+
return pageFiles
|
|
549
|
+
.map(fileName => path.join(pagesDir, fileName))
|
|
550
|
+
.find(filePath => /data-name\s*=\s*['"]home['"]/.test(fs.readFileSync(filePath, "utf8"))) || null;
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
const getRelativeModuleImport = (sourceFile, targetFile) => {
|
|
554
|
+
let relativePath = path.relative(path.dirname(sourceFile), targetFile).replace(/\\/g, "/");
|
|
555
|
+
if (!relativePath.startsWith(".")) relativePath = `./${relativePath}`;
|
|
556
|
+
return relativePath;
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
const addInitIapToExistingImport = (content) => {
|
|
560
|
+
const iapImportRegex = /import\s*\{([^}]*)\}\s*from\s*(['"])([^'"]*\/IAP-\d+(?:\.\d+)*\/IAP-check-And-LoadAd\.js)\2\s*;?/;
|
|
561
|
+
const match = content.match(iapImportRegex);
|
|
562
|
+
if (!match || /\binitIAP\b/.test(match[1])) return content;
|
|
563
|
+
|
|
564
|
+
const importNames = match[1].trim();
|
|
565
|
+
const nextImportNames = importNames ? `initIAP, ${importNames}` : "initIAP";
|
|
566
|
+
return content.replace(iapImportRegex, `import { ${nextImportNames} } from ${match[2]}${match[3]}${match[2]};`);
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
const addInitIapCall = (content) => {
|
|
570
|
+
if (/\binitIAP\s*\(/.test(content)) return content;
|
|
571
|
+
|
|
572
|
+
const pageInitRegex = /(\$on\(\s*(['"])pageInit\2\s*,\s*(?:async\s*)?\(\)\s*=>\s*\{\s*\r?\n)/;
|
|
573
|
+
if (pageInitRegex.test(content)) {
|
|
574
|
+
return content.replace(pageInitRegex, "$1 initIAP();\n");
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const componentStartRegex = /(export\s+default\s*\([^)]*\)\s*=>\s*\{\s*\r?\n)/;
|
|
578
|
+
if (componentStartRegex.test(content)) {
|
|
579
|
+
return content.replace(componentStartRegex, "$1 initIAP();\n");
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
throw new Error("Unable to find a Framework7 component or pageInit lifecycle for IAP startup.");
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
const ensureIapStartupOnHomePage = () => {
|
|
586
|
+
const iapConfig = getAdmobIapConfig()?.IAP;
|
|
587
|
+
if (!isAnyIapStoreEnabled(iapConfig)) {
|
|
588
|
+
console.log("ℹ️ IAP is disabled for every store. AdMob will use direct startup.");
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const latestIapDir = getLatestIapDir();
|
|
593
|
+
if (!latestIapDir) {
|
|
594
|
+
throw new Error("IAP is enabled but no IAP-x.x folder was found.");
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
const homePagePath = getHomePagePath();
|
|
598
|
+
if (!homePagePath) {
|
|
599
|
+
throw new Error("IAP is enabled but a Framework7 Home page could not be found in src/pages.");
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
const iapModulePath = path.join(latestIapDir, "IAP-check-And-LoadAd.js");
|
|
603
|
+
if (!fs.existsSync(iapModulePath)) {
|
|
604
|
+
throw new Error(`IAP startup module is missing: ${iapModulePath}`);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
let content = fs.readFileSync(homePagePath, "utf8");
|
|
608
|
+
const originalContent = content;
|
|
609
|
+
const staticInitImportRegex = /import\s*\{[^}]*\binitIAP\b[^}]*\}\s*from\s*['"][^'"]*\/IAP-\d+(?:\.\d+)*\/IAP-check-And-LoadAd\.js['"]\s*;?/;
|
|
610
|
+
|
|
611
|
+
content = addInitIapToExistingImport(content);
|
|
612
|
+
|
|
613
|
+
if (!staticInitImportRegex.test(content)) {
|
|
614
|
+
const relativeImport = getRelativeModuleImport(homePagePath, iapModulePath);
|
|
615
|
+
const scriptStartRegex = /<script>\s*\r?\n/;
|
|
616
|
+
if (!scriptStartRegex.test(content)) {
|
|
617
|
+
throw new Error(`Unable to find the script block in ${homePagePath}`);
|
|
618
|
+
}
|
|
619
|
+
content = content.replace(scriptStartRegex, `$&import { initIAP } from '${relativeImport}';\n`);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
content = addInitIapCall(content);
|
|
623
|
+
|
|
624
|
+
if (content !== originalContent) {
|
|
625
|
+
fs.writeFileSync(homePagePath, content, "utf8");
|
|
626
|
+
console.log(`✅ Added direct IAP startup to ${path.relative(process.cwd(), homePagePath)}.`);
|
|
627
|
+
} else {
|
|
628
|
+
console.log(`ℹ️ Direct IAP startup already configured in ${path.relative(process.cwd(), homePagePath)}.`);
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
// ======================================================
|
|
633
|
+
// ENSURE IAP STARTS FROM THE HOME PAGE END
|
|
634
|
+
// ======================================================
|
|
635
635
|
|
|
636
636
|
|
|
637
637
|
|
|
@@ -1348,10 +1348,10 @@ let _admobConfig;
|
|
|
1348
1348
|
|
|
1349
1349
|
const androidPlatformPath = path.join(process.cwd(), 'android');
|
|
1350
1350
|
const iosPlatformPath = path.join(process.cwd(), 'ios');
|
|
1351
|
-
const androidManifestPath = path.join(process.cwd(), 'android', 'app', 'src', 'main', 'AndroidManifest.xml');
|
|
1352
|
-
const androidAppBuildGradlePath = path.join(process.cwd(), 'android', 'app', 'build.gradle');
|
|
1353
|
-
const AMAZON_WINDOW_EXTENSIONS_DEPENDENCY = 'implementation "androidx.window.extensions.core:core:1.0.0"';
|
|
1354
|
-
const AMAZON_WINDOW_EXTENSIONS_DEPENDENCY_PATTERN = /^[ \t]*implementation\s+["']androidx\.window\.extensions\.core:core:[^"']+["'][ \t]*(?:\r?\n)?/gm;
|
|
1351
|
+
const androidManifestPath = path.join(process.cwd(), 'android', 'app', 'src', 'main', 'AndroidManifest.xml');
|
|
1352
|
+
const androidAppBuildGradlePath = path.join(process.cwd(), 'android', 'app', 'build.gradle');
|
|
1353
|
+
const AMAZON_WINDOW_EXTENSIONS_DEPENDENCY = 'implementation "androidx.window.extensions.core:core:1.0.0"';
|
|
1354
|
+
const AMAZON_WINDOW_EXTENSIONS_DEPENDENCY_PATTERN = /^[ \t]*implementation\s+["']androidx\.window\.extensions\.core:core:[^"']+["'][ \t]*(?:\r?\n)?/gm;
|
|
1355
1355
|
const infoPlistPath = path.join(process.cwd(), 'ios', 'App', 'App', 'Info.plist');
|
|
1356
1356
|
const iosSceneDelegatePath = path.join(process.cwd(), 'ios', 'App', 'App', 'SceneDelegate.swift');
|
|
1357
1357
|
const resourcesPath = path.join(process.cwd(), 'resources', 'res');
|
|
@@ -1623,7 +1623,8 @@ function updateInfoPlist(admobConfig) {
|
|
|
1623
1623
|
const plistData = plist.parse(plistContent);
|
|
1624
1624
|
|
|
1625
1625
|
plistData.GADApplicationIdentifier = admobConfig.APP_ID_IOS;
|
|
1626
|
-
plistData.NSUserTrackingUsageDescription
|
|
1626
|
+
if (isKidsAdmobApp()) delete plistData.NSUserTrackingUsageDescription;
|
|
1627
|
+
else plistData.NSUserTrackingUsageDescription = admobConfig.USER_TRACKING_DESCRIPTION;
|
|
1627
1628
|
plistData.GADDelayAppMeasurementInit = true;
|
|
1628
1629
|
|
|
1629
1630
|
// https://developers.google.com/admob/ios/quick-start
|
|
@@ -1684,25 +1685,7 @@ function updateIOSSceneDelegateForATT() {
|
|
|
1684
1685
|
}
|
|
1685
1686
|
|
|
1686
1687
|
let content = fs.readFileSync(iosSceneDelegatePath, 'utf8');
|
|
1687
|
-
if (content.includes('ATTrackingManager.requestTrackingAuthorization')) return;
|
|
1688
|
-
|
|
1689
1688
|
const newline = content.includes('\r\n') ? '\r\n' : '\n';
|
|
1690
|
-
const sceneClass = /class SceneDelegate\s*:\s*[^\{]+\{/;
|
|
1691
|
-
if (!sceneClass.test(content) || !/import UIKit\r?\n/.test(content) || !content.trimEnd().endsWith('}')) {
|
|
1692
|
-
console.warn('SceneDelegate.swift has an unexpected structure. Skipping the iOS ATT scene update.');
|
|
1693
|
-
return;
|
|
1694
|
-
}
|
|
1695
|
-
|
|
1696
|
-
if (!content.includes('import AppTrackingTransparency')) {
|
|
1697
|
-
content = content.replace(/import UIKit\r?\n/, (match) => `${match}import AppTrackingTransparency${newline}`);
|
|
1698
|
-
}
|
|
1699
|
-
|
|
1700
|
-
if (!content.includes('isTrackingAuthorizationRequestScheduled')) {
|
|
1701
|
-
content = content.replace(sceneClass, (match) =>
|
|
1702
|
-
`${match}${newline} private var isTrackingAuthorizationRequestScheduled = false`
|
|
1703
|
-
);
|
|
1704
|
-
}
|
|
1705
|
-
|
|
1706
1689
|
const requestBody = [
|
|
1707
1690
|
' if ATTrackingManager.trackingAuthorizationStatus == .notDetermined &&',
|
|
1708
1691
|
' !isTrackingAuthorizationRequestScheduled {',
|
|
@@ -1719,6 +1702,36 @@ function updateIOSSceneDelegateForATT() {
|
|
|
1719
1702
|
' }',
|
|
1720
1703
|
].join(newline);
|
|
1721
1704
|
|
|
1705
|
+
if (isKidsAdmobApp()) {
|
|
1706
|
+
const originalContent = content;
|
|
1707
|
+
content = content.split(requestBody).join('');
|
|
1708
|
+
if (content.includes('ATTrackingManager.requestTrackingAuthorization')) {
|
|
1709
|
+
throw new Error('Kids app still contains a custom ATT request in SceneDelegate.swift. Remove that request before building.');
|
|
1710
|
+
}
|
|
1711
|
+
content = content.replace(/^[ \t]*private var isTrackingAuthorizationRequestScheduled = false\r?\n/gm, '');
|
|
1712
|
+
if (!content.includes('ATTrackingManager')) {
|
|
1713
|
+
content = content.replace(/^import AppTrackingTransparency\r?\n/gm, '');
|
|
1714
|
+
}
|
|
1715
|
+
if (content !== originalContent) fs.writeFileSync(iosSceneDelegatePath, content, 'utf8');
|
|
1716
|
+
console.log('iOS ATT scene prompt disabled for this kids app.');
|
|
1717
|
+
return;
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
if (content.includes('ATTrackingManager.requestTrackingAuthorization')) return;
|
|
1721
|
+
const sceneClass = /class SceneDelegate\s*:\s*[^\{]+\{/;
|
|
1722
|
+
if (!sceneClass.test(content) || !/import UIKit\r?\n/.test(content) || !content.trimEnd().endsWith('}')) {
|
|
1723
|
+
console.warn('SceneDelegate.swift has an unexpected structure. Skipping the iOS ATT scene update.');
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1726
|
+
if (!content.includes('import AppTrackingTransparency')) {
|
|
1727
|
+
content = content.replace(/import UIKit\r?\n/, (match) => `${match}import AppTrackingTransparency${newline}`);
|
|
1728
|
+
}
|
|
1729
|
+
if (!content.includes('isTrackingAuthorizationRequestScheduled')) {
|
|
1730
|
+
content = content.replace(sceneClass, (match) =>
|
|
1731
|
+
`${match}${newline} private var isTrackingAuthorizationRequestScheduled = false`
|
|
1732
|
+
);
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1722
1735
|
const activeSceneMethod = /func sceneDidBecomeActive\s*\(\s*_ scene:\s*UIScene\s*\)\s*\{/;
|
|
1723
1736
|
if (activeSceneMethod.test(content)) {
|
|
1724
1737
|
content = content.replace(activeSceneMethod, (match) => `${match}${newline}${requestBody}`);
|
|
@@ -1982,7 +1995,7 @@ function updateImports(oldName, newName) {
|
|
|
1982
1995
|
|
|
1983
1996
|
|
|
1984
1997
|
let _serverVersions = null;
|
|
1985
|
-
async function fetchVersions() {
|
|
1998
|
+
async function fetchVersions() {
|
|
1986
1999
|
|
|
1987
2000
|
if (_serverVersions) return _serverVersions;
|
|
1988
2001
|
|
|
@@ -2019,125 +2032,125 @@ async function fetchVersions() {
|
|
|
2019
2032
|
|
|
2020
2033
|
});
|
|
2021
2034
|
|
|
2022
|
-
}
|
|
2023
|
-
|
|
2024
|
-
function getAgentInstructionsZipLayout(zip) {
|
|
2025
|
-
const entries = zip.getEntries().filter(entry => !entry.isDirectory);
|
|
2026
|
-
|
|
2027
|
-
for (const entry of entries) {
|
|
2028
|
-
const normalizedName = entry.entryName.replace(/\\/g, "/");
|
|
2029
|
-
if (
|
|
2030
|
-
normalizedName.startsWith("/") ||
|
|
2031
|
-
normalizedName.split("/").includes("..") ||
|
|
2032
|
-
path.isAbsolute(entry.entryName)
|
|
2033
|
-
) {
|
|
2034
|
-
throw new Error(`Unsafe path in agent instructions ZIP: ${entry.entryName}`);
|
|
2035
|
-
}
|
|
2036
|
-
}
|
|
2037
|
-
|
|
2038
|
-
const normalizedEntries = entries.map(entry => ({
|
|
2039
|
-
entry,
|
|
2040
|
-
name: entry.entryName.replace(/\\/g, "/")
|
|
2041
|
-
}));
|
|
2042
|
-
const agentFile = normalizedEntries.find(({ name }) =>
|
|
2043
|
-
name.toLowerCase() === AGENT_INSTRUCTIONS_FILE.toLowerCase()
|
|
2044
|
-
);
|
|
2045
|
-
const supportFiles = normalizedEntries
|
|
2046
|
-
.filter(({ name }) => name.toLowerCase() !== AGENT_INSTRUCTIONS_FILE.toLowerCase())
|
|
2047
|
-
.map(({ entry, name }) => {
|
|
2048
|
-
const agentDirectoryPrefix = `${AGENT_INSTRUCTIONS_DIR.toLowerCase()}/`;
|
|
2049
|
-
const relativePath = name.toLowerCase().startsWith(agentDirectoryPrefix)
|
|
2050
|
-
? name.slice(name.indexOf("/") + 1)
|
|
2051
|
-
: name;
|
|
2052
|
-
|
|
2053
|
-
return { entry, relativePath };
|
|
2054
|
-
})
|
|
2055
|
-
.filter(({ relativePath }) =>
|
|
2056
|
-
relativePath &&
|
|
2057
|
-
path.basename(relativePath).toLowerCase() !== AGENT_INSTRUCTIONS_VERSION_FILE.toLowerCase()
|
|
2058
|
-
);
|
|
2059
|
-
|
|
2060
|
-
if (!agentFile || !supportFiles.length) {
|
|
2061
|
-
throw new Error(
|
|
2062
|
-
`Agent instructions ZIP must contain ${AGENT_INSTRUCTIONS_FILE} (case-insensitive) and at least one supporting file.`
|
|
2063
|
-
);
|
|
2064
|
-
}
|
|
2065
|
-
|
|
2066
|
-
return { agentFile: agentFile.entry, supportFiles };
|
|
2067
|
-
}
|
|
2068
|
-
|
|
2069
|
-
function readInstalledAgentInstructionsVersion(projectRoot) {
|
|
2070
|
-
const versionFile = path.join(projectRoot, AGENT_INSTRUCTIONS_DIR, AGENT_INSTRUCTIONS_VERSION_FILE);
|
|
2071
|
-
if (!fs.existsSync(versionFile)) return "0";
|
|
2072
|
-
|
|
2073
|
-
const installedVersion = String(fs.readFileSync(versionFile, "utf8")).trim();
|
|
2074
|
-
return /^\d+(?:\.\d+)*$/.test(installedVersion) ? installedVersion : "0";
|
|
2075
|
-
}
|
|
2076
|
-
|
|
2077
|
-
async function syncAgentInstructions() {
|
|
2078
|
-
const projectRoot = process.cwd();
|
|
2079
|
-
const targetAgentFile = path.join(projectRoot, AGENT_INSTRUCTIONS_FILE);
|
|
2080
|
-
const targetAgentDir = path.join(projectRoot, AGENT_INSTRUCTIONS_DIR);
|
|
2081
|
-
const localVersion = readInstalledAgentInstructionsVersion(projectRoot);
|
|
2082
|
-
|
|
2083
|
-
const versions = await fetchVersions();
|
|
2084
|
-
const remoteVersion = String(versions?.[AGENT_INSTRUCTIONS_VERSION_KEY] || "").trim();
|
|
2085
|
-
|
|
2086
|
-
if (!/^\d+(?:\.\d+)*$/.test(remoteVersion)) {
|
|
2087
|
-
throw new Error(`Required agent instructions could not be resolved from the server.`);
|
|
2088
|
-
}
|
|
2089
|
-
|
|
2090
|
-
const remoteIsNewer = compareVersionStrings(remoteVersion, localVersion) > 0;
|
|
2091
|
-
if (!remoteIsNewer) {
|
|
2092
|
-
console.log(`✅ Agent instructions do not need an update (local ${localVersion}, online ${remoteVersion}).`);
|
|
2093
|
-
return;
|
|
2094
|
-
}
|
|
2095
|
-
|
|
2096
|
-
const zipName = `${AGENT_INSTRUCTIONS_ZIP_PREFIX}-${remoteVersion}.zip`;
|
|
2097
|
-
const url = `https://htmlcodeplay.com/code-play-plugin/${zipName}`;
|
|
2098
|
-
const tempRoot = fs.mkdtempSync(path.join(require("os").tmpdir(), "codeplay-agents-"));
|
|
2099
|
-
const zipPath = path.join(tempRoot, zipName);
|
|
2100
|
-
const extractPath = path.join(tempRoot, "extracted");
|
|
2101
|
-
|
|
2102
|
-
try {
|
|
2103
|
-
console.log(`🔍 Checking latest agent instructions: ${zipName}`);
|
|
2104
|
-
if (!(await urlExists(url))) {
|
|
2105
|
-
throw new Error(`Required agent instructions archive not found: ${url}`);
|
|
2106
|
-
}
|
|
2107
|
-
|
|
2108
|
-
await downloadFile(url, zipPath);
|
|
2109
|
-
console.log(`⬇️ Downloaded agent instructions archive: ${zipName}`);
|
|
2110
|
-
const zip = new AdmZip(zipPath);
|
|
2111
|
-
const archiveLayout = getAgentInstructionsZipLayout(zip);
|
|
2112
|
-
|
|
2113
|
-
const stagedAgentFile = path.join(extractPath, AGENT_INSTRUCTIONS_FILE);
|
|
2114
|
-
const stagedAgentDir = path.join(extractPath, AGENT_INSTRUCTIONS_DIR);
|
|
2115
|
-
fs.mkdirSync(stagedAgentDir, { recursive: true });
|
|
2116
|
-
fs.writeFileSync(stagedAgentFile, archiveLayout.agentFile.getData());
|
|
2117
|
-
archiveLayout.supportFiles.forEach(({ entry, relativePath }) => {
|
|
2118
|
-
const stagedSupportFile = path.join(stagedAgentDir, relativePath);
|
|
2119
|
-
fs.mkdirSync(path.dirname(stagedSupportFile), { recursive: true });
|
|
2120
|
-
fs.writeFileSync(stagedSupportFile, entry.getData());
|
|
2121
|
-
});
|
|
2122
|
-
|
|
2123
|
-
fs.rmSync(targetAgentDir, { recursive: true, force: true });
|
|
2124
|
-
fs.mkdirSync(targetAgentDir, { recursive: true });
|
|
2125
|
-
fs.copyFileSync(stagedAgentFile, targetAgentFile);
|
|
2126
|
-
fs.cpSync(stagedAgentDir, targetAgentDir, { recursive: true, force: true });
|
|
2127
|
-
fs.writeFileSync(
|
|
2128
|
-
path.join(targetAgentDir, AGENT_INSTRUCTIONS_VERSION_FILE),
|
|
2129
|
-
`${remoteVersion}\n`,
|
|
2130
|
-
"utf8"
|
|
2131
|
-
);
|
|
2132
|
-
|
|
2133
|
-
writeUpdateLine(`Agent instructions ${localVersion} -> ${remoteVersion}`);
|
|
2134
|
-
console.log(`✅ Agent instructions replaced in the project root → v${remoteVersion}.`);
|
|
2135
|
-
} catch (error) {
|
|
2136
|
-
throw new Error(`Required agent instructions installation failed: ${error?.message || error}`);
|
|
2137
|
-
} finally {
|
|
2138
|
-
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
2139
|
-
}
|
|
2140
|
-
}
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
function getAgentInstructionsZipLayout(zip) {
|
|
2038
|
+
const entries = zip.getEntries().filter(entry => !entry.isDirectory);
|
|
2039
|
+
|
|
2040
|
+
for (const entry of entries) {
|
|
2041
|
+
const normalizedName = entry.entryName.replace(/\\/g, "/");
|
|
2042
|
+
if (
|
|
2043
|
+
normalizedName.startsWith("/") ||
|
|
2044
|
+
normalizedName.split("/").includes("..") ||
|
|
2045
|
+
path.isAbsolute(entry.entryName)
|
|
2046
|
+
) {
|
|
2047
|
+
throw new Error(`Unsafe path in agent instructions ZIP: ${entry.entryName}`);
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
const normalizedEntries = entries.map(entry => ({
|
|
2052
|
+
entry,
|
|
2053
|
+
name: entry.entryName.replace(/\\/g, "/")
|
|
2054
|
+
}));
|
|
2055
|
+
const agentFile = normalizedEntries.find(({ name }) =>
|
|
2056
|
+
name.toLowerCase() === AGENT_INSTRUCTIONS_FILE.toLowerCase()
|
|
2057
|
+
);
|
|
2058
|
+
const supportFiles = normalizedEntries
|
|
2059
|
+
.filter(({ name }) => name.toLowerCase() !== AGENT_INSTRUCTIONS_FILE.toLowerCase())
|
|
2060
|
+
.map(({ entry, name }) => {
|
|
2061
|
+
const agentDirectoryPrefix = `${AGENT_INSTRUCTIONS_DIR.toLowerCase()}/`;
|
|
2062
|
+
const relativePath = name.toLowerCase().startsWith(agentDirectoryPrefix)
|
|
2063
|
+
? name.slice(name.indexOf("/") + 1)
|
|
2064
|
+
: name;
|
|
2065
|
+
|
|
2066
|
+
return { entry, relativePath };
|
|
2067
|
+
})
|
|
2068
|
+
.filter(({ relativePath }) =>
|
|
2069
|
+
relativePath &&
|
|
2070
|
+
path.basename(relativePath).toLowerCase() !== AGENT_INSTRUCTIONS_VERSION_FILE.toLowerCase()
|
|
2071
|
+
);
|
|
2072
|
+
|
|
2073
|
+
if (!agentFile || !supportFiles.length) {
|
|
2074
|
+
throw new Error(
|
|
2075
|
+
`Agent instructions ZIP must contain ${AGENT_INSTRUCTIONS_FILE} (case-insensitive) and at least one supporting file.`
|
|
2076
|
+
);
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
return { agentFile: agentFile.entry, supportFiles };
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
function readInstalledAgentInstructionsVersion(projectRoot) {
|
|
2083
|
+
const versionFile = path.join(projectRoot, AGENT_INSTRUCTIONS_DIR, AGENT_INSTRUCTIONS_VERSION_FILE);
|
|
2084
|
+
if (!fs.existsSync(versionFile)) return "0";
|
|
2085
|
+
|
|
2086
|
+
const installedVersion = String(fs.readFileSync(versionFile, "utf8")).trim();
|
|
2087
|
+
return /^\d+(?:\.\d+)*$/.test(installedVersion) ? installedVersion : "0";
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
async function syncAgentInstructions() {
|
|
2091
|
+
const projectRoot = process.cwd();
|
|
2092
|
+
const targetAgentFile = path.join(projectRoot, AGENT_INSTRUCTIONS_FILE);
|
|
2093
|
+
const targetAgentDir = path.join(projectRoot, AGENT_INSTRUCTIONS_DIR);
|
|
2094
|
+
const localVersion = readInstalledAgentInstructionsVersion(projectRoot);
|
|
2095
|
+
|
|
2096
|
+
const versions = await fetchVersions();
|
|
2097
|
+
const remoteVersion = String(versions?.[AGENT_INSTRUCTIONS_VERSION_KEY] || "").trim();
|
|
2098
|
+
|
|
2099
|
+
if (!/^\d+(?:\.\d+)*$/.test(remoteVersion)) {
|
|
2100
|
+
throw new Error(`Required agent instructions could not be resolved from the server.`);
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
const remoteIsNewer = compareVersionStrings(remoteVersion, localVersion) > 0;
|
|
2104
|
+
if (!remoteIsNewer) {
|
|
2105
|
+
console.log(`✅ Agent instructions do not need an update (local ${localVersion}, online ${remoteVersion}).`);
|
|
2106
|
+
return;
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
const zipName = `${AGENT_INSTRUCTIONS_ZIP_PREFIX}-${remoteVersion}.zip`;
|
|
2110
|
+
const url = `https://htmlcodeplay.com/code-play-plugin/${zipName}`;
|
|
2111
|
+
const tempRoot = fs.mkdtempSync(path.join(require("os").tmpdir(), "codeplay-agents-"));
|
|
2112
|
+
const zipPath = path.join(tempRoot, zipName);
|
|
2113
|
+
const extractPath = path.join(tempRoot, "extracted");
|
|
2114
|
+
|
|
2115
|
+
try {
|
|
2116
|
+
console.log(`🔍 Checking latest agent instructions: ${zipName}`);
|
|
2117
|
+
if (!(await urlExists(url))) {
|
|
2118
|
+
throw new Error(`Required agent instructions archive not found: ${url}`);
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
await downloadFile(url, zipPath);
|
|
2122
|
+
console.log(`⬇️ Downloaded agent instructions archive: ${zipName}`);
|
|
2123
|
+
const zip = new AdmZip(zipPath);
|
|
2124
|
+
const archiveLayout = getAgentInstructionsZipLayout(zip);
|
|
2125
|
+
|
|
2126
|
+
const stagedAgentFile = path.join(extractPath, AGENT_INSTRUCTIONS_FILE);
|
|
2127
|
+
const stagedAgentDir = path.join(extractPath, AGENT_INSTRUCTIONS_DIR);
|
|
2128
|
+
fs.mkdirSync(stagedAgentDir, { recursive: true });
|
|
2129
|
+
fs.writeFileSync(stagedAgentFile, archiveLayout.agentFile.getData());
|
|
2130
|
+
archiveLayout.supportFiles.forEach(({ entry, relativePath }) => {
|
|
2131
|
+
const stagedSupportFile = path.join(stagedAgentDir, relativePath);
|
|
2132
|
+
fs.mkdirSync(path.dirname(stagedSupportFile), { recursive: true });
|
|
2133
|
+
fs.writeFileSync(stagedSupportFile, entry.getData());
|
|
2134
|
+
});
|
|
2135
|
+
|
|
2136
|
+
fs.rmSync(targetAgentDir, { recursive: true, force: true });
|
|
2137
|
+
fs.mkdirSync(targetAgentDir, { recursive: true });
|
|
2138
|
+
fs.copyFileSync(stagedAgentFile, targetAgentFile);
|
|
2139
|
+
fs.cpSync(stagedAgentDir, targetAgentDir, { recursive: true, force: true });
|
|
2140
|
+
fs.writeFileSync(
|
|
2141
|
+
path.join(targetAgentDir, AGENT_INSTRUCTIONS_VERSION_FILE),
|
|
2142
|
+
`${remoteVersion}\n`,
|
|
2143
|
+
"utf8"
|
|
2144
|
+
);
|
|
2145
|
+
|
|
2146
|
+
writeUpdateLine(`Agent instructions ${localVersion} -> ${remoteVersion}`);
|
|
2147
|
+
console.log(`✅ Agent instructions replaced in the project root → v${remoteVersion}.`);
|
|
2148
|
+
} catch (error) {
|
|
2149
|
+
throw new Error(`Required agent instructions installation failed: ${error?.message || error}`);
|
|
2150
|
+
} finally {
|
|
2151
|
+
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2141
2154
|
|
|
2142
2155
|
|
|
2143
2156
|
|
|
@@ -2918,11 +2931,11 @@ const sourceImportsPackage = (packageName, ignoredFilePath) => {
|
|
|
2918
2931
|
});
|
|
2919
2932
|
};
|
|
2920
2933
|
|
|
2921
|
-
function runNpmCommand(command) {
|
|
2922
|
-
console.log(`🚀 ${command}`);
|
|
2923
|
-
execSync(command, { stdio: "inherit" });
|
|
2924
|
-
};
|
|
2925
|
-
|
|
2934
|
+
function runNpmCommand(command) {
|
|
2935
|
+
console.log(`🚀 ${command}`);
|
|
2936
|
+
execSync(command, { stdio: "inherit" });
|
|
2937
|
+
};
|
|
2938
|
+
|
|
2926
2939
|
function removeOneSignalPlugin() {
|
|
2927
2940
|
if (!isPackageAvailable(ONESIGNAL_PLUGIN_NAME)) {
|
|
2928
2941
|
console.log('ℹ️ OneSignal is not installed. Skipping removal.');
|
|
@@ -2938,8 +2951,8 @@ function removeOneSignalPlugin() {
|
|
|
2938
2951
|
console.log(`✅ Uninstalled ${ONESIGNAL_PLUGIN_NAME}.`);
|
|
2939
2952
|
}
|
|
2940
2953
|
|
|
2941
|
-
const CODEPLAY_SYSTEM_BARS_PLUGIN = "capacitor-codeplay-system-bars";
|
|
2942
|
-
|
|
2954
|
+
const CODEPLAY_SYSTEM_BARS_PLUGIN = "capacitor-codeplay-system-bars";
|
|
2955
|
+
|
|
2943
2956
|
function ensureMandatoryCapacitorPlugins() {
|
|
2944
2957
|
const requiredPackages = [
|
|
2945
2958
|
"@capacitor/device",
|
|
@@ -2957,31 +2970,31 @@ function ensureMandatoryCapacitorPlugins() {
|
|
|
2957
2970
|
}
|
|
2958
2971
|
}
|
|
2959
2972
|
|
|
2960
|
-
const syncCodeplaySystemBarsPackage = () => {
|
|
2961
|
-
if (!fs.existsSync(packageJsonPath)) {
|
|
2962
|
-
console.warn(`⚠️ package.json not found. Skipping ${CODEPLAY_SYSTEM_BARS_PLUGIN} package sync.`);
|
|
2963
|
-
return;
|
|
2964
|
-
}
|
|
2965
|
-
|
|
2966
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
2967
|
-
const declaredVersion = packageJson.dependencies?.[CODEPLAY_SYSTEM_BARS_PLUGIN];
|
|
2968
|
-
const usesLocalReference = typeof declaredVersion === "string" && declaredVersion.startsWith("file:");
|
|
2969
|
-
|
|
2970
|
-
if (usesLocalReference) {
|
|
2971
|
-
console.log(`ℹ️ Replacing the local ${CODEPLAY_SYSTEM_BARS_PLUGIN} reference with the npm package.`);
|
|
2972
|
-
runNpmCommand(`npm install ${CODEPLAY_SYSTEM_BARS_PLUGIN}`);
|
|
2973
|
-
return;
|
|
2974
|
-
}
|
|
2975
|
-
|
|
2976
|
-
if (!isPackageAvailable(CODEPLAY_SYSTEM_BARS_PLUGIN)) {
|
|
2977
|
-
runNpmCommand(`npm install ${CODEPLAY_SYSTEM_BARS_PLUGIN}`);
|
|
2978
|
-
return;
|
|
2979
|
-
}
|
|
2980
|
-
|
|
2981
|
-
console.log(`ℹ️ ${CODEPLAY_SYSTEM_BARS_PLUGIN} is already installed.`);
|
|
2982
|
-
};
|
|
2983
|
-
|
|
2984
|
-
const ADMOB_NEXTGEN_DEFAULTS = {
|
|
2973
|
+
const syncCodeplaySystemBarsPackage = () => {
|
|
2974
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
2975
|
+
console.warn(`⚠️ package.json not found. Skipping ${CODEPLAY_SYSTEM_BARS_PLUGIN} package sync.`);
|
|
2976
|
+
return;
|
|
2977
|
+
}
|
|
2978
|
+
|
|
2979
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
2980
|
+
const declaredVersion = packageJson.dependencies?.[CODEPLAY_SYSTEM_BARS_PLUGIN];
|
|
2981
|
+
const usesLocalReference = typeof declaredVersion === "string" && declaredVersion.startsWith("file:");
|
|
2982
|
+
|
|
2983
|
+
if (usesLocalReference) {
|
|
2984
|
+
console.log(`ℹ️ Replacing the local ${CODEPLAY_SYSTEM_BARS_PLUGIN} reference with the npm package.`);
|
|
2985
|
+
runNpmCommand(`npm install ${CODEPLAY_SYSTEM_BARS_PLUGIN}`);
|
|
2986
|
+
return;
|
|
2987
|
+
}
|
|
2988
|
+
|
|
2989
|
+
if (!isPackageAvailable(CODEPLAY_SYSTEM_BARS_PLUGIN)) {
|
|
2990
|
+
runNpmCommand(`npm install ${CODEPLAY_SYSTEM_BARS_PLUGIN}`);
|
|
2991
|
+
return;
|
|
2992
|
+
}
|
|
2993
|
+
|
|
2994
|
+
console.log(`ℹ️ ${CODEPLAY_SYSTEM_BARS_PLUGIN} is already installed.`);
|
|
2995
|
+
};
|
|
2996
|
+
|
|
2997
|
+
const ADMOB_NEXTGEN_DEFAULTS = {
|
|
2985
2998
|
VERSION: "1.6",
|
|
2986
2999
|
ios: { nativeid: "" },
|
|
2987
3000
|
android: { nativeid: "" },
|
|
@@ -3054,6 +3067,10 @@ function readJsonSafe(filePath) {
|
|
|
3054
3067
|
}
|
|
3055
3068
|
}
|
|
3056
3069
|
|
|
3070
|
+
function isKidsAdmobApp() {
|
|
3071
|
+
return readJsonSafe(getAdmobJsonPath())?.config?.isKidsApp === true;
|
|
3072
|
+
}
|
|
3073
|
+
|
|
3057
3074
|
function pickFirstValue(...values) {
|
|
3058
3075
|
return values.find(value => typeof value === "string" && value.trim() !== "") || "";
|
|
3059
3076
|
}
|
|
@@ -3127,7 +3144,9 @@ const mergeNextgenConfigWithoutReplacingExisting = (defaultConfig, oldConfig, ex
|
|
|
3127
3144
|
const buildNextgenAdmobConfigFromOldConfig = (templateConfig, existingNextgenConfig, oldConfig) => {
|
|
3128
3145
|
const mergedConfig = mergeNextgenConfigWithoutReplacingExisting(templateConfig, oldConfig, existingNextgenConfig);
|
|
3129
3146
|
|
|
3130
|
-
|
|
3147
|
+
const templateVersion = templateConfig.VERSION || ADMOB_NEXTGEN_DEFAULTS.VERSION;
|
|
3148
|
+
mergedConfig.VERSION = compareVersionStrings(existingNextgenConfig?.VERSION || '0', templateVersion) > 0
|
|
3149
|
+
? existingNextgenConfig.VERSION : templateVersion;
|
|
3131
3150
|
|
|
3132
3151
|
return ensureAdmobNextgenConfigDefaults(mergedConfig);
|
|
3133
3152
|
};
|
|
@@ -3720,19 +3739,19 @@ const getCurrentStoreId = () => {
|
|
|
3720
3739
|
if (!fs.existsSync(commonFilePath)) return 1;
|
|
3721
3740
|
|
|
3722
3741
|
const commonFileContent = fs.readFileSync(commonFilePath, "utf8");
|
|
3723
|
-
const environmentStoreIdMatch = commonFileContent.match(
|
|
3724
|
-
/^[ \t]*export\s+let\s+_storeid\s*=\s*import\.meta\.env\.VITE_STORE_ID\s*\|\|\s*(\d+)\s*;/m
|
|
3725
|
-
);
|
|
3726
|
-
if (environmentStoreIdMatch) return Number(environmentStoreIdMatch[1]);
|
|
3727
|
-
|
|
3728
|
-
const directStoreIdMatch = commonFileContent.match(
|
|
3729
|
-
/^[ \t]*export\s+let\s+_storeid\s*=\s*(\d+)\s*;/m
|
|
3730
|
-
);
|
|
3731
|
-
|
|
3732
|
-
return directStoreIdMatch ? Number(directStoreIdMatch[1]) : 1;
|
|
3733
|
-
};
|
|
3734
|
-
|
|
3735
|
-
const getRevenueCatStoreState = (iapConfig) => {
|
|
3742
|
+
const environmentStoreIdMatch = commonFileContent.match(
|
|
3743
|
+
/^[ \t]*export\s+let\s+_storeid\s*=\s*import\.meta\.env\.VITE_STORE_ID\s*\|\|\s*(\d+)\s*;/m
|
|
3744
|
+
);
|
|
3745
|
+
if (environmentStoreIdMatch) return Number(environmentStoreIdMatch[1]);
|
|
3746
|
+
|
|
3747
|
+
const directStoreIdMatch = commonFileContent.match(
|
|
3748
|
+
/^[ \t]*export\s+let\s+_storeid\s*=\s*(\d+)\s*;/m
|
|
3749
|
+
);
|
|
3750
|
+
|
|
3751
|
+
return directStoreIdMatch ? Number(directStoreIdMatch[1]) : 1;
|
|
3752
|
+
};
|
|
3753
|
+
|
|
3754
|
+
const getRevenueCatStoreState = (iapConfig) => {
|
|
3736
3755
|
const storeId = getCurrentStoreId();
|
|
3737
3756
|
const configuration = iapConfig.configuration || {};
|
|
3738
3757
|
const storeMap = {
|
|
@@ -3762,43 +3781,69 @@ const getRevenueCatStoreState = (iapConfig) => {
|
|
|
3762
3781
|
return {
|
|
3763
3782
|
storeId,
|
|
3764
3783
|
store: storeMap[storeId] || null
|
|
3765
|
-
};
|
|
3766
|
-
};
|
|
3767
|
-
|
|
3768
|
-
const syncAmazonFireWebViewDependency = (enabled) => {
|
|
3769
|
-
if (!fs.existsSync(androidAppBuildGradlePath)) {
|
|
3770
|
-
console.error(`❌ Android app build.gradle not found: ${androidAppBuildGradlePath}`);
|
|
3771
|
-
process.exit(1);
|
|
3772
|
-
}
|
|
3773
|
-
|
|
3774
|
-
const currentContent = fs.readFileSync(androidAppBuildGradlePath, "utf8");
|
|
3775
|
-
let nextContent = currentContent.replace(AMAZON_WINDOW_EXTENSIONS_DEPENDENCY_PATTERN, "");
|
|
3776
|
-
|
|
3777
|
-
if (enabled) {
|
|
3778
|
-
const newline = nextContent.includes("\r\n") ? "\r\n" : "\n";
|
|
3779
|
-
const dependenciesHeaderPattern = /(^dependencies[ \t]*\{[ \t]*\r?\n)/m;
|
|
3780
|
-
|
|
3781
|
-
if (!dependenciesHeaderPattern.test(nextContent)) {
|
|
3782
|
-
console.error(`❌ dependencies block not found in ${androidAppBuildGradlePath}`);
|
|
3783
|
-
process.exit(1);
|
|
3784
|
-
}
|
|
3785
|
-
|
|
3786
|
-
nextContent = nextContent.replace(
|
|
3787
|
-
dependenciesHeaderPattern,
|
|
3788
|
-
`$1 ${AMAZON_WINDOW_EXTENSIONS_DEPENDENCY}${newline}`
|
|
3789
|
-
);
|
|
3790
|
-
}
|
|
3791
|
-
|
|
3792
|
-
if (nextContent !== currentContent) {
|
|
3793
|
-
fs.writeFileSync(androidAppBuildGradlePath, nextContent, "utf8");
|
|
3794
|
-
}
|
|
3795
|
-
|
|
3796
|
-
console.log(enabled
|
|
3797
|
-
? "✅ Amazon Fire WebView compatibility dependency enabled for Store ID 7."
|
|
3798
|
-
: "ℹ️ Amazon Fire WebView compatibility dependency disabled for this store.");
|
|
3799
|
-
};
|
|
3800
|
-
|
|
3801
|
-
|
|
3784
|
+
};
|
|
3785
|
+
};
|
|
3786
|
+
|
|
3787
|
+
const syncAmazonFireWebViewDependency = (enabled) => {
|
|
3788
|
+
if (!fs.existsSync(androidAppBuildGradlePath)) {
|
|
3789
|
+
console.error(`❌ Android app build.gradle not found: ${androidAppBuildGradlePath}`);
|
|
3790
|
+
process.exit(1);
|
|
3791
|
+
}
|
|
3792
|
+
|
|
3793
|
+
const currentContent = fs.readFileSync(androidAppBuildGradlePath, "utf8");
|
|
3794
|
+
let nextContent = currentContent.replace(AMAZON_WINDOW_EXTENSIONS_DEPENDENCY_PATTERN, "");
|
|
3795
|
+
|
|
3796
|
+
if (enabled) {
|
|
3797
|
+
const newline = nextContent.includes("\r\n") ? "\r\n" : "\n";
|
|
3798
|
+
const dependenciesHeaderPattern = /(^dependencies[ \t]*\{[ \t]*\r?\n)/m;
|
|
3799
|
+
|
|
3800
|
+
if (!dependenciesHeaderPattern.test(nextContent)) {
|
|
3801
|
+
console.error(`❌ dependencies block not found in ${androidAppBuildGradlePath}`);
|
|
3802
|
+
process.exit(1);
|
|
3803
|
+
}
|
|
3804
|
+
|
|
3805
|
+
nextContent = nextContent.replace(
|
|
3806
|
+
dependenciesHeaderPattern,
|
|
3807
|
+
`$1 ${AMAZON_WINDOW_EXTENSIONS_DEPENDENCY}${newline}`
|
|
3808
|
+
);
|
|
3809
|
+
}
|
|
3810
|
+
|
|
3811
|
+
if (nextContent !== currentContent) {
|
|
3812
|
+
fs.writeFileSync(androidAppBuildGradlePath, nextContent, "utf8");
|
|
3813
|
+
}
|
|
3814
|
+
|
|
3815
|
+
console.log(enabled
|
|
3816
|
+
? "✅ Amazon Fire WebView compatibility dependency enabled for Store ID 7."
|
|
3817
|
+
: "ℹ️ Amazon Fire WebView compatibility dependency disabled for this store.");
|
|
3818
|
+
};
|
|
3819
|
+
|
|
3820
|
+
function syncAndroidAdIdPermission() {
|
|
3821
|
+
if (!fs.existsSync(androidManifestPath)) return;
|
|
3822
|
+
const originalContent = fs.readFileSync(androidManifestPath, 'utf8');
|
|
3823
|
+
const newline = originalContent.includes('\r\n') ? '\r\n' : '\n';
|
|
3824
|
+
const marker = '<!-- Codeplay: child-directed advertising ID exclusion -->';
|
|
3825
|
+
const permission = 'com.google.android.gms.permission.AD_ID';
|
|
3826
|
+
const permissionTag = `<uses-permission android:name="${permission}" tools:node="remove" />`;
|
|
3827
|
+
const generatedRule = new RegExp(`^[ \\t]*${marker}\\r?\\n[ \\t]*<uses-permission\\b[^>]*tools:node="remove"[^>]*\\/>\\r?\\n`, 'gm');
|
|
3828
|
+
const hadGeneratedRule = originalContent.includes(marker);
|
|
3829
|
+
let content = originalContent.replace(generatedRule, '');
|
|
3830
|
+
if (isKidsAdmobApp()) {
|
|
3831
|
+
content = content.replace(/(?:^[ \t]*)?<uses-permission\b[^>]*>(?:[ \t\r\n]*<\/uses-permission>)?[ \t]*(?:\r?\n)?/gm, tag =>
|
|
3832
|
+
/android:name\s*=\s*["']com\.google\.android\.gms\.permission\.AD_ID["']/.test(tag) ? '' : tag);
|
|
3833
|
+
if (!/xmlns:tools\s*=/.test(content)) {
|
|
3834
|
+
content = content.replace(/<manifest\b/, '<manifest xmlns:tools="http://schemas.android.com/tools"');
|
|
3835
|
+
}
|
|
3836
|
+
content = content.replace(/(<manifest\b[^>]*>)(?:\r?\n)?/, (match, root) => `${root}${newline} ${marker}${newline} ${permissionTag}${newline}`);
|
|
3837
|
+
} else if (hadGeneratedRule) {
|
|
3838
|
+
content = content.replace(/(<manifest\b[^>]*>)(?:\r?\n)?/, (match, root) => `${root}${newline} <uses-permission android:name="${permission}" />${newline}`);
|
|
3839
|
+
}
|
|
3840
|
+
if (content !== originalContent) {
|
|
3841
|
+
fs.writeFileSync(androidManifestPath, content, 'utf8');
|
|
3842
|
+
console.log(isKidsAdmobApp() ? 'Android advertising ID permission excluded for this kids app.' : 'Android advertising ID permission restored for this non-kids app.');
|
|
3843
|
+
}
|
|
3844
|
+
}
|
|
3845
|
+
|
|
3846
|
+
const ensureAndroidPermission = (permission, enabled) => {
|
|
3802
3847
|
if (!fs.existsSync(androidManifestPath)) return false;
|
|
3803
3848
|
|
|
3804
3849
|
let manifestContent = fs.readFileSync(androidManifestPath, "utf8");
|
|
@@ -3825,15 +3870,15 @@ const ensureAndroidPermission = (permission, enabled) => {
|
|
|
3825
3870
|
return true;
|
|
3826
3871
|
};
|
|
3827
3872
|
|
|
3828
|
-
const syncRevenueCatIapSetup = () => {
|
|
3829
|
-
const admobConfig = getAdmobIapConfig();
|
|
3830
|
-
const iapConfig = admobConfig?.IAP;
|
|
3831
|
-
|
|
3832
|
-
if (!iapConfig) {
|
|
3833
|
-
syncAmazonFireWebViewDependency(false);
|
|
3834
|
-
console.log("ℹ️ IAP configuration not found. Skipping RevenueCat package sync.");
|
|
3835
|
-
return;
|
|
3836
|
-
}
|
|
3873
|
+
const syncRevenueCatIapSetup = () => {
|
|
3874
|
+
const admobConfig = getAdmobIapConfig();
|
|
3875
|
+
const iapConfig = admobConfig?.IAP;
|
|
3876
|
+
|
|
3877
|
+
if (!iapConfig) {
|
|
3878
|
+
syncAmazonFireWebViewDependency(false);
|
|
3879
|
+
console.log("ℹ️ IAP configuration not found. Skipping RevenueCat package sync.");
|
|
3880
|
+
return;
|
|
3881
|
+
}
|
|
3837
3882
|
|
|
3838
3883
|
ensureIapDesignInCapacitorConfig(iapConfig);
|
|
3839
3884
|
|
|
@@ -3841,9 +3886,9 @@ const syncRevenueCatIapSetup = () => {
|
|
|
3841
3886
|
iapConfig.playstore === true ||
|
|
3842
3887
|
iapConfig.ios === true ||
|
|
3843
3888
|
iapConfig.amazon === true;
|
|
3844
|
-
const { storeId, store } = getRevenueCatStoreState(iapConfig);
|
|
3845
|
-
const revenueCatEnabledForCurrentStore = store?.enabled === true;
|
|
3846
|
-
syncAmazonFireWebViewDependency(storeId === 7 && iapConfig.amazon === true);
|
|
3889
|
+
const { storeId, store } = getRevenueCatStoreState(iapConfig);
|
|
3890
|
+
const revenueCatEnabledForCurrentStore = store?.enabled === true;
|
|
3891
|
+
syncAmazonFireWebViewDependency(storeId === 7 && iapConfig.amazon === true);
|
|
3847
3892
|
|
|
3848
3893
|
if (revenueCatEnabledForCurrentStore && !store.apiKey) {
|
|
3849
3894
|
console.error(`❌ RevenueCat IAP is enabled for ${store.name} but ${store.apiKeyName} is missing.`);
|
|
@@ -4246,18 +4291,19 @@ async function main() {
|
|
|
4246
4291
|
validateAndRestoreSignDetails();
|
|
4247
4292
|
ensureMandatoryCapacitorPlugins();
|
|
4248
4293
|
|
|
4249
|
-
await loadPluginVersions(); // 🔥 NEW
|
|
4250
|
-
await syncAgentInstructions();
|
|
4251
|
-
|
|
4252
|
-
await syncAdmobNextgenMigration();
|
|
4253
|
-
syncCodeplaySystemBarsPackage();
|
|
4254
|
-
syncSystemBarsSafeAreaMigration();
|
|
4255
|
-
await checkPlugins();
|
|
4256
|
-
ensureIapStartupOnHomePage();
|
|
4257
|
-
syncRevenueCatIapSetup();
|
|
4294
|
+
await loadPluginVersions(); // 🔥 NEW
|
|
4295
|
+
await syncAgentInstructions();
|
|
4296
|
+
|
|
4297
|
+
await syncAdmobNextgenMigration();
|
|
4298
|
+
syncCodeplaySystemBarsPackage();
|
|
4299
|
+
syncSystemBarsSafeAreaMigration();
|
|
4300
|
+
await checkPlugins();
|
|
4301
|
+
ensureIapStartupOnHomePage();
|
|
4302
|
+
syncRevenueCatIapSetup();
|
|
4258
4303
|
syncFirebaseAnalyticsSetup();
|
|
4259
4304
|
checkAndupdateDropInViteConfig();
|
|
4260
4305
|
checkAdmobConfigurationProperty();
|
|
4306
|
+
syncAndroidAdIdPermission();
|
|
4261
4307
|
}
|
|
4262
4308
|
|
|
4263
4309
|
await main();
|
|
@@ -4272,6 +4318,11 @@ await main();
|
|
|
4272
4318
|
/*
|
|
4273
4319
|
Release Notes
|
|
4274
4320
|
|
|
4321
|
+
6.5
|
|
4322
|
+
Kids ad configuration disables iOS ATT prompts and excludes Android AD_ID during builds.
|
|
4323
|
+
Non-kids apps retain tracking prompts and normal permission behavior.
|
|
4324
|
+
Ad configuration migration preserves newer local configuration versions.
|
|
4325
|
+
|
|
4275
4326
|
5.1
|
|
4276
4327
|
Kotlin version update is commented. Previously admob is not worked if not update the kotlin version to higher version
|
|
4277
4328
|
|