Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ lib/
│ ├── transport/ # Network and batching logic
│ ├── tracing/ # OpenTelemetry integration
│ └── util/ # Shared utilities
ios/Classes/ # iOS-specific implementation (Swift)
ios/faro/Sources/faro/ # iOS-specific implementation (Swift, SPM layout)
android/src/main/java/ # Android-specific implementation (Java)
test/ # Unit and widget tests
example/ # Example Flutter app
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- iOS: Swift Package Manager support (`ios/faro/Package.swift`) alongside CocoaPods,
per [Flutter plugin author guidance](https://docs.flutter.dev/packages-and-plugins/swift-package-manager/for-plugin-authors).

### Changed

- Bump Android `compileSdkVersion` from 35 to 36 (aligned with Flutter default since May 2025).
- iOS: minimum deployment target raised from 11.0 to **13.0** (podspec and SPM).
- iOS: native Swift sources moved from `ios/Classes/` to `ios/faro/Sources/faro/`.
- Raised package `environment` to `sdk: >=3.11.0` and `flutter: >=3.41.0` for Flutter SPM
(`FlutterFramework`) integration.
- iOS CocoaPods: removed stale `vendored_frameworks` / `preserve_paths` for a missing
`CrashReporter.xcframework`; PLCrashReporter continues to come from the pod dependency.
- Dart: removed a deprecated linter rule and small fixes so `flutter analyze` exits cleanly
on current stable.
- Reformatted Dart sources with the current stable `dart format` so CI format checks pass.

## [0.13.0] - 2026-04-09

Expand Down
1 change: 0 additions & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ linter:
- avoid_bool_literals_in_conditional_expressions
- avoid_catching_errors
- avoid_init_to_null
- avoid_null_checks_in_equality_operators
- avoid_positional_boolean_parameters
- avoid_private_typedef_functions
- avoid_redundant_argument_values
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import 'package:faro_example/shared/models/demo_log_entry.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

typedef AppDiagnosticsLogCallback = void Function(
String message, {
DemoLogTone tone,
});
typedef AppDiagnosticsLogCallback =
void Function(String message, {DemoLogTone tone});

final appDiagnosticsDemoServiceProvider = Provider<AppDiagnosticsDemoService>(
(ref) => const AppDiagnosticsDemoService(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ class AppDiagnosticsPage extends ConsumerWidget {
appBar: AppBar(
title: const Text('App Diagnostics'),
actions: [
TextButton(
onPressed: actions.clearLog,
child: const Text('Clear'),
),
TextButton(onPressed: actions.clearLog, child: const Text('Clear')),
],
),
body: Column(
Expand All @@ -38,10 +35,7 @@ class AppDiagnosticsPage extends ConsumerWidget {
),
child: Row(
children: [
Icon(
Icons.warning_amber,
color: Colors.orange.shade800,
),
Icon(Icons.warning_amber, color: Colors.orange.shade800),
const SizedBox(width: 8),
const Expanded(
child: Text(
Expand All @@ -56,10 +50,7 @@ class AppDiagnosticsPage extends ConsumerWidget {
const SizedBox(height: 16),
const Text(
'Failure and ANR demos',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';

/// Immutable UI state for the app diagnostics page.
class AppDiagnosticsPageUiState extends Equatable {
const AppDiagnosticsPageUiState({
required this.log,
required this.isRunning,
});
const AppDiagnosticsPageUiState({required this.log, required this.isRunning});

final List<DemoLogEntry> log;
final bool isRunning;
Expand Down Expand Up @@ -43,24 +40,14 @@ class _AppDiagnosticsPageViewModel extends Notifier<AppDiagnosticsPageUiState>
AppDiagnosticsPageUiState build() {
_service = ref.watch(appDiagnosticsDemoServiceProvider);

return const AppDiagnosticsPageUiState(
log: [],
isRunning: false,
);
return const AppDiagnosticsPageUiState(log: [], isRunning: false);
}

void _addLog(
String message, {
DemoLogTone tone = DemoLogTone.neutral,
}) {
void _addLog(String message, {DemoLogTone tone = DemoLogTone.neutral}) {
state = state.copyWith(
log: [
...state.log,
DemoLogEntry(
message: message,
timestamp: DateTime.now(),
tone: tone,
),
DemoLogEntry(message: message, timestamp: DateTime.now(), tone: tone),
],
);
}
Expand Down Expand Up @@ -93,15 +80,17 @@ class _AppDiagnosticsPageViewModel extends Notifier<AppDiagnosticsPageUiState>

final _viewModelProvider =
NotifierProvider<_AppDiagnosticsPageViewModel, AppDiagnosticsPageUiState>(
_AppDiagnosticsPageViewModel.new,
);
_AppDiagnosticsPageViewModel.new,
);

final appDiagnosticsPageUiStateProvider =
Provider<AppDiagnosticsPageUiState>((ref) {
final appDiagnosticsPageUiStateProvider = Provider<AppDiagnosticsPageUiState>((
ref,
) {
return ref.watch(_viewModelProvider);
});

final appDiagnosticsPageActionsProvider =
Provider<AppDiagnosticsPageActions>((ref) {
final appDiagnosticsPageActionsProvider = Provider<AppDiagnosticsPageActions>((
ref,
) {
return ref.read(_viewModelProvider.notifier);
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import 'package:faro/faro.dart';
import 'package:faro_example/shared/models/demo_log_entry.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

typedef CustomTelemetryLogCallback = void Function(
String message, {
DemoLogTone tone,
});
typedef CustomTelemetryLogCallback =
void Function(String message, {DemoLogTone tone});

final customTelemetryDemoServiceProvider = Provider<CustomTelemetryDemoService>(
(ref) => const CustomTelemetryDemoService(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,15 @@ class CustomTelemetryPage extends ConsumerWidget {
final uiState = ref.watch(customTelemetryPageUiStateProvider);
final actions = ref.watch(customTelemetryPageActionsProvider);

final dataCollectionColor =
uiState.isDataCollectionEnabled ? Colors.green : Colors.orange;
final dataCollectionColor = uiState.isDataCollectionEnabled
? Colors.green
: Colors.orange;

return Scaffold(
appBar: AppBar(
title: const Text('Custom Telemetry'),
actions: [
TextButton(
onPressed: actions.clearLog,
child: const Text('Clear'),
),
TextButton(onPressed: actions.clearLog, child: const Text('Clear')),
],
),
body: Column(
Expand Down Expand Up @@ -62,10 +60,7 @@ class CustomTelemetryPage extends ConsumerWidget {
const SizedBox(height: 16),
const Text(
'Telemetry Signals',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,11 @@ class _CustomTelemetryPageViewModel extends Notifier<CustomTelemetryPageUiState>
);
}

void _addLog(
String message, {
DemoLogTone tone = DemoLogTone.neutral,
}) {
void _addLog(String message, {DemoLogTone tone = DemoLogTone.neutral}) {
state = state.copyWith(
log: [
...state.log,
DemoLogEntry(
message: message,
timestamp: DateTime.now(),
tone: tone,
),
DemoLogEntry(message: message, timestamp: DateTime.now(), tone: tone),
],
);
}
Expand Down Expand Up @@ -121,15 +114,17 @@ class _CustomTelemetryPageViewModel extends Notifier<CustomTelemetryPageUiState>

final _viewModelProvider =
NotifierProvider<_CustomTelemetryPageViewModel, CustomTelemetryPageUiState>(
_CustomTelemetryPageViewModel.new,
);
_CustomTelemetryPageViewModel.new,
);

final customTelemetryPageUiStateProvider =
Provider<CustomTelemetryPageUiState>((ref) {
return ref.watch(_viewModelProvider);
});
final customTelemetryPageUiStateProvider = Provider<CustomTelemetryPageUiState>(
(ref) {
return ref.watch(_viewModelProvider);
},
);

final customTelemetryPageActionsProvider =
Provider<CustomTelemetryPageActions>((ref) {
return ref.read(_viewModelProvider.notifier);
});
final customTelemetryPageActionsProvider = Provider<CustomTelemetryPageActions>(
(ref) {
return ref.read(_viewModelProvider.notifier);
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ class _FeatureCatalogPageState extends State<FeatureCatalogPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Features'),
),
appBar: AppBar(title: const Text('Features')),
body: ListView(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.fromLTRB(16, 16, 16, 32),
Expand Down Expand Up @@ -135,10 +133,7 @@ class _FeatureCatalogPageState extends State<FeatureCatalogPage> {
}

class _SectionHeader extends StatelessWidget {
const _SectionHeader({
required this.title,
required this.subtitle,
});
const _SectionHeader({required this.title, required this.subtitle});

final String title;
final String subtitle;
Expand All @@ -150,16 +145,16 @@ class _SectionHeader extends StatelessWidget {
children: [
Text(
title,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
style: Theme.of(
context,
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 4),
Text(
subtitle,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Colors.grey.shade700,
),
style: Theme.of(
context,
).textTheme.bodySmall?.copyWith(color: Colors.grey.shade700),
),
],
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import 'package:faro_example/shared/models/demo_log_entry.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;

typedef NetworkRequestLogCallback = void Function(
String message, {
DemoLogTone tone,
});
typedef NetworkRequestLogCallback =
void Function(String message, {DemoLogTone tone});

final networkRequestsDemoServiceProvider = Provider<NetworkRequestsDemoService>(
(ref) => const NetworkRequestsDemoService(),
Expand All @@ -24,9 +22,7 @@ class NetworkRequestsDemoService {
request: () {
return http.post(
Uri.parse('https://httpbin.io/post'),
body: jsonEncode(<String, String>{
'title': 'This is a title',
}),
body: jsonEncode(<String, String>{'title': 'This is a title'}),
);
},
log: log,
Expand All @@ -40,9 +36,7 @@ class NetworkRequestsDemoService {
request: () {
return http.post(
Uri.parse('https://httpbin.io/unstable'),
body: jsonEncode(<String, String>{
'title': 'This is a title',
}),
body: jsonEncode(<String, String>{'title': 'This is a title'}),
);
},
log: log,
Expand Down Expand Up @@ -73,29 +67,25 @@ class NetworkRequestsDemoService {
required Future<http.Response> Function() request,
required NetworkRequestLogCallback log,
}) async {
log(
'$label -> sending request',
tone: DemoLogTone.info,
);
log('$label -> sending request', tone: DemoLogTone.info);

try {
final response = await request();
final isFailure = response.statusCode >= 400;
final matchedExpectation = isFailure == expectedFailure;
final tone =
matchedExpectation ? DemoLogTone.success : DemoLogTone.warning;
final expectationLabel =
expectedFailure ? 'expected failure' : 'expected success';
final tone = matchedExpectation
? DemoLogTone.success
: DemoLogTone.warning;
final expectationLabel = expectedFailure
? 'expected failure'
: 'expected success';

log(
'$label -> status ${response.statusCode} ($expectationLabel)',
tone: tone,
);
} catch (error) {
log(
'$label -> threw $error',
tone: DemoLogTone.error,
);
log('$label -> threw $error', tone: DemoLogTone.error);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ class NetworkRequestsPage extends ConsumerWidget {
appBar: AppBar(
title: const Text('Network Requests'),
actions: [
TextButton(
onPressed: actions.clearLog,
child: const Text('Clear'),
),
TextButton(onPressed: actions.clearLog, child: const Text('Clear')),
],
),
body: Column(
Expand All @@ -31,10 +28,7 @@ class NetworkRequestsPage extends ConsumerWidget {
children: [
const Text(
'HTTP tracking demos',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text(
Expand Down
Loading
Loading