Moving Swiftly, to Dart
When you’ve spent years immersed in building sleek and responsive apps on iOS using Swift and Objective-C, the opportunity to delve into new territories like Dart and Flutter presents itself as an exciting adventure. I recently embarked on a journey to learn to build apps with Flutter, and this is my initial experience. I will say, that I’m primarily still focused on iOS app development, but I am always interested in being able to offer Android Apps in addition to the iOS apps. And that is typically difficult to do, having to manage two individual apps can be quite time-consuming. Every update in one requires an update in the other, and you also have to keep on top of both OS revisions, tool revisions, etc. It’s quite a lot to expect a single engineer to manage Android and iOS development well. So the idea of using a cross-platform tool is very exciting.
The Entryway: Dart and Flutter
The Dart language reminded me of Kotlin, or Java. Dart’s syntax is clear and concise, and though it deviates from Swift, I found it readable and pleasant. Dart can be executed using a Dart virutal machine and Just-In-Time compilation and/or it can be compiled to native code. Offering both makes development easier, and production build run fast. I really enjoyed Dart.
Flutter is like a robust, externally sourced framework that transforms UI building. It reminds me a bit of Apache Flask. Here is a random example of flask and flutter for a login screen, just to show how they are similar. I suppose all UI frameworks are similar, and I also saw similarities with UI building in iOS (but lacking the awesome tooling of XCode)
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="955" minHeight="600">
<s:VGroup horizontalAlign="center" verticalAlign="middle" width="100%" height="100%">
<s:Label text="Login" fontSize="24" marginBottom="20"/>
<s:Form width="300">
<s:FormItem label="Username:">
<s:TextInput id="usernameInput"/>
</s:FormItem>
<s:FormItem label="Password:">
<s:TextInput id="passwordInput" displayAsPassword="true"/>
</s:FormItem>
<s:Button label="Login" click="login()"/>
</s:Form>
</s:VGroup>
<fx:Script>
<![CDATA[
private function login():void {
// Handle login logic here
var username:String = usernameInput.text;
var password:String = passwordInput.text;
trace("Username: " + username + ", Password: " + password);
}
]]>
</fx:Script>
</s:Application>
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Login',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: LoginScreen(),
);
}
}
class LoginScreen extends StatelessWidget {
final TextEditingController _usernameController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
void _login(BuildContext context) {
final username = _usernameController.text;
final password = _passwordController.text;
print('Username: $username, Password: $password');
// Handle login logic here
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Login'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: _usernameController,
decoration: InputDecoration(labelText: 'Username'),
),
TextField(
controller: _passwordController,
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () => _login(context),
child: Text('Login'),
),
],
),
),
);
}
}
Widgets: Flutter’s Building Blocks
In Flutter, everything is a widget—a bit like UIView, but with greater range and composability. Stateless and Stateful widgets are Flutter’s equivalents to plain old structuring and dynamic, event-driven view controllers. Understanding widget trees becomes pivotal, much like mastering UIView hierarchies in iOS.
The example above shows quite a few widgets. But it really gets interesting when you are building an app, and deciding which widgets you want to use for what. There are many choices and best practices to learn as you go.
Cocoapods? Meet Pubspec.yaml
One impending question was, where’s my Podfile? In Flutter, pubspec.yaml
steps in. This Flutter file manages your project’s packages—akin but not quite a direct replacement to CocoaPods in the iOS ecosystem. After adding dependencies here, running ‘flutter pub get
’ will fetch the necessary packages. Here is an excerpt of the pubspec from the app. As you can see it has dependencies, but also defines the app, including assets and fonts.
name: fc_mobile
description: "Client Mobile app mostly focused on reading content."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1
environment:
sdk: ^3.5.3
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
# adding Firebase libs
firebase_core: ^3.4.0
firebase_auth: ^5.2.0
# cloud_functions: ^4.1.0
cloud_firestore: ^5.4.0
firebase_storage: ^12.2.0
firebase_ui_auth: ^1.16.0
google_fonts: ^6.2.1
# intl
flutter_localizations:
sdk: flutter
easy_localization: ^3.0.0
# cached images
cached_network_image: ^3.3.0
Making the UI iOS-Like
Creating an iOS-like UI in Flutter is undoubtedly possible. Flutter’s Cupertino library translates familiar native iOS aesthetics, from navigation bars to icons, into the widget ecosystem. However, it’s not plug-and-play. Attention to design patters and some fine-tuning, like adjusting fonts and icons, goes a long way in capturing that sleek iOS feel.
![](https://i0.wp.com/mikelynchgames.com/wp-content/uploads/2025/01/CupertinoFormSection.png?resize=300%2C294&ssl=1)
Building for iOS
When it’s time to build for iOS, Flutter’s integration with Xcode simplifies the process. Running ‘flutter run
’ felt parallel to the smooth process within Xcode—after getting provisioning profiles and certificates in order, of course. The Flutter DevTools also provide a user-friendly route for debugging, offering instruments that are intuitive even for seasoned iOS developers.
The Ecosystem and Community
Whenever I hit roadblocks, the Flutter and Dart community emerged as an invaluable resource. Thanks to detailed documentation and a large community, finding solutions and exploring examples felt very collaborative. Platforms like GitHub are teeming with open-source plugins to augment your apps. For instance, StackOverflow has quite a few answers at the ready.
Wrapping Up
My Flutter project was both an enlightening and challenging experience. It’s a powerful toolkit that offers cross-platform capabilities—isolating from platform constraints. The transition wasn’t without hitches, but Flutter’s structured support system smooths the learning curve significantly.
For any iOS dev contemplating venturing into the cross-platform world, Flutter seems like a dream come true. Not without issues of it’s own, and of course game development is it’s own mixture of tradeoffs, but for many business like applications, Flutter seems fantastic.