codeplay-common 4.9.4 → 4.9.6

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.
@@ -4448,6 +4448,21 @@ function syncAndroidBuildOptimization() {
4448
4448
  }
4449
4449
  // Android build optimization END
4450
4450
 
4451
+ function syncAndroidCordovaResourceKeep() {
4452
+ if (buildPlatform !== 'android' || !fs.existsSync(androidPlatformPath)) return;
4453
+
4454
+ // Cordova loads config.xml by name; preserve it even when no plugins are installed yet.
4455
+ const rawPath = path.join(androidPlatformPath, 'app', 'src', 'main', 'res', 'raw');
4456
+ const keepPath = path.join(rawPath, 'codeplay_cordova_keep.xml');
4457
+ const content = '<?xml version="1.0" encoding="utf-8"?>\n'
4458
+ + '<resources xmlns:tools="http://schemas.android.com/tools"\n'
4459
+ + ' tools:keep="@xml/config" />\n';
4460
+ if (fs.existsSync(keepPath) && fs.readFileSync(keepPath, 'utf8') === content) return;
4461
+
4462
+ fs.mkdirSync(rawPath, { recursive: true });
4463
+ fs.writeFileSync(keepPath, content, 'utf8');
4464
+ }
4465
+
4451
4466
  async function main() {
4452
4467
  validateThemeFolderLocation();
4453
4468
  validateAndRestoreSignDetails();
@@ -4467,6 +4482,7 @@ async function main() {
4467
4482
  checkAdmobConfigurationProperty();
4468
4483
  syncAndroidAdIdPermission();
4469
4484
  syncAndroidBuildOptimization();
4485
+ syncAndroidCordovaResourceKeep();
4470
4486
  }
4471
4487
 
4472
4488
  await main();
@@ -3,9 +3,9 @@
3
3
  //node take-screen-image.js --profiles vivo-store //only taking screenshot for vivo-store - Not only vivo, we can do this to all of our store images.
4
4
  //node take-screen-image.js --vivo-existing //Used if we already took the screenshot and those vivo screenshots are not there then execute this to resize the screenshot for vivo store.
5
5
  //node take-screen-image.js --oppo-existing //Used if we already took the screenshot and those oppo screenshots are not there then execute this to resize the screenshot for Oppo store.
6
- //node take-screen-image.js --profiles iphone,iphone-duo,ipad //Capture current App Store sizes; iPhone-Duo uses the 2007x2853 inner display.
7
- //Apple also accepts 1398x2034 for the Duo outer display. This profile captures the inner display only.
8
- //New captures create iPhone-Duo folders automatically. Reframing existing files does not recapture responsive UI at the new viewport sizes.
6
+ //App Store: import actual iOS/iPadOS PNG captures; Android replay is not an Apple screenshot source.
7
+ //node take-screen-image.js --apple-source "C:\captures\iphone" --profiles iphone
8
+ //Add --apple-promotional to reuse screenshot-copy.json captions around the original capture.
9
9
 
10
10
 
11
11
  /*
@@ -74,6 +74,22 @@ const browserExecutablePaths = [
74
74
  'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe',
75
75
  ];
76
76
 
77
+ // Full-display sizes from Apple's screenshot specifications, checked 2026-10-20.
78
+ // https://developer.apple.com/help/app-store-connect/reference/app-information/screenshot-specifications/
79
+ // Source captures retain their size; never resize one Apple device family into another.
80
+ const appleScreenshotSizes = {
81
+ iphone: [
82
+ [1260, 2736], [1290, 2796], [1320, 2868], [1284, 2778], [1242, 2688],
83
+ [1179, 2556], [1206, 2622], [1170, 2532], [1125, 2436], [1080, 2340],
84
+ [1242, 2208], [750, 1334], [640, 1136], [640, 960],
85
+ ],
86
+ 'iphone-duo': [[1398, 2034], [2007, 2853]],
87
+ ipad: [
88
+ [2064, 2752], [2048, 2732], [1488, 2266], [1668, 2420],
89
+ [1668, 2388], [1640, 2360], [1668, 2224], [1536, 2048], [768, 1024],
90
+ ],
91
+ };
92
+
77
93
  const deviceProfiles = [
78
94
  {
79
95
  name: 'android-phone',
@@ -520,12 +536,25 @@ function parseArguments() {
520
536
  screenshots: '',
521
537
  androidFrame: '',
522
538
  iosFrame: '',
539
+ appleSource: '',
540
+ applePromotional: false,
541
+ appleExisting: false,
523
542
  };
524
543
 
525
544
  for (let index = 0; index < args.length; index += 1) {
526
545
  const argument = args[index];
527
546
 
528
- if (argument === '--amazon-assets') {
547
+ if (argument === '--apple-existing') {
548
+ options.appleExisting = true;
549
+ } else if (argument === '--apple-source') {
550
+ options.appleSource = args[index + 1] || '';
551
+ if (!options.appleSource || options.appleSource.startsWith('--')) {
552
+ throw new Error('--apple-source requires a directory of genuine iOS/iPadOS PNG captures.');
553
+ }
554
+ index += 1;
555
+ } else if (argument === '--apple-promotional') {
556
+ options.applePromotional = true;
557
+ } else if (argument === '--amazon-assets') {
529
558
  options.amazonAssets = true;
530
559
  } else if (argument === '--samsung-assets') {
531
560
  options.samsungAssets = true;
@@ -588,6 +617,9 @@ function printProfiles() {
588
617
  + `(folder ${profile.outputDirectory}, viewport ${profile.width}x${profile.height}, `
589
618
  + `${(profile.outputFormat || 'png').toUpperCase()} ${outputWidth}x${outputHeight}${framedSize})`,
590
619
  );
620
+ if (isAppleProfile(profile)) {
621
+ console.log(' Native Apple capture required; Android replay/reframing is disabled.');
622
+ }
591
623
  if (profile.storeRequirements) {
592
624
  console.log(
593
625
  ` Store limits: ${profile.storeRequirements.minImages}-${profile.storeRequirements.maxImages} images, `
@@ -603,12 +635,14 @@ function printHelp() {
603
635
  console.log('');
604
636
  console.log('Usage:');
605
637
  console.log(' node take-screen-image.js');
606
- console.log(' node take-screen-image.js --profiles iphone,ipad');
607
- console.log(' node take-screen-image.js --profiles iphone,iphone-duo,ipad');
608
- console.log(' node take-screen-image.js --android-frame graphite --ios-frame titanium');
609
- console.log(' node take-screen-image.js --prefix home --profiles android-phone,ipad');
638
+ console.log(' node take-screen-image.js --apple-source "C:\\captures\\iphone" --profiles iphone');
639
+ console.log(' node take-screen-image.js --apple-source "C:\\captures\\ipad" --profiles ipad --apple-promotional');
640
+ console.log(' node take-screen-image.js --apple-source "C:\\captures\\duo" --profiles iphone-duo');
641
+ console.log(' node take-screen-image.js --apple-existing --profiles iphone,iphone-duo,ipad');
642
+ console.log(' node take-screen-image.js --android-frame graphite');
643
+ console.log(' node take-screen-image.js --prefix home --profiles android-phone');
610
644
  console.log(' node take-screen-image.js --frame-existing');
611
- console.log(' node take-screen-image.js --reframe-existing --profiles android-phone,iphone');
645
+ console.log(' node take-screen-image.js --reframe-existing --profiles android-phone');
612
646
  console.log(' node take-screen-image.js --reframe-existing --screenshots 1,2');
613
647
  console.log(' node take-screen-image.js --refresh-info 1');
614
648
  console.log(' node take-screen-image.js --vivo-existing');
@@ -620,7 +654,15 @@ function printHelp() {
620
654
  console.log(' node take-screen-image.js --delete 3,4,5');
621
655
  console.log('');
622
656
  console.log('A normal capture automatically creates any missing Amazon, Samsung, and Play Store assets.');
623
- console.log('Frame defaults: Android graphite (A), iPhone midnight (D).');
657
+ console.log('Frame default: Android graphite (A). Apple imports do not add a device frame.');
658
+ console.log('iPhone/iPad profiles require --apple-source and exactly one profile per import.');
659
+ console.log('Name captures 1.png, 2.png, etc. to reuse existing promotional copy.');
660
+ console.log('Apple originals and optional promotions are saved separately under Store-upload/Apple-Native.');
661
+ console.log('Imports preserve source dimensions and system bars; the tool cannot verify capture provenance.');
662
+ console.log('Use full-display PNG captures without alpha channels, up to 10 per size.');
663
+ console.log('Each size gets its own folder. Re-importing a filename at that size never overwrites it.');
664
+ console.log('--apple-existing reprocesses Store-image-Screenshot images without synthetic system bars or frames.');
665
+ console.log('Reprocessed images go to Store-upload/Apple-Reprocessed; they are not native Apple captures.');
624
666
  }
625
667
 
626
668
  async function chooseFrameStyles(options) {
@@ -634,7 +676,7 @@ async function chooseFrameStyles(options) {
634
676
  const terminal = canPrompt ? readline.createInterface({ input: process.stdin, output: process.stdout }) : null;
635
677
 
636
678
  try {
637
- for (const platform of ['android', 'ios']) {
679
+ for (const platform of ['android']) {
638
680
  if (!choices[platform] && terminal) {
639
681
  const names = Object.values(frameStyles[platform]).map((style) => style.label);
640
682
  choices[platform] = await terminal.question(
@@ -651,7 +693,7 @@ async function chooseFrameStyles(options) {
651
693
  if (terminal) terminal.close();
652
694
  }
653
695
 
654
- console.log(`Frame selection: Android ${choices.android}, iPhone ${choices.ios}.`);
696
+ console.log(`Frame selection: Android ${choices.android}. Apple captures keep their native appearance.`);
655
697
  return choices;
656
698
  }
657
699
 
@@ -1732,6 +1774,8 @@ async function waitForReplayLayout(client, snapshot) {
1732
1774
  }
1733
1775
 
1734
1776
  function getFrameAdornment(frameType) {
1777
+ if (frameType === 'native-apple') return '';
1778
+
1735
1779
  if (frameType === 'iphone') {
1736
1780
  return '';
1737
1781
  }
@@ -2135,6 +2179,7 @@ function createDeviceFrameHtml(
2135
2179
  ) {
2136
2180
  const screenshotDataUrl = `data:image/${imageFormat === 'jpeg' ? 'jpeg' : 'png'};base64,${screenshotBuffer.toString('base64')}`;
2137
2181
  const aspectRatio = `${imageWidth} / ${imageHeight}`;
2182
+ const useDuoFrame = profile.name === 'iphone-duo' && profile.frameType !== 'native-apple';
2138
2183
  const phonePlatform = profile.frameType === 'iphone' ? 'ios' : profile.frameType === 'android-phone' ? 'android' : null;
2139
2184
  const statusBarPlatform = profile.frameType === 'ipad' ? 'ipad' : phonePlatform;
2140
2185
  const phoneStyle = phonePlatform && frameStyles[phonePlatform][selectedFrameStyles[phonePlatform]];
@@ -2265,7 +2310,7 @@ function createDeviceFrameHtml(
2265
2310
  border-radius: 999px;
2266
2311
  background: #000;
2267
2312
  }
2268
- ${profile.name === 'iphone-duo' ? `
2313
+ ${useDuoFrame ? `
2269
2314
  .device.iphone-duo {
2270
2315
  --duo-radius: clamp(24px, 4vw, 100px);
2271
2316
  --duo-bezel: clamp(5px, 0.65vw, 14px);
@@ -2614,10 +2659,30 @@ function createDeviceFrameHtml(
2614
2659
  </style>
2615
2660
  </head>
2616
2661
  <body class="${phonePlatform ? 'phone-frame' : ''} ${screenshotCopy ? 'has-copy' : ''}">
2662
+ ${profile.frameType === 'native-apple' ? `<style>
2663
+ .device.native-apple {
2664
+ box-sizing: border-box;
2665
+ width: auto;
2666
+ height: 68%;
2667
+ padding: 0;
2668
+ border: 0;
2669
+ border-radius: 0;
2670
+ background: transparent;
2671
+ box-shadow: 0 2vh 5vh rgba(0,0,0,0.2);
2672
+ }
2673
+ .device.native-apple .screen { border-radius: 0; box-shadow: none; }
2674
+ .device.native-apple .screen img { object-fit: contain; }
2675
+ @media (orientation: landscape) {
2676
+ body.has-copy .device.native-apple {
2677
+ width: min(60vw, ${84 * imageWidth / imageHeight}vh);
2678
+ height: auto;
2679
+ }
2680
+ }
2681
+ </style>` : ''}
2617
2682
  ${createPromotionalDecorations(palette)}
2618
2683
  ${createScreenshotCopyMarkup(screenshotCopy)}
2619
- <main class="device ${profile.frameType}${profile.name === 'iphone-duo' ? ' iphone-duo' : ''}">
2620
- <div class="screen">${phoneStatusBar}<img src="${screenshotDataUrl}" />${phoneNavigation}${profile.name === 'iphone-duo' ? '<div class="duo-camera" aria-hidden="true"></div>' : ''}</div>
2684
+ <main class="device ${profile.frameType}${useDuoFrame ? ' iphone-duo' : ''}">
2685
+ <div class="screen">${phoneStatusBar}<img src="${screenshotDataUrl}" />${phoneNavigation}${useDuoFrame ? '<div class="duo-camera" aria-hidden="true"></div>' : ''}</div>
2621
2686
  ${getFrameAdornment(profile.frameType)}
2622
2687
  </main>
2623
2688
  </body>
@@ -3836,6 +3901,134 @@ async function runInteractiveCaptureLoop(
3836
3901
  console.log('\nResponsive screenshot tool closed.');
3837
3902
  }
3838
3903
 
3904
+ function isAppleProfile(profile) {
3905
+ return /^(iphone|ipad|apple)(-|$)/.test(profile.name) || profile.name === 'mac';
3906
+ }
3907
+
3908
+ function validateAppleScreenshot(profile, metadata, fileName) {
3909
+ const family = profile.name === 'iphone-duo' ? 'iphone-duo'
3910
+ : profile.name.startsWith('ipad') ? 'ipad' : 'iphone';
3911
+ const validSize = appleScreenshotSizes[family].some(([width, height]) => (
3912
+ (metadata.width === width && metadata.height === height)
3913
+ || (metadata.width === height && metadata.height === width)
3914
+ ));
3915
+ if (!validSize) {
3916
+ throw new Error(`${fileName}: ${metadata.width}x${metadata.height} is not a supported full-display ${family} screenshot size. Capture the correct Apple device; do not resize another device's image.`);
3917
+ }
3918
+ if (metadata.hasAlpha) {
3919
+ throw new Error(`${fileName}: Apple screenshots cannot include an alpha channel. Export an RGB PNG without transparency.`);
3920
+ }
3921
+ }
3922
+
3923
+ async function importAppleScreenshots(options) {
3924
+ const profiles = selectProfiles(options.profiles);
3925
+ if (!options.profiles || profiles.length !== 1
3926
+ || !['iphone', 'iphone-duo', 'ipad', 'iphone-store', 'ipad-store'].includes(profiles[0].name)) {
3927
+ throw new Error('--apple-source requires one profile: iphone, iphone-duo, ipad, iphone-store, or ipad-store.');
3928
+ }
3929
+ if (options.frameExisting || options.reframeExisting || options.dryRun
3930
+ || options.refreshInfo || options.vivoExisting || options.oppoExisting
3931
+ || options.amazonAssets || options.samsungAssets || options.prefix || options.screenshots
3932
+ || options.deleteRequested || options.iosFrame) {
3933
+ throw new Error('Use --apple-source separately from capture, reframe, asset, and screenshot-selection options.');
3934
+ }
3935
+
3936
+ const sourceDirectory = fs.realpathSync(path.resolve(options.appleSource));
3937
+ const isExistingSource = options.appleExisting
3938
+ && sourceDirectory === fs.realpathSync(path.join(screenshotDirectory, profiles[0].outputDirectory));
3939
+ if (options.appleExisting && !isExistingSource) {
3940
+ throw new Error('--apple-existing only reads the selected Store-image-Screenshot profile folder.');
3941
+ }
3942
+ for (const legacyProfile of isExistingSource ? [] : deviceProfiles.filter(isAppleProfile)) {
3943
+ for (const root of [screenshotDirectory, inFrameDirectory, uploadDirectory]) {
3944
+ const legacyDirectory = path.join(root, legacyProfile.outputDirectory);
3945
+ if (!fs.existsSync(legacyDirectory)) continue;
3946
+ const relative = path.relative(fs.realpathSync(legacyDirectory), sourceDirectory);
3947
+ if (!relative || (relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))) {
3948
+ throw new Error('This source is a legacy Android replay/framed Apple output. Import original captures from the actual Apple app instead.');
3949
+ }
3950
+ }
3951
+ }
3952
+ const sourceFiles = fs.readdirSync(sourceDirectory, { withFileTypes: true })
3953
+ .filter((entry) => entry.isFile() && /\.png$/i.test(entry.name))
3954
+ .map((entry) => entry.name)
3955
+ .sort((first, second) => first.localeCompare(second, undefined, { numeric: true }));
3956
+ if (!sourceFiles.length) throw new Error('No PNG captures found in --apple-source.');
3957
+
3958
+ const profile = profiles[0];
3959
+ const nativeDirectory = path.join(uploadDirectory, isExistingSource ? 'Apple-Reprocessed' : 'Apple-Native');
3960
+ const originalsDirectory = path.join(nativeDirectory, 'Originals', profile.outputDirectory);
3961
+ const promotionalDirectory = path.join(nativeDirectory, 'Promotional');
3962
+ // Preflight the complete import before writing anything. Never overwrite previous assets.
3963
+ const captures = [];
3964
+ const sizeCounts = new Map();
3965
+ const plannedOutputs = new Set();
3966
+ for (const fileName of sourceFiles) {
3967
+ const buffer = fs.readFileSync(path.join(sourceDirectory, fileName));
3968
+ const metadata = await sharp(buffer).metadata();
3969
+ if (metadata.format !== 'png' || !metadata.width || !metadata.height
3970
+ || (metadata.pages || 1) !== 1 || (metadata.orientation && metadata.orientation !== 1)) {
3971
+ throw new Error(`Use an unrotated, single-image PNG capture: ${fileName}`);
3972
+ }
3973
+ validateAppleScreenshot(profile, metadata, fileName);
3974
+ // Decode the whole image before copying it; a valid PNG header alone is insufficient.
3975
+ await sharp(buffer).stats();
3976
+ const size = `${metadata.width}x${metadata.height}`;
3977
+ if (!sizeCounts.has(size)) {
3978
+ const existingDirectory = path.join(originalsDirectory, size);
3979
+ const existingCount = fs.existsSync(existingDirectory)
3980
+ ? fs.readdirSync(existingDirectory).filter((name) => /\.png$/i.test(name)).length : 0;
3981
+ sizeCounts.set(size, existingCount);
3982
+ }
3983
+ sizeCounts.set(size, sizeCounts.get(size) + 1);
3984
+ if (sizeCounts.get(size) > 10) throw new Error(`Apple allows up to 10 screenshots per size; ${size} exceeds that limit.`);
3985
+ const originalPath = path.join(originalsDirectory, size, fileName);
3986
+ const promotionalPath = path.join(promotionalDirectory, profile.outputDirectory, size, `${path.parse(fileName).name}.png`);
3987
+ for (const target of [originalPath, ...(options.applePromotional ? [promotionalPath] : [])]) {
3988
+ if (fs.existsSync(target)) throw new Error(`Output already exists; move it or rename the input first: ${target}`);
3989
+ const key = target.toLowerCase();
3990
+ if (plannedOutputs.has(key)) throw new Error(`Duplicate output filename: ${fileName}`);
3991
+ plannedOutputs.add(key);
3992
+ }
3993
+ if (options.applePromotional && !getScreenshotCopy(fileName)) {
3994
+ throw new Error(`No promotional copy for ${fileName}. Use a matching screenshot-copy.json name or omit --apple-promotional.`);
3995
+ }
3996
+ captures.push({ fileName, buffer, metadata, originalPath, size });
3997
+ }
3998
+
3999
+ let browser;
4000
+ let client;
4001
+ try {
4002
+ if (options.applePromotional) {
4003
+ browser = await launchReplayBrowser();
4004
+ client = await createReplayPage(browser);
4005
+ }
4006
+ for (const { fileName, buffer, metadata, originalPath, size } of captures) {
4007
+ fs.mkdirSync(path.dirname(originalPath), { recursive: true });
4008
+ fs.writeFileSync(originalPath, buffer, { flag: 'wx' });
4009
+ console.log(`Saved unchanged source image (${metadata.width}x${metadata.height}): ${originalPath}`);
4010
+ if (client) {
4011
+ await captureFramedScreenshot(client, buffer, {
4012
+ ...profile,
4013
+ outputDirectory: path.join(profile.outputDirectory, size),
4014
+ frameType: 'native-apple',
4015
+ screenshotOnly: false,
4016
+ framedWidth: metadata.width,
4017
+ framedHeight: metadata.height,
4018
+ }, fileName, true, promotionalDirectory);
4019
+ }
4020
+ }
4021
+ } finally {
4022
+ if (client) client.close();
4023
+ if (browser) await closeReplayBrowser(browser);
4024
+ }
4025
+ console.log('Apple image processing complete. Source dimensions are preserved; no system bars or device frames were added.');
4026
+ console.log(isExistingSource
4027
+ ? 'These images reuse Android-derived app content; they are not native iOS/iPadOS captures.'
4028
+ : 'Use captures from the actual iOS/iPadOS app; this tool cannot verify their origin.');
4029
+ console.log('Check current App Store Connect size requirements and replace old screenshots in every size/localization.');
4030
+ }
4031
+
3839
4032
  async function getInteractiveOptions(options) {
3840
4033
  if (
3841
4034
  !process.stdin.isTTY
@@ -3882,6 +4075,34 @@ async function main() {
3882
4075
  return;
3883
4076
  }
3884
4077
 
4078
+ if (options.appleExisting) {
4079
+ if (options.appleSource) throw new Error('Use --apple-existing separately from --apple-source.');
4080
+ const profiles = selectProfiles(options.profiles || 'iphone,iphone-duo,ipad');
4081
+ if (profiles.some((profile) => !['iphone', 'iphone-duo', 'ipad', 'iphone-store', 'ipad-store'].includes(profile.name))) {
4082
+ throw new Error('--apple-existing supports only iPhone/iPad screenshot profiles.');
4083
+ }
4084
+ for (const profile of profiles) {
4085
+ await importAppleScreenshots({
4086
+ ...options,
4087
+ profiles: profile.name,
4088
+ appleSource: path.join(screenshotDirectory, profile.outputDirectory),
4089
+ applePromotional: true,
4090
+ });
4091
+ }
4092
+ return;
4093
+ }
4094
+
4095
+ if (options.appleSource) {
4096
+ await importAppleScreenshots(options);
4097
+ return;
4098
+ }
4099
+ if (options.applePromotional) {
4100
+ throw new Error('--apple-promotional requires --apple-source.');
4101
+ }
4102
+ if (options.iosFrame) {
4103
+ throw new Error('--ios-frame is no longer used. Import native Apple captures with --apple-source.');
4104
+ }
4105
+
3885
4106
  if (options.deleteRequested) {
3886
4107
  deleteMatchingImages(options.deleteNames);
3887
4108
  return;
@@ -3889,6 +4110,21 @@ async function main() {
3889
4110
 
3890
4111
  options = await getInteractiveOptions(options);
3891
4112
 
4113
+ if (!options.amazonAssets && !options.samsungAssets && !options.vivoExisting
4114
+ && !options.oppoExisting && !options.refreshInfo) {
4115
+ const selected = selectProfiles(options.profiles);
4116
+ const appleProfiles = selected.filter(isAppleProfile);
4117
+ if (appleProfiles.length) {
4118
+ const explicitSelection = options.profiles.split(',').some((name) => name.trim() && name.trim().toLowerCase() !== 'all');
4119
+ if (explicitSelection) {
4120
+ throw new Error('Apple screenshots require native captures. Import iPhone/iPad captures with --apple-source <directory> --profiles iphone, iphone-duo, or ipad (one per import). Android replay/reframing is disabled for every Apple profile, including Watch, Vision Pro, TV, and Mac.');
4121
+ }
4122
+ options.profiles = selected.filter((profile) => !isAppleProfile(profile))
4123
+ .map((profile) => profile.name).join(',');
4124
+ console.log('Skipping all Apple Android replay profiles. Import native iPhone/iPad captures with --apple-source.');
4125
+ }
4126
+ }
4127
+
3892
4128
  if (!options.dryRun) {
3893
4129
  initializeScreenshotData();
3894
4130
  }
@@ -4022,7 +4258,7 @@ async function main() {
4022
4258
  replayClient = await createReplayPage(replayBrowser);
4023
4259
 
4024
4260
  console.log(
4025
- 'Apple, TV, Chromebook, Mac, and XR profiles are viewport approximations of the live Android WebView.',
4261
+ 'Non-Apple profiles are viewport approximations of the live Android WebView. Apple profiles require native captures.',
4026
4262
  );
4027
4263
 
4028
4264
  if (interactiveMode) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeplay-common",
3
- "version": "4.9.4",
3
+ "version": "4.9.6",
4
4
  "description": "Common build scripts and files",
5
5
  "scripts": {
6
6
  "postinstall": "node scripts/sync-files.js",