react-native-bootsplash 6.0.0-beta.8 → 6.0.0

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/src/generate.ts CHANGED
@@ -1,14 +1,11 @@
1
- import { getConfig as getExpoConfig } from "@expo/config";
2
1
  import * as Expo from "@expo/config-plugins";
3
- import { assignColorValue } from "@expo/config-plugins/build/android/Colors";
4
- import { addImports } from "@expo/config-plugins/build/android/codeMod";
5
- import { mergeContents } from "@expo/config-plugins/build/utils/generateCode";
6
2
  import plist from "@expo/plist";
7
3
  import { findProjectRoot } from "@react-native-community/cli-tools";
8
4
  import {
9
5
  AndroidProjectConfig,
10
6
  IOSProjectConfig,
11
7
  } from "@react-native-community/cli-types";
8
+ import childProcess from "child_process";
12
9
  import crypto from "crypto";
13
10
  import detectIndent from "detect-indent";
14
11
  import fs from "fs-extra";
@@ -19,8 +16,10 @@ import { Options as PrettierOptions } from "prettier";
19
16
  import * as htmlPlugin from "prettier/plugins/html";
20
17
  import * as cssPlugin from "prettier/plugins/postcss";
21
18
  import * as prettier from "prettier/standalone";
19
+ import semver from "semver";
22
20
  import sharp, { Sharp } from "sharp";
23
21
  import { dedent } from "ts-dedent";
22
+ import util from "util";
24
23
  import formatXml, { XMLFormatterOptions } from "xml-formatter";
25
24
  import { Manifest } from ".";
26
25
 
@@ -40,6 +39,11 @@ type Color = {
40
39
  rgb: RGBColor;
41
40
  };
42
41
 
42
+ const promisifiedExec = util.promisify(childProcess.exec);
43
+
44
+ const exec = (cmd: string) =>
45
+ promisifiedExec(cmd).then(({ stdout, stderr }) => stdout || stderr);
46
+
43
47
  export const log = {
44
48
  error: (text: string) => {
45
49
  console.log(pc.red(`❌ ${text}`));
@@ -180,6 +184,25 @@ export const hfs = {
180
184
  },
181
185
  };
182
186
 
187
+ export const getExpoConfig = (projectRoot: string): { isExpo: boolean } => {
188
+ try {
189
+ const pkg = hfs.json(
190
+ path.resolve(projectRoot, "node_modules", "expo", "package.json"),
191
+ ) as { version?: string };
192
+
193
+ const version = pkg.version;
194
+
195
+ if (version == null || semver.lt(version, "51.0.20")) {
196
+ log.error("Requires Expo 51.0.20 (or higher)");
197
+ process.exit(1);
198
+ }
199
+
200
+ return { isExpo: true };
201
+ } catch {
202
+ return { isExpo: false };
203
+ }
204
+ };
205
+
183
206
  export const writeJson = (filePath: string, content: object) => {
184
207
  hfs.write(filePath, JSON.stringify(content, null, 2));
185
208
  log.write(filePath);
@@ -256,7 +279,7 @@ export const writeXmlLike = async (
256
279
  }
257
280
  };
258
281
 
259
- const cleanIOS = (dir: string) => {
282
+ export const cleanIOSAssets = (dir: string) => {
260
283
  hfs
261
284
  .readDir(dir)
262
285
  .filter((file) => file === "Colors.xcassets" || file === "Images.xcassets")
@@ -458,10 +481,12 @@ const getIOSOutputPath = ({
458
481
  return iosOutputPath;
459
482
  };
460
483
 
461
- const getHtmlTemplatePath = ({
484
+ const getHtmlTemplatePath = async ({
485
+ isExpo,
462
486
  html,
463
487
  platforms,
464
488
  }: {
489
+ isExpo: boolean;
465
490
  html: string;
466
491
  platforms: Platforms;
467
492
  }) => {
@@ -469,6 +494,24 @@ const getHtmlTemplatePath = ({
469
494
  return;
470
495
  }
471
496
 
497
+ if (isExpo) {
498
+ const htmlTemplatePath = path.resolve(workingPath, html);
499
+
500
+ const htmlTemplateRelativePath = path.relative(
501
+ workingPath,
502
+ htmlTemplatePath,
503
+ );
504
+
505
+ if (
506
+ htmlTemplateRelativePath === "public/index.html" &&
507
+ !hfs.exists(htmlTemplatePath)
508
+ ) {
509
+ const cmd = `npx expo customize ${htmlTemplateRelativePath}`;
510
+ console.log(pc.dim(`Running ${cmd}`));
511
+ await exec(cmd);
512
+ }
513
+ }
514
+
472
515
  const htmlTemplatePath = path.resolve(workingPath, html);
473
516
 
474
517
  if (!hfs.exists(htmlTemplatePath)) {
@@ -565,14 +608,9 @@ export const generate = async ({
565
608
  darkLogo?: string;
566
609
  darkBrand?: string;
567
610
  }) => {
568
- const isExpo =
569
- getExpoConfig(projectRoot, { skipSDKVersionRequirement: true }).exp
570
- .sdkVersion != null;
611
+ const { isExpo } = getExpoConfig(workingPath);
571
612
 
572
- const [nodeStringVersion = ""] = process.versions.node.split(".");
573
- const nodeVersion = Number.parseInt(nodeStringVersion, 10);
574
-
575
- if (!Number.isNaN(nodeVersion) && nodeVersion < 18) {
613
+ if (semver.lt(process.versions.node, "18.0.0")) {
576
614
  log.error("Requires Node 18 (or higher)");
577
615
  process.exit(1);
578
616
  }
@@ -687,7 +725,8 @@ export const generate = async ({
687
725
  platforms,
688
726
  });
689
727
 
690
- const htmlTemplatePath = getHtmlTemplatePath({
728
+ const htmlTemplatePath = await getHtmlTemplatePath({
729
+ isExpo,
691
730
  html,
692
731
  platforms,
693
732
  });
@@ -849,10 +888,10 @@ export const generate = async ({
849
888
  ];
850
889
 
851
890
  const nextStyle = parseHtml(dedent`
852
- <style name="BootTheme" parent="${parent}">
853
- ${styleItems.join("\n")}
854
- </style>
855
- `);
891
+ <style name="BootTheme" parent="${parent}">
892
+ ${styleItems.join("\n")}
893
+ </style>
894
+ `);
856
895
 
857
896
  prevStyle?.remove(); // remove the existing style
858
897
  stylesXml.root.querySelector("resources")?.appendChild(nextStyle);
@@ -869,7 +908,7 @@ export const generate = async ({
869
908
  log.title("🍏", "iOS");
870
909
 
871
910
  hfs.ensureDir(iosOutputPath);
872
- cleanIOS(iosOutputPath);
911
+ cleanIOSAssets(iosOutputPath);
873
912
 
874
913
  const storyboardPath = path.resolve(iosOutputPath, "BootSplash.storyboard");
875
914
 
@@ -1002,18 +1041,19 @@ export const generate = async ({
1002
1041
 
1003
1042
  const project = Expo.IOSConfig.XcodeUtils.getPbxproj(projectRoot);
1004
1043
  const projectName = path.basename(iosOutputPath);
1044
+ const groupName = path.parse(xcodeProjectPath).name;
1005
1045
 
1006
1046
  Expo.IOSConfig.XcodeUtils.addResourceFileToGroup({
1007
- filepath: path.join(projectName, "BootSplash.storyboard"),
1008
- groupName: path.parse(xcodeProjectPath).name,
1009
1047
  project,
1048
+ filepath: path.join(projectName, "BootSplash.storyboard"),
1049
+ groupName,
1010
1050
  isBuildFile: true,
1011
1051
  });
1012
1052
 
1013
1053
  Expo.IOSConfig.XcodeUtils.addResourceFileToGroup({
1014
- filepath: path.join(projectName, "Colors.xcassets"),
1015
- groupName: path.parse(xcodeProjectPath).name,
1016
1054
  project,
1055
+ filepath: path.join(projectName, "Colors.xcassets"),
1056
+ groupName,
1017
1057
  isBuildFile: true,
1018
1058
  });
1019
1059
 
@@ -1170,345 +1210,3 @@ ${pc.blue("┗━━━━━━━━━━━━━━━━━━━━━━
1170
1210
  `\n💖 Thanks for using ${pc.underline("react-native-bootsplash")}`,
1171
1211
  );
1172
1212
  };
1173
-
1174
- type ExpoPlugin = Expo.ConfigPlugin<{
1175
- assetsDir?: string;
1176
- android?: {
1177
- parentTheme?: "TransparentStatus" | "EdgeToEdge";
1178
- darkContentBarsStyle?: boolean;
1179
- };
1180
- }>;
1181
-
1182
- const withAndroidAssets: ExpoPlugin = (config, props) =>
1183
- Expo.withDangerousMod(config, [
1184
- "android",
1185
- (config) => {
1186
- const { assetsDir = "assets/bootsplash" } = props;
1187
- const { platformProjectRoot } = config.modRequest;
1188
-
1189
- const srcDir = path.resolve(workingPath, assetsDir, "android");
1190
-
1191
- const destDir = path.resolve(
1192
- platformProjectRoot,
1193
- "app",
1194
- "src",
1195
- "main",
1196
- "res",
1197
- );
1198
-
1199
- for (const drawableDir of hfs.readDir(srcDir)) {
1200
- const srcDrawableDir = path.join(srcDir, drawableDir);
1201
- const destDrawableDir = path.join(destDir, drawableDir);
1202
-
1203
- hfs.ensureDir(destDrawableDir);
1204
-
1205
- for (const file of hfs.readDir(srcDrawableDir)) {
1206
- hfs.copy(
1207
- path.join(srcDrawableDir, file),
1208
- path.join(destDrawableDir, file),
1209
- );
1210
- }
1211
- }
1212
-
1213
- return config;
1214
- },
1215
- ]);
1216
-
1217
- const withAndroidManifest: ExpoPlugin = (config) =>
1218
- Expo.withAndroidManifest(config, (config) => {
1219
- config.modResults.manifest.application?.forEach((application) => {
1220
- if (application.$["android:name"] === ".MainApplication") {
1221
- const { activity } = application;
1222
-
1223
- activity?.forEach((activity) => {
1224
- if (activity.$["android:name"] === ".MainActivity") {
1225
- activity.$["android:theme"] = "@style/BootTheme";
1226
- }
1227
- });
1228
- }
1229
- });
1230
-
1231
- return config;
1232
- });
1233
-
1234
- const withMainActivity: ExpoPlugin = (config) =>
1235
- Expo.withMainActivity(config, (config) => {
1236
- const { modResults } = config;
1237
- const { language } = modResults;
1238
-
1239
- const withImports = addImports(
1240
- modResults.contents.replace(
1241
- /(\/\/ )?setTheme\(R\.style\.AppTheme\)/,
1242
- "// setTheme(R.style.AppTheme)",
1243
- ),
1244
- ["android.os.Bundle", "com.zoontek.rnbootsplash.RNBootSplash"],
1245
- language === "java",
1246
- );
1247
-
1248
- // indented with 4 spaces
1249
- const withInit = mergeContents({
1250
- src: withImports,
1251
- comment: " //",
1252
- tag: "bootsplash-init",
1253
- offset: 0,
1254
- anchor: /super\.onCreate\(null\)/,
1255
- newSrc:
1256
- " RNBootSplash.init(this, R.style.BootTheme)" +
1257
- (language === "java" ? ";" : ""),
1258
- });
1259
-
1260
- return {
1261
- ...config,
1262
- modResults: {
1263
- ...modResults,
1264
- contents: withInit.contents,
1265
- },
1266
- };
1267
- });
1268
-
1269
- const withAndroidStyles: ExpoPlugin = (config, props) =>
1270
- Expo.withAndroidStyles(config, async (config) => {
1271
- const { assetsDir = "assets/bootsplash", android = {} } = props;
1272
- const { parentTheme, darkContentBarsStyle } = android;
1273
-
1274
- const { modResults } = config;
1275
- const { resources } = modResults;
1276
- const { style = [] } = resources;
1277
-
1278
- const manifest = (await hfs.json(
1279
- path.resolve(workingPath, assetsDir, "manifest.json"),
1280
- )) as Manifest;
1281
-
1282
- const item = [
1283
- {
1284
- $: { name: "postBootSplashTheme" },
1285
- _: "@style/AppTheme",
1286
- },
1287
- {
1288
- $: { name: "bootSplashBackground" },
1289
- _: "@color/bootsplash_background",
1290
- },
1291
- {
1292
- $: { name: "bootSplashLogo" },
1293
- _: "@drawable/bootsplash_logo",
1294
- },
1295
- ];
1296
-
1297
- if (manifest.brand != null) {
1298
- item.push({
1299
- $: { name: "bootSplashBrand" },
1300
- _: "@drawable/bootsplash_brand",
1301
- });
1302
- }
1303
- if (darkContentBarsStyle != null) {
1304
- item.push({
1305
- $: { name: "darkContentBarsStyle" },
1306
- _: String(darkContentBarsStyle),
1307
- });
1308
- }
1309
-
1310
- const withBootTheme = [
1311
- ...style.filter(({ $ }) => $.name !== "BootTheme"),
1312
- {
1313
- $: {
1314
- name: "BootTheme",
1315
- parent:
1316
- parentTheme === "TransparentStatus"
1317
- ? "Theme.BootSplash.TransparentStatus"
1318
- : parentTheme === "EdgeToEdge"
1319
- ? "Theme.BootSplash.EdgeToEdge"
1320
- : "Theme.BootSplash",
1321
- },
1322
- item,
1323
- },
1324
- ];
1325
-
1326
- return {
1327
- ...config,
1328
- modResults: {
1329
- ...modResults,
1330
- resources: {
1331
- ...resources,
1332
- style: withBootTheme,
1333
- },
1334
- },
1335
- };
1336
- });
1337
-
1338
- const withAndroidColors: ExpoPlugin = (config, props) =>
1339
- Expo.withAndroidColors(config, async (config) => {
1340
- const { assetsDir = "assets/bootsplash" } = props;
1341
-
1342
- const manifest = (await hfs.json(
1343
- path.resolve(workingPath, assetsDir, "manifest.json"),
1344
- )) as Manifest;
1345
-
1346
- config.modResults = assignColorValue(config.modResults, {
1347
- name: "bootsplash_background",
1348
- value: manifest.background,
1349
- });
1350
-
1351
- return config;
1352
- });
1353
-
1354
- const withAndroidColorsNight: ExpoPlugin = (config, props) =>
1355
- Expo.withAndroidColorsNight(config, async (config) => {
1356
- const { assetsDir = "assets/bootsplash" } = props;
1357
-
1358
- const manifest = (await hfs.json(
1359
- path.resolve(workingPath, assetsDir, "manifest.json"),
1360
- )) as Manifest;
1361
-
1362
- if (manifest.darkBackground != null) {
1363
- config.modResults = assignColorValue(config.modResults, {
1364
- name: "bootsplash_background",
1365
- value: manifest.darkBackground,
1366
- });
1367
- }
1368
-
1369
- return config;
1370
- });
1371
-
1372
- const withIOSAssets: ExpoPlugin = (config, props) =>
1373
- Expo.withDangerousMod(config, [
1374
- "ios",
1375
- (config) => {
1376
- const { assetsDir = "assets/bootsplash" } = props;
1377
- const { platformProjectRoot, projectName = "" } = config.modRequest;
1378
-
1379
- const srcDir = path.resolve(workingPath, assetsDir, "ios");
1380
- const destDir = path.resolve(platformProjectRoot, projectName);
1381
-
1382
- cleanIOS(destDir);
1383
-
1384
- hfs.copy(
1385
- path.join(srcDir, "BootSplash.storyboard"),
1386
- path.join(destDir, "BootSplash.storyboard"),
1387
- );
1388
-
1389
- for (const xcassetsDir of ["Colors.xcassets", "Images.xcassets"]) {
1390
- const srcXcassetsDir = path.join(srcDir, xcassetsDir);
1391
- const destXcassetsDir = path.join(destDir, xcassetsDir);
1392
-
1393
- hfs.ensureDir(destXcassetsDir);
1394
-
1395
- for (const file of hfs.readDir(srcXcassetsDir)) {
1396
- hfs.copy(
1397
- path.join(srcXcassetsDir, file),
1398
- path.join(destXcassetsDir, file),
1399
- );
1400
- }
1401
- }
1402
-
1403
- return config;
1404
- },
1405
- ]);
1406
-
1407
- const withAppDelegate: ExpoPlugin = (config) =>
1408
- Expo.withAppDelegate(config, (config) => {
1409
- const { modResults } = config;
1410
- const { language } = modResults;
1411
-
1412
- if (language !== "objc" && language !== "objcpp") {
1413
- throw new Error(
1414
- `Cannot modify the project AppDelegate as it's not in a supported language: ${language}`,
1415
- );
1416
- }
1417
-
1418
- const withHeader = mergeContents({
1419
- src: modResults.contents,
1420
- comment: "//",
1421
- tag: "bootsplash-header",
1422
- offset: 1,
1423
- anchor: /#import "AppDelegate\.h"/,
1424
- newSrc: '#import "RNBootSplash.h"',
1425
- });
1426
-
1427
- const withRootView = mergeContents({
1428
- src: withHeader.contents,
1429
- comment: "//",
1430
- tag: "bootsplash-init",
1431
- offset: 0,
1432
- anchor: /@end/,
1433
- newSrc: dedent`
1434
- - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName initProps:(NSDictionary *)initProps {
1435
- UIView *rootView = [super createRootViewWithBridge:bridge moduleName:moduleName initProps:initProps];
1436
- [RNBootSplash initWithStoryboard:@"BootSplash" rootView:rootView];
1437
- return rootView;
1438
- }
1439
- `,
1440
- });
1441
-
1442
- return {
1443
- ...config,
1444
- modResults: {
1445
- ...modResults,
1446
- contents: withRootView.contents,
1447
- },
1448
- };
1449
- });
1450
-
1451
- const withInfoPlist: ExpoPlugin = (config) =>
1452
- Expo.withInfoPlist(config, (config) => {
1453
- config.modResults["UILaunchStoryboardName"] = "BootSplash";
1454
- return config;
1455
- });
1456
-
1457
- const withXcodeProject: ExpoPlugin = (config) =>
1458
- Expo.withXcodeProject(config, (config) => {
1459
- const { projectName = "" } = config.modRequest;
1460
-
1461
- Expo.IOSConfig.XcodeUtils.addResourceFileToGroup({
1462
- filepath: path.join(projectName, "BootSplash.storyboard"),
1463
- groupName: projectName,
1464
- project: config.modResults,
1465
- isBuildFile: true,
1466
- });
1467
-
1468
- Expo.IOSConfig.XcodeUtils.addResourceFileToGroup({
1469
- filepath: path.join(projectName, "Colors.xcassets"),
1470
- groupName: projectName,
1471
- project: config.modResults,
1472
- isBuildFile: true,
1473
- });
1474
-
1475
- return config;
1476
- });
1477
-
1478
- const withoutExpoSplashScreen: ExpoPlugin = Expo.createRunOncePlugin(
1479
- (config) => config,
1480
- "expo-splash-screen",
1481
- "skip",
1482
- );
1483
-
1484
- export const withGenerate: ExpoPlugin = (config, props = {}) => {
1485
- const plugins: ExpoPlugin[] = [];
1486
- const { platforms = [] } = config;
1487
-
1488
- plugins.push(withoutExpoSplashScreen);
1489
-
1490
- if (platforms.includes("android")) {
1491
- plugins.push(
1492
- withAndroidAssets,
1493
- withAndroidManifest,
1494
- withMainActivity,
1495
- withAndroidStyles,
1496
- withAndroidColors,
1497
- withAndroidColorsNight,
1498
- );
1499
- }
1500
-
1501
- if (platforms.includes("ios")) {
1502
- plugins.push(
1503
- withIOSAssets,
1504
- withAppDelegate,
1505
- withInfoPlist,
1506
- withXcodeProject,
1507
- );
1508
- }
1509
-
1510
- return Expo.withPlugins(
1511
- config,
1512
- plugins.map((plugin) => [plugin, props]),
1513
- );
1514
- };