Custom Update UI
Build your own update experience using SwiftPatch hooks. Below are four ready-to-use patterns -- pick the one that fits your app.
Pattern 1: Update Banner
A subtle banner at the top of the screen. Great for optional updates.
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { useSwiftPatch, UpdateStatus } from '@swiftpatch/react-native';
function UpdateBanner() {
const { status, availableUpdate, downloadProgress, downloadUpdate, restart } =
useSwiftPatch();
if (status === UpdateStatus.UP_TO_DATE || status === UpdateStatus.CHECKING) {
return null;
}
return (
<View style={styles.banner}>
{status === UpdateStatus.UPDATE_AVAILABLE && (
<TouchableOpacity onPress={downloadUpdate} style={styles.row}>
<Text style={styles.text}>
Version {availableUpdate?.version} available
</Text>
<Text style={styles.action}>Update</Text>
</TouchableOpacity>
)}
{status === UpdateStatus.DOWNLOADING && (
<View style={styles.row}>
<Text style={styles.text}>
Downloading... {downloadProgress?.percentage}%
</Text>
<View style={[styles.progressBar, { width: `${downloadProgress?.percentage}%` }]} />
</View>
)}
{status === UpdateStatus.RESTART_REQUIRED && (
<TouchableOpacity onPress={restart} style={styles.row}>
<Text style={styles.text}>Update ready</Text>
<Text style={styles.action}>Restart</Text>
</TouchableOpacity>
)}
</View>
);
}
const styles = StyleSheet.create({
banner: { backgroundColor: '#6366f1', paddingHorizontal: 16, paddingVertical: 12 },
row: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' },
text: { color: 'white', fontSize: 14 },
action: { color: 'white', fontWeight: 'bold', fontSize: 14 },
progressBar: { position: 'absolute', bottom: 0, left: 0, height: 2, backgroundColor: 'white' },
});
Pattern 2: Full-Screen Modal
A more prominent prompt. Good when you want to encourage users to update.
import React from 'react';
import { Modal, View, Text, Button, ActivityIndicator, StyleSheet } from 'react-native';
import { useSwiftPatch, UpdateStatus } from '@swiftpatch/react-native';
function UpdateModal() {
const { status, availableUpdate, downloadProgress, downloadUpdate, restart } = useSwiftPatch();
const showModal =
status === UpdateStatus.UPDATE_AVAILABLE ||
status === UpdateStatus.DOWNLOADING ||
status === UpdateStatus.RESTART_REQUIRED;
if (!showModal) return null;
return (
<Modal visible animationType="slide" transparent>
<View style={styles.overlay}>
<View style={styles.modal}>
<Text style={styles.title}>Update Available</Text>
<Text style={styles.version}>Version {availableUpdate?.version}</Text>
{availableUpdate?.releaseNote && (
<Text style={styles.description}>{availableUpdate.releaseNote}</Text>
)}
{status === UpdateStatus.UPDATE_AVAILABLE && (
<Button title="Download Update" onPress={downloadUpdate} />
)}
{status === UpdateStatus.DOWNLOADING && (
<View style={styles.progress}>
<ActivityIndicator size="large" color="#6366f1" />
<Text style={styles.progressText}>{downloadProgress?.percentage}%</Text>
</View>
)}
{status === UpdateStatus.RESTART_REQUIRED && (
<Button title="Restart Now" onPress={restart} />
)}
</View>
</View>
</Modal>
);
}
const styles = StyleSheet.create({
overlay: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(0,0,0,0.5)' },
modal: { backgroundColor: 'white', borderRadius: 16, padding: 24, width: '80%', alignItems: 'center' },
title: { fontSize: 20, fontWeight: 'bold', marginBottom: 8 },
version: { fontSize: 16, color: '#6366f1', marginBottom: 12 },
description: { fontSize: 14, color: '#666', textAlign: 'center', marginBottom: 20 },
progress: { alignItems: 'center', gap: 12 },
progressText: { fontSize: 18, fontWeight: 'bold' },
});
Pattern 3: Silent Background Updates
No UI at all. The update downloads and installs silently, then applies on the next restart.
import { useEffect } from 'react';
import { useSwiftPatch, UpdateStatus } from '@swiftpatch/react-native';
function SilentUpdater() {
const { status, downloadUpdate, installUpdate } = useSwiftPatch();
useEffect(() => {
if (status === UpdateStatus.UPDATE_AVAILABLE) {
downloadUpdate()
.then(() => installUpdate())
.catch(console.error);
}
}, [status]);
return null;
}
The update applies on next restart based on installMode.
tip
This is the simplest approach. Users never see an update prompt -- changes just appear next time they open the app.
Pattern 4: Mandatory Update Gate
Block the entire app until a mandatory update is applied:
import { useSwiftPatch, UpdateStatus } from '@swiftpatch/react-native';
function MandatoryUpdateGate({ children }) {
const { availableUpdate, isRestartRequired, restart } = useSwiftPatch();
if (availableUpdate?.isMandatory && isRestartRequired) {
return (
<View style={styles.fullScreen}>
<Text style={styles.title}>Update Required</Text>
<Text>A required update has been downloaded.</Text>
<Button title="Restart Now" onPress={restart} />
</View>
);
}
return children;
}
warning
Only use this pattern for mandatory updates. Blocking optional updates frustrates users.