react-native-custom-splash 3.0.1 → 3.0.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-custom-splash",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "description": "A custom splash screen module for React Native with native iOS and Android support, fully compatible with Expo",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -3,18 +3,13 @@ const path = require('path');
3
3
  const fs = require('fs');
4
4
 
5
5
  /**
6
- * FINAL WORKING iOS Splash - Xcode Compatible
6
+ * BULLET-PROOF iOS Splash Screen
7
+ * This completely replaces Expo's splash with user's custom splash
7
8
  */
8
9
  function withForcediOSSplash(config, pluginConfig) {
9
- // Disable Expo's splash
10
- config = {
11
- ...config,
12
- splash: undefined,
13
- ios: {
14
- ...config.ios,
15
- splash: undefined
16
- }
17
- };
10
+ // COMPLETELY DISABLE Expo's splash
11
+ if (config.splash) delete config.splash;
12
+ if (config.ios && config.ios.splash) delete config.ios.splash;
18
13
 
19
14
  return withDangerousMod(config, [
20
15
  'ios',
@@ -22,250 +17,212 @@ function withForcediOSSplash(config, pluginConfig) {
22
17
  const projectRoot = config.modRequest.projectRoot;
23
18
  const iosPath = config.modRequest.platformProjectRoot;
24
19
  const projectName = config.modRequest.projectName;
20
+ const projectDir = path.join(iosPath, projectName);
21
+ const assetsPath = path.join(projectDir, 'Images.xcassets');
25
22
 
26
- console.log('\nšŸ”„ SETTING UP CUSTOM SPLASH...\n');
23
+ console.log('\nšŸ”„ CUSTOM SPLASH SCREEN SETUP...\n');
27
24
 
28
- // Delete ALL old splash files
25
+ // STEP 1: DELETE ALL EXPO SPLASH FILES
29
26
  const filesToDelete = [
30
- path.join(iosPath, projectName, 'SplashScreen.storyboard'),
31
- path.join(iosPath, projectName, 'LaunchScreen.storyboard'),
32
- path.join(iosPath, projectName, 'Images.xcassets', 'SplashScreenLegacy.imageset'),
33
- path.join(iosPath, projectName, 'Images.xcassets', 'SplashScreen.imageset'),
34
- path.join(iosPath, projectName, 'Images.xcassets', 'SplashScreenBackground.imageset'),
27
+ 'SplashScreen.storyboard',
28
+ 'LaunchScreen.storyboard',
35
29
  ];
36
30
 
37
- filesToDelete.forEach(filePath => {
38
- try {
39
- if (fs.existsSync(filePath)) {
40
- if (fs.lstatSync(filePath).isDirectory()) {
41
- fs.rmSync(filePath, { recursive: true, force: true });
42
- } else {
43
- fs.unlinkSync(filePath);
44
- }
45
- }
46
- } catch (e) {
47
- // Ignore
31
+ const foldersToDelete = [
32
+ 'Images.xcassets/SplashScreen.imageset',
33
+ 'Images.xcassets/SplashScreenBackground.imageset',
34
+ 'Images.xcassets/SplashScreenLegacy.imageset',
35
+ ];
36
+
37
+ filesToDelete.forEach(file => {
38
+ const fullPath = path.join(projectDir, file);
39
+ if (fs.existsSync(fullPath)) {
40
+ fs.unlinkSync(fullPath);
41
+ console.log('šŸ—‘ļø Deleted:', file);
42
+ }
43
+ });
44
+
45
+ foldersToDelete.forEach(folder => {
46
+ const fullPath = path.join(projectDir, folder);
47
+ if (fs.existsSync(fullPath)) {
48
+ fs.rmSync(fullPath, { recursive: true, force: true });
49
+ console.log('šŸ—‘ļø Deleted:', folder);
48
50
  }
49
51
  });
50
52
 
51
- // Update Info.plist
52
- const plistPath = path.join(iosPath, projectName, 'Info.plist');
53
+ // STEP 2: UPDATE INFO.PLIST
54
+ const plistPath = path.join(projectDir, 'Info.plist');
53
55
  if (fs.existsSync(plistPath)) {
54
56
  let plist = fs.readFileSync(plistPath, 'utf8');
55
- plist = plist.replace(/<key>UILaunchStoryboardName<\/key>\s*<string>.*?<\/string>/g, '');
57
+
58
+ // Remove old references
59
+ plist = plist.replace(/<key>UILaunchStoryboardName<\/key>\s*<string>.*?<\/string>/gs, '');
56
60
  plist = plist.replace(/<key>UILaunchScreen<\/key>[\s\S]*?<\/dict>/g, '');
57
61
 
58
- if (!plist.includes('UILaunchStoryboardName')) {
59
- plist = plist.replace(
60
- '</dict>\n</plist>',
61
- '\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n</dict>\n</plist>'
62
- );
63
- }
62
+ // Add LaunchScreen reference
63
+ plist = plist.replace(
64
+ '</dict>\n</plist>',
65
+ '\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n</dict>\n</plist>'
66
+ );
64
67
 
65
68
  fs.writeFileSync(plistPath, plist);
66
69
  console.log('āœ… Info.plist updated');
67
70
  }
68
71
 
69
- const assetsPath = path.join(iosPath, projectName, 'Images.xcassets');
70
- let hasImage = false;
72
+ // STEP 3: COPY USER IMAGES
73
+ let hasBackground = false;
71
74
  let hasLogo = false;
72
75
 
73
- // Copy splash_image
74
76
  if (pluginConfig.image) {
75
- const srcImage = path.join(projectRoot, pluginConfig.image);
76
- if (fs.existsSync(srcImage)) {
77
- const destDir = path.join(assetsPath, 'SplashImage.imageset');
78
-
79
- if (fs.existsSync(destDir)) {
80
- fs.rmSync(destDir, { recursive: true, force: true });
77
+ const srcPath = path.join(projectRoot, pluginConfig.image);
78
+ if (fs.existsSync(srcPath)) {
79
+ const imagesetDir = path.join(assetsPath, 'SplashBackground.imageset');
80
+ if (fs.existsSync(imagesetDir)) {
81
+ fs.rmSync(imagesetDir, { recursive: true, force: true });
81
82
  }
82
- fs.mkdirSync(destDir, { recursive: true });
83
-
84
- // Copy image
85
- fs.copyFileSync(srcImage, path.join(destDir, 'splash.png'));
83
+ fs.mkdirSync(imagesetDir, { recursive: true });
86
84
 
87
- // Create Contents.json
88
- const contents = {
85
+ fs.copyFileSync(srcPath, path.join(imagesetDir, 'background.png'));
86
+ fs.writeFileSync(path.join(imagesetDir, 'Contents.json'), JSON.stringify({
89
87
  images: [
90
- {
91
- filename: 'splash.png',
92
- idiom: 'universal',
93
- scale: '1x'
94
- },
95
- {
96
- filename: 'splash.png',
97
- idiom: 'universal',
98
- scale: '2x'
99
- },
100
- {
101
- filename: 'splash.png',
102
- idiom: 'universal',
103
- scale: '3x'
104
- }
88
+ { idiom: 'universal', filename: 'background.png', scale: '1x' },
89
+ { idiom: 'universal', filename: 'background.png', scale: '2x' },
90
+ { idiom: 'universal', filename: 'background.png', scale: '3x' }
105
91
  ],
106
- info: {
107
- author: 'xcode',
108
- version: 1
109
- }
110
- };
111
-
112
- fs.writeFileSync(
113
- path.join(destDir, 'Contents.json'),
114
- JSON.stringify(contents, null, 2)
115
- );
116
-
117
- hasImage = true;
118
- console.log('āœ… Background image copied: SplashImage');
92
+ info: { author: 'xcode', version: 1 }
93
+ }, null, 2));
94
+
95
+ hasBackground = true;
96
+ console.log('āœ… Background image: SplashBackground');
119
97
  }
120
98
  }
121
99
 
122
- // Copy splash_logo
123
100
  if (pluginConfig.logo) {
124
- const srcLogo = path.join(projectRoot, pluginConfig.logo);
125
- if (fs.existsSync(srcLogo)) {
126
- const destDir = path.join(assetsPath, 'SplashLogo.imageset');
127
-
128
- if (fs.existsSync(destDir)) {
129
- fs.rmSync(destDir, { recursive: true, force: true });
101
+ const srcPath = path.join(projectRoot, pluginConfig.logo);
102
+ if (fs.existsSync(srcPath)) {
103
+ const imagesetDir = path.join(assetsPath, 'SplashLogo.imageset');
104
+ if (fs.existsSync(imagesetDir)) {
105
+ fs.rmSync(imagesetDir, { recursive: true, force: true });
130
106
  }
131
- fs.mkdirSync(destDir, { recursive: true });
107
+ fs.mkdirSync(imagesetDir, { recursive: true });
132
108
 
133
- // Copy logo
134
- fs.copyFileSync(srcLogo, path.join(destDir, 'logo.png'));
135
-
136
- // Create Contents.json
137
- const contents = {
109
+ fs.copyFileSync(srcPath, path.join(imagesetDir, 'logo.png'));
110
+ fs.writeFileSync(path.join(imagesetDir, 'Contents.json'), JSON.stringify({
138
111
  images: [
139
- {
140
- filename: 'logo.png',
141
- idiom: 'universal',
142
- scale: '1x'
143
- },
144
- {
145
- filename: 'logo.png',
146
- idiom: 'universal',
147
- scale: '2x'
148
- },
149
- {
150
- filename: 'logo.png',
151
- idiom: 'universal',
152
- scale: '3x'
153
- }
112
+ { idiom: 'universal', filename: 'logo.png', scale: '1x' },
113
+ { idiom: 'universal', filename: 'logo.png', scale: '2x' },
114
+ { idiom: 'universal', filename: 'logo.png', scale: '3x' }
154
115
  ],
155
- info: {
156
- author: 'xcode',
157
- version: 1
158
- }
159
- };
160
-
161
- fs.writeFileSync(
162
- path.join(destDir, 'Contents.json'),
163
- JSON.stringify(contents, null, 2)
164
- );
116
+ info: { author: 'xcode', version: 1 }
117
+ }, null, 2));
165
118
 
166
119
  hasLogo = true;
167
- console.log('āœ… Logo image copied: SplashLogo');
120
+ console.log('āœ… Logo image: SplashLogo');
168
121
  }
169
122
  }
170
123
 
171
- // Create LaunchScreen.storyboard
172
- const storyboard = createXcodeStoryboard(hasImage, hasLogo, pluginConfig.backgroundColor);
173
- const storyboardPath = path.join(iosPath, projectName, 'LaunchScreen.storyboard');
174
-
175
- if (fs.existsSync(storyboardPath)) {
176
- fs.unlinkSync(storyboardPath);
177
- }
178
-
179
- fs.writeFileSync(storyboardPath, storyboard);
180
-
181
- console.log('āœ… LaunchScreen.storyboard created!');
182
- console.log(` Background: ${hasImage ? 'SplashImage āœ“' : 'Color only'}`);
183
- console.log(` Logo: ${hasLogo ? 'SplashLogo āœ“' : 'None'}`);
184
- console.log(` Color: ${pluginConfig.backgroundColor}\n`);
185
-
186
- return config;
187
- },
188
- ]);
189
- }
190
-
191
- function createXcodeStoryboard(hasImage, hasLogo, bgColor) {
192
- const color = bgColor.replace('#', '');
193
- const r = parseInt(color.substr(0, 2), 16) / 255;
194
- const g = parseInt(color.substr(2, 2), 16) / 255;
195
- const b = parseInt(color.substr(4, 2), 16) / 255;
196
-
197
- // Build subviews
198
- let subviews = '';
199
- let constraints = '';
200
- let resources = '';
201
-
202
- if (hasImage) {
203
- subviews += `
204
- <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="SplashImage" translatesAutoresizingMaskIntoConstraints="NO" id="splash-bg">
205
- <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
206
- </imageView>`;
207
-
208
- constraints += `
209
- <constraint firstItem="splash-bg" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="bg-top"/>
210
- <constraint firstItem="splash-bg" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="bg-leading"/>
211
- <constraint firstItem="splash-bg" firstAttribute="trailing" secondItem="Ze5-6b-2t3" secondAttribute="trailing" id="bg-trailing"/>
212
- <constraint firstItem="splash-bg" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="bg-bottom"/>`;
213
-
214
- resources += `
215
- <image name="SplashImage" width="1242" height="2688"/>`;
216
- }
217
-
218
- if (hasLogo) {
219
- subviews += `
220
- <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="SplashLogo" translatesAutoresizingMaskIntoConstraints="NO" id="splash-logo">
221
- <rect key="frame" x="132" y="373" width="150" height="150"/>
222
- <constraints>
223
- <constraint firstAttribute="width" constant="150" id="logo-width"/>
224
- <constraint firstAttribute="height" constant="150" id="logo-height"/>
225
- </constraints>
226
- </imageView>`;
227
-
228
- constraints += `
229
- <constraint firstItem="splash-logo" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="logo-centerx"/>
230
- <constraint firstItem="splash-logo" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="logo-centery"/>`;
231
-
232
- resources += `
233
- <image name="SplashLogo" width="512" height="512"/>`;
234
- }
124
+ // STEP 4: CREATE CLEAN LAUNCHSCREEN.STORYBOARD
125
+ const bgColor = pluginConfig.backgroundColor || '#FFFFFF';
126
+ const color = bgColor.replace('#', '');
127
+ const r = (parseInt(color.substr(0, 2), 16) / 255).toFixed(6);
128
+ const g = (parseInt(color.substr(2, 2), 16) / 255).toFixed(6);
129
+ const b = (parseInt(color.substr(4, 2), 16) / 255).toFixed(6);
235
130
 
236
- return `<?xml version="1.0" encoding="UTF-8"?>
237
- <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
238
- <device id="retina6_1" orientation="portrait" appearance="light"/>
131
+ let storyboard = `<?xml version="1.0" encoding="UTF-8"?>
132
+ <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
133
+ <device id="retina6_12" orientation="portrait" appearance="light"/>
239
134
  <dependencies>
240
- <deployment identifier="iOS"/>
241
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
135
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
242
136
  <capability name="Safe area layout guides" minToolsVersion="9.0"/>
243
137
  <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
244
138
  </dependencies>
245
139
  <scenes>
246
- <!--View Controller-->
247
140
  <scene sceneID="EHf-IW-A2E">
248
141
  <objects>
249
142
  <viewController id="01J-lp-oVM" sceneMemberID="viewController">
250
- <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
251
- <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
143
+ <view key="view" contentMode="scaleToFill" id="mainView">
144
+ <rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
252
145
  <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
253
- <subviews>${subviews}
146
+ <subviews>`;
147
+
148
+ // Add background image if exists
149
+ if (hasBackground) {
150
+ storyboard += `
151
+ <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="SplashBackground" translatesAutoresizingMaskIntoConstraints="NO" id="backgroundImageView">
152
+ <rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
153
+ </imageView>`;
154
+ }
155
+
156
+ // Add logo if exists
157
+ if (hasLogo) {
158
+ storyboard += `
159
+ <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="SplashLogo" translatesAutoresizingMaskIntoConstraints="NO" id="logoImageView">
160
+ <rect key="frame" x="121.5" y="376" width="150" height="100"/>
161
+ <constraints>
162
+ <constraint firstAttribute="width" constant="150" id="logoWidth"/>
163
+ <constraint firstAttribute="height" constant="100" id="logoHeight"/>
164
+ </constraints>
165
+ </imageView>`;
166
+ }
167
+
168
+ storyboard += `
254
169
  </subviews>
255
- <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
170
+ <viewLayoutGuide key="safeArea" id="safeAreaGuide"/>
256
171
  <color key="backgroundColor" red="${r}" green="${g}" blue="${b}" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
257
- <constraints>${constraints}
172
+ <constraints>`;
173
+
174
+ // Add background constraints
175
+ if (hasBackground) {
176
+ storyboard += `
177
+ <constraint firstItem="backgroundImageView" firstAttribute="top" secondItem="mainView" secondAttribute="top" id="bgTop"/>
178
+ <constraint firstItem="backgroundImageView" firstAttribute="leading" secondItem="mainView" secondAttribute="leading" id="bgLeading"/>
179
+ <constraint firstItem="backgroundImageView" firstAttribute="trailing" secondItem="mainView" secondAttribute="trailing" id="bgTrailing"/>
180
+ <constraint firstItem="backgroundImageView" firstAttribute="bottom" secondItem="mainView" secondAttribute="bottom" id="bgBottom"/>`;
181
+ }
182
+
183
+ // Add logo constraints
184
+ if (hasLogo) {
185
+ storyboard += `
186
+ <constraint firstItem="logoImageView" firstAttribute="centerX" secondItem="mainView" secondAttribute="centerX" id="logoCenterX"/>
187
+ <constraint firstItem="logoImageView" firstAttribute="centerY" secondItem="mainView" secondAttribute="centerY" id="logoCenterY"/>`;
188
+ }
189
+
190
+ storyboard += `
258
191
  </constraints>
259
192
  </view>
260
193
  </viewController>
261
- <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
194
+ <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
262
195
  </objects>
263
- <point key="canvasLocation" x="53" y="375"/>
196
+ <point key="canvasLocation" x="0" y="0"/>
264
197
  </scene>
265
198
  </scenes>
266
- <resources>${resources}
199
+ <resources>`;
200
+
201
+ if (hasBackground) {
202
+ storyboard += `
203
+ <image name="SplashBackground" width="1242" height="2688"/>`;
204
+ }
205
+ if (hasLogo) {
206
+ storyboard += `
207
+ <image name="SplashLogo" width="512" height="512"/>`;
208
+ }
209
+
210
+ storyboard += `
267
211
  </resources>
268
212
  </document>`;
213
+
214
+ // Write storyboard
215
+ const storyboardPath = path.join(projectDir, 'LaunchScreen.storyboard');
216
+ fs.writeFileSync(storyboardPath, storyboard);
217
+
218
+ console.log('āœ… LaunchScreen.storyboard created');
219
+ console.log(` šŸ“ø Background: ${hasBackground ? 'YES' : 'NO'}`);
220
+ console.log(` šŸŽØ Logo: ${hasLogo ? 'YES' : 'NO'}`);
221
+ console.log(` 🌈 Color: ${bgColor}\n`);
222
+
223
+ return config;
224
+ },
225
+ ]);
269
226
  }
270
227
 
271
228
  module.exports = withForcediOSSplash;