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 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
- - **Native iOS & Android** splash screens
8
- - **Expo compatible** with config plugin
9
- - **Customizable** splash images
10
- - **Animated transitions** for smooth hiding
11
- - **TypeScript** support
12
- - **Auto-show** on app launch
13
- - **Manual control** with show/hide methods
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
- Add the plugin to your `app.json` or `app.config.js`:
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
- "react-native-custom-splash"
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
- Then run prebuild:
38
-
39
- ```bash
40
- npx expo prebuild
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
- ### For Bare React Native Projects
72
+ ---
44
73
 
45
- ```bash
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
- #### iOS Setup
76
+ Great for a clean, minimal look with just your logo.
52
77
 
53
- 1. Install pods:
54
- ```bash
55
- cd ios && pod install && cd ..
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
- 2. The module will be automatically linked.
96
+ **Project Structure:**
97
+ ```
98
+ your-project/
99
+ ├── assets/
100
+ │ └── logo.png ← Your center logo (512×512px)
101
+ └── app.json
102
+ ```
59
103
 
60
- #### Android Setup
104
+ ---
61
105
 
62
- 1. Add the package to your `MainApplication.kt`:
106
+ ### **Option 3: Background Image + Center Logo**
63
107
 
64
- ```kotlin
65
- import com.rncustomsplash.SplashScreenPackage
108
+ Maximum customization - background image with logo on top.
66
109
 
67
- // In getPackages() method:
68
- packages.add(SplashScreenPackage())
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
- 2. Show splash in `MainActivity.kt`:
72
-
73
- ```kotlin
74
- import com.rncustomsplash.SplashScreenModule
75
-
76
- override fun onCreate(savedInstanceState: Bundle?) {
77
- SplashScreenModule.show(this)
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
- ## Adding Custom Splash Images
138
+ ---
83
139
 
84
- ### iOS
140
+ ### **Option 4: Only Background Color**
85
141
 
86
- Add your splash image to your Xcode project:
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
- ### Android
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
- Add your splash image to Android resources:
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
- You can also customize the background color in `android/app/src/main/res/values/colors.xml`:
162
+ ### Step 3: Run prebuild
98
163
 
99
- ```xml
100
- <color name="splash_background">#FFFFFF</color>
164
+ ```bash
165
+ npx expo prebuild --clean
101
166
  ```
102
167
 
103
- ## Usage
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
- ```typescript
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 is ready
112
- // The splash screen shows automatically on launch
113
-
114
- // Simple hide (instant)
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
- ## Example Project
194
+ ## ⚙️ Configuration Options Reference
131
195
 
132
- A complete working example is included in the `example/` directory. It demonstrates:
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
- - Automatic splash screen on launch
135
- - ✅ Loading progress simulation
136
- - ✅ Animated hide transitions
137
- - ✅ Manual show/hide controls
138
- - ✅ Full TypeScript integration
203
+ ## 📱 API Reference
139
204
 
140
- ### Run the Example
205
+ ### `SplashScreen.hide(animated)`
141
206
 
142
- ```bash
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
- See [example/README.md](./example/README.md) for detailed instructions.
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
- ## API Reference
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
- ```typescript
227
+ **Example:**
228
+ ```javascript
158
229
  SplashScreen.show();
159
230
  ```
160
231
 
161
- ### `SplashScreen.hide(animated?)`
232
+ ## 🎨 Image Guidelines
162
233
 
163
- Hides the splash screen.
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
- **Parameters:**
166
- - `animated` (boolean, optional): Whether to animate the hide transition. Default: `false`
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
- **Returns:** `Promise<boolean>` - Resolves to `true` if successful
249
+ Full TypeScript support is included:
169
250
 
170
251
  ```typescript
171
- // Hide instantly
172
- await SplashScreen.hide();
252
+ import SplashScreen, { SplashScreenInterface } from 'react-native-custom-splash';
173
253
 
174
- // Hide with fade animation
175
- await SplashScreen.hide(true);
254
+ const hideSplash = async (): Promise<void> => {
255
+ await SplashScreen.hide(true);
256
+ };
176
257
  ```
177
258
 
178
- ## Example
259
+ ### React Navigation Integration
179
260
 
180
- ```typescript
181
- import React, { useEffect, useState } from 'react';
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
- export default function App() {
186
- const [appIsReady, setAppIsReady] = useState(false);
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
- setAppIsReady(true);
277
+ setIsReady(true);
201
278
  }
202
279
  }
203
280
 
204
281
  prepare();
205
282
  }, []);
206
283
 
207
- useEffect(() => {
208
- if (appIsReady) {
209
- // Hide splash screen with animation when app is ready
284
+ React.useEffect(() => {
285
+ if (isReady) {
210
286
  SplashScreen.hide(true);
211
287
  }
212
- }, [appIsReady]);
288
+ }, [isReady]);
213
289
 
214
- if (!appIsReady) {
215
- return null; // Splash screen is visible
290
+ if (!isReady) {
291
+ return null;
216
292
  }
217
293
 
218
294
  return (
219
- <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
220
- <Text>App is ready!</Text>
221
- </View>
295
+ <NavigationContainer>
296
+ {/* Your navigation */}
297
+ </NavigationContainer>
222
298
  );
223
299
  }
224
300
  ```
225
301
 
226
- ## Troubleshooting
302
+ ## 🔄 Migration from Manual Setup
227
303
 
228
- ### iOS
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
- **Module not found:**
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
- **Splash image not showing:**
236
- - Verify the image is named `splash` in your Assets catalog
237
- - Check that the image is added to the target
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
- **Module not found:**
242
- - Verify `SplashScreenPackage()` is added to `MainApplication.kt`
243
- - Clean build: `cd android && ./gradlew clean && cd ..`
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
- **Splash image not showing:**
247
- - Check that `splash.png` exists in `res/drawable/`
248
- - Verify the resource name matches in `splash_screen.xml`
335
+ ```xml
336
+ <color name="splash_background">#FFFFFF</color>
337
+ ```
249
338
 
250
- ### Expo
339
+ ## ❓ Troubleshooting
251
340
 
252
- **Plugin not working:**
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
- ## TypeScript
343
+ **Full Error:**
344
+ ```
345
+ PluginError: Plugin is an unexpected object, with keys: "backgroundColor, image, logoWidth".
346
+ ```
258
347
 
259
- This package includes TypeScript definitions. The module exports the following interface:
348
+ **Cause:** Your plugin configuration is not properly wrapped in square brackets.
260
349
 
261
- ```typescript
262
- interface SplashScreenInterface {
263
- show(): void;
264
- hide(animated?: boolean): Promise<boolean>;
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
- ## License
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
- ## Issues
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
- If you encounter any issues, please file them on the GitHub repository.
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)
@@ -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,14 @@
1
+ {
2
+ "expo": {
3
+ "name": "Example - Single Full Image",
4
+ "slug": "splash-example-full-image",
5
+ "plugins": [
6
+ [
7
+ "react-native-custom-splash",
8
+ {
9
+ "image": "./assets/splash.png"
10
+ }
11
+ ]
12
+ ]
13
+ }
14
+ }
@@ -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
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "expo": {
3
+ "name": "Example - Color Only",
4
+ "slug": "splash-example-color-only",
5
+ "plugins": [
6
+ [
7
+ "react-native-custom-splash",
8
+ {
9
+ "backgroundColor": "#FF6B6B"
10
+ }
11
+ ]
12
+ ]
13
+ }
14
+ }
@@ -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
- // Users should add their splash image to their app's assets
45
- if let splashImage = UIImage(named: "splash") {
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 splash image is provided
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": "1.0.3",
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
  ]
@@ -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
- * Plugin to add SplashScreenModule to Android
14
+ * Validate and normalize plugin configuration
12
15
  */
13
- const withSplashScreenAndroid = (config) => {
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 add SplashScreenModule to iOS
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
- // The native files will be linked via CocoaPods
75
- // No additional configuration needed here
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
  };