craft-native 0.0.120 → 0.0.121

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.
@@ -275,6 +275,41 @@ ${accessedXml}
275
275
  </plist>
276
276
  `;
277
277
  }
278
+ function pngHasAlpha(bytes) {
279
+ const signature = [137, 80, 78, 71, 13, 10, 26, 10];
280
+ if (bytes.length < 33 || signature.some((byte, index) => bytes[index] !== byte))
281
+ return false;
282
+ const colourType = bytes[25];
283
+ if (colourType === 4 || colourType === 6)
284
+ return true;
285
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
286
+ for (let offset = 8;offset + 8 <= bytes.length; ) {
287
+ const length = view.getUint32(offset);
288
+ const type = String.fromCharCode(bytes[offset + 4], bytes[offset + 5], bytes[offset + 6], bytes[offset + 7]);
289
+ if (type === "tRNS")
290
+ return true;
291
+ if (type === "IDAT" || type === "IEND")
292
+ return false;
293
+ offset += 12 + length;
294
+ }
295
+ return false;
296
+ }
297
+ function writeOpaqueIcon(source, target) {
298
+ const bytes = new Uint8Array(readFileSync(source));
299
+ if (!pngHasAlpha(bytes) || process.platform !== "darwin") {
300
+ cpSync(source, target);
301
+ return;
302
+ }
303
+ const flattened = `${target}.flatten.jpg`;
304
+ const run = (args) => Bun.spawnSync(["sips", ...args], { stdout: "ignore", stderr: "pipe" });
305
+ const toJpeg = run(["-s", "format", "jpeg", "-s", "formatOptions", "100", source, "--out", flattened]);
306
+ const toPng = toJpeg.exitCode === 0 ? run(["-s", "format", "png", flattened, "--out", target]) : toJpeg;
307
+ rmSync(flattened, { force: true });
308
+ if (toPng.exitCode !== 0) {
309
+ cpSync(source, target);
310
+ console.warn(`[craft] Could not remove the app icon's alpha channel; App Store Connect will refuse it: ${toPng.stderr.toString().trim()}`);
311
+ }
312
+ }
278
313
  function renderAssetCatalog(output, config) {
279
314
  const catalog = join(output, "Assets.xcassets");
280
315
  const appIcon = join(catalog, "AppIcon.appiconset");
@@ -287,7 +322,7 @@ function renderAssetCatalog(output, config) {
287
322
  if (config.appIconPath) {
288
323
  if (!existsSync(config.appIconPath))
289
324
  throw new Error(`App icon not found: ${config.appIconPath}`);
290
- cpSync(config.appIconPath, join(appIcon, iconFilename));
325
+ writeOpaqueIcon(config.appIconPath, join(appIcon, iconFilename));
291
326
  }
292
327
  writeFileSync(join(appIcon, "Contents.json"), `${JSON.stringify({
293
328
  images: iconFilename ? [{
@@ -437,7 +472,7 @@ async function init(options) {
437
472
  cpSync(join(TEMPLATES_DIR, "CraftNativeActions.swift"), join(output, "Sources", "CraftNativeActions.swift"));
438
473
  cpSync(join(TEMPLATES_DIR, "CraftNativeMutation.swift"), join(output, "Sources", "CraftNativeMutation.swift"));
439
474
  const infoPlistTemplate = readFileSync(join(TEMPLATES_DIR, "Info.plist.template"), "utf-8");
440
- const infoPlist = infoPlistTemplate.replace(/\{\{APP_NAME\}\}/g, xmlEscape(displayName)).replace(/\{\{BUNDLE_ID\}\}/g, finalBundleId).replace(/\{\{VERSION\}\}/g, config.version || "1.0.0").replace(/\{\{BUILD_NUMBER\}\}/g, config.buildNumber || "1").replace(/\{\{UI_STYLE\}\}/g, renderAppearance(config).interfaceStyle).replace(/\{\{STATUS_BAR_STYLE\}\}/g, renderAppearance(config).statusBarStyle).replace(/\{\{ORIENTATIONS\}\}/g, renderOrientations(config)).replace(/\{\{USAGE_DESCRIPTIONS\}\}/g, renderUsageDescriptions(config)).replace(/\{\{URL_TYPES\}\}/g, renderUrlTypes(config)).replace(/\{\{APP_BOUND_DOMAINS\}\}/g, renderAppBoundDomains(config)).replace(/\{\{BACKGROUND_MODES\}\}/g, renderBackgroundModes(config)).replace(/\{\{LIVE_ACTIVITY_SUPPORT\}\}/g, config.enableLiveActivities ? ` <key>NSSupportsLiveActivities</key>
475
+ const infoPlist = infoPlistTemplate.replace(/\{\{APP_NAME\}\}/g, xmlEscape(displayName)).replace(/\{\{BUNDLE_ID\}\}/g, finalBundleId).replace(/\{\{VERSION\}\}/g, config.version || "1.0.0").replace(/\{\{BUILD_NUMBER\}\}/g, config.buildNumber || "1").replace(/\{\{UI_STYLE\}\}/g, renderAppearance(config).interfaceStyle).replace(/\{\{STATUS_BAR_STYLE\}\}/g, renderAppearance(config).statusBarStyle).replace(/\{\{ORIENTATIONS\}\}/g, renderOrientations(config)).replace(/\{\{USAGE_DESCRIPTIONS\}\}/g, renderUsageDescriptions(config)).replace(/\{\{URL_TYPES\}\}/g, renderUrlTypes(config)).replace(/\{\{APP_BOUND_DOMAINS\}\}/g, renderAppBoundDomains(config)).replace(/\{\{BACKGROUND_MODES\}\}/g, renderBackgroundModes(config)).replace(/\{\{NON_EXEMPT_ENCRYPTION\}\}/g, config.usesNonExemptEncryption ? "true" : "false").replace(/\{\{LIVE_ACTIVITY_SUPPORT\}\}/g, config.enableLiveActivities ? ` <key>NSSupportsLiveActivities</key>
441
476
  <true/>
442
477
  <key>NSSupportsLiveActivitiesFrequentUpdates</key>
443
478
  <true/>` : "");
@@ -758,6 +793,7 @@ export {
758
793
  renderAppearance,
759
794
  renderAppBoundDomains,
760
795
  productName,
796
+ pngHasAlpha,
761
797
  pickSimulator,
762
798
  orderSimulators,
763
799
  open,