react-native-custom-splash 1.0.2 → 2.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/README.md +220 -167
- package/ios/SplashScreenModule.swift +31 -4
- package/package.json +5 -1
- package/plugin/src/index.js +278 -9
- package/react-native-custom-splash.podspec +1 -1
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,257 +20,312 @@ 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
|
+
Add the plugin configuration to your `app.json`:
|
|
26
41
|
|
|
27
42
|
```json
|
|
28
43
|
{
|
|
29
44
|
"expo": {
|
|
45
|
+
"name": "YourApp",
|
|
30
46
|
"plugins": [
|
|
31
|
-
|
|
47
|
+
[
|
|
48
|
+
"react-native-custom-splash",
|
|
49
|
+
{
|
|
50
|
+
"backgroundColor": "#FFFFFF",
|
|
51
|
+
"image": "./assets/splash-background.png",
|
|
52
|
+
"logo": "./assets/logo.png",
|
|
53
|
+
"logoWidth": 150
|
|
54
|
+
}
|
|
55
|
+
]
|
|
32
56
|
]
|
|
33
57
|
}
|
|
34
58
|
}
|
|
35
59
|
```
|
|
36
60
|
|
|
37
|
-
|
|
61
|
+
### Step 3: Run prebuild
|
|
38
62
|
|
|
39
63
|
```bash
|
|
40
|
-
npx expo prebuild
|
|
64
|
+
npx expo prebuild --clean
|
|
41
65
|
```
|
|
42
66
|
|
|
43
|
-
|
|
67
|
+
**That's it!** 🎉 The plugin will automatically:
|
|
68
|
+
- ✅ Copy your images to iOS and Android native folders
|
|
69
|
+
- ✅ Configure the native splash screen
|
|
70
|
+
- ✅ Set up all the required files
|
|
71
|
+
- ✅ Handle different screen densities
|
|
44
72
|
|
|
45
|
-
|
|
46
|
-
npm install react-native-custom-splash
|
|
47
|
-
# or
|
|
48
|
-
yarn add react-native-custom-splash
|
|
49
|
-
```
|
|
73
|
+
### Step 4: Use in your app
|
|
50
74
|
|
|
51
|
-
|
|
75
|
+
```javascript
|
|
76
|
+
import SplashScreen from 'react-native-custom-splash';
|
|
77
|
+
import React, { useEffect } from 'react';
|
|
52
78
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
79
|
+
function App() {
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
// Hide splash screen after app loads
|
|
82
|
+
setTimeout(() => {
|
|
83
|
+
SplashScreen.hide(true); // true = animated
|
|
84
|
+
}, 2000);
|
|
85
|
+
}, []);
|
|
57
86
|
|
|
58
|
-
|
|
87
|
+
return (
|
|
88
|
+
// Your app content
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
59
92
|
|
|
60
|
-
|
|
93
|
+
## ⚙️ Configuration Options
|
|
61
94
|
|
|
62
|
-
|
|
95
|
+
| Option | Type | Default | Description |
|
|
96
|
+
|--------|------|---------|-------------|
|
|
97
|
+
| `backgroundColor` | `string` | `#FFFFFF` | Background color for the splash screen (hex color) |
|
|
98
|
+
| `image` | `string` | `null` | Path to full background image (relative to project root) |
|
|
99
|
+
| `logo` | `string` | `null` | Path to center logo image (relative to project root) |
|
|
100
|
+
| `logoWidth` | `number` | `150` | Width of the center logo in pixels |
|
|
63
101
|
|
|
64
|
-
|
|
65
|
-
import com.rncustomsplash.SplashScreenPackage
|
|
102
|
+
### Configuration Examples
|
|
66
103
|
|
|
67
|
-
|
|
68
|
-
|
|
104
|
+
#### Only Background Color
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"plugins": [
|
|
108
|
+
[
|
|
109
|
+
"react-native-custom-splash",
|
|
110
|
+
{
|
|
111
|
+
"backgroundColor": "#FF6B6B"
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
]
|
|
115
|
+
}
|
|
69
116
|
```
|
|
70
117
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
118
|
+
#### Background Color + Logo
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"plugins": [
|
|
122
|
+
[
|
|
123
|
+
"react-native-custom-splash",
|
|
124
|
+
{
|
|
125
|
+
"backgroundColor": "#1E3A8A",
|
|
126
|
+
"logo": "./assets/logo.png",
|
|
127
|
+
"logoWidth": 200
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
]
|
|
79
131
|
}
|
|
80
132
|
```
|
|
81
133
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
You can also customize the background color in `android/app/src/main/res/values/colors.xml`:
|
|
98
|
-
|
|
99
|
-
```xml
|
|
100
|
-
<color name="splash_background">#FFFFFF</color>
|
|
134
|
+
#### Full Background Image + Logo
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"plugins": [
|
|
138
|
+
[
|
|
139
|
+
"react-native-custom-splash",
|
|
140
|
+
{
|
|
141
|
+
"backgroundColor": "#FFFFFF",
|
|
142
|
+
"image": "./assets/splash-bg.png",
|
|
143
|
+
"logo": "./assets/logo.png",
|
|
144
|
+
"logoWidth": 180
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
]
|
|
148
|
+
}
|
|
101
149
|
```
|
|
102
150
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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();
|
|
122
|
-
}, []);
|
|
123
|
-
|
|
124
|
-
return (
|
|
125
|
-
// Your app content
|
|
126
|
-
);
|
|
151
|
+
#### Only Background Image (No Logo)
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"plugins": [
|
|
155
|
+
[
|
|
156
|
+
"react-native-custom-splash",
|
|
157
|
+
{
|
|
158
|
+
"backgroundColor": "#000000",
|
|
159
|
+
"image": "./assets/splash-full.png"
|
|
160
|
+
}
|
|
161
|
+
]
|
|
162
|
+
]
|
|
127
163
|
}
|
|
128
164
|
```
|
|
129
165
|
|
|
130
|
-
##
|
|
166
|
+
## 📱 API Reference
|
|
131
167
|
|
|
132
|
-
|
|
168
|
+
### `SplashScreen.hide(animated)`
|
|
133
169
|
|
|
134
|
-
|
|
135
|
-
- ✅ Loading progress simulation
|
|
136
|
-
- ✅ Animated hide transitions
|
|
137
|
-
- ✅ Manual show/hide controls
|
|
138
|
-
- ✅ Full TypeScript integration
|
|
170
|
+
Hides the splash screen.
|
|
139
171
|
|
|
140
|
-
|
|
172
|
+
**Parameters:**
|
|
173
|
+
- `animated` (boolean): Whether to animate the hide transition. Default: `true`
|
|
141
174
|
|
|
142
|
-
|
|
143
|
-
cd example
|
|
144
|
-
npm install
|
|
145
|
-
npx expo prebuild
|
|
146
|
-
npm run ios # or npm run android
|
|
147
|
-
```
|
|
175
|
+
**Returns:** Promise<boolean>
|
|
148
176
|
|
|
149
|
-
|
|
177
|
+
**Example:**
|
|
178
|
+
```javascript
|
|
179
|
+
// With animation (recommended)
|
|
180
|
+
await SplashScreen.hide(true);
|
|
150
181
|
|
|
151
|
-
|
|
182
|
+
// Without animation
|
|
183
|
+
await SplashScreen.hide(false);
|
|
184
|
+
```
|
|
152
185
|
|
|
153
186
|
### `SplashScreen.show()`
|
|
154
187
|
|
|
155
|
-
Shows the splash screen.
|
|
188
|
+
Shows the splash screen (usually not needed as it shows automatically on app launch).
|
|
156
189
|
|
|
157
|
-
|
|
190
|
+
**Example:**
|
|
191
|
+
```javascript
|
|
158
192
|
SplashScreen.show();
|
|
159
193
|
```
|
|
160
194
|
|
|
161
|
-
|
|
195
|
+
## 🎨 Image Guidelines
|
|
162
196
|
|
|
163
|
-
|
|
197
|
+
### Background Image
|
|
198
|
+
- **Recommended size:** 1242 x 2688 px (iPhone 13 Pro Max size)
|
|
199
|
+
- **Format:** PNG or JPG
|
|
200
|
+
- **Aspect ratio:** Match your target device screens
|
|
201
|
+
- **Tip:** The plugin will handle different screen densities automatically
|
|
164
202
|
|
|
165
|
-
|
|
166
|
-
-
|
|
203
|
+
### Logo Image
|
|
204
|
+
- **Recommended size:** 512 x 512 px (or your desired aspect ratio)
|
|
205
|
+
- **Format:** PNG with transparency recommended
|
|
206
|
+
- **Tip:** The logo will be centered and sized according to `logoWidth`
|
|
207
|
+
|
|
208
|
+
## 🔧 Advanced Usage
|
|
167
209
|
|
|
168
|
-
|
|
210
|
+
### TypeScript Support
|
|
211
|
+
|
|
212
|
+
Full TypeScript support is included:
|
|
169
213
|
|
|
170
214
|
```typescript
|
|
171
|
-
|
|
172
|
-
await SplashScreen.hide();
|
|
215
|
+
import SplashScreen, { SplashScreenInterface } from 'react-native-custom-splash';
|
|
173
216
|
|
|
174
|
-
|
|
175
|
-
await SplashScreen.hide(true);
|
|
217
|
+
const hideSplash = async (): Promise<void> => {
|
|
218
|
+
await SplashScreen.hide(true);
|
|
219
|
+
};
|
|
176
220
|
```
|
|
177
221
|
|
|
178
|
-
|
|
222
|
+
### React Navigation Integration
|
|
179
223
|
|
|
180
|
-
```
|
|
181
|
-
import
|
|
182
|
-
import { View, Text, ActivityIndicator } from 'react-native';
|
|
224
|
+
```javascript
|
|
225
|
+
import { NavigationContainer } from '@react-navigation/native';
|
|
183
226
|
import SplashScreen from 'react-native-custom-splash';
|
|
184
227
|
|
|
185
|
-
|
|
186
|
-
const [
|
|
228
|
+
function App() {
|
|
229
|
+
const [isReady, setIsReady] = React.useState(false);
|
|
187
230
|
|
|
188
|
-
useEffect(() => {
|
|
231
|
+
React.useEffect(() => {
|
|
189
232
|
async function prepare() {
|
|
190
233
|
try {
|
|
191
234
|
// Load your resources here
|
|
192
235
|
await loadFonts();
|
|
193
236
|
await loadData();
|
|
194
|
-
|
|
195
|
-
// Artificially delay for demo
|
|
196
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
197
237
|
} catch (e) {
|
|
198
238
|
console.warn(e);
|
|
199
239
|
} finally {
|
|
200
|
-
|
|
240
|
+
setIsReady(true);
|
|
201
241
|
}
|
|
202
242
|
}
|
|
203
243
|
|
|
204
244
|
prepare();
|
|
205
245
|
}, []);
|
|
206
246
|
|
|
207
|
-
useEffect(() => {
|
|
208
|
-
if (
|
|
209
|
-
// Hide splash screen with animation when app is ready
|
|
247
|
+
React.useEffect(() => {
|
|
248
|
+
if (isReady) {
|
|
210
249
|
SplashScreen.hide(true);
|
|
211
250
|
}
|
|
212
|
-
}, [
|
|
251
|
+
}, [isReady]);
|
|
213
252
|
|
|
214
|
-
if (!
|
|
215
|
-
return null;
|
|
253
|
+
if (!isReady) {
|
|
254
|
+
return null;
|
|
216
255
|
}
|
|
217
256
|
|
|
218
257
|
return (
|
|
219
|
-
<
|
|
220
|
-
|
|
221
|
-
</
|
|
258
|
+
<NavigationContainer>
|
|
259
|
+
{/* Your navigation */}
|
|
260
|
+
</NavigationContainer>
|
|
222
261
|
);
|
|
223
262
|
}
|
|
224
263
|
```
|
|
225
264
|
|
|
226
|
-
##
|
|
227
|
-
|
|
228
|
-
### iOS
|
|
265
|
+
## 🔄 Migration from Manual Setup
|
|
229
266
|
|
|
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
|
|
267
|
+
If you were using the old manual method, you can now simplify:
|
|
234
268
|
|
|
235
|
-
**
|
|
236
|
-
|
|
237
|
-
|
|
269
|
+
**Before (Manual Method):**
|
|
270
|
+
1. ❌ Manually copy images to `ios/` folder
|
|
271
|
+
2. ❌ Open Xcode and add images to Assets
|
|
272
|
+
3. ❌ Manually copy images to `android/app/src/main/res/drawable/`
|
|
273
|
+
4. ❌ Manually edit `colors.xml`
|
|
274
|
+
5. ❌ Configure multiple drawable folders
|
|
238
275
|
|
|
239
|
-
|
|
276
|
+
**After (Automatic Method):**
|
|
277
|
+
1. ✅ Add images to `assets/` folder
|
|
278
|
+
2. ✅ Configure in `app.json`
|
|
279
|
+
3. ✅ Run `npx expo prebuild --clean`
|
|
280
|
+
4. ✅ Done!
|
|
240
281
|
|
|
241
|
-
|
|
242
|
-
- Verify `SplashScreenPackage()` is added to `MainApplication.kt`
|
|
243
|
-
- Clean build: `cd android && ./gradlew clean && cd ..`
|
|
244
|
-
- Rebuild the app
|
|
282
|
+
## 🛠️ Manual Setup (Non-Expo Projects)
|
|
245
283
|
|
|
246
|
-
|
|
247
|
-
- Check that `splash.png` exists in `res/drawable/`
|
|
248
|
-
- Verify the resource name matches in `splash_screen.xml`
|
|
284
|
+
If you're not using Expo, you can still use this package with manual setup:
|
|
249
285
|
|
|
250
|
-
###
|
|
286
|
+
### iOS
|
|
251
287
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
- Rebuild the app
|
|
288
|
+
Add your splash image to your Xcode project:
|
|
289
|
+
1. Open your project in Xcode
|
|
290
|
+
2. Add an image asset named `splash_image` for background and/or `splash_logo` for center logo to your Assets catalog
|
|
256
291
|
|
|
257
|
-
|
|
292
|
+
### Android
|
|
258
293
|
|
|
259
|
-
|
|
294
|
+
Add your images to Android resources:
|
|
295
|
+
1. Add `splash_image.png` (background) and/or `splash_logo.png` (center logo) to `android/app/src/main/res/drawable/`
|
|
296
|
+
2. Customize the background color in `android/app/src/main/res/values/colors.xml`:
|
|
260
297
|
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
show(): void;
|
|
264
|
-
hide(animated?: boolean): Promise<boolean>;
|
|
265
|
-
}
|
|
298
|
+
```xml
|
|
299
|
+
<color name="splash_background">#FFFFFF</color>
|
|
266
300
|
```
|
|
267
301
|
|
|
268
|
-
##
|
|
302
|
+
## ❓ Troubleshooting
|
|
303
|
+
|
|
304
|
+
### Splash screen not showing
|
|
305
|
+
- Make sure you run `npx expo prebuild --clean` after changing configuration
|
|
306
|
+
- Check that your image paths in `app.json` are correct and files exist
|
|
307
|
+
- Try cleaning your build: `cd ios && pod install && cd ..` for iOS
|
|
308
|
+
|
|
309
|
+
### Images not updating
|
|
310
|
+
- Run `npx expo prebuild --clean` to force regeneration of native projects
|
|
311
|
+
- Clear build caches and rebuild
|
|
312
|
+
|
|
313
|
+
### TypeScript errors
|
|
314
|
+
- Make sure you have `@types/react` and `@types/react-native` installed
|
|
315
|
+
- The package includes TypeScript definitions
|
|
316
|
+
|
|
317
|
+
## 📄 License
|
|
269
318
|
|
|
270
319
|
MIT
|
|
271
320
|
|
|
272
|
-
## Contributing
|
|
321
|
+
## 🤝 Contributing
|
|
273
322
|
|
|
274
323
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
275
324
|
|
|
276
|
-
##
|
|
325
|
+
## 💖 Support
|
|
326
|
+
|
|
327
|
+
If you find this package helpful, please give it a ⭐️ on [GitHub](https://github.com/vijaykishan312/react-native-custom-splash)!
|
|
328
|
+
|
|
329
|
+
---
|
|
277
330
|
|
|
278
|
-
|
|
331
|
+
Made with ❤️ for the React Native community
|
|
@@ -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.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",
|
|
@@ -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": "*",
|
package/plugin/src/index.js
CHANGED
|
@@ -3,14 +3,210 @@ 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
|
+
* Get plugin configuration from app.json
|
|
12
15
|
*/
|
|
13
|
-
|
|
16
|
+
function getPluginConfig(config) {
|
|
17
|
+
const plugins = config.plugins || [];
|
|
18
|
+
const splashPlugin = plugins.find(plugin => {
|
|
19
|
+
if (Array.isArray(plugin) && plugin[0] === 'react-native-custom-splash') {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
return plugin === 'react-native-custom-splash';
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (Array.isArray(splashPlugin) && splashPlugin[1]) {
|
|
26
|
+
return splashPlugin[1];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Default configuration
|
|
30
|
+
return {
|
|
31
|
+
backgroundColor: '#FFFFFF',
|
|
32
|
+
image: null,
|
|
33
|
+
logo: null,
|
|
34
|
+
logoWidth: 150,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Copy and resize image to Android drawable folders
|
|
40
|
+
*/
|
|
41
|
+
async function copyImageToAndroid(projectRoot, imagePath, outputName, resDir) {
|
|
42
|
+
if (!imagePath || !fs.existsSync(path.join(projectRoot, imagePath))) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const sourceImage = path.join(projectRoot, imagePath);
|
|
47
|
+
|
|
48
|
+
// Define sizes for different densities
|
|
49
|
+
const densities = {
|
|
50
|
+
'mdpi': 1,
|
|
51
|
+
'hdpi': 1.5,
|
|
52
|
+
'xhdpi': 2,
|
|
53
|
+
'xxhdpi': 3,
|
|
54
|
+
'xxxhdpi': 4,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
for (const [density, scale] of Object.entries(densities)) {
|
|
58
|
+
const drawableDir = path.join(resDir, `drawable-${density}`);
|
|
59
|
+
|
|
60
|
+
// Create directory if it doesn't exist
|
|
61
|
+
if (!fs.existsSync(drawableDir)) {
|
|
62
|
+
fs.mkdirSync(drawableDir, { recursive: true });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const outputPath = path.join(drawableDir, `${outputName}.png`);
|
|
66
|
+
|
|
67
|
+
// Copy the image (you can add resizing logic here if needed)
|
|
68
|
+
fs.copyFileSync(sourceImage, outputPath);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Copy image to iOS assets
|
|
76
|
+
*/
|
|
77
|
+
async function copyImageToIOS(projectRoot, imagePath, outputName, iosProjectPath, projectName) {
|
|
78
|
+
if (!imagePath || !fs.existsSync(path.join(projectRoot, imagePath))) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const sourceImage = path.join(projectRoot, imagePath);
|
|
83
|
+
const assetsDir = path.join(iosProjectPath, projectName, 'Images.xcassets', `${outputName}.imageset`);
|
|
84
|
+
|
|
85
|
+
// Create imageset directory
|
|
86
|
+
if (!fs.existsSync(assetsDir)) {
|
|
87
|
+
fs.mkdirSync(assetsDir, { recursive: true });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Copy image files for different scales
|
|
91
|
+
const scales = ['1x', '2x', '3x'];
|
|
92
|
+
const images = [];
|
|
93
|
+
|
|
94
|
+
for (const scale of scales) {
|
|
95
|
+
const filename = `${outputName}@${scale}.png`;
|
|
96
|
+
const destPath = path.join(assetsDir, filename);
|
|
97
|
+
fs.copyFileSync(sourceImage, destPath);
|
|
98
|
+
|
|
99
|
+
images.push({
|
|
100
|
+
idiom: 'universal',
|
|
101
|
+
filename: filename,
|
|
102
|
+
scale: scale,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Create Contents.json
|
|
107
|
+
const contentsJson = {
|
|
108
|
+
images: images,
|
|
109
|
+
info: {
|
|
110
|
+
author: 'xcode',
|
|
111
|
+
version: 1,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
fs.writeFileSync(
|
|
116
|
+
path.join(assetsDir, 'Contents.json'),
|
|
117
|
+
JSON.stringify(contentsJson, null, 2)
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Update Android colors.xml
|
|
125
|
+
*/
|
|
126
|
+
function updateAndroidColors(resDir, backgroundColor) {
|
|
127
|
+
const valuesDir = path.join(resDir, 'values');
|
|
128
|
+
if (!fs.existsSync(valuesDir)) {
|
|
129
|
+
fs.mkdirSync(valuesDir, { recursive: true });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const colorsPath = path.join(valuesDir, 'colors.xml');
|
|
133
|
+
const colorsXml = `<?xml version="1.0" encoding="utf-8"?>
|
|
134
|
+
<resources>
|
|
135
|
+
<color name="splash_background">${backgroundColor}</color>
|
|
136
|
+
</resources>
|
|
137
|
+
`;
|
|
138
|
+
|
|
139
|
+
fs.writeFileSync(colorsPath, colorsXml);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Update Android splash drawable
|
|
144
|
+
*/
|
|
145
|
+
function updateAndroidSplashDrawable(resDir, hasImage, hasLogo) {
|
|
146
|
+
const drawableDir = path.join(resDir, 'drawable');
|
|
147
|
+
if (!fs.existsSync(drawableDir)) {
|
|
148
|
+
fs.mkdirSync(drawableDir, { recursive: true });
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const splashPath = path.join(drawableDir, 'splash.xml');
|
|
152
|
+
|
|
153
|
+
let items = [];
|
|
154
|
+
|
|
155
|
+
// Background color
|
|
156
|
+
items.push(' <item android:drawable="@color/splash_background"/>');
|
|
157
|
+
|
|
158
|
+
// Background image if provided
|
|
159
|
+
if (hasImage) {
|
|
160
|
+
items.push(' <item>');
|
|
161
|
+
items.push(' <bitmap');
|
|
162
|
+
items.push(' android:gravity="fill"');
|
|
163
|
+
items.push(' android:src="@drawable/splash_image"/>');
|
|
164
|
+
items.push(' </item>');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Logo if provided
|
|
168
|
+
if (hasLogo) {
|
|
169
|
+
items.push(' <item>');
|
|
170
|
+
items.push(' <bitmap');
|
|
171
|
+
items.push(' android:gravity="center"');
|
|
172
|
+
items.push(' android:src="@drawable/splash_logo"/>');
|
|
173
|
+
items.push(' </item>');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const splashXml = `<?xml version="1.0" encoding="utf-8"?>
|
|
177
|
+
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
|
178
|
+
${items.join('\n')}
|
|
179
|
+
</layer-list>
|
|
180
|
+
`;
|
|
181
|
+
|
|
182
|
+
fs.writeFileSync(splashPath, splashXml);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Update Android splash layout
|
|
187
|
+
*/
|
|
188
|
+
function updateAndroidSplashLayout(resDir) {
|
|
189
|
+
const layoutDir = path.join(resDir, 'layout');
|
|
190
|
+
if (!fs.existsSync(layoutDir)) {
|
|
191
|
+
fs.mkdirSync(layoutDir, { recursive: true });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const layoutPath = path.join(layoutDir, 'splash_screen.xml');
|
|
195
|
+
const layoutXml = `<?xml version="1.0" encoding="utf-8"?>
|
|
196
|
+
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
197
|
+
android:layout_width="match_parent"
|
|
198
|
+
android:layout_height="match_parent"
|
|
199
|
+
android:background="@drawable/splash">
|
|
200
|
+
</FrameLayout>
|
|
201
|
+
`;
|
|
202
|
+
|
|
203
|
+
fs.writeFileSync(layoutPath, layoutXml);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Plugin to configure Android splash screen
|
|
208
|
+
*/
|
|
209
|
+
const withSplashScreenAndroid = (config, pluginConfig) => {
|
|
14
210
|
// Add package to MainApplication
|
|
15
211
|
config = withMainApplication(config, async (config) => {
|
|
16
212
|
const { modResults } = config;
|
|
@@ -61,18 +257,89 @@ const withSplashScreenAndroid = (config) => {
|
|
|
61
257
|
return config;
|
|
62
258
|
});
|
|
63
259
|
|
|
260
|
+
// Configure Android resources
|
|
261
|
+
config = withDangerousMod(config, [
|
|
262
|
+
'android',
|
|
263
|
+
async (config) => {
|
|
264
|
+
const projectRoot = config.modRequest.projectRoot;
|
|
265
|
+
const resDir = path.join(
|
|
266
|
+
config.modRequest.platformProjectRoot,
|
|
267
|
+
'app',
|
|
268
|
+
'src',
|
|
269
|
+
'main',
|
|
270
|
+
'res'
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
// Update colors
|
|
274
|
+
updateAndroidColors(resDir, pluginConfig.backgroundColor);
|
|
275
|
+
|
|
276
|
+
// Copy images if provided
|
|
277
|
+
let hasImage = false;
|
|
278
|
+
let hasLogo = false;
|
|
279
|
+
|
|
280
|
+
if (pluginConfig.image) {
|
|
281
|
+
hasImage = await copyImageToAndroid(
|
|
282
|
+
projectRoot,
|
|
283
|
+
pluginConfig.image,
|
|
284
|
+
'splash_image',
|
|
285
|
+
resDir
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (pluginConfig.logo) {
|
|
290
|
+
hasLogo = await copyImageToAndroid(
|
|
291
|
+
projectRoot,
|
|
292
|
+
pluginConfig.logo,
|
|
293
|
+
'splash_logo',
|
|
294
|
+
resDir
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Update splash drawable
|
|
299
|
+
updateAndroidSplashDrawable(resDir, hasImage, hasLogo);
|
|
300
|
+
|
|
301
|
+
// Update splash layout
|
|
302
|
+
updateAndroidSplashLayout(resDir);
|
|
303
|
+
|
|
304
|
+
return config;
|
|
305
|
+
},
|
|
306
|
+
]);
|
|
307
|
+
|
|
64
308
|
return config;
|
|
65
309
|
};
|
|
66
310
|
|
|
67
311
|
/**
|
|
68
|
-
* Plugin to
|
|
312
|
+
* Plugin to configure iOS splash screen
|
|
69
313
|
*/
|
|
70
|
-
const withSplashScreenIOS = (config) => {
|
|
314
|
+
const withSplashScreenIOS = (config, pluginConfig) => {
|
|
71
315
|
return withDangerousMod(config, [
|
|
72
316
|
'ios',
|
|
73
317
|
async (config) => {
|
|
74
|
-
|
|
75
|
-
|
|
318
|
+
const projectRoot = config.modRequest.projectRoot;
|
|
319
|
+
const iosProjectPath = config.modRequest.platformProjectRoot;
|
|
320
|
+
const projectName = config.modRequest.projectName;
|
|
321
|
+
|
|
322
|
+
// Copy images to iOS assets
|
|
323
|
+
if (pluginConfig.image) {
|
|
324
|
+
await copyImageToIOS(
|
|
325
|
+
projectRoot,
|
|
326
|
+
pluginConfig.image,
|
|
327
|
+
'splash_image',
|
|
328
|
+
iosProjectPath,
|
|
329
|
+
projectName
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (pluginConfig.logo) {
|
|
334
|
+
await copyImageToIOS(
|
|
335
|
+
projectRoot,
|
|
336
|
+
pluginConfig.logo,
|
|
337
|
+
'splash_logo',
|
|
338
|
+
iosProjectPath,
|
|
339
|
+
projectName
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
|
|
76
343
|
return config;
|
|
77
344
|
},
|
|
78
345
|
]);
|
|
@@ -81,9 +348,11 @@ const withSplashScreenIOS = (config) => {
|
|
|
81
348
|
/**
|
|
82
349
|
* Main plugin export
|
|
83
350
|
*/
|
|
84
|
-
module.exports = (config) => {
|
|
351
|
+
module.exports = (config, props = {}) => {
|
|
352
|
+
const pluginConfig = props || getPluginConfig(config);
|
|
353
|
+
|
|
85
354
|
return withPlugins(config, [
|
|
86
|
-
withSplashScreenAndroid,
|
|
87
|
-
withSplashScreenIOS,
|
|
355
|
+
[withSplashScreenAndroid, pluginConfig],
|
|
356
|
+
[withSplashScreenIOS, pluginConfig],
|
|
88
357
|
]);
|
|
89
358
|
};
|
|
@@ -3,7 +3,7 @@ require "json"
|
|
|
3
3
|
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
4
|
|
|
5
5
|
Pod::Spec.new do |s|
|
|
6
|
-
s.name = "
|
|
6
|
+
s.name = "react-native-custom-splash"
|
|
7
7
|
s.version = package["version"]
|
|
8
8
|
s.summary = package["description"]
|
|
9
9
|
s.homepage = package["repository"]["url"]
|