craft-native 0.0.119 → 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.
- package/dist/android/templates/MainActivityNative.kt.template +378 -54
- package/dist/cli.js +1 -1
- package/dist/components/index.d.ts +9 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/ios/src/index.d.ts +12 -0
- package/dist/ios/src/index.js +38 -2
- package/dist/ios/templates/CraftNativeScreen.swift +414 -52
- package/dist/ios/templates/Info.plist.template +2 -0
- package/dist/ios/templates/project.yml.template +17 -0
- package/package.json +1 -1
package/dist/ios/src/index.js
CHANGED
|
@@ -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
|
-
|
|
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,
|