Refactor Flutter to Swift
Overview
Transform Flutter/Dart codebases into Swift/iOS equivalents with equivalent functionality, architecture, and patterns.
When to Use
- User wants to port an existing Flutter app to iOS
- User asks to "convert Flutter to Swift"
- User has Dart code and wants equivalent Swift
- User mentions "porting Android to iOS"
- User asks to "rewrite this in Swift"
Dart to Swift Mapping
Data Types
| Dart | Swift |
|---|---|
String |
String |
int |
Int |
double |
Double |
bool |
Bool |
List<Type> |
[Type] |
Map<Key, Value> |
[Key: Value] |
Type? |
Type? |
enum |
enum (same) |
class |
class or struct |
abstract class |
protocol |
Common Conversions
// Dart
class User {
final String id;
final String name;
final String? email;
User({required this.id, required this.name, this.email});
}
// Swift
struct User: Codable, Identifiable {
let id: String
var name: String
var email: String?
}
Flutter Widget to SwiftUI
// Flutter
class ContentView extends StatelessWidget {
const ContentView({super.key});
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Count: $_count'),
ElevatedButton(
onPressed: () => setState(() => _count++),
child: const Text('Increment'),
),
],
);
}
}
// SwiftUI
struct ContentView: View {
@State private var count = 0
var body: some View {
VStack {
Text("Count: \(count)")
Button("Increment") {
count += 1
}
}
}
}
Riverpod to Combine
// Dart Riverpod
class UserNotifier extends StateNotifier<AsyncValue<User?>> {
final NetworkService _networkService;
UserNotifier(this._networkService) : super(const AsyncValue.data(null));
Future<void> fetchUser() async {
state = const AsyncValue.loading();
try {
final user = await _networkService.fetchUser();
state = AsyncValue.data(user);
} catch (e, st) {
state = AsyncValue.error(e, st);
}
}
}
final userProvider = StateNotifierProvider<UserNotifier, AsyncValue<User?>>((ref) {
return UserNotifier(ref.read(networkServiceProvider));
});
// Swift Combine
class UserViewModel: ObservableObject {
@Published var user: User?
@Published var isLoading = false
@Published var error: Error?
private let networkService: NetworkService
init(networkService: NetworkService) {
self.networkService = networkService
}
@MainActor
func fetchUser() async {
isLoading = true
error = nil
do {
user = try await networkService.fetchUser()
} catch {
self.error = error
}
isLoading = false
}
}
Dio to URLSession
// Dart Dio
class NetworkService {
final Dio _dio;
Future<User> fetchUser() async {
final response = await _dio.get('/users/1');
return User.fromJson(response.data);
}
}
// Swift URLSession
class NetworkService {
static let shared = NetworkService()
func fetchUser() async throws -> User {
let url = URL(string: "https://api.example.com/users/1")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(User.self, from: data)
}
}
Hive to Core Data
// Dart Hive
@HiveType(typeId: 0)
class UserModel extends HiveObject {
@HiveField(0)
late String id;
@HiveField(1)
late String name;
@HiveField(2)
String? email;
}
// Swift Core Data
@objc(UserEntity)
public class UserEntity: NSManagedObject {
@NSManaged public var id: UUID
@NSManaged public var name: String
@NSManaged public var email: String?
}
Conversion Process
- Analyze Dart code - Identify architecture (Riverpod, BLoC), patterns used
- Map dependencies - Find Flutter-only libraries and find Swift equivalents
- Convert data models - Dart classes to Swift structs/classes
- Convert views - Flutter widgets to SwiftUI views
- Convert state management - Riverpod -> Combine
- Convert networking - Dio -> URLSession
- Convert persistence - Hive/SQLite -> Core Data
- Test equivalence - Ensure same behavior
Best Practices
- Preserve original logic and behavior
- Use Swift idioms, don't just translate literally
- Use Codable for data classes
- Use Combine for reactive state
- Use SwiftUI for views
- Handle async/await properly
- Preserve error handling patterns
- Test both implementations for parity
Source: OMIXEC/Mobile-dev-skills — distributed by TomeVault.