react-native-bootsplash
Version:
Display a bootsplash on your app starts. Hide it when you want.
341 lines (339 loc) • 10.7 kB
JavaScript
;
import * as Expo from "@expo/config-plugins";
import { assignColorValue } from "@expo/config-plugins/build/android/Colors";
import { addImports } from "@expo/config-plugins/build/android/codeMod";
import { mergeContents } from "@expo/config-plugins/build/utils/generateCode";
import path from "path";
import semver from "semver";
import { dedent } from "ts-dedent";
import { cleanIOSAssets, getExpoConfig, hfs, log } from "./generate";
const withExpoVersionCheck = platform => config => Expo.withDangerousMod(config, [platform, config => {
getExpoConfig(config.modRequest.projectRoot); // will exit process if expo < 51.0.20
return config;
}]);
const withAndroidAssets = (config, props) => Expo.withDangerousMod(config, ["android", config => {
const {
assetsDir = "assets/bootsplash"
} = props;
const {
projectRoot,
platformProjectRoot
} = config.modRequest;
const srcDir = path.resolve(projectRoot, assetsDir, "android");
if (!hfs.exists(srcDir)) {
const error = `"${path.relative(projectRoot, srcDir)}" doesn't exist. Did you run the asset generation command?`;
log.error(error);
process.exit(1);
}
const destDir = path.resolve(platformProjectRoot, "app", "src", "main", "res");
for (const drawableDir of hfs.readDir(srcDir)) {
const srcDrawableDir = path.join(srcDir, drawableDir);
const destDrawableDir = path.join(destDir, drawableDir);
if (hfs.isDir(srcDrawableDir)) {
hfs.ensureDir(destDrawableDir);
for (const file of hfs.readDir(srcDrawableDir)) {
hfs.copy(path.join(srcDrawableDir, file), path.join(destDrawableDir, file));
}
}
}
return config;
}]);
const withAndroidManifest = config => Expo.withAndroidManifest(config, config => {
config.modResults.manifest.application?.forEach(application => {
if (application.$["android:name"] === ".MainApplication") {
const {
activity
} = application;
activity?.forEach(activity => {
if (activity.$["android:name"] === ".MainActivity") {
activity.$["android:theme"] = "@style/BootTheme";
}
});
}
});
return config;
});
const withMainActivity = config => Expo.withMainActivity(config, config => {
const {
modResults
} = config;
const {
language
} = modResults;
const withImports = addImports(modResults.contents.replace(/(\/\/ )?setTheme\(R\.style\.AppTheme\)/, "// setTheme(R.style.AppTheme)"), ["android.os.Bundle", "com.zoontek.rnbootsplash.RNBootSplash"], language === "java");
// indented with 4 spaces
const withInit = mergeContents({
src: withImports,
comment: " //",
tag: "bootsplash-init",
offset: 0,
anchor: /super\.onCreate\(null\)/,
newSrc: " RNBootSplash.init(this, R.style.BootTheme)" + (language === "java" ? ";" : "")
});
return {
...config,
modResults: {
...modResults,
contents: withInit.contents
}
};
});
const withAndroidStyles = (config, props) => Expo.withAndroidStyles(config, async config => {
const {
assetsDir = "assets/bootsplash",
android = {}
} = props;
const {
parentTheme,
darkContentBarsStyle
} = android;
const {
modRequest,
modResults
} = config;
const {
resources
} = modResults;
const {
style = []
} = resources;
const manifest = await hfs.json(path.resolve(modRequest.projectRoot, assetsDir, "manifest.json"));
const item = [{
$: {
name: "postBootSplashTheme"
},
_: "@style/AppTheme"
}, {
$: {
name: "bootSplashBackground"
},
_: "@color/bootsplash_background"
}, {
$: {
name: "bootSplashLogo"
},
_: "@drawable/bootsplash_logo"
}];
if (manifest.brand != null) {
item.push({
$: {
name: "bootSplashBrand"
},
_: "@drawable/bootsplash_brand"
});
}
if (darkContentBarsStyle != null) {
item.push({
$: {
name: "darkContentBarsStyle"
},
_: String(darkContentBarsStyle)
});
}
const withBootTheme = [...style.filter(({
$
}) => $.name !== "BootTheme"), {
$: {
name: "BootTheme",
parent: parentTheme === "TransparentStatus" ? "Theme.BootSplash.TransparentStatus" : parentTheme === "EdgeToEdge" ? "Theme.BootSplash.EdgeToEdge" : "Theme.BootSplash"
},
item
}];
return {
...config,
modResults: {
...modResults,
resources: {
...resources,
style: withBootTheme
}
}
};
});
const withAndroidColors = (config, props) => Expo.withAndroidColors(config, async config => {
const {
assetsDir = "assets/bootsplash"
} = props;
const {
projectRoot
} = config.modRequest;
const manifest = await hfs.json(path.resolve(projectRoot, assetsDir, "manifest.json"));
config.modResults = assignColorValue(config.modResults, {
name: "bootsplash_background",
value: manifest.background
});
return config;
});
const withAndroidColorsNight = (config, props) => Expo.withAndroidColorsNight(config, async config => {
const {
assetsDir = "assets/bootsplash"
} = props;
const {
projectRoot
} = config.modRequest;
const manifest = await hfs.json(path.resolve(projectRoot, assetsDir, "manifest.json"));
if (manifest.darkBackground != null) {
config.modResults = assignColorValue(config.modResults, {
name: "bootsplash_background",
value: manifest.darkBackground
});
}
return config;
});
const withIOSAssets = (config, props) => Expo.withDangerousMod(config, ["ios", config => {
const {
assetsDir = "assets/bootsplash"
} = props;
const {
projectRoot,
platformProjectRoot,
projectName = ""
} = config.modRequest;
const srcDir = path.resolve(projectRoot, assetsDir, "ios");
const destDir = path.resolve(platformProjectRoot, projectName);
if (!hfs.exists(srcDir)) {
const error = `"${path.relative(projectRoot, srcDir)}" doesn't exist. Did you run the asset generation command?`;
log.error(error);
process.exit(1);
}
cleanIOSAssets(destDir);
hfs.copy(path.join(srcDir, "BootSplash.storyboard"), path.join(destDir, "BootSplash.storyboard"));
for (const xcassetsDir of ["Colors.xcassets", "Images.xcassets"]) {
const srcXcassetsDir = path.join(srcDir, xcassetsDir);
const destXcassetsDir = path.join(destDir, xcassetsDir);
if (hfs.isDir(srcXcassetsDir)) {
hfs.ensureDir(destXcassetsDir);
for (const file of hfs.readDir(srcXcassetsDir)) {
hfs.copy(path.join(srcXcassetsDir, file), path.join(destXcassetsDir, file));
}
}
}
return config;
}]);
const withAppDelegate = config => Expo.withAppDelegate(config, config => {
const {
modResults,
sdkVersion = "0.1.0"
} = config;
const {
language
} = modResults;
if (language !== "objc" && language !== "objcpp" && language !== "swift") {
throw new Error(`Cannot modify the project AppDelegate as it's not in a supported language: ${language}`);
}
const withRootView = (() => {
// SDK 53 deprecates support for Obj-C AppDelegate
if (semver.major(sdkVersion) >= 53) {
const withHeader = mergeContents({
src: modResults.contents,
comment: "//",
tag: "bootsplash-header",
offset: 1,
anchor: /import Expo/,
newSrc: "import RNBootSplash"
});
return mergeContents({
src: withHeader.contents,
comment: "//",
tag: "bootsplash-init",
offset: 1,
anchor: /class ReactNativeDelegate: ExpoReactNativeFactoryDelegate {/,
newSrc: dedent`
public override func customize(_ rootView: UIView) {
super.customize(rootView)
RNBootSplash.initWithStoryboard("BootSplash", rootView: rootView)
}
`
});
}
if (language === "swift") {
const withHeader = mergeContents({
src: modResults.contents,
comment: "//",
tag: "bootsplash-header",
offset: 1,
anchor: /import Expo/,
newSrc: "import RNBootSplash"
});
return mergeContents({
src: withHeader.contents,
comment: "//",
tag: "bootsplash-init",
offset: 1,
anchor: /public class AppDelegate: ExpoAppDelegate {/,
newSrc: dedent`
override func customize(_ rootView: RCTRootView!) {
super.customize(rootView)
RNBootSplash.initWithStoryboard("BootSplash", rootView: rootView)
}
`
});
}
const withHeader = mergeContents({
src: modResults.contents,
comment: "//",
tag: "bootsplash-header",
offset: 1,
anchor: /#import "AppDelegate\.h"/,
newSrc: '#import "RNBootSplash.h"'
});
return mergeContents({
src: withHeader.contents,
comment: "//",
tag: "bootsplash-init",
offset: 0,
anchor: /@end/,
newSrc: dedent`
- (void)customizeRootView:(RCTRootView *)rootView {
[super customizeRootView:rootView];
[RNBootSplash initWithStoryboard:@"BootSplash" rootView:rootView];
}
`
});
})();
return {
...config,
modResults: {
...modResults,
contents: withRootView.contents
}
};
});
const withInfoPlist = config => Expo.withInfoPlist(config, config => {
config.modResults["UILaunchStoryboardName"] = "BootSplash";
return config;
});
const withXcodeProject = config => Expo.withXcodeProject(config, config => {
const {
projectName = ""
} = config.modRequest;
Expo.IOSConfig.XcodeUtils.addResourceFileToGroup({
filepath: path.join(projectName, "BootSplash.storyboard"),
groupName: projectName,
project: config.modResults,
isBuildFile: true
});
Expo.IOSConfig.XcodeUtils.addResourceFileToGroup({
filepath: path.join(projectName, "Colors.xcassets"),
groupName: projectName,
project: config.modResults,
isBuildFile: true
});
return config;
});
const withoutExpoSplashScreen = Expo.createRunOncePlugin(config => config, "expo-splash-screen", "skip");
export const withBootSplash = (config, props = {}) => {
const plugins = [];
const {
platforms = []
} = config;
plugins.push(withoutExpoSplashScreen);
if (platforms.includes("android")) {
plugins.push(withExpoVersionCheck("android"), withAndroidAssets, withAndroidManifest, withMainActivity, withAndroidStyles, withAndroidColors, withAndroidColorsNight);
}
if (platforms.includes("ios")) {
plugins.push(withExpoVersionCheck("ios"), withIOSAssets, withAppDelegate, withInfoPlist, withXcodeProject);
}
return Expo.withPlugins(config, plugins.map(plugin => [plugin, props]));
};
//# sourceMappingURL=expo.js.map