react-native-test-app
Version:
react-native-test-app provides a test app for all supported platforms as a package
125 lines (108 loc) • 3.8 kB
JavaScript
// @ts-check
"use strict";
/**
* This script (and its dependencies) currently cannot be converted to ESM
* because it is consumed in `react-native.config.js`.
*/
const nodefs = require("node:fs");
const path = require("node:path");
const { pathToFileURL } = require("node:url");
const { isMain, readJSONFile, readTextFile } = require("../scripts/helpers.js");
/**
* @param {Record<string, string>[]} entries
* @param {string[]} names
* @param {string[]} attributes
* @param {string} attributeNamePrefix
* @returns {Record<string, string>[]}
*/
function toXML(entries, names, attributes, attributeNamePrefix) {
const xml = [];
for (const e of entries) {
const attrName = names.find((name) => name in e);
if (!attrName) {
continue;
}
const entry = { [attributeNamePrefix + attrName]: e[attrName] };
for (const attr of attributes) {
if (attr in e) {
entry[attributeNamePrefix + attr] = e[attr].toString();
}
}
xml.push(entry);
}
return xml;
}
/**
* @param {string} appManifestPath
* @param {string} manifestOutput
* @returns {number}
*/
function generateAndroidManifest(appManifestPath, manifestOutput, fs = nodefs) {
if (fs.existsSync(manifestOutput)) {
const lastModifiedByUser = fs.statSync(appManifestPath).mtimeMs;
const generationTime = fs.statSync(manifestOutput).mtimeMs;
if (lastModifiedByUser <= generationTime) {
return 0;
}
}
const { XMLBuilder, XMLParser } = require("fast-xml-parser");
/** @type {import("../scripts/types.js").AndroidConfig} */
const appManifest = readJSONFile(appManifestPath, fs);
const android = appManifest.android ?? {};
const attributeNamePrefix = "@_";
const xmlOptions = {
attributeNamePrefix,
ignoreAttributes: false,
format: true,
suppressBooleanAttributes: false,
};
const manifestSource = path.join(
__dirname,
"app",
"src",
"main",
"AndroidManifest.xml"
);
const xml = new XMLParser(xmlOptions).parse(readTextFile(manifestSource, fs));
/** @type {import("../scripts/types.js").AndroidManifest} */
const manifest = xml["manifest"];
// https://developer.android.com/guide/topics/manifest/uses-feature-element
const features = android.features;
if (Array.isArray(features)) {
const names = ["android:name", "android:glEsVersion"];
const attributes = ["android:required"];
const entries = toXML(features, names, attributes, attributeNamePrefix);
if (entries.length > 0) {
manifest["uses-feature"] = entries;
}
}
// https://developer.android.com/guide/topics/manifest/uses-permission-element
const permissions = android.permissions;
if (Array.isArray(permissions)) {
const names = ["android:name"];
const attributes = ["android:maxSdkVersion"];
const entries = toXML(permissions, names, attributes, attributeNamePrefix);
if (entries.length > 0) {
manifest["uses-permission"] = entries;
}
}
// https://developer.android.com/guide/topics/manifest/meta-data-element
const metaData = android.metaData;
if (Array.isArray(metaData)) {
const names = ["android:name"];
const attributes = ["android:value"];
const entries = toXML(metaData, names, attributes, attributeNamePrefix);
if (entries.length > 0) {
manifest.application["meta-data"] = entries;
}
}
const builder = new XMLBuilder(xmlOptions);
fs.mkdirSync(path.dirname(manifestOutput), { recursive: true, mode: 0o755 });
fs.writeFileSync(manifestOutput, builder.build(xml));
return 0;
}
exports.generateAndroidManifest = generateAndroidManifest;
if (isMain(pathToFileURL(__filename))) {
const [, , appManifestPath, manifestOutput] = process.argv;
process.exitCode = generateAndroidManifest(appManifestPath, manifestOutput);
}