Cross-Platform Mobile Development
Introduction
Cross-platform development allows you to build mobile applications that run on multiple platforms using a single codebase. This guide covers popular frameworks and best practices for cross-platform development.
Key Benefits:
- Single codebase for multiple platforms
- Faster development time
- Cost-effective maintenance
- Consistent user experience
- Broader market reach
- Code reusability
React Native Development
Basic App Structure
// App.js
import React, { useState } from 'react';
import {
View,
Text,
TextInput,
TouchableOpacity,
StyleSheet,
Alert
} from 'react-native';
const App = () => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleLogin = () => {
if (!username || !password) {
Alert.alert('Error', 'Please fill in all fields');
return;
}
// Add login logic here
console.log('Login:', { username, password });
};
return (
Welcome
Login
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
padding: 20,
backgroundColor: '#fff',
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 20,
textAlign: 'center',
},
input: {
height: 50,
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 8,
marginBottom: 15,
paddingHorizontal: 15,
},
button: {
backgroundColor: '#007AFF',
height: 50,
borderRadius: 8,
justifyContent: 'center',
alignItems: 'center',
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: 'bold',
},
});
Custom Components
// components/CustomButton.js
import React from 'react';
import {
TouchableOpacity,
Text,
StyleSheet,
ActivityIndicator
} from 'react-native';
const CustomButton = ({
title,
onPress,
isLoading,
disabled,
style,
}) => {
return (
{isLoading ? (
) : (
{title}
)}
);
};
const styles = StyleSheet.create({
button: {
backgroundColor: '#007AFF',
padding: 15,
borderRadius: 8,
alignItems: 'center',
},
disabled: {
backgroundColor: '#ccc',
},
text: {
color: '#fff',
fontSize: 16,
fontWeight: 'bold',
},
});
export default CustomButton;
Flutter Development
Basic App Structure
// main.dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: LoginScreen(),
);
}
}
class LoginScreen extends StatefulWidget {
@override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State {
final _formKey = GlobalKey();
String? _username;
String? _password;
bool _isLoading = false;
void _handleLogin() {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
setState(() => _isLoading = true);
// Simulate API call
Future.delayed(Duration(seconds: 2), () {
setState(() => _isLoading = false);
print('Login: $_username, $_password');
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Login')),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextFormField(
decoration: InputDecoration(
labelText: 'Username',
border: OutlineInputBorder(),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter username';
}
return null;
},
onSaved: (value) => _username = value,
),
SizedBox(height: 16),
TextFormField(
decoration: InputDecoration(
labelText: 'Password',
border: OutlineInputBorder(),
),
obscureText: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter password';
}
return null;
},
onSaved: (value) => _password = value,
),
SizedBox(height: 24),
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: _isLoading ? null : _handleLogin,
child: _isLoading
? CircularProgressIndicator(color: Colors.white)
: Text('Login'),
),
),
],
),
),
),
);
}
}
Custom Widget
// custom_button.dart
import 'package:flutter/material.dart';
class CustomButton extends StatelessWidget {
final String title;
final VoidCallback onPressed;
final bool isLoading;
final bool disabled;
const CustomButton({
Key? key,
required this.title,
required this.onPressed,
this.isLoading = false,
this.disabled = false,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: (disabled || isLoading) ? null : onPressed,
style: ElevatedButton.styleFrom(
primary: disabled ? Colors.grey : Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: isLoading
? SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
color: Colors.white,
strokeWidth: 2,
),
)
: Text(
title,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
);
}
}
Xamarin Development
Basic App Structure
// LoginPage.xaml.cs
using Xamarin.Forms;
public partial class LoginPage : ContentPage
{
private readonly LoginViewModel _viewModel;
public LoginPage()
{
InitializeComponent();
_viewModel = new LoginViewModel();
BindingContext = _viewModel;
}
}
// LoginViewModel.cs
public class LoginViewModel : INotifyPropertyChanged
{
private string _username;
private string _password;
private bool _isLoading;
private ICommand _loginCommand;
public string Username
{
get => _username;
set
{
_username = value;
OnPropertyChanged();
}
}
public string Password
{
get => _password;
set
{
_password = value;
OnPropertyChanged();
}
}
public bool IsLoading
{
get => _isLoading;
set
{
_isLoading = value;
OnPropertyChanged();
}
}
public ICommand LoginCommand
{
get
{
return _loginCommand ?? (_loginCommand =
new Command(async () => await Login()));
}
}
private async Task Login()
{
if (string.IsNullOrEmpty(Username) ||
string.IsNullOrEmpty(Password))
{
await Application.Current.MainPage
.DisplayAlert("Error", "Please fill in all fields", "OK");
return;
}
IsLoading = true;
try
{
// Add login logic here
await Task.Delay(2000); // Simulate API call
Debug.WriteLine($"Login: {Username}, {Password}");
}
catch (Exception ex)
{
await Application.Current.MainPage
.DisplayAlert("Error", ex.Message, "OK");
}
finally
{
IsLoading = false;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(
[CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(propertyName));
}
}
Deployment
Deployment Steps:
- Android Deployment:
- Generate signed APK
- Configure Play Store listing
- Upload APK/Bundle
- Release management
- iOS Deployment:
- Code signing
- App Store Connect setup
- TestFlight testing
- App Store submission
Framework Comparison
React Native:
- Pros:
- Large community
- JavaScript/React familiarity
- Hot reloading
- Native performance
- Cons:
- Bridge overhead
- Platform-specific code
- Native module dependencies
Flutter:
- Pros:
- Single UI codebase
- High performance
- Rich widget library
- Great documentation
- Cons:
- Dart learning curve
- Larger app size
- Newer ecosystem
Xamarin:
- Pros:
- C# development
- Native UI
- Microsoft support
- Code sharing
- Cons:
- Smaller community
- Platform-specific UI
- Commercial licensing