react-native-custom-splash 2.1.5 → 3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-custom-splash",
3
- "version": "2.1.5",
3
+ "version": "3.0.0",
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",
@@ -17,7 +17,7 @@
17
17
  "android",
18
18
  "native-module"
19
19
  ],
20
- "author": "Your Name",
20
+ "author": "Vijay Kishan",
21
21
  "license": "MIT",
22
22
  "repository": {
23
23
  "type": "git",
@@ -8,6 +8,7 @@ const {
8
8
  } = require('@expo/config-plugins');
9
9
  const path = require('path');
10
10
  const fs = require('fs');
11
+ const withForcediOSSplash = require('./withCustomSplash');
11
12
 
12
13
  /**
13
14
  * Validate and normalize plugin configuration
@@ -530,6 +531,6 @@ module.exports = (config, props = {}) => {
530
531
 
531
532
  return withPlugins(config, [
532
533
  [withSplashScreenAndroid, pluginConfig],
533
- [withSplashScreenIOS, pluginConfig],
534
+ [withForcediOSSplash, pluginConfig],
534
535
  ]);
535
536
  };
@@ -0,0 +1,242 @@
1
+ const { withDangerousMod, withPlugins } = require('@expo/config-plugins');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+
5
+ /**
6
+ * ULTIMATE iOS Splash Fix - Forceful & Complete
7
+ * This DISABLES Expo's splash and FORCES user images
8
+ */
9
+ function withForcediOSSplash(config, pluginConfig) {
10
+ // STEP 1: Disable Expo's default splash completely
11
+ config = {
12
+ ...config,
13
+ splash: undefined, // Remove Expo splash config
14
+ ios: {
15
+ ...config.ios,
16
+ splash: undefined // Remove iOS splash config
17
+ }
18
+ };
19
+
20
+ // STEP 2: Use dangerousMod to forcefully set everything
21
+ return withDangerousMod(config, [
22
+ 'ios',
23
+ async (config) => {
24
+ const projectRoot = config.modRequest.projectRoot;
25
+ const iosPath = config.modRequest.platformProjectRoot;
26
+ const projectName = config.modRequest.projectName;
27
+
28
+ console.log('\nļæ½ FORCING CUSTOM SPLASH SCREEN (FINAL FIX)...\n');
29
+
30
+ // Wait a bit to ensure Expo is done
31
+ await new Promise(resolve => setTimeout(resolve, 100));
32
+
33
+ // NUCLEAR OPTION: Delete EVERYTHING splash-related
34
+ const filesToDelete = [
35
+ path.join(iosPath, projectName, 'SplashScreen.storyboard'),
36
+ path.join(iosPath, projectName, 'LaunchScreen.storyboard'),
37
+ path.join(iosPath, projectName, 'Images.xcassets', 'SplashScreenLegacy.imageset'),
38
+ path.join(iosPath, projectName, 'Images.xcassets', 'SplashScreen.imageset'),
39
+ path.join(iosPath, projectName, 'Images.xcassets', 'SplashScreenBackground.imageset'),
40
+ ];
41
+
42
+ filesToDelete.forEach(filePath => {
43
+ try {
44
+ if (fs.existsSync(filePath)) {
45
+ if (fs.lstatSync(filePath).isDirectory()) {
46
+ fs.rmSync(filePath, { recursive: true, force: true });
47
+ } else {
48
+ fs.unlinkSync(filePath);
49
+ }
50
+ console.log('šŸ—‘ļø Deleted:', path.basename(filePath));
51
+ }
52
+ } catch (e) {
53
+ // Ignore errors
54
+ }
55
+ });
56
+
57
+ // Force update Info.plist
58
+ const plistPath = path.join(iosPath, projectName, 'Info.plist');
59
+ if (fs.existsSync(plistPath)) {
60
+ let plist = fs.readFileSync(plistPath, 'utf8');
61
+
62
+ // Remove ALL launch screen configurations
63
+ plist = plist.replace(/<key>UILaunchStoryboardName<\/key>\s*<string>.*?<\/string>/g, '');
64
+ plist = plist.replace(/<key>UILaunchScreen<\/key>[\s\S]*?<\/dict>/g, '');
65
+
66
+ // Add our LaunchScreen BEFORE closing dict
67
+ if (!plist.includes('UILaunchStoryboardName')) {
68
+ plist = plist.replace(
69
+ '</dict>\n</plist>',
70
+ '\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n</dict>\n</plist>'
71
+ );
72
+ }
73
+
74
+ fs.writeFileSync(plistPath, plist);
75
+ console.log('āœ… Info.plist FORCED');
76
+ }
77
+
78
+ // Copy user images with FORCE
79
+ const assetsPath = path.join(iosPath, projectName, 'Images.xcassets');
80
+ let hasImage = false;
81
+ let hasLogo = false;
82
+
83
+ if (pluginConfig.image) {
84
+ const srcImage = path.join(projectRoot, pluginConfig.image);
85
+ if (fs.existsSync(srcImage)) {
86
+ const destDir = path.join(assetsPath, 'splash_image.imageset');
87
+
88
+ // Force delete and recreate
89
+ if (fs.existsSync(destDir)) {
90
+ fs.rmSync(destDir, { recursive: true, force: true });
91
+ }
92
+ fs.mkdirSync(destDir, { recursive: true });
93
+
94
+ // Copy for all scales
95
+ ['', '@2x', '@3x'].forEach(scale => {
96
+ fs.copyFileSync(srcImage, path.join(destDir, `splash_image${scale}.png`));
97
+ });
98
+
99
+ // Force Contents.json
100
+ fs.writeFileSync(
101
+ path.join(destDir, 'Contents.json'),
102
+ JSON.stringify({
103
+ images: [
104
+ { idiom: 'universal', filename: 'splash_image.png', scale: '1x' },
105
+ { idiom: 'universal', filename: 'splash_image@2x.png', scale: '2x' },
106
+ { idiom: 'universal', filename: 'splash_image@3x.png', scale: '3x' }
107
+ ],
108
+ info: { author: 'xcode', version: 1 }
109
+ }, null, 2)
110
+ );
111
+
112
+ hasImage = true;
113
+ console.log('āœ… FORCED: splash_image');
114
+ }
115
+ }
116
+
117
+ if (pluginConfig.logo) {
118
+ const srcLogo = path.join(projectRoot, pluginConfig.logo);
119
+ if (fs.existsSync(srcLogo)) {
120
+ const destDir = path.join(assetsPath, 'splash_logo.imageset');
121
+
122
+ // Force delete and recreate
123
+ if (fs.existsSync(destDir)) {
124
+ fs.rmSync(destDir, { recursive: true, force: true });
125
+ }
126
+ fs.mkdirSync(destDir, { recursive: true });
127
+
128
+ // Copy for all scales
129
+ ['', '@2x', '@3x'].forEach(scale => {
130
+ fs.copyFileSync(srcLogo, path.join(destDir, `splash_logo${scale}.png`));
131
+ });
132
+
133
+ // Force Contents.json
134
+ fs.writeFileSync(
135
+ path.join(destDir, 'Contents.json'),
136
+ JSON.stringify({
137
+ images: [
138
+ { idiom: 'universal', filename: 'splash_logo.png', scale: '1x' },
139
+ { idiom: 'universal', filename: 'splash_logo@2x.png', scale: '2x' },
140
+ { idiom: 'universal', filename: 'splash_logo@3x.png', scale: '3x' }
141
+ ],
142
+ info: { author: 'xcode', version: 1 }
143
+ }, null, 2)
144
+ );
145
+
146
+ hasLogo = true;
147
+ console.log('āœ… FORCED: splash_logo');
148
+ }
149
+ }
150
+
151
+ // FORCE create LaunchScreen.storyboard
152
+ const storyboard = createForcedStoryboard(hasImage, hasLogo, pluginConfig.backgroundColor);
153
+ const storyboardPath = path.join(iosPath, projectName, 'LaunchScreen.storyboard');
154
+
155
+ // Delete if exists
156
+ if (fs.existsSync(storyboardPath)) {
157
+ fs.unlinkSync(storyboardPath);
158
+ }
159
+
160
+ // Write with force
161
+ fs.writeFileSync(storyboardPath, storyboard, { flag: 'w' });
162
+
163
+ console.log('āœ… FORCED: LaunchScreen.storyboard');
164
+ console.log(` šŸ–¼ļø Background: ${hasImage ? 'splash_image' : 'color'}`);
165
+ console.log(` šŸŽØ Logo: ${hasLogo ? 'splash_logo' : 'none'}`);
166
+ console.log(` 🌈 Color: ${pluginConfig.backgroundColor}`);
167
+ console.log('\nāœ… CUSTOM SPLASH FORCED SUCCESSFULLY!\n');
168
+
169
+ return config;
170
+ },
171
+ ]);
172
+ }
173
+
174
+ function createForcedStoryboard(hasImage, hasLogo, bgColor) {
175
+ const color = bgColor.replace('#', '');
176
+ const r = parseInt(color.substr(0, 2), 16) / 255;
177
+ const g = parseInt(color.substr(2, 2), 16) / 255;
178
+ const b = parseInt(color.substr(4, 2), 16) / 255;
179
+
180
+ const bgImage = hasImage ? `
181
+ <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="splash_image" translatesAutoresizingMaskIntoConstraints="NO" id="BG">
182
+ <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
183
+ </imageView>` : '';
184
+
185
+ const logoImage = hasLogo ? `
186
+ <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="splash_logo" translatesAutoresizingMaskIntoConstraints="NO" id="LOGO">
187
+ <rect key="frame" x="132" y="348" width="150" height="150"/>
188
+ <constraints>
189
+ <constraint firstAttribute="width" constant="150" id="LW"/>
190
+ <constraint firstAttribute="height" constant="150" id="LH"/>
191
+ </constraints>
192
+ </imageView>` : '';
193
+
194
+ const bgConstraints = hasImage ? `
195
+ <constraint firstItem="BG" firstAttribute="top" secondItem="V" secondAttribute="top" id="BT"/>
196
+ <constraint firstItem="BG" firstAttribute="leading" secondItem="V" secondAttribute="leading" id="BL"/>
197
+ <constraint firstItem="BG" firstAttribute="trailing" secondItem="V" secondAttribute="trailing" id="BR"/>
198
+ <constraint firstItem="BG" firstAttribute="bottom" secondItem="V" secondAttribute="bottom" id="BB"/>` : '';
199
+
200
+ const logoConstraints = hasLogo ? `
201
+ <constraint firstItem="LOGO" firstAttribute="centerX" secondItem="V" secondAttribute="centerX" id="LX"/>
202
+ <constraint firstItem="LOGO" firstAttribute="centerY" secondItem="V" secondAttribute="centerY" id="LY"/>` : '';
203
+
204
+ const resources = [];
205
+ if (hasImage) resources.push(' <image name="splash_image" width="1242" height="2688"/>');
206
+ if (hasLogo) resources.push(' <image name="splash_logo" width="512" height="512"/>');
207
+
208
+ return `<?xml version="1.0" encoding="UTF-8"?>
209
+ <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="VC">
210
+ <device id="retina6_1" orientation="portrait" appearance="light"/>
211
+ <dependencies>
212
+ <deployment identifier="iOS"/>
213
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
214
+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
215
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
216
+ </dependencies>
217
+ <scenes>
218
+ <scene sceneID="SC">
219
+ <objects>
220
+ <viewController id="VC" sceneMemberID="viewController">
221
+ <view key="view" contentMode="scaleToFill" id="V">
222
+ <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
223
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
224
+ <subviews>${bgImage}${logoImage}
225
+ </subviews>
226
+ <viewLayoutGuide key="safeArea" id="SA"/>
227
+ <color key="backgroundColor" red="${r}" green="${g}" blue="${b}" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
228
+ <constraints>${bgConstraints}${logoConstraints}
229
+ </constraints>
230
+ </view>
231
+ </viewController>
232
+ <placeholder placeholderIdentifier="IBFirstResponder" id="FR" userLabel="First Responder" sceneMemberID="firstResponder"/>
233
+ </objects>
234
+ <point key="canvasLocation" x="53" y="375"/>
235
+ </scene>
236
+ </scenes>
237
+ <resources>${resources.join('\n')}
238
+ </resources>
239
+ </document>`;
240
+ }
241
+
242
+ module.exports = withForcediOSSplash;