Skip to content

Distribution

Beyond the official app stores, there are various ways to distribute your rebranded Lumo app. This guide covers alternative distribution methods, enterprise deployment, and web-based solutions.

MethodProsConsBest For
App StoresWide reach, trust, automatic updatesStore fees, review processGeneral public
Direct APK/IPAFull control, no feesManual updates, security concernsBeta testing, internal use
Enterprise DistributionInternal deploymentLimited to organizationCorporate environments
Progressive Web AppCross-platform, easy updatesLimited native featuresWeb-first users
F-DroidOpen source communityLimited reachPrivacy-focused users
  • Reach: 2.5+ billion active devices
  • Fee: $25 one-time registration + 15-30% commission
  • Review: Automated + manual review
  • Distribution: Global, automatic updates
  • Reach: 1+ billion active devices
  • Fee: $99/year + 15-30% commission
  • Review: Manual review process
  • Distribution: Global, automatic updates
  • Maximum user reach and discoverability
  • Built-in payment processing
  • Automatic update mechanism
  • User trust and security validation
  • Marketing and promotional opportunities
Terminal window
# Build release APK
flutter build apk --release --obfuscate --split-debug-info=build/debug-info
# Install directly on device
adb install build/app/outputs/flutter-apk/app-release.apk

Setup Web Server:

<!DOCTYPE html>
<html>
<head>
<title>YourAuth - Download</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div class="download-page">
<h1>Download YourAuth</h1>
<p>Secure two-factor authentication for your devices</p>
<div class="download-section">
<h2>Android</h2>
<a href="downloads/yourauth-v1.0.0.apk" class="download-btn">
Download APK (v1.0.0)
</a>
<p><small>Requires Android 6.0 or later</small></p>
</div>
<div class="installation-guide">
<h3>Installation Instructions</h3>
<ol>
<li>Download the APK file</li>
<li>Enable "Unknown Sources" in Settings</li>
<li>Tap the downloaded file to install</li>
<li>Grant necessary permissions</li>
</ol>
</div>
</div>
</body>
</html>

APK Signing Verification:

Terminal window
# Verify APK signature
apksigner verify --verbose yourauth-v1.0.0.apk
# Check certificate details
keytool -printcert -jarfile yourauth-v1.0.0.apk

Best Practices:

  • Always sign APKs with your release certificate
  • Provide SHA-256 checksums for verification
  • Use HTTPS for download links
  • Include installation instructions
  • Warn users about security implications

Requirements:

  • Apple Enterprise Developer Program ($299/year)
  • In-house distribution certificate
  • Enterprise provisioning profile

Build Process:

Terminal window
# Build for enterprise distribution
flutter build ios --release --obfuscate --split-debug-info=build/debug-info
# Archive in Xcode with enterprise profile
# Export as Enterprise IPA

Limitations:

  • Maximum 100 test devices per year
  • Requires device UDIDs to be registered
  • Intended for testing, not production

Process:

  1. Register device UDIDs in Apple Developer Portal
  2. Create Ad Hoc provisioning profile
  3. Build and sign IPA with Ad Hoc profile
  4. Distribute via TestFlight or direct installation
web/service-worker.js
const CACHE_NAME = 'yourauth-v1.0.0';
const urlsToCache = [
'/',
'/static/js/bundle.js',
'/static/css/main.css',
'/manifest.json'
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => cache.addAll(urlsToCache))
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((response) => {
return response || fetch(event.request);
})
);
});
{
"name": "YourAuth",
"short_name": "YourAuth",
"description": "Secure two-factor authentication",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#1976d2",
"icons": [
{
"src": "/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
// web/index.html additions
<head>
<!-- PWA configuration -->
<link rel="manifest" href="manifest.json">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="YourAuth">
<!-- Service Worker -->
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('flutter-first-frame', function () {
navigator.serviceWorker.register('flutter_service_worker.js');
});
}
</script>
</head>

Missing Features:

  • Camera access (limited on iOS)
  • Biometric authentication
  • Push notifications (limited)
  • Full screen access
  • Direct file system access

Alternatives:

  • Use WebRTC for camera access
  • Implement PIN-based authentication
  • Use web push for notifications
  • Provide file download/upload

Requirements:

  • Open source code
  • No proprietary dependencies
  • Reproducible builds
  • FOSS license

Submission Process:

  1. Make source code available
  2. Submit merge request to F-Droid repository
  3. F-Droid builds app from source
  4. Review and approval process

Benefits:

  • Privacy-focused user base
  • No Google Play Services dependency
  • Free distribution
  • Open source community trust

Submission Process:

  1. Create Amazon Developer account
  2. Upload APK (same as Play Store build)
  3. Complete app information
  4. Submit for review

Considerations:

  • Smaller user base than Google Play
  • Good for Fire TV/Tablet distribution
  • Different review process and guidelines

Benefits:

  • Pre-installed on Samsung devices
  • Good for Samsung ecosystem integration
  • Alternative revenue stream

Considerations:

  • Important for markets without Google Play
  • Growing user base in certain regions
  • Requires Huawei Developer account
Terminal window
# Example with Microsoft Intune
# Upload APK to Intune portal
# Configure app protection policies
# Deploy to managed devices

Setup:

  1. Create internal app catalog
  2. Host APK/IPA files securely
  3. Implement device authentication
  4. Provide installation instructions

Example Enterprise Portal:

<div class="enterprise-portal">
<h1>Company Apps</h1>
<div class="app-card">
<img src="yourauth-icon.png" alt="YourAuth">
<h3>YourAuth Enterprise</h3>
<p>Two-factor authentication for company accounts</p>
<div class="download-options">
<a href="downloads/yourauth-enterprise-android.apk">Android</a>
<a href="downloads/yourauth-enterprise-ios.ipa">iOS</a>
</div>
</div>
</div>

Pre-configured Settings:

lib/config/enterprise_config.dart
class EnterpriseConfig {
static const bool isEnterpriseMode = bool.fromEnvironment('ENTERPRISE_MODE');
static const String companyName = String.fromEnvironment('COMPANY_NAME', defaultValue: 'Your Company');
static const String supportEmail = String.fromEnvironment('SUPPORT_EMAIL', defaultValue: 'support@company.com');
static const bool enforceBackup = bool.fromEnvironment('ENFORCE_BACKUP', defaultValue: true);
// Pre-configured accounts
static const List<String> preConfiguredServices = [
'company-sso',
'company-vpn',
'company-email',
];
}
Terminal window
# Android enterprise build
flutter build apk --release \
--dart-define=ENTERPRISE_MODE=true \
--dart-define=COMPANY_NAME="Acme Corp" \
--dart-define=SUPPORT_EMAIL="it-support@acme.com"
# iOS enterprise build
flutter build ios --release \
--dart-define=ENTERPRISE_MODE=true \
--dart-define=COMPANY_NAME="Acme Corp"
lib/services/update_service.dart
class UpdateService {
static const String updateCheckUrl = 'https://yourapp.com/api/version';
Future<UpdateInfo?> checkForUpdates() async {
try {
final response = await http.get(Uri.parse(updateCheckUrl));
final data = json.decode(response.body);
final latestVersion = data['latest_version'];
final currentVersion = await PackageInfo.fromPlatform().then((info) => info.version);
if (_isNewerVersion(latestVersion, currentVersion)) {
return UpdateInfo(
version: latestVersion,
downloadUrl: data['download_url'],
changelog: data['changelog'],
isRequired: data['is_required'] ?? false,
);
}
return null;
} catch (e) {
return null;
}
}
bool _isNewerVersion(String latest, String current) {
// Implement semantic version comparison
return latest.compareTo(current) > 0;
}
}
lib/widgets/update_dialog.dart
class UpdateDialog extends StatelessWidget {
final UpdateInfo updateInfo;
const UpdateDialog({super.key, required this.updateInfo});
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Update Available'),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Version ${updateInfo.version} is available'),
const SizedBox(height: 16),
Text('Changes:'),
Text(updateInfo.changelog),
],
),
actions: [
if (!updateInfo.isRequired)
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Later'),
),
ElevatedButton(
onPressed: () => _downloadUpdate(updateInfo.downloadUrl),
child: const Text('Update'),
),
],
);
}
void _downloadUpdate(String url) {
// Open download URL or trigger in-app update
launch(url);
}
}
// Add dependency: in_app_update
dependencies:
in_app_update: ^4.2.2
lib/services/in_app_update_service.dart
import 'package:in_app_update/in_app_update.dart';
class InAppUpdateService {
Future<void> checkForUpdate() async {
final updateInfo = await InAppUpdate.checkForUpdate();
if (updateInfo.updateAvailability == UpdateAvailability.updateAvailable) {
if (updateInfo.immediateUpdateAllowed) {
await InAppUpdate.performImmediateUpdate();
} else if (updateInfo.flexibleUpdateAllowed) {
await InAppUpdate.startFlexibleUpdate();
}
}
}
}
  • Always sign release builds
  • Use different certificates for debug/release
  • Protect signing keys securely
  • Verify signatures before distribution
Terminal window
# Generate checksums
sha256sum yourauth-v1.0.0.apk > yourauth-v1.0.0.apk.sha256
# Publish checksums alongside downloads
# Users can verify: sha256sum -c yourauth-v1.0.0.apk.sha256

HTTPS Requirements:

  • Use HTTPS for all download links
  • Implement certificate pinning if hosting yourself
  • Validate SSL certificates

Access Control:

  • Implement authentication for enterprise distributions
  • Use signed URLs for temporary download access
  • Log download activities
  • Ensure open source license compliance
  • Include required attribution
  • Document third-party components
  • Update terms for direct distribution
  • Clarify support responsibilities
  • Define usage limitations
  • Update for different distribution methods
  • Clarify data collection practices
  • Include contact information
// Track downloads with Google Analytics
gtag('event', 'download', {
event_category: 'app',
event_label: 'android_apk',
value: 1
});
// Track installation completion
class InstallationTracker {
static Future<void> trackFirstLaunch() async {
final prefs = await SharedPreferences.getInstance();
final isFirstLaunch = prefs.getBool('first_launch') ?? true;
if (isFirstLaunch) {
await prefs.setBool('first_launch', false);
// Send analytics event
await Analytics.track('app_installed', {
'distribution_method': 'direct_apk',
'timestamp': DateTime.now().toIso8601String(),
});
}
}
}
lib/widgets/feedback_dialog.dart
class FeedbackDialog extends StatefulWidget {
@override
State<FeedbackDialog> createState() => _FeedbackDialogState();
}
class _FeedbackDialogState extends State<FeedbackDialog> {
final _feedbackController = TextEditingController();
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Send Feedback'),
content: TextField(
controller: _feedbackController,
decoration: const InputDecoration(
hintText: 'Tell us what you think...',
),
maxLines: 5,
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Cancel'),
),
ElevatedButton(
onPressed: _submitFeedback,
child: const Text('Send'),
),
],
);
}
void _submitFeedback() {
// Send feedback to your backend
FeedbackService.submitFeedback(_feedbackController.text);
Navigator.of(context).pop();
}
}

Your app distribution strategy is now comprehensive and flexible! 📦

  1. Build Process - Automated build and deployment
  2. Development Setup - Continue development
  3. Architecture - Technical deep dive