app_health_pings 0.0.1
app_health_pings: ^0.0.1 copied to clipboard
Low-overhead heartbeats and basic device info to your backend. Helps catch broken builds and environment drift early.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:app_health_pings/app_health_pings.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize health pings with your backend endpoint
await AppHealthPings.initialize(
AppHealthConfig(
endpoint: Uri.parse('https://your-backend.com/health-pings'),
authToken: 'your-optional-bearer-token',
tags: {
'env': 'development',
'version': '1.0.0',
'build': 'debug',
},
interval: const Duration(minutes: 5), // Ping every 5 minutes
maxInterval: const Duration(minutes: 30), // Max backoff
enabled: true,
sendOnStart: true,
sendOnResume: true,
collectDeviceInfo: true,
connectTimeout: const Duration(seconds: 10),
),
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'App Health Pings Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'App Health Pings Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _lastPingStatus = 'Not sent yet';
bool _isHeartbeatActive = true;
void _sendManualPing() async {
setState(() {
_lastPingStatus = 'Sending...';
});
try {
await AppHealthPings.pingNow(
reason: 'manual_trigger',
extra: {
'user_action': 'button_press',
'timestamp': DateTime.now().toIso8601String(),
},
);
setState(() {
_lastPingStatus = 'Manual ping sent successfully!';
});
} catch (e) {
setState(() {
_lastPingStatus = 'Failed to send ping: $e';
});
}
}
void _toggleHeartbeat() {
setState(() {
_isHeartbeatActive = !_isHeartbeatActive;
});
if (_isHeartbeatActive) {
AppHealthPings.startHeartbeat();
} else {
AppHealthPings.stopHeartbeat();
}
}
void _sendCustomPing() async {
setState(() {
_lastPingStatus = 'Sending custom ping...';
});
try {
await AppHealthPings.pingNow(
reason: 'feature_usage',
extra: {
'feature': 'custom_ping_demo',
'user_id': 'demo_user_123',
'session_data': {
'screen': 'home',
'action': 'custom_ping_button',
},
},
);
setState(() {
_lastPingStatus = 'Custom ping with extra data sent!';
});
} catch (e) {
setState(() {
_lastPingStatus = 'Failed to send custom ping: $e';
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'App Health Pings Status',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text('Last Action: $_lastPingStatus'),
const SizedBox(height: 8),
Row(
children: [
const Text('Heartbeat: '),
Icon(
_isHeartbeatActive ? Icons.favorite : Icons.favorite_border,
color: _isHeartbeatActive ? Colors.red : Colors.grey,
),
Text(_isHeartbeatActive ? ' Active' : ' Stopped'),
],
),
],
),
),
),
const SizedBox(height: 24),
const Text(
'Demo Actions:',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
ElevatedButton.icon(
onPressed: _sendManualPing,
icon: const Icon(Icons.send),
label: const Text('Send Manual Ping'),
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _sendCustomPing,
icon: const Icon(Icons.data_usage),
label: const Text('Send Custom Ping with Extra Data'),
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _toggleHeartbeat,
icon: Icon(_isHeartbeatActive ? Icons.pause : Icons.play_arrow),
label: Text(_isHeartbeatActive ? 'Stop Heartbeat' : 'Start Heartbeat'),
),
const SizedBox(height: 24),
const Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'What This Demo Shows:',
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Text('• Automatic health pings every 5 minutes'),
Text('• Manual ping triggers'),
Text('• Custom pings with extra payload data'),
Text('• Heartbeat control (start/stop)'),
Text('• App lifecycle pings (resume/start)'),
Text('• Device info and connectivity collection'),
],
),
),
),
const SizedBox(height: 16),
const Card(
color: Colors.orange,
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.warning, color: Colors.white),
SizedBox(width: 8),
Text(
'Note:',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
SizedBox(height: 8),
Text(
'This demo uses a placeholder endpoint. Replace with your actual backend URL in main.dart to see real pings.',
style: TextStyle(color: Colors.white),
),
],
),
),
),
],
),
),
);
}
}