react-native-custom-splash 1.0.3 → 2.0.2
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/README.md +311 -150
- package/example/README.md +175 -0
- package/example/app.json +38 -0
- package/example/app.json.option1-full-image +14 -0
- package/example/app.json.option2-color-logo +16 -0
- package/example/app.json.option3-image-logo +17 -0
- package/example/app.json.option4-color-only +14 -0
- package/ios/SplashScreenModule.swift +31 -4
- package/package.json +7 -1
- package/plugin/src/index.js +336 -9
package/README.md
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
# react-native-custom-splash
|
|
1
|
+
# react-native-custom-splash 🎨
|
|
2
2
|
|
|
3
|
-
A custom splash screen module for React Native with native iOS and Android support, fully compatible with Expo
|
|
3
|
+
A powerful and easy-to-use custom splash screen module for React Native with native iOS and Android support, **fully compatible with Expo**!
|
|
4
4
|
|
|
5
|
-
## Features
|
|
5
|
+
## ✨ Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
7
|
+
- 🚀 **Zero Native Code Required** - Just configure in `app.json`
|
|
8
|
+
- 🎨 **Auto Image Setup** - Automatically copies images from your project to native folders
|
|
9
|
+
- 🖼️ **Background + Logo Support** - Add a full background image and/or center logo
|
|
10
|
+
- 🎨 **Customizable Colors** - Set your brand's background color
|
|
11
|
+
- 📱 **Native Performance** - Pure native implementation for both iOS and Android
|
|
12
|
+
- ⚡ **Expo Compatible** - Works seamlessly with Expo managed workflow
|
|
13
|
+
- 🔄 **Simple API** - Easy show/hide methods with animation support
|
|
14
14
|
|
|
15
|
-
## Installation
|
|
16
|
-
|
|
17
|
-
### For Expo Projects
|
|
15
|
+
## 📦 Installation
|
|
18
16
|
|
|
19
17
|
```bash
|
|
20
18
|
npm install react-native-custom-splash
|
|
@@ -22,103 +20,169 @@ npm install react-native-custom-splash
|
|
|
22
20
|
yarn add react-native-custom-splash
|
|
23
21
|
```
|
|
24
22
|
|
|
25
|
-
|
|
23
|
+
## 🎯 Quick Start (The Easy Way!)
|
|
24
|
+
|
|
25
|
+
### Step 1: Add your images to your project
|
|
26
|
+
|
|
27
|
+
Create an `assets` folder in your project root and add your images:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
your-project/
|
|
31
|
+
├── assets/
|
|
32
|
+
│ ├── splash-background.png (your full background image - optional)
|
|
33
|
+
│ └── logo.png (your center logo - optional)
|
|
34
|
+
├── app.json
|
|
35
|
+
└── ...
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Step 2: Configure in app.json
|
|
39
|
+
|
|
40
|
+
Choose one of the 4 configuration options below based on your needs:
|
|
41
|
+
|
|
42
|
+
## 🎨 Configuration Examples
|
|
43
|
+
|
|
44
|
+
### **Option 1: Single Full Image** (Most Common) ⭐
|
|
45
|
+
|
|
46
|
+
Perfect for a complete branded splash screen with your custom design.
|
|
26
47
|
|
|
27
48
|
```json
|
|
28
49
|
{
|
|
29
50
|
"expo": {
|
|
51
|
+
"name": "YourApp",
|
|
30
52
|
"plugins": [
|
|
31
|
-
|
|
53
|
+
[
|
|
54
|
+
"react-native-custom-splash",
|
|
55
|
+
{
|
|
56
|
+
"image": "./assets/splash.png"
|
|
57
|
+
}
|
|
58
|
+
]
|
|
32
59
|
]
|
|
33
60
|
}
|
|
34
61
|
}
|
|
35
62
|
```
|
|
36
63
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
64
|
+
**Project Structure:**
|
|
65
|
+
```
|
|
66
|
+
your-project/
|
|
67
|
+
├── assets/
|
|
68
|
+
│ └── splash.png ← Your full-screen image (1242×2688px)
|
|
69
|
+
└── app.json
|
|
41
70
|
```
|
|
42
71
|
|
|
43
|
-
|
|
72
|
+
---
|
|
44
73
|
|
|
45
|
-
|
|
46
|
-
npm install react-native-custom-splash
|
|
47
|
-
# or
|
|
48
|
-
yarn add react-native-custom-splash
|
|
49
|
-
```
|
|
74
|
+
### **Option 2: Background Color + Center Logo**
|
|
50
75
|
|
|
51
|
-
|
|
76
|
+
Great for a clean, minimal look with just your logo.
|
|
52
77
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"expo": {
|
|
81
|
+
"name": "YourApp",
|
|
82
|
+
"plugins": [
|
|
83
|
+
[
|
|
84
|
+
"react-native-custom-splash",
|
|
85
|
+
{
|
|
86
|
+
"backgroundColor": "#4F46E5",
|
|
87
|
+
"logo": "./assets/logo.png",
|
|
88
|
+
"logoWidth": 180
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
56
94
|
```
|
|
57
95
|
|
|
58
|
-
|
|
96
|
+
**Project Structure:**
|
|
97
|
+
```
|
|
98
|
+
your-project/
|
|
99
|
+
├── assets/
|
|
100
|
+
│ └── logo.png ← Your center logo (512×512px)
|
|
101
|
+
└── app.json
|
|
102
|
+
```
|
|
59
103
|
|
|
60
|
-
|
|
104
|
+
---
|
|
61
105
|
|
|
62
|
-
|
|
106
|
+
### **Option 3: Background Image + Center Logo**
|
|
63
107
|
|
|
64
|
-
|
|
65
|
-
import com.rncustomsplash.SplashScreenPackage
|
|
108
|
+
Maximum customization - background image with logo on top.
|
|
66
109
|
|
|
67
|
-
|
|
68
|
-
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"expo": {
|
|
113
|
+
"name": "YourApp",
|
|
114
|
+
"plugins": [
|
|
115
|
+
[
|
|
116
|
+
"react-native-custom-splash",
|
|
117
|
+
{
|
|
118
|
+
"backgroundColor": "#FFFFFF",
|
|
119
|
+
"image": "./assets/splash-bg.png",
|
|
120
|
+
"logo": "./assets/logo.png",
|
|
121
|
+
"logoWidth": 150
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
}
|
|
69
127
|
```
|
|
70
128
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
super.onCreate(savedInstanceState)
|
|
79
|
-
}
|
|
129
|
+
**Project Structure:**
|
|
130
|
+
```
|
|
131
|
+
your-project/
|
|
132
|
+
├── assets/
|
|
133
|
+
│ ├── splash-bg.png ← Background image
|
|
134
|
+
│ └── logo.png ← Center logo
|
|
135
|
+
└── app.json
|
|
80
136
|
```
|
|
81
137
|
|
|
82
|
-
|
|
138
|
+
---
|
|
83
139
|
|
|
84
|
-
###
|
|
140
|
+
### **Option 4: Only Background Color**
|
|
85
141
|
|
|
86
|
-
|
|
87
|
-
1. Open your project in Xcode
|
|
88
|
-
2. Add an image asset named `splash` to your Assets catalog
|
|
89
|
-
3. Or add a `splash.png` file to your project
|
|
142
|
+
Simple solid color background.
|
|
90
143
|
|
|
91
|
-
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"expo": {
|
|
147
|
+
"name": "YourApp",
|
|
148
|
+
"plugins": [
|
|
149
|
+
[
|
|
150
|
+
"react-native-custom-splash",
|
|
151
|
+
{
|
|
152
|
+
"backgroundColor": "#FF6B6B"
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
92
159
|
|
|
93
|
-
|
|
94
|
-
1. Add `splash.png` (or `splash.jpg`) to `android/app/src/main/res/drawable/`
|
|
95
|
-
2. Or create a drawable resource named `splash`
|
|
160
|
+
---
|
|
96
161
|
|
|
97
|
-
|
|
162
|
+
### Step 3: Run prebuild
|
|
98
163
|
|
|
99
|
-
```
|
|
100
|
-
|
|
164
|
+
```bash
|
|
165
|
+
npx expo prebuild --clean
|
|
101
166
|
```
|
|
102
167
|
|
|
103
|
-
|
|
168
|
+
**That's it!** 🎉 The plugin will automatically:
|
|
169
|
+
- ✅ Copy your images to iOS and Android native folders
|
|
170
|
+
- ✅ Configure the native splash screen
|
|
171
|
+
- ✅ Set up all the required files
|
|
172
|
+
- ✅ Handle different screen densities
|
|
104
173
|
|
|
105
|
-
|
|
174
|
+
### Step 4: Use in your app
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
106
177
|
import SplashScreen from 'react-native-custom-splash';
|
|
107
|
-
import { useEffect } from 'react';
|
|
178
|
+
import React, { useEffect } from 'react';
|
|
108
179
|
|
|
109
180
|
function App() {
|
|
110
181
|
useEffect(() => {
|
|
111
|
-
// Hide splash screen after app
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
SplashScreen.hide(false);
|
|
116
|
-
|
|
117
|
-
// Or with animation
|
|
118
|
-
SplashScreen.hide(true);
|
|
119
|
-
|
|
120
|
-
// You can also show it again
|
|
121
|
-
// SplashScreen.show();
|
|
182
|
+
// Hide splash screen after app loads
|
|
183
|
+
setTimeout(() => {
|
|
184
|
+
SplashScreen.hide(true); // true = animated
|
|
185
|
+
}, 2000);
|
|
122
186
|
}, []);
|
|
123
187
|
|
|
124
188
|
return (
|
|
@@ -127,152 +191,249 @@ function App() {
|
|
|
127
191
|
}
|
|
128
192
|
```
|
|
129
193
|
|
|
130
|
-
##
|
|
194
|
+
## ⚙️ Configuration Options Reference
|
|
131
195
|
|
|
132
|
-
|
|
196
|
+
| Option | Type | Default | Description |
|
|
197
|
+
|--------|------|---------|-------------|
|
|
198
|
+
| `backgroundColor` | `string` | `#FFFFFF` | Background color (hex format: #RRGGBB) |
|
|
199
|
+
| `image` | `string` | `null` | Path to full background image (optional) |
|
|
200
|
+
| `logo` | `string` | `null` | Path to center logo image (optional) |
|
|
201
|
+
| `logoWidth` | `number` | `150` | Width of the center logo in pixels |
|
|
133
202
|
|
|
134
|
-
|
|
135
|
-
- ✅ Loading progress simulation
|
|
136
|
-
- ✅ Animated hide transitions
|
|
137
|
-
- ✅ Manual show/hide controls
|
|
138
|
-
- ✅ Full TypeScript integration
|
|
203
|
+
## 📱 API Reference
|
|
139
204
|
|
|
140
|
-
###
|
|
205
|
+
### `SplashScreen.hide(animated)`
|
|
141
206
|
|
|
142
|
-
|
|
143
|
-
cd example
|
|
144
|
-
npm install
|
|
145
|
-
npx expo prebuild
|
|
146
|
-
npm run ios # or npm run android
|
|
147
|
-
```
|
|
207
|
+
Hides the splash screen.
|
|
148
208
|
|
|
149
|
-
|
|
209
|
+
**Parameters:**
|
|
210
|
+
- `animated` (boolean): Whether to animate the hide transition. Default: `true`
|
|
211
|
+
|
|
212
|
+
**Returns:** Promise<boolean>
|
|
213
|
+
|
|
214
|
+
**Example:**
|
|
215
|
+
```javascript
|
|
216
|
+
// With animation (recommended)
|
|
217
|
+
await SplashScreen.hide(true);
|
|
150
218
|
|
|
151
|
-
|
|
219
|
+
// Without animation
|
|
220
|
+
await SplashScreen.hide(false);
|
|
221
|
+
```
|
|
152
222
|
|
|
153
223
|
### `SplashScreen.show()`
|
|
154
224
|
|
|
155
|
-
Shows the splash screen.
|
|
225
|
+
Shows the splash screen (usually not needed as it shows automatically on app launch).
|
|
156
226
|
|
|
157
|
-
|
|
227
|
+
**Example:**
|
|
228
|
+
```javascript
|
|
158
229
|
SplashScreen.show();
|
|
159
230
|
```
|
|
160
231
|
|
|
161
|
-
|
|
232
|
+
## 🎨 Image Guidelines
|
|
162
233
|
|
|
163
|
-
|
|
234
|
+
### Background Image
|
|
235
|
+
- **Recommended size:** 1242 x 2688 px (iPhone 13 Pro Max size)
|
|
236
|
+
- **Format:** PNG or JPG
|
|
237
|
+
- **Aspect ratio:** Match your target device screens
|
|
238
|
+
- **Tip:** The plugin will handle different screen densities automatically
|
|
164
239
|
|
|
165
|
-
|
|
166
|
-
-
|
|
240
|
+
### Logo Image
|
|
241
|
+
- **Recommended size:** 512 x 512 px (or your desired aspect ratio)
|
|
242
|
+
- **Format:** PNG with transparency recommended
|
|
243
|
+
- **Tip:** The logo will be centered and sized according to `logoWidth`
|
|
244
|
+
|
|
245
|
+
## 🔧 Advanced Usage
|
|
246
|
+
|
|
247
|
+
### TypeScript Support
|
|
167
248
|
|
|
168
|
-
|
|
249
|
+
Full TypeScript support is included:
|
|
169
250
|
|
|
170
251
|
```typescript
|
|
171
|
-
|
|
172
|
-
await SplashScreen.hide();
|
|
252
|
+
import SplashScreen, { SplashScreenInterface } from 'react-native-custom-splash';
|
|
173
253
|
|
|
174
|
-
|
|
175
|
-
await SplashScreen.hide(true);
|
|
254
|
+
const hideSplash = async (): Promise<void> => {
|
|
255
|
+
await SplashScreen.hide(true);
|
|
256
|
+
};
|
|
176
257
|
```
|
|
177
258
|
|
|
178
|
-
|
|
259
|
+
### React Navigation Integration
|
|
179
260
|
|
|
180
|
-
```
|
|
181
|
-
import
|
|
182
|
-
import { View, Text, ActivityIndicator } from 'react-native';
|
|
261
|
+
```javascript
|
|
262
|
+
import { NavigationContainer } from '@react-navigation/native';
|
|
183
263
|
import SplashScreen from 'react-native-custom-splash';
|
|
184
264
|
|
|
185
|
-
|
|
186
|
-
const [
|
|
265
|
+
function App() {
|
|
266
|
+
const [isReady, setIsReady] = React.useState(false);
|
|
187
267
|
|
|
188
|
-
useEffect(() => {
|
|
268
|
+
React.useEffect(() => {
|
|
189
269
|
async function prepare() {
|
|
190
270
|
try {
|
|
191
271
|
// Load your resources here
|
|
192
272
|
await loadFonts();
|
|
193
273
|
await loadData();
|
|
194
|
-
|
|
195
|
-
// Artificially delay for demo
|
|
196
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
197
274
|
} catch (e) {
|
|
198
275
|
console.warn(e);
|
|
199
276
|
} finally {
|
|
200
|
-
|
|
277
|
+
setIsReady(true);
|
|
201
278
|
}
|
|
202
279
|
}
|
|
203
280
|
|
|
204
281
|
prepare();
|
|
205
282
|
}, []);
|
|
206
283
|
|
|
207
|
-
useEffect(() => {
|
|
208
|
-
if (
|
|
209
|
-
// Hide splash screen with animation when app is ready
|
|
284
|
+
React.useEffect(() => {
|
|
285
|
+
if (isReady) {
|
|
210
286
|
SplashScreen.hide(true);
|
|
211
287
|
}
|
|
212
|
-
}, [
|
|
288
|
+
}, [isReady]);
|
|
213
289
|
|
|
214
|
-
if (!
|
|
215
|
-
return null;
|
|
290
|
+
if (!isReady) {
|
|
291
|
+
return null;
|
|
216
292
|
}
|
|
217
293
|
|
|
218
294
|
return (
|
|
219
|
-
<
|
|
220
|
-
|
|
221
|
-
</
|
|
295
|
+
<NavigationContainer>
|
|
296
|
+
{/* Your navigation */}
|
|
297
|
+
</NavigationContainer>
|
|
222
298
|
);
|
|
223
299
|
}
|
|
224
300
|
```
|
|
225
301
|
|
|
226
|
-
##
|
|
302
|
+
## 🔄 Migration from Manual Setup
|
|
227
303
|
|
|
228
|
-
|
|
304
|
+
If you were using the old manual method, you can now simplify:
|
|
305
|
+
|
|
306
|
+
**Before (Manual Method):**
|
|
307
|
+
1. ❌ Manually copy images to `ios/` folder
|
|
308
|
+
2. ❌ Open Xcode and add images to Assets
|
|
309
|
+
3. ❌ Manually copy images to `android/app/src/main/res/drawable/`
|
|
310
|
+
4. ❌ Manually edit `colors.xml`
|
|
311
|
+
5. ❌ Configure multiple drawable folders
|
|
312
|
+
|
|
313
|
+
**After (Automatic Method):**
|
|
314
|
+
1. ✅ Add images to `assets/` folder
|
|
315
|
+
2. ✅ Configure in `app.json`
|
|
316
|
+
3. ✅ Run `npx expo prebuild --clean`
|
|
317
|
+
4. ✅ Done!
|
|
318
|
+
|
|
319
|
+
## 🛠️ Manual Setup (Non-Expo Projects)
|
|
229
320
|
|
|
230
|
-
|
|
231
|
-
- Make sure you ran `pod install` in the `ios/` directory
|
|
232
|
-
- Clean build folder: `cd ios && rm -rf build && cd ..`
|
|
233
|
-
- Rebuild the app
|
|
321
|
+
If you're not using Expo, you can still use this package with manual setup:
|
|
234
322
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
323
|
+
### iOS
|
|
324
|
+
|
|
325
|
+
Add your splash image to your Xcode project:
|
|
326
|
+
1. Open your project in Xcode
|
|
327
|
+
2. Add an image asset named `splash_image` for background and/or `splash_logo` for center logo to your Assets catalog
|
|
238
328
|
|
|
239
329
|
### Android
|
|
240
330
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
- Rebuild the app
|
|
331
|
+
Add your images to Android resources:
|
|
332
|
+
1. Add `splash_image.png` (background) and/or `splash_logo.png` (center logo) to `android/app/src/main/res/drawable/`
|
|
333
|
+
2. Customize the background color in `android/app/src/main/res/values/colors.xml`:
|
|
245
334
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
335
|
+
```xml
|
|
336
|
+
<color name="splash_background">#FFFFFF</color>
|
|
337
|
+
```
|
|
249
338
|
|
|
250
|
-
|
|
339
|
+
## ❓ Troubleshooting
|
|
251
340
|
|
|
252
|
-
|
|
253
|
-
- Make sure you added the plugin to `app.json`
|
|
254
|
-
- Run `npx expo prebuild --clean`
|
|
255
|
-
- Rebuild the app
|
|
341
|
+
### ⚠️ Error: "Plugin is an unexpected object"
|
|
256
342
|
|
|
257
|
-
|
|
343
|
+
**Full Error:**
|
|
344
|
+
```
|
|
345
|
+
PluginError: Plugin is an unexpected object, with keys: "backgroundColor, image, logoWidth".
|
|
346
|
+
```
|
|
258
347
|
|
|
259
|
-
|
|
348
|
+
**Cause:** Your plugin configuration is not properly wrapped in square brackets.
|
|
260
349
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
350
|
+
**❌ Wrong:**
|
|
351
|
+
```json
|
|
352
|
+
{
|
|
353
|
+
"plugins": [
|
|
354
|
+
"react-native-custom-splash",
|
|
355
|
+
{
|
|
356
|
+
"backgroundColor": "#FF6B6B"
|
|
357
|
+
}
|
|
358
|
+
]
|
|
265
359
|
}
|
|
266
360
|
```
|
|
267
361
|
|
|
268
|
-
|
|
362
|
+
**✅ Correct:**
|
|
363
|
+
```json
|
|
364
|
+
{
|
|
365
|
+
"plugins": [
|
|
366
|
+
[
|
|
367
|
+
"react-native-custom-splash",
|
|
368
|
+
{
|
|
369
|
+
"backgroundColor": "#FF6B6B"
|
|
370
|
+
}
|
|
371
|
+
]
|
|
372
|
+
]
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
**Key Point:** When passing configuration to a plugin, wrap BOTH the plugin name and the config object in square brackets `[]`.
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
### Splash screen not showing
|
|
381
|
+
- Make sure you run `npx expo prebuild --clean` after changing configuration
|
|
382
|
+
- Check that your image paths in `app.json` are correct and files exist
|
|
383
|
+
- Verify images are in the `assets/` folder
|
|
384
|
+
- Try cleaning your build:
|
|
385
|
+
- iOS: `cd ios && pod install && cd ..`
|
|
386
|
+
- Android: `cd android && ./gradlew clean && cd ..`
|
|
387
|
+
|
|
388
|
+
### Images not updating
|
|
389
|
+
- Run `npx expo prebuild --clean` to force regeneration of native projects
|
|
390
|
+
- Delete `ios/` and `android/` folders, then run `npx expo prebuild --clean` again
|
|
391
|
+
- Clear build caches:
|
|
392
|
+
- iOS: `rm -rf ios/Pods ios/build`
|
|
393
|
+
- Android: `cd android && ./gradlew clean && cd ..`
|
|
394
|
+
|
|
395
|
+
### Image paths not working
|
|
396
|
+
- Use relative paths from project root: `"./assets/splash.png"` ✅
|
|
397
|
+
- Don't use absolute paths: `"/Users/..."` ❌
|
|
398
|
+
- Make sure the file extension matches (`.png`, `.jpg`)
|
|
399
|
+
- Check file actually exists at that path
|
|
400
|
+
|
|
401
|
+
### Background color not working
|
|
402
|
+
- Use hex format: `"#FF6B6B"` ✅
|
|
403
|
+
- Don't forget the `#`: `"FF6B6B"` ❌
|
|
404
|
+
- Use 6-digit format: `"#FFFFFF"` ✅ not `"#FFF"` ❌
|
|
405
|
+
|
|
406
|
+
### TypeScript errors
|
|
407
|
+
- Make sure you have `@types/react` and `@types/react-native` installed
|
|
408
|
+
- The package includes TypeScript definitions
|
|
409
|
+
- Try: `npm install --save-dev @types/react @types/react-native`
|
|
410
|
+
|
|
411
|
+
### Pod install fails (iOS)
|
|
412
|
+
```bash
|
|
413
|
+
cd ios
|
|
414
|
+
rm -rf Pods Podfile.lock
|
|
415
|
+
pod install --repo-update
|
|
416
|
+
cd ..
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Still having issues?
|
|
420
|
+
1. Delete `node_modules/` and reinstall: `npm install` or `yarn install`
|
|
421
|
+
2. Delete `ios/` and `android/` folders
|
|
422
|
+
3. Run `npx expo prebuild --clean`
|
|
423
|
+
4. Check the [GitHub Issues](https://github.com/vijaykishan312/react-native-custom-splash/issues)
|
|
424
|
+
|
|
425
|
+
## 📄 License
|
|
269
426
|
|
|
270
427
|
MIT
|
|
271
428
|
|
|
272
|
-
## Contributing
|
|
429
|
+
## 🤝 Contributing
|
|
273
430
|
|
|
274
431
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
275
432
|
|
|
276
|
-
##
|
|
433
|
+
## 💖 Support
|
|
434
|
+
|
|
435
|
+
If you find this package helpful, please give it a ⭐️ on [GitHub](https://github.com/vijaykishan312/react-native-custom-splash)!
|
|
436
|
+
|
|
437
|
+
---
|
|
277
438
|
|
|
278
|
-
|
|
439
|
+
Made with ❤️ for the React Native community
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# react-native-custom-splash Example App
|
|
2
|
+
|
|
3
|
+
This example demonstrates how to use `react-native-custom-splash` in your Expo app.
|
|
4
|
+
|
|
5
|
+
## 📁 Project Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
example/
|
|
9
|
+
├── assets/
|
|
10
|
+
│ ├── splash-bg.png ← Background image for splash
|
|
11
|
+
│ ├── logo.png ← Center logo
|
|
12
|
+
│ ├── icon.png ← App icon
|
|
13
|
+
│ └── ...
|
|
14
|
+
├── app.json ← Configuration with plugin setup
|
|
15
|
+
├── App.tsx ← Main app with SplashScreen usage
|
|
16
|
+
└── package.json
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 🚀 Running the Example
|
|
20
|
+
|
|
21
|
+
### 1. Install Dependencies
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
cd example
|
|
25
|
+
npm install
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 2. Run Prebuild
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx expo prebuild --clean
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 3. Run on Device/Simulator
|
|
35
|
+
|
|
36
|
+
**iOS:**
|
|
37
|
+
```bash
|
|
38
|
+
npx expo run:ios
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Android:**
|
|
42
|
+
```bash
|
|
43
|
+
npx expo run:android
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 🎨 Configuration Examples
|
|
47
|
+
|
|
48
|
+
The example `app.json` is configured with **Option 3** (Background Image + Logo):
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"plugins": [
|
|
53
|
+
[
|
|
54
|
+
"react-native-custom-splash",
|
|
55
|
+
{
|
|
56
|
+
"backgroundColor": "#4F46E5",
|
|
57
|
+
"image": "./assets/splash-bg.png",
|
|
58
|
+
"logo": "./assets/logo.png",
|
|
59
|
+
"logoWidth": 180
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Try Different Configurations:
|
|
67
|
+
|
|
68
|
+
#### Option 1: Single Full Image (Simplest)
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"plugins": [
|
|
72
|
+
[
|
|
73
|
+
"react-native-custom-splash",
|
|
74
|
+
{
|
|
75
|
+
"image": "./assets/splash.png"
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### Option 2: Color + Logo (Minimal)
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"plugins": [
|
|
86
|
+
[
|
|
87
|
+
"react-native-custom-splash",
|
|
88
|
+
{
|
|
89
|
+
"backgroundColor": "#4F46E5",
|
|
90
|
+
"logo": "./assets/logo.png",
|
|
91
|
+
"logoWidth": 180
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
#### Option 4: Only Color (Fastest)
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"plugins": [
|
|
102
|
+
[
|
|
103
|
+
"react-native-custom-splash",
|
|
104
|
+
{
|
|
105
|
+
"backgroundColor": "#FF6B6B"
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**After changing configuration:**
|
|
113
|
+
```bash
|
|
114
|
+
npx expo prebuild --clean
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## 💡 Usage in Code
|
|
118
|
+
|
|
119
|
+
Check `App.tsx` to see how the splash screen is used:
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import SplashScreen from 'react-native-custom-splash';
|
|
123
|
+
import { useEffect } from 'react';
|
|
124
|
+
|
|
125
|
+
function App() {
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
// Hide splash after 2 seconds
|
|
128
|
+
const timer = setTimeout(() => {
|
|
129
|
+
SplashScreen.hide(true); // true = with animation
|
|
130
|
+
}, 2000);
|
|
131
|
+
|
|
132
|
+
return () => clearTimeout(timer);
|
|
133
|
+
}, []);
|
|
134
|
+
|
|
135
|
+
// Your app content...
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## 🖼️ Image Guidelines
|
|
140
|
+
|
|
141
|
+
### Background Image (`splash-bg.png`)
|
|
142
|
+
- **Size:** 1242 x 2688 px (iPhone 13 Pro Max)
|
|
143
|
+
- **Format:** PNG or JPG
|
|
144
|
+
- **Aspect Ratio:** 9:19.5 (standard phone ratio)
|
|
145
|
+
- **Design:** Center-weighted content
|
|
146
|
+
|
|
147
|
+
### Logo (`logo.png`)
|
|
148
|
+
- **Size:** 512 x 512 px (or your aspect ratio)
|
|
149
|
+
- **Format:** PNG with transparency
|
|
150
|
+
- **Design:** Will be scaled based on `logoWidth`
|
|
151
|
+
|
|
152
|
+
## 🔧 Troubleshooting
|
|
153
|
+
|
|
154
|
+
### Changes not reflecting?
|
|
155
|
+
```bash
|
|
156
|
+
# Clean everything and rebuild
|
|
157
|
+
npx expo prebuild --clean
|
|
158
|
+
cd ios && pod install && cd ..
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Images not showing?
|
|
162
|
+
- Check image paths in `app.json` are correct
|
|
163
|
+
- Ensure images exist in `assets/` folder
|
|
164
|
+
- Run `npx expo prebuild --clean`
|
|
165
|
+
|
|
166
|
+
### TypeScript errors?
|
|
167
|
+
```bash
|
|
168
|
+
npm install --save-dev @types/react @types/react-native
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## 📚 Learn More
|
|
172
|
+
|
|
173
|
+
- [Main README](../README.md)
|
|
174
|
+
- [npm Package](https://www.npmjs.com/package/react-native-custom-splash)
|
|
175
|
+
- [GitHub Repository](https://github.com/vijaykishan312/react-native-custom-splash)
|
package/example/app.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"expo": {
|
|
3
|
+
"name": "SplashScreenExample",
|
|
4
|
+
"slug": "splash-screen-example",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"orientation": "portrait",
|
|
7
|
+
"icon": "./assets/icon.png",
|
|
8
|
+
"userInterfaceStyle": "light",
|
|
9
|
+
"assetBundlePatterns": [
|
|
10
|
+
"**/*"
|
|
11
|
+
],
|
|
12
|
+
"ios": {
|
|
13
|
+
"supportsTablet": true,
|
|
14
|
+
"bundleIdentifier": "com.example.splashscreen"
|
|
15
|
+
},
|
|
16
|
+
"android": {
|
|
17
|
+
"adaptiveIcon": {
|
|
18
|
+
"foregroundImage": "./assets/adaptive-icon.png",
|
|
19
|
+
"backgroundColor": "#ffffff"
|
|
20
|
+
},
|
|
21
|
+
"package": "com.example.splashscreen"
|
|
22
|
+
},
|
|
23
|
+
"web": {
|
|
24
|
+
"favicon": "./assets/favicon.png"
|
|
25
|
+
},
|
|
26
|
+
"plugins": [
|
|
27
|
+
[
|
|
28
|
+
"react-native-custom-splash",
|
|
29
|
+
{
|
|
30
|
+
"backgroundColor": "#4F46E5",
|
|
31
|
+
"image": "./assets/splash-bg.png",
|
|
32
|
+
"logo": "./assets/logo.png",
|
|
33
|
+
"logoWidth": 180
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"expo": {
|
|
3
|
+
"name": "Example - Color + Logo",
|
|
4
|
+
"slug": "splash-example-color-logo",
|
|
5
|
+
"plugins": [
|
|
6
|
+
[
|
|
7
|
+
"react-native-custom-splash",
|
|
8
|
+
{
|
|
9
|
+
"backgroundColor": "#4F46E5",
|
|
10
|
+
"logo": "./assets/logo.png",
|
|
11
|
+
"logoWidth": 180
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"expo": {
|
|
3
|
+
"name": "Example - Image + Logo",
|
|
4
|
+
"slug": "splash-example-image-logo",
|
|
5
|
+
"plugins": [
|
|
6
|
+
[
|
|
7
|
+
"react-native-custom-splash",
|
|
8
|
+
{
|
|
9
|
+
"backgroundColor": "#FFFFFF",
|
|
10
|
+
"image": "./assets/splash-bg.png",
|
|
11
|
+
"logo": "./assets/logo.png",
|
|
12
|
+
"logoWidth": 150
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -40,16 +40,22 @@ class SplashScreenModule: NSObject {
|
|
|
40
40
|
let splashVC = UIViewController()
|
|
41
41
|
splashVC.view.backgroundColor = .white
|
|
42
42
|
|
|
43
|
-
// Try to load splash image from the main bundle
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
// Try to load background splash image from the main bundle
|
|
44
|
+
if let splashImage = UIImage(named: "splash_image") {
|
|
45
|
+
let imageView = UIImageView(image: splashImage)
|
|
46
|
+
imageView.contentMode = .scaleAspectFill
|
|
47
|
+
imageView.frame = splashVC.view.bounds
|
|
48
|
+
imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
49
|
+
splashVC.view.addSubview(imageView)
|
|
50
|
+
} else if let splashImage = UIImage(named: "splash") {
|
|
51
|
+
// Fallback to old "splash" name for backward compatibility
|
|
46
52
|
let imageView = UIImageView(image: splashImage)
|
|
47
53
|
imageView.contentMode = .scaleAspectFill
|
|
48
54
|
imageView.frame = splashVC.view.bounds
|
|
49
55
|
imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
50
56
|
splashVC.view.addSubview(imageView)
|
|
51
57
|
} else {
|
|
52
|
-
// Fallback: show white screen if no
|
|
58
|
+
// Fallback: show white screen if no background image
|
|
53
59
|
if #available(iOS 13.0, *) {
|
|
54
60
|
splashVC.view.backgroundColor = .systemBackground
|
|
55
61
|
} else {
|
|
@@ -57,6 +63,27 @@ class SplashScreenModule: NSObject {
|
|
|
57
63
|
}
|
|
58
64
|
}
|
|
59
65
|
|
|
66
|
+
// Add center logo if available
|
|
67
|
+
if let logoImage = UIImage(named: "splash_logo") {
|
|
68
|
+
let logoView = UIImageView(image: logoImage)
|
|
69
|
+
logoView.contentMode = .scaleAspectFit
|
|
70
|
+
|
|
71
|
+
// Set logo size (150pt width by default, maintaining aspect ratio)
|
|
72
|
+
let logoWidth: CGFloat = 150
|
|
73
|
+
let aspectRatio = logoImage.size.height / logoImage.size.width
|
|
74
|
+
let logoHeight = logoWidth * aspectRatio
|
|
75
|
+
|
|
76
|
+
logoView.frame = CGRect(
|
|
77
|
+
x: (splashVC.view.bounds.width - logoWidth) / 2,
|
|
78
|
+
y: (splashVC.view.bounds.height - logoHeight) / 2,
|
|
79
|
+
width: logoWidth,
|
|
80
|
+
height: logoHeight
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
logoView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin, .flexibleBottomMargin]
|
|
84
|
+
splashVC.view.addSubview(logoView)
|
|
85
|
+
}
|
|
86
|
+
|
|
60
87
|
window.rootViewController = splashVC
|
|
61
88
|
window.makeKeyAndVisible()
|
|
62
89
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-custom-splash",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.2",
|
|
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",
|
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
"type": "git",
|
|
24
24
|
"url": "git+https://github.com/vijaykishan312/react-native-custom-splash.git"
|
|
25
25
|
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@expo/config-plugins": "^8.0.0",
|
|
28
|
+
"@expo/image-utils": "^0.5.0"
|
|
29
|
+
},
|
|
26
30
|
"peerDependencies": {
|
|
27
31
|
"react": "*",
|
|
28
32
|
"react-native": "*",
|
|
@@ -40,6 +44,8 @@
|
|
|
40
44
|
"plugin/",
|
|
41
45
|
"app.plugin.js",
|
|
42
46
|
"react-native-custom-splash.podspec",
|
|
47
|
+
"example/app.json*",
|
|
48
|
+
"example/README.md",
|
|
43
49
|
"README.md",
|
|
44
50
|
"LICENSE"
|
|
45
51
|
]
|
package/plugin/src/index.js
CHANGED
|
@@ -3,14 +3,257 @@ const {
|
|
|
3
3
|
withPlugins,
|
|
4
4
|
withMainActivity,
|
|
5
5
|
withMainApplication,
|
|
6
|
+
AndroidConfig,
|
|
7
|
+
IOSConfig,
|
|
6
8
|
} = require('@expo/config-plugins');
|
|
7
9
|
const path = require('path');
|
|
8
10
|
const fs = require('fs');
|
|
11
|
+
const { generateImageAsync } = require('@expo/image-utils');
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
|
-
*
|
|
14
|
+
* Validate and normalize plugin configuration
|
|
12
15
|
*/
|
|
13
|
-
|
|
16
|
+
function validateAndNormalizeConfig(props) {
|
|
17
|
+
// Check if props is valid
|
|
18
|
+
if (!props || typeof props !== 'object') {
|
|
19
|
+
console.warn('⚠️ react-native-custom-splash: No configuration provided, using defaults');
|
|
20
|
+
return {
|
|
21
|
+
backgroundColor: '#FFFFFF',
|
|
22
|
+
image: null,
|
|
23
|
+
logo: null,
|
|
24
|
+
logoWidth: 150,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Validate backgroundColor
|
|
29
|
+
if (props.backgroundColor && !/^#[0-9A-Fa-f]{6}$/.test(props.backgroundColor)) {
|
|
30
|
+
console.warn(`⚠️ react-native-custom-splash: Invalid backgroundColor "${props.backgroundColor}", using default #FFFFFF`);
|
|
31
|
+
props.backgroundColor = '#FFFFFF';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Validate logoWidth
|
|
35
|
+
if (props.logoWidth && (typeof props.logoWidth !== 'number' || props.logoWidth <= 0)) {
|
|
36
|
+
console.warn(`⚠️ react-native-custom-splash: Invalid logoWidth "${props.logoWidth}", using default 150`);
|
|
37
|
+
props.logoWidth = 150;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Validate image path
|
|
41
|
+
if (props.image && typeof props.image !== 'string') {
|
|
42
|
+
console.warn(`⚠️ react-native-custom-splash: Invalid image path, must be a string`);
|
|
43
|
+
props.image = null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Validate logo path
|
|
47
|
+
if (props.logo && typeof props.logo !== 'string') {
|
|
48
|
+
console.warn(`⚠️ react-native-custom-splash: Invalid logo path, must be a string`);
|
|
49
|
+
props.logo = null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
backgroundColor: props.backgroundColor || '#FFFFFF',
|
|
54
|
+
image: props.image || null,
|
|
55
|
+
logo: props.logo || null,
|
|
56
|
+
logoWidth: props.logoWidth || 150,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get plugin configuration from app.json
|
|
62
|
+
*/
|
|
63
|
+
function getPluginConfig(config) {
|
|
64
|
+
const plugins = config.plugins || [];
|
|
65
|
+
const splashPlugin = plugins.find(plugin => {
|
|
66
|
+
if (Array.isArray(plugin) && plugin[0] === 'react-native-custom-splash') {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
return plugin === 'react-native-custom-splash';
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (Array.isArray(splashPlugin) && splashPlugin[1]) {
|
|
73
|
+
return validateAndNormalizeConfig(splashPlugin[1]);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Default configuration
|
|
77
|
+
return {
|
|
78
|
+
backgroundColor: '#FFFFFF',
|
|
79
|
+
image: null,
|
|
80
|
+
logo: null,
|
|
81
|
+
logoWidth: 150,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Copy and resize image to Android drawable folders
|
|
87
|
+
*/
|
|
88
|
+
async function copyImageToAndroid(projectRoot, imagePath, outputName, resDir) {
|
|
89
|
+
if (!imagePath || !fs.existsSync(path.join(projectRoot, imagePath))) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const sourceImage = path.join(projectRoot, imagePath);
|
|
94
|
+
|
|
95
|
+
// Define sizes for different densities
|
|
96
|
+
const densities = {
|
|
97
|
+
'mdpi': 1,
|
|
98
|
+
'hdpi': 1.5,
|
|
99
|
+
'xhdpi': 2,
|
|
100
|
+
'xxhdpi': 3,
|
|
101
|
+
'xxxhdpi': 4,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
for (const [density, scale] of Object.entries(densities)) {
|
|
105
|
+
const drawableDir = path.join(resDir, `drawable-${density}`);
|
|
106
|
+
|
|
107
|
+
// Create directory if it doesn't exist
|
|
108
|
+
if (!fs.existsSync(drawableDir)) {
|
|
109
|
+
fs.mkdirSync(drawableDir, { recursive: true });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const outputPath = path.join(drawableDir, `${outputName}.png`);
|
|
113
|
+
|
|
114
|
+
// Copy the image (you can add resizing logic here if needed)
|
|
115
|
+
fs.copyFileSync(sourceImage, outputPath);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Copy image to iOS assets
|
|
123
|
+
*/
|
|
124
|
+
async function copyImageToIOS(projectRoot, imagePath, outputName, iosProjectPath, projectName) {
|
|
125
|
+
if (!imagePath || !fs.existsSync(path.join(projectRoot, imagePath))) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const sourceImage = path.join(projectRoot, imagePath);
|
|
130
|
+
const assetsDir = path.join(iosProjectPath, projectName, 'Images.xcassets', `${outputName}.imageset`);
|
|
131
|
+
|
|
132
|
+
// Create imageset directory
|
|
133
|
+
if (!fs.existsSync(assetsDir)) {
|
|
134
|
+
fs.mkdirSync(assetsDir, { recursive: true });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Copy image files for different scales
|
|
138
|
+
const scales = ['1x', '2x', '3x'];
|
|
139
|
+
const images = [];
|
|
140
|
+
|
|
141
|
+
for (const scale of scales) {
|
|
142
|
+
const filename = `${outputName}@${scale}.png`;
|
|
143
|
+
const destPath = path.join(assetsDir, filename);
|
|
144
|
+
fs.copyFileSync(sourceImage, destPath);
|
|
145
|
+
|
|
146
|
+
images.push({
|
|
147
|
+
idiom: 'universal',
|
|
148
|
+
filename: filename,
|
|
149
|
+
scale: scale,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Create Contents.json
|
|
154
|
+
const contentsJson = {
|
|
155
|
+
images: images,
|
|
156
|
+
info: {
|
|
157
|
+
author: 'xcode',
|
|
158
|
+
version: 1,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
fs.writeFileSync(
|
|
163
|
+
path.join(assetsDir, 'Contents.json'),
|
|
164
|
+
JSON.stringify(contentsJson, null, 2)
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Update Android colors.xml
|
|
172
|
+
*/
|
|
173
|
+
function updateAndroidColors(resDir, backgroundColor) {
|
|
174
|
+
const valuesDir = path.join(resDir, 'values');
|
|
175
|
+
if (!fs.existsSync(valuesDir)) {
|
|
176
|
+
fs.mkdirSync(valuesDir, { recursive: true });
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const colorsPath = path.join(valuesDir, 'colors.xml');
|
|
180
|
+
const colorsXml = `<?xml version="1.0" encoding="utf-8"?>
|
|
181
|
+
<resources>
|
|
182
|
+
<color name="splash_background">${backgroundColor}</color>
|
|
183
|
+
</resources>
|
|
184
|
+
`;
|
|
185
|
+
|
|
186
|
+
fs.writeFileSync(colorsPath, colorsXml);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Update Android splash drawable
|
|
191
|
+
*/
|
|
192
|
+
function updateAndroidSplashDrawable(resDir, hasImage, hasLogo) {
|
|
193
|
+
const drawableDir = path.join(resDir, 'drawable');
|
|
194
|
+
if (!fs.existsSync(drawableDir)) {
|
|
195
|
+
fs.mkdirSync(drawableDir, { recursive: true });
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const splashPath = path.join(drawableDir, 'splash.xml');
|
|
199
|
+
|
|
200
|
+
let items = [];
|
|
201
|
+
|
|
202
|
+
// Background color
|
|
203
|
+
items.push(' <item android:drawable="@color/splash_background"/>');
|
|
204
|
+
|
|
205
|
+
// Background image if provided
|
|
206
|
+
if (hasImage) {
|
|
207
|
+
items.push(' <item>');
|
|
208
|
+
items.push(' <bitmap');
|
|
209
|
+
items.push(' android:gravity="fill"');
|
|
210
|
+
items.push(' android:src="@drawable/splash_image"/>');
|
|
211
|
+
items.push(' </item>');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Logo if provided
|
|
215
|
+
if (hasLogo) {
|
|
216
|
+
items.push(' <item>');
|
|
217
|
+
items.push(' <bitmap');
|
|
218
|
+
items.push(' android:gravity="center"');
|
|
219
|
+
items.push(' android:src="@drawable/splash_logo"/>');
|
|
220
|
+
items.push(' </item>');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const splashXml = `<?xml version="1.0" encoding="utf-8"?>
|
|
224
|
+
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
|
225
|
+
${items.join('\n')}
|
|
226
|
+
</layer-list>
|
|
227
|
+
`;
|
|
228
|
+
|
|
229
|
+
fs.writeFileSync(splashPath, splashXml);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Update Android splash layout
|
|
234
|
+
*/
|
|
235
|
+
function updateAndroidSplashLayout(resDir) {
|
|
236
|
+
const layoutDir = path.join(resDir, 'layout');
|
|
237
|
+
if (!fs.existsSync(layoutDir)) {
|
|
238
|
+
fs.mkdirSync(layoutDir, { recursive: true });
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const layoutPath = path.join(layoutDir, 'splash_screen.xml');
|
|
242
|
+
const layoutXml = `<?xml version="1.0" encoding="utf-8"?>
|
|
243
|
+
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
244
|
+
android:layout_width="match_parent"
|
|
245
|
+
android:layout_height="match_parent"
|
|
246
|
+
android:background="@drawable/splash">
|
|
247
|
+
</FrameLayout>
|
|
248
|
+
`;
|
|
249
|
+
|
|
250
|
+
fs.writeFileSync(layoutPath, layoutXml);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Plugin to configure Android splash screen
|
|
255
|
+
*/
|
|
256
|
+
const withSplashScreenAndroid = (config, pluginConfig) => {
|
|
14
257
|
// Add package to MainApplication
|
|
15
258
|
config = withMainApplication(config, async (config) => {
|
|
16
259
|
const { modResults } = config;
|
|
@@ -61,18 +304,89 @@ const withSplashScreenAndroid = (config) => {
|
|
|
61
304
|
return config;
|
|
62
305
|
});
|
|
63
306
|
|
|
307
|
+
// Configure Android resources
|
|
308
|
+
config = withDangerousMod(config, [
|
|
309
|
+
'android',
|
|
310
|
+
async (config) => {
|
|
311
|
+
const projectRoot = config.modRequest.projectRoot;
|
|
312
|
+
const resDir = path.join(
|
|
313
|
+
config.modRequest.platformProjectRoot,
|
|
314
|
+
'app',
|
|
315
|
+
'src',
|
|
316
|
+
'main',
|
|
317
|
+
'res'
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
// Update colors
|
|
321
|
+
updateAndroidColors(resDir, pluginConfig.backgroundColor);
|
|
322
|
+
|
|
323
|
+
// Copy images if provided
|
|
324
|
+
let hasImage = false;
|
|
325
|
+
let hasLogo = false;
|
|
326
|
+
|
|
327
|
+
if (pluginConfig.image) {
|
|
328
|
+
hasImage = await copyImageToAndroid(
|
|
329
|
+
projectRoot,
|
|
330
|
+
pluginConfig.image,
|
|
331
|
+
'splash_image',
|
|
332
|
+
resDir
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (pluginConfig.logo) {
|
|
337
|
+
hasLogo = await copyImageToAndroid(
|
|
338
|
+
projectRoot,
|
|
339
|
+
pluginConfig.logo,
|
|
340
|
+
'splash_logo',
|
|
341
|
+
resDir
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Update splash drawable
|
|
346
|
+
updateAndroidSplashDrawable(resDir, hasImage, hasLogo);
|
|
347
|
+
|
|
348
|
+
// Update splash layout
|
|
349
|
+
updateAndroidSplashLayout(resDir);
|
|
350
|
+
|
|
351
|
+
return config;
|
|
352
|
+
},
|
|
353
|
+
]);
|
|
354
|
+
|
|
64
355
|
return config;
|
|
65
356
|
};
|
|
66
357
|
|
|
67
358
|
/**
|
|
68
|
-
* Plugin to
|
|
359
|
+
* Plugin to configure iOS splash screen
|
|
69
360
|
*/
|
|
70
|
-
const withSplashScreenIOS = (config) => {
|
|
361
|
+
const withSplashScreenIOS = (config, pluginConfig) => {
|
|
71
362
|
return withDangerousMod(config, [
|
|
72
363
|
'ios',
|
|
73
364
|
async (config) => {
|
|
74
|
-
|
|
75
|
-
|
|
365
|
+
const projectRoot = config.modRequest.projectRoot;
|
|
366
|
+
const iosProjectPath = config.modRequest.platformProjectRoot;
|
|
367
|
+
const projectName = config.modRequest.projectName;
|
|
368
|
+
|
|
369
|
+
// Copy images to iOS assets
|
|
370
|
+
if (pluginConfig.image) {
|
|
371
|
+
await copyImageToIOS(
|
|
372
|
+
projectRoot,
|
|
373
|
+
pluginConfig.image,
|
|
374
|
+
'splash_image',
|
|
375
|
+
iosProjectPath,
|
|
376
|
+
projectName
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
if (pluginConfig.logo) {
|
|
381
|
+
await copyImageToIOS(
|
|
382
|
+
projectRoot,
|
|
383
|
+
pluginConfig.logo,
|
|
384
|
+
'splash_logo',
|
|
385
|
+
iosProjectPath,
|
|
386
|
+
projectName
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
|
|
76
390
|
return config;
|
|
77
391
|
},
|
|
78
392
|
]);
|
|
@@ -81,9 +395,22 @@ const withSplashScreenIOS = (config) => {
|
|
|
81
395
|
/**
|
|
82
396
|
* Main plugin export
|
|
83
397
|
*/
|
|
84
|
-
module.exports = (config) => {
|
|
398
|
+
module.exports = (config, props = {}) => {
|
|
399
|
+
// Validate the props parameter
|
|
400
|
+
let pluginConfig;
|
|
401
|
+
|
|
402
|
+
if (props && Object.keys(props).length > 0) {
|
|
403
|
+
// Props provided directly (from array syntax)
|
|
404
|
+
pluginConfig = validateAndNormalizeConfig(props);
|
|
405
|
+
} else {
|
|
406
|
+
// Try to get from config (fallback)
|
|
407
|
+
pluginConfig = getPluginConfig(config);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
console.log('✅ react-native-custom-splash configured with:', pluginConfig);
|
|
411
|
+
|
|
85
412
|
return withPlugins(config, [
|
|
86
|
-
withSplashScreenAndroid,
|
|
87
|
-
withSplashScreenIOS,
|
|
413
|
+
[withSplashScreenAndroid, pluginConfig],
|
|
414
|
+
[withSplashScreenIOS, pluginConfig],
|
|
88
415
|
]);
|
|
89
416
|
};
|