Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ios/entitlements.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-check
import * as nodefs from "node:fs";
import * as path from "node:path";
import { isObject, toPlist } from "./utils.mjs";
import { isObject, plistFromJSON } from "./utils.mjs";

/** @import { ApplePlatform, JSONObject } from "../scripts/types.js"; */

Expand Down Expand Up @@ -56,7 +56,7 @@ export function generateEntitlements(
}

const filename = "App.entitlements";
const entitlements = toPlist(
const entitlements = plistFromJSON(
{
...(targetPlatform === "macos"
? DEFAULT_MACOS_ENTITLEMENTS
Expand Down
98 changes: 98 additions & 0 deletions ios/infoPlist.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// @ts-check
import * as nodefs from "node:fs";
import * as path from "node:path";
import {
isObject,
jsonFromPlist,
plistFromJSON,
projectPath,
resolveResources,
} from "./utils.mjs";

/** @import { ApplePlatform, JSONArray, JSONObject } from "../scripts/types.js"; */

/**
* @param {JSONObject} appConfig
* @param {ApplePlatform} targetPlatform
* @param {JSONObject} info
*/
function setMacProperties(appConfig, targetPlatform, info) {
if (targetPlatform !== "macos") {
return;
}

const config = appConfig[targetPlatform];
if (!isObject(config)) {
return;
}

const category = config["applicationCategoryType"];
if (typeof category === "string") {
info["LSApplicationCategoryType"] = category;
}

const copyright = config["humanReadableCopyright"];
if (typeof copyright === "string") {
info["NSHumanReadableCopyright"] = copyright;
}
}

/**
* @param {JSONObject} appConfig
* @param {ApplePlatform} targetPlatform
* @param {string} destination
* @returns {void}
*/
export function generateInfoPlist(
appConfig,
targetPlatform,
destination,
fs = nodefs
) {
const filename = "ReactTestApp/Info.plist";
const infoPlistSrc = projectPath(filename, targetPlatform);

const info = jsonFromPlist(infoPlistSrc);

const resources = resolveResources(appConfig, targetPlatform);
registerFonts(resources, targetPlatform, info);
setMacProperties(appConfig, targetPlatform, info);

const infoPlistDst = path.join(destination, path.basename(infoPlistSrc));
fs.writeFileSync(infoPlistDst, plistFromJSON(info, filename));
}

/**
* @param {JSONArray | undefined} resources
* @param {ApplePlatform} targetPlatform
* @param {JSONObject} info
*/
export function registerFonts(resources, targetPlatform, info) {
if (!resources) {
return;
}

const fontFiles = [".otf", ".ttf"];
const fonts = [];
for (const filename of resources) {
if (typeof filename === "string") {
const extname = path.extname(filename);
if (fontFiles.includes(extname)) {
fonts.push(path.basename(filename));
}
}
}

if (fonts.length > 0) {
switch (targetPlatform) {
case "macos":
// https://developer.apple.com/documentation/bundleresources/information_property_list/atsapplicationfontspath
info["ATSApplicationFontsPath"] = ".";
break;
default:
// https://developer.apple.com/documentation/uikit/text_display_and_fonts/adding_a_custom_font_to_your_app
info["UIAppFonts"] = fonts;
break;
}
}
}
4 changes: 2 additions & 2 deletions ios/privacyManifest.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-check
import * as nodefs from "node:fs";
import * as path from "node:path";
import { isObject, toPlist } from "./utils.mjs";
import { isObject, plistFromJSON } from "./utils.mjs";

/**
* @import { ApplePlatform, JSONObject, JSONValue } from "../scripts/types.js";
Expand Down Expand Up @@ -107,6 +107,6 @@ export function generatePrivacyManifest(
}

const filename = "PrivacyInfo.xcprivacy";
const xcprivacy = toPlist(manifest, filename);
const xcprivacy = plistFromJSON(manifest, filename);
fs.writeFileSync(path.join(destination, filename), xcprivacy);
}
52 changes: 45 additions & 7 deletions ios/utils.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,28 @@ export function isObject(obj) {
}

/**
* @param {string} p
* @param {ApplePlatform} targetPlatform
* @returns {string}
* @param {string} filename
* @returns {JSONObject}
*/
export function projectPath(p, targetPlatform) {
const packageDir = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
return path.join(packageDir, targetPlatform, p);
export function jsonFromPlist(filename) {
const args = ["-convert", "json", "-o", "-", filename];
const plutil = spawnSync("/usr/bin/plutil", args, {
stdio: ["ignore", "pipe", "inherit"],
});

if (plutil.status !== 0) {
throw new Error(`Failed to read '${filename}'`);
}

return JSON.parse(plutil.stdout.toString());
}

/**
* @param {JSONObject} source
* @param {string} filename
* @returns {string}
*/
export function toPlist(source, filename) {
export function plistFromJSON(source, filename) {
const args = ["-convert", "xml1", "-r", "-o", "-", "--", "-"];
const plutil = spawnSync("/usr/bin/plutil", args, {
stdio: ["pipe", "pipe", "inherit"],
Expand All @@ -45,3 +52,34 @@ export function toPlist(source, filename) {

return plutil.stdout.toString();
}

/**
* @param {string} p
* @param {ApplePlatform} targetPlatform
* @returns {string}
*/
export function projectPath(p, targetPlatform) {
const packageDir = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
return path.join(packageDir, targetPlatform, p);
}

/**
* @param {JSONObject} appConfig
* @param {ApplePlatform} targetPlatform
* @returns {JSONValue[] | undefined}
*/
export function resolveResources(appConfig, targetPlatform) {
const resources = appConfig["resources"];
if (resources && typeof resources === "object") {
if (Array.isArray(resources)) {
return resources;
}

const res = resources[targetPlatform];
if (Array.isArray(res)) {
return res;
}
}

return undefined;
}
2 changes: 1 addition & 1 deletion test/ios/entitlements.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { fs, setMockFiles } from "../fs.mock.ts";

const macosOnly = { skip: process.platform === "win32" };

describe("generatePrivacyManifest()", macosOnly, () => {
describe("generateEntitlements()", macosOnly, () => {
const targetPlatforms = ["ios", "macos", "visionos"] as const;

function generateEntitlements(
Expand Down
Loading
Loading