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 +2 -2
- package/plugin/src/index.js +2 -1
- package/plugin/src/withCustomSplash.js +242 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-custom-splash",
|
|
3
|
-
"version": "
|
|
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": "
|
|
20
|
+
"author": "Vijay Kishan",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"repository": {
|
|
23
23
|
"type": "git",
|
package/plugin/src/index.js
CHANGED
|
@@ -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
|
-
[
|
|
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;
|