Uygulama açılırken kullanıcıya daha iyi bir deneyim sunmak için:
- ❌ Ekstra loading screen göstermemek
- ✅ Native LaunchScreen'i data yüklenene kadar göstermek
- ✅ Smooth ve profesyonel geçiş yapmak
- ✅ Uygulama açılırken kritik verileri önceden yüklemek
npm install react-native-splash-screen
# veya
yarn add react-native-splash-screencd ios && pod install && cd ..Objective-C kullanıyorsan: ios/YourApp/AppDelegate.mm
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import "RNSplashScreen.h" // ✅ Import ekle
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ... React Native setup ...
[RNSplashScreen show]; // ✅ SplashScreen'i göster
return YES;
}
@endSwift kullanıyorsan: ios/YourApp/AppDelegate.swift
import UIKit
import RNSplashScreen // ✅ Import ekle
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// React Native bridge setup...
let bridge = RCTBridge(delegate: self, launchOptions: launchOptions)
let rootView = RCTRootView(bridge: bridge!, moduleName: "YourApp", initialProperties: nil)
let rootViewController = UIViewController()
rootViewController.view = rootView
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = rootViewController
self.window?.makeKeyAndVisible()
// ✅ SplashScreen'i göster (LaunchScreen'i uzat)
RNSplashScreen.show()
return true
}
}Eğer Swift kullanıyorsan ve Bridging Header yoksa:
- Xcode'da
File→New→File→Header File - İsim:
YourApp-Bridging-Header.h
İçeriği:
#import <React/RCTBridgeModule.h>
#import <React/RCTBridge.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTRootView.h>
#import <React/RCTUtils.h>
#import <React/RCTConvert.h>
#import <React/RCTBundleURLProvider.h>
#import "RNSplashScreen.h" // ✅ SplashScreen import- Build Settings'de ara:
Objective-C Bridging Header - Value:
YourApp/YourApp-Bridging-Header.h
android/app/src/main/java/com/yourapp/MainActivity.java:
package com.yourapp;
import android.os.Bundle;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactActivityDelegate;
import org.devio.rn.splashscreen.SplashScreen; // ✅ Import ekle
public class MainActivity extends ReactActivity {
@Override
protected String getMainComponentName() {
return "YourApp";
}
@Override
protected void onCreate(Bundle savedInstanceState) {
SplashScreen.show(this); // ✅ LaunchScreen'i göster
super.onCreate(savedInstanceState);
}
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new DefaultReactActivityDelegate(
this,
getMainComponentName(),
DefaultNewArchitectureEntryPoint.getFabricEnabled()
);
}
}android/app/src/main/res/layout/launch_screen.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/launch_screen" />
</LinearLayout>Logo'yu android/app/src/main/res/drawable/ klasörüne ekle.
src/App.tsx:
import React, { useEffect, useState } from 'react';
import { View, ActivityIndicator } from 'react-native';
import SplashScreen from 'react-native-splash-screen';
import { NavigationContainer } from '@react-navigation/native';
import { RootNavigator } from './navigation/RootNavigator';
const App = () => {
const [isAppReady, setIsAppReady] = useState(false);
useEffect(() => {
initializeApp();
}, []);
const initializeApp = async () => {
try {
// ✅ 1. Kritik verileri paralel olarak yükle
await Promise.all([
fetchUserInfo(), // Kullanıcı bilgisi
fetchAppConfig(), // App konfigürasyonu
loadCachedData(), // Cache'den data
initializeServices(), // Push notification, analytics vs
]);
console.log('✅ App initialization completed');
// ✅ 2. Data hazır, LaunchScreen'i kapat
SplashScreen.hide();
// ✅ 3. App render'a hazır
setIsAppReady(true);
} catch (error) {
console.error('❌ App initialization error:', error);
// ⚠️ Hata olsa bile splash'ı kapat (sonsuz bekletme olmasın)
SplashScreen.hide();
setIsAppReady(true);
}
};
// Fetch fonksiyonları
const fetchUserInfo = async () => {
// API call
await new Promise(resolve => setTimeout(resolve, 1000));
};
const fetchAppConfig = async () => {
// API call
await new Promise(resolve => setTimeout(resolve, 500));
};
const loadCachedData = async () => {
// AsyncStorage'dan data yükle
await new Promise(resolve => setTimeout(resolve, 300));
};
const initializeServices = async () => {
// OneSignal, Firebase, Analytics vs.
await new Promise(resolve => setTimeout(resolve, 500));
};
// ✅ Data yüklenene kadar null render et
// LaunchScreen bu süre boyunca gözükmeye devam eder
if (!isAppReady) {
return null;
}
return (
<NavigationContainer>
<RootNavigator />
</NavigationContainer>
);
};
export default App;Eğer app-wide state kullanıyorsan:
src/App.tsx:
import React, { useEffect, useState } from 'react';
import SplashScreen from 'react-native-splash-screen';
import { NavigationContainer } from '@react-navigation/native';
import { AppProvider } from './context/AppContext';
import { RootNavigator } from './navigation/RootNavigator';
const App = () => {
const [isAppReady, setIsAppReady] = useState(false);
useEffect(() => {
initializeApp();
}, []);
const initializeApp = async () => {
try {
await Promise.all([
fetchUserInfo(),
fetchAppConfig(),
]);
SplashScreen.hide();
setIsAppReady(true);
} catch (error) {
console.error('App init error:', error);
SplashScreen.hide();
setIsAppReady(true);
}
};
const fetchUserInfo = async () => {
// API call
};
const fetchAppConfig = async () => {
// API call
};
if (!isAppReady) {
return null;
}
return (
<AppProvider>
<NavigationContainer>
<RootNavigator />
</NavigationContainer>
</AppProvider>
);
};
export default App;- Xcode'da
ios/YourApp.xcworkspaceaç LaunchScreen.storyboarddosyasını seç- Interface Builder'da:
- ImageView ekle (Logo için)
- Constraints ayarla:
- Center X = Superview Center X
- Center Y = Superview Center Y
- Width = 200, Height = 200 (sabit boyut)
- Background Color ayarla
- Logo görseli:
Assets.xcassetsiçineLaunchScreenimage set ekle- 1x, 2x, 3x versiyonlarını ekle
- ❌ Custom font kullanılamaz
- ❌ Animation yapılamaz
- ❌ Network request olmaz
- ❌ Dinamik content olmaz
- ✅ Sadece statik görsel ve renkler
android/app/src/main/res/values/styles.xml:
<resources>
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
</style>
<!-- ✅ Splash Screen Theme -->
<style name="SplashTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowBackground">@drawable/launch_screen</item>
</style>
</resources>android/app/src/main/AndroidManifest.xml:
<application
android:name=".MainApplication"
android:theme="@style/AppTheme">
<!-- ✅ MainActivity'ye SplashTheme uygula -->
<activity
android:name=".MainActivity"
android:theme="@style/SplashTheme"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>┌─────────────────────────────────────────┐
│ App Açılışı (Native) │
└───────────────┬─────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ LaunchScreen Gösteriliyor │
│ (Native Storyboard/XML) │
└───────────────┬─────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ AppDelegate: RNSplashScreen.show() │
│ (LaunchScreen uzatılıyor) │
└───────────────┬─────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ React Native Bundle Yükleniyor │
└───────────────┬─────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ App.tsx: initializeApp() Başlıyor │
│ • fetchUserInfo() │
│ • fetchAppConfig() │
│ • loadCachedData() │
│ • initializeServices() │
└───────────────┬─────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Tüm Data Hazır │
└───────────────┬─────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ SplashScreen.hide() │
│ setIsAppReady(true) │
└───────────────┬─────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ NavigationContainer Render │
│ Ana Ekran Gösteriliyor │
└─────────────────────────────────────────┘
const initializeApp = async () => {
try {
// ✅ Maximum 5 saniye bekle
await Promise.race([
Promise.all([
fetchUserInfo(),
fetchAppConfig(),
]),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), 5000)
)
]);
SplashScreen.hide();
setIsAppReady(true);
} catch (error) {
console.error('App init error:', error);
SplashScreen.hide();
setIsAppReady(true);
}
};const fetchUserInfo = async () => {
try {
const response = await api.get('/user/info');
await AsyncStorage.setItem('userInfo', JSON.stringify(response.data));
return response.data;
} catch (error) {
// ⚠️ Hata olsa bile app açılsın
console.warn('User info fetch failed:', error);
return null;
}
};const loadCachedData = async () => {
try {
// ✅ Önce cache'den yükle
const cached = await AsyncStorage.getItem('userInfo');
if (cached) {
// Cache'li data'yı kullan
return JSON.parse(cached);
}
} catch (error) {
console.warn('Cache load failed:', error);
}
return null;
};cd ios
rm -rf Pods Podfile.lock
pod install
cd ..
npx react-native run-ios- Build Settings → Objective-C Bridging Header
- Path:
YourApp/YourApp-Bridging-Header.h - Clean Build: Cmd+Shift+K
android/app/build.gradle:
dependencies {
implementation project(':react-native-splash-screen')
}android/settings.gradle:
include ':react-native-splash-screen'
project(':react-native-splash-screen').projectDir =
new File(rootProject.projectDir, '../node_modules/react-native-splash-screen/android')// ✅ Her durumda kapatıldığından emin ol
useEffect(() => {
const timer = setTimeout(() => {
SplashScreen.hide();
}, 10000); // 10 saniye max
return () => clearTimeout(timer);
}, []);-
react-native-splash-screenyüklendi -
pod installyapıldı -
AppDelegatedüzenlendi (RNSplashScreen.show()) - Bridging Header oluşturuldu (Swift ise)
-
LaunchScreen.storyboarddüzenlendi - Logo eklendi
- Build ve test edildi
-
react-native-splash-screenyüklendi -
MainActivitydüzenlendi -
launch_screen.xmloluşturuldu - Logo
drawable/klasörüne eklendi -
styles.xmldüzenlendi -
AndroidManifest.xmldüzenlendi - Build ve test edildi
-
App.tsxdüzenlendi -
initializeApp()fonksiyonu oluşturuldu - Kritik API'ler belirlendi
-
SplashScreen.hide()eklendi - Error handling eklendi
- Timeout mekanizması eklendi
- Test edildi
Bu pattern ile:
- ✅ Kullanıcı loading screen görmez
- ✅ Native LaunchScreen smooth bir şekilde uzatılır
- ✅ App açılırken data hazır olur
- ✅ Profesyonel bir UX sağlanır
Örnek Kullanım:
- Instagram, WhatsApp, Twitter gibi popüler uygulamalar bu pattern'i kullanır
- Kullanıcı hiç loading görmeden direkt ana ekrana geçer
- Tüm kritik data arka planda yüklenmiş olur
Son Güncelleme: Kasım 2025 React Native Version: 0.80+ Pattern: LaunchScreen Extended