# Create new React Native project
npx create-expo-app@latest
# Navigate to project
cd app-name
# Install all required dependencies
npm install react-native-webview
npm install @react-native-community/netinfo
npm install react-native-share
npm install react-native-fs
npm install react-native-splash-screen
npm install @react-navigation/native
npm install @react-navigation/native-stack
npm install react-native-screens
npm install react-native-safe-area-context
npm install react-native-permissions
# For iOS (Mac only)
cd ios && pod install && cd ..
import React, { useEffect, useState, useRef } from 'react';
import {
SafeAreaView,
StatusBar,
StyleSheet,
View,
BackHandler,
Alert,
Platform,
Linking,
TouchableOpacity,
Text,
} from 'react-native';
import { WebView } from 'react-native-webview';
import NetInfo from '@react-native-community/netinfo';
import Share from 'react-native-share';
import SplashScreen from './components/SplashScreen';
import OfflineNotice from './components/OfflineNotice';
const App = () => {
// State management
const [showSplash, setShowSplash] = useState(true);
const [isLoading, setIsLoading] = useState(true);
const [loadProgress, setLoadProgress] = useState(0);
const [isConnected, setIsConnected] = useState(true);
const [canGoBack, setCanGoBack] = useState(false);
const [currentUrl, setCurrentUrl] = useState('');
const webViewRef = useRef(null);
// 🔴 CONFIGURE YOUR WEBSITE
const WEBSITE_URL = 'https://your-website.com';
const SPLASH_DURATION = 3000;
// Network connectivity monitoring
useEffect(() => {
const unsubscribe = NetInfo.addEventListener(state => {
setIsConnected(state.isConnected);
if (!state.isConnected) {
Alert.alert('No Internet', 'Please check your connection');
}
});
return () => unsubscribe();
}, []);
// Splash screen timer
useEffect(() => {
const timer = setTimeout(() => {
setShowSplash(false);
}, SPLASH_DURATION);
return () => clearTimeout(timer);
}, []);
// Android back button handler
useEffect(() => {
const backHandler = BackHandler.addEventListener(
'hardwareBackPress',
handleBackPress
);
return () => backHandler.remove();
}, [canGoBack]);
// Handle back button press
const handleBackPress = () => {
if (canGoBack && webViewRef.current) {
webViewRef.current.goBack();
return true;
}
Alert.alert(
'Exit App',
'Do you want to exit?',
[
{ text: 'Cancel', style: 'cancel' },
{ text: 'Exit', onPress: () => BackHandler.exitApp() }
]
);
return true;
};
// Handle navigation state changes
const handleNavigationStateChange = (navState) => {
setCanGoBack(navState.canGoBack);
setCurrentUrl(navState.url);
};
// Handle URL opening (external links)
const handleShouldStartLoadWithRequest = (request) => {
// Handle external links
if (request.url.startsWith('http://') || request.url.startsWith('https://')) {
// Check if it's your domain
if (!request.url.includes(WEBSITE_URL.replace('https://', '').replace('http://', ''))) {
Linking.openURL(request.url);
return false;
}
}
// Handle phone calls
if (request.url.startsWith('tel:')) {
Linking.openURL(request.url);
return false;
}
// Handle emails
if (request.url.startsWith('mailto:')) {
Linking.openURL(request.url);
return false;
}
return true;
};
// Share functionality
const handleShare = async () => {
try {
await Share.open({
title: 'Share this app',
message: `Check out this amazing app: ${currentUrl}`,
url: currentUrl,
});
} catch (error) {
console.log('Error sharing:', error);
}
};
// Refresh page
const handleRefresh = () => {
if (webViewRef.current) {
webViewRef.current.reload();
}
};
// JavaScript to inject into WebView
const injectedJavaScript = `
// Disable zoom
const meta = document.createElement('meta');
meta.setAttribute('content', 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no');
meta.setAttribute('name', 'viewport');
document.getElementsByTagName('head')[0].appendChild(meta);
// Send messages to React Native
window.ReactNativeWebView.postMessage(JSON.stringify({
type: 'PAGE_LOADED',
url: window.location.href
}));
true;
`;
// Handle messages from WebView
const handleMessage = (event) => {
try {
const data = JSON.parse(event.nativeEvent.data);
console.log('Message from WebView:', data);
} catch (error) {
console.log('Error parsing message:', error);
}
};
// Show splash screen
if (showSplash) {
return ;
}
return (
{/* Offline Notice */}
{!isConnected && }
{/* Loading Progress Bar */}
{isLoading && (
)}
{/* Action Buttons */}
🔄
📤
{canGoBack && (
webViewRef.current?.goBack()}>
⬅️
)}
{/* WebView */}
{
setIsLoading(true);
setLoadProgress(0);
}}
onLoadProgress={({ nativeEvent }) => {
setLoadProgress(nativeEvent.progress);
}}
onLoadEnd={() => {
setIsLoading(false);
setLoadProgress(1);
}}
// Error handling
onError={(syntheticEvent) => {
const { nativeEvent } = syntheticEvent;
console.warn('WebView error:', nativeEvent);
Alert.alert('Error', 'Failed to load page. Please try again.');
}}
// Navigation
onNavigationStateChange={handleNavigationStateChange}
onShouldStartLoadWithRequest={handleShouldStartLoadWithRequest}
// Message handling
onMessage={handleMessage}
injectedJavaScript={injectedJavaScript}
// Settings
javaScriptEnabled={true}
domStorageEnabled={true}
startInLoadingState={true}
scalesPageToFit={true}
allowsBackForwardNavigationGestures={true}
allowsInlineMediaPlayback={true}
mediaPlaybackRequiresUserAction={false}
// Security
mixedContentMode="compatibility"
allowFileAccess={false}
// Performance
cacheEnabled={true}
cacheMode="LOAD_DEFAULT"
// Pull to refresh (iOS)
bounces={true}
pullToRefreshEnabled={true}
// Custom headers
// headers={{
// 'Custom-Header': 'value'
// }}
/>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ffffff',
},
webview: {
flex: 1,
},
progressBar: {
height: 3,
width: '100%',
backgroundColor: '#e0e0e0',
},
progress: {
height: '100%',
backgroundColor: '#667eea',
},
actionBar: {
flexDirection: 'row',
justifyContent: 'flex-end',
padding: 10,
backgroundColor: '#f7fafc',
borderBottomWidth: 1,
borderBottomColor: '#e2e8f0',
},
actionButton: {
marginLeft: 15,
padding: 8,
},
actionText: {
fontSize: 20,
},
});
export default App;
Create folder: components and create file SplashScreen.js
import React, { useEffect, useRef } from 'react';
import {
View,
Text,
Image,
StyleSheet,
Animated,
StatusBar,
Dimensions,
} from 'react-native';
const { width, height } = Dimensions.get('window');
const SplashScreen = () => {
const fadeAnim = useRef(new Animated.Value(0)).current;
const scaleAnim = useRef(new Animated.Value(0.3)).current;
useEffect(() => {
Animated.parallel([
Animated.timing(fadeAnim, {
toValue: 1,
duration: 1000,
useNativeDriver: true,
}),
Animated.spring(scaleAnim, {
toValue: 1,
friction: 4,
useNativeDriver: true,
}),
]).start();
}, []);
return (
{/* Animated Background */}
{/* Logo */}
{/* App Name */}
My Awesome App
{/* Tagline */}
Your tagline here
{/* Loading Indicator */}
{/* Footer */}
© 2024 Your Company
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#667eea',
justifyContent: 'center',
alignItems: 'center',
position: 'relative',
},
backgroundCircle1: {
position: 'absolute',
width: width * 1.5,
height: width * 1.5,
borderRadius: width * 0.75,
backgroundColor: 'rgba(118, 75, 162, 0.3)',
top: -width * 0.5,
right: -width * 0.3,
},
backgroundCircle2: {
position: 'absolute',
width: width * 1.2,
height: width * 1.2,
borderRadius: width * 0.6,
backgroundColor: 'rgba(118, 75, 162, 0.2)',
bottom: -width * 0.4,
left: -width * 0.2,
},
logoContainer: {
marginBottom: 30,
},
logo: {
width: 150,
height: 150,
},
appName: {
fontSize: 32,
fontWeight: 'bold',
color: '#ffffff',
marginBottom: 10,
textAlign: 'center',
},
tagline: {
fontSize: 16,
color: 'rgba(255, 255, 255, 0.8)',
marginBottom: 40,
textAlign: 'center',
},
loadingContainer: {
flexDirection: 'row',
marginTop: 20,
},
loadingDot: {
width: 10,
height: 10,
borderRadius: 5,
backgroundColor: '#ffffff',
marginHorizontal: 5,
opacity: 0.7,
},
loadingDotDelay1: {
opacity: 0.5,
},
loadingDotDelay2: {
opacity: 0.3,
},
footer: {
position: 'absolute',
bottom: 30,
fontSize: 12,
color: 'rgba(255, 255, 255, 0.6)',
},
});
export default SplashScreen;
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const OfflineNotice = () => {
return (
⚠️ No Internet Connection
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: '#ff6b6b',
padding: 10,
alignItems: 'center',
},
text: {
color: '#ffffff',
fontSize: 14,
fontWeight: '600',
},
});
export default OfflineNotice;
Edit android/app/src/main/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
android:hardwareAccelerated="true">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Deep Linking -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="your-website.com" />
</intent-filter>
</activity>
<!-- File Provider for file sharing -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>
Edit android/app/build.gradle - Add these to dependencies:
dependencies {
implementation "com.facebook.react:react-native:+"
// WebView
implementation project(':react-native-webview')
// Network Info
implementation project(':react-native-community_netinfo')
}
Edit ios/MyAdvancedWebApp/Info.plist
<dict>
<!-- App Transport Security -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<!-- Camera Permission -->
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to upload photos</string>
<!-- Photo Library Permission -->
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs photo library access</string>
<!-- Microphone Permission -->
<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access</string>
<!-- URL Schemes for Deep Linking -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
</dict>
// Add this useEffect for deep linking
useEffect(() => {
// Handle initial URL
Linking.getInitialURL().then(url => {
if (url && webViewRef.current) {
webViewRef.current.injectJavaScript(
`window.location.href = '${url}';`
);
}
});
// Handle URL updates
const subscription = Linking.addEventListener('url', ({ url }) => {
if (url && webViewRef.current) {
webViewRef.current.injectJavaScript(
`window.location.href = '${url}';`
);
}
});
return () => subscription.remove();
}, []);
# In project root
mkdir assets
# Add your logo
# Place logo.png (512x512 recommended) in assets folder
Replace icons in android/app/src/main/res/
Use Xcode to add icons to ios/MyAdvancedWebApp/Images.xcassets/AppIcon.appiconset/
# Android
npx react-native run-android
# iOS
npx react-native run-ios
# Build Release APK (Android)
cd android
./gradlew assembleRelease
# APK location: android/app/build/outputs/apk/release/app-release.apk
Native pull-to-refresh gesture on iOS
Smart Android back button navigation
Real-time network status detection
Native share dialog for content
Visual loading progress indicator
Handle external URLs and app links
Beautiful animated splash screen
Optimized caching and rendering
Custom headers and cookie control
Camera, phone, email integration
Works seamlessly on iOS & Android
Two-way communication with website
WEBSITE_URL in App.jsassets/logo.pngandroid/app/build.gradle// Add to WebView props
onFileDownload={({ nativeEvent }) => {
const { downloadUrl } = nativeEvent;
// Handle file download
console.log('Download:', downloadUrl);
}}
// Modify existing injectedJavaScript
const injectedJavaScript = `
// Hide specific elements
const element = document.querySelector('.ads');
if (element) element.style.display = 'none';
// Add custom CSS
const style = document.createElement('style');
style.innerHTML = 'body { font-size: 16px !important; }';
document.head.appendChild(style);
// Track user interactions
document.addEventListener('click', (e) => {
window.ReactNativeWebView.postMessage(JSON.stringify({
type: 'CLICK',
target: e.target.tagName
}));
});
true;
`;
import CookieManager from '@react-native-cookies/cookies';
// Clear cookies
CookieManager.clearAll().then(() => {
console.log('Cookies cleared');
});
// Get cookies
CookieManager.get('https://your-site.com').then((cookies) => {
console.log('Cookies:', cookies);
});
cd ios && pod install and rebuild
# If you need more features, install these:
# Push Notifications
npm install @react-native-firebase/app
npm install @react-native-firebase/messaging
# Analytics
npm install @react-native-firebase/analytics
# Geolocation
npm install @react-native-community/geolocation
# AsyncStorage (for local data)
npm install @react-native-async-storage/async-storage
# Biometric Authentication
npm install react-native-biometrics
# QR Code Scanner
npm install react-native-camera
# In-App Browser
npm install react-native-inappbrowser-reborn
startInLoadingState for smooth transitionsshouldComponentUpdate for React optimization# Generate signing key
keytool -genkeypair -v -storetype PKCS12 -keystore my-app.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
# Edit android/gradle.properties
MYAPP_UPLOAD_STORE_FILE=my-app.keystore
MYAPP_UPLOAD_KEY_ALIAS=my-key-alias
MYAPP_UPLOAD_STORE_PASSWORD=*****
MYAPP_UPLOAD_KEY_PASSWORD=*****
# Build
cd android
./gradlew bundleRelease
# Output: android/app/build/outputs/bundle/release/app-release.aab
# Open Xcode
open ios/MyAdvancedWebApp.xcworkspace
# In Xcode:
# 1. Select Product > Archive
# 2. Organizer will open
# 3. Select "Distribute App"
# 4. Follow App Store submission steps
You now have a production-ready React Native app with all advanced features including:
React Native WebView app is ready for production
zenbyt web to app conversion documentation