Skip to content
95 changes: 49 additions & 46 deletions packages/plugins/plugin_firebase/lib/plugin_firebase.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
library analytics_plugin_firebase;

import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions, Firebase;
import 'package:segment_analytics/event.dart';
import 'package:segment_analytics/logger.dart';
import 'package:segment_analytics/plugin.dart';
import 'package:segment_analytics/map_transform.dart';

import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:firebase_core/firebase_core.dart'
show FirebaseOptions, Firebase;

export 'package:firebase_core/firebase_core.dart'
show FirebaseOptions, Firebase;

import 'package:segment_analytics/plugin.dart';
import 'package:segment_analytics_plugin_firebase/properties.dart';

export 'package:firebase_core/firebase_core.dart' show FirebaseOptions, Firebase;

class FirebaseDestination extends DestinationPlugin {
final Future<void> firebaseFuture;

Expand All @@ -27,15 +23,26 @@ class FirebaseDestination extends DestinationPlugin {

@override
Future<RawEvent?> identify(IdentifyEvent event) async {
// Set user ID if provided
if (event.userId != null) {
await FirebaseAnalytics.instance.setUserId(id: event.userId!);
await FirebaseAnalytics.instance.setUserId(id: event.userId);
}

// Set user properties from traits if provided
if (event.traits != null) {
await Future.wait(event.traits!.toJson().entries.map((entry) async {
await FirebaseAnalytics.instance
.setUserProperty(name: entry.key, value: entry.value.toString());
}));
// Transform and cast traits to the required format
final transformedTraits = recurseMapper(event.traits?.toJson(), mappings);
final userProperties = castParameterType(transformedTraits as Map<String, Object?>);

// Set each user property individually
for (final entry in userProperties.entries) {
await FirebaseAnalytics.instance.setUserProperty(
name: entry.key,
value: entry.value.toString(),
);
}
}

return event;
}

Expand All @@ -48,44 +55,37 @@ class FirebaseDestination extends DestinationPlugin {
switch (event.event) {
case 'Product Clicked':
if (!(properties.containsKey('list_id') ||
properties.containsKey('list_name') ||
properties.containsKey('list_name') ||
properties.containsKey('name') ||
properties.containsKey('itemId')) ) {
properties.containsKey('itemId'))) {
throw Exception("Missing properties: list_name, list_id, name and itemID");
}

AnalyticsEventItem itemClicked = AnalyticsEventItem(
itemName: properties['name'].toString(),
itemId: properties['itemId'].toString());
AnalyticsEventItem itemClicked =
AnalyticsEventItem(itemName: properties['name'].toString(), itemId: properties['itemId'].toString());

await FirebaseAnalytics.instance.logSelectItem(
itemListName: properties['list_name'].toString(),
itemListId: properties['list_id'].toString(),
items:[itemClicked],
itemListName: properties['list_name'].toString(),
itemListId: properties['list_id'].toString(),
items: [itemClicked],
);
break;
case 'Product Viewed':
await FirebaseAnalytics.instance.logViewItem(
currency: properties["currency"]?.toString(),
items: event.properties == null
? null
: [AnalyticsEventItemJson(event.properties!)],
items: event.properties == null ? null : [AnalyticsEventItemJson(event.properties!)],
value: double.tryParse(properties["value"].toString()));
break;
case 'Product Added':
await FirebaseAnalytics.instance.logAddToCart(
currency: properties["currency"]?.toString(),
items: event.properties == null
? null
: [AnalyticsEventItemJson(event.properties!)],
items: event.properties == null ? null : [AnalyticsEventItemJson(event.properties!)],
value: double.tryParse(properties["value"].toString()));
break;
case 'Product Removed':
await FirebaseAnalytics.instance.logRemoveFromCart(
currency: properties["currency"]?.toString(),
items: event.properties == null
? null
: [AnalyticsEventItemJson(event.properties!)],
items: event.properties == null ? null : [AnalyticsEventItemJson(event.properties!)],
value: double.tryParse(properties["value"].toString()));
break;
case 'Checkout Started':
Expand All @@ -100,7 +100,7 @@ class FirebaseDestination extends DestinationPlugin {
creativeName: properties["creativeName"]?.toString(),
creativeSlot: properties["creativeSlot"]?.toString(),
items: properties["items"] as List<AnalyticsEventItemJson>,
locationId: properties["locationdId"]?.toString(),
locationId: properties["locationId"]?.toString(),
promotionId: properties["promotionId"]?.toString(),
promotionName: properties["promotionName"]?.toString());
break;
Expand Down Expand Up @@ -147,12 +147,10 @@ class FirebaseDestination extends DestinationPlugin {
value: double.tryParse(properties["value"].toString()));
break;
case 'Cart Shared':
if (event.properties == null ||
event.properties!['products'] == null) {
if (event.properties == null || event.properties!['products'] == null) {
log("Error tracking event '${event.event}' for Firebase: products property must be a list of products");
} else if (event.properties!['products'] is List) {
await Future.wait(
(event.properties!['products'] as List).map((product) async {
await Future.wait((event.properties!['products'] as List).map((product) async {
final productProperties = mapProperties(product, mappings);
if (productProperties.containsKey("contentType") &&
productProperties.containsKey("itemId") &&
Expand Down Expand Up @@ -189,20 +187,18 @@ class FirebaseDestination extends DestinationPlugin {
searchTerm: properties["searchTerm"].toString(),
destination: properties["destination"]?.toString(),
endDate: properties["endDate"]?.toString(),
numberOfNights:
int.tryParse(properties["numberOfNights"].toString()),
numberOfPassengers:
int.tryParse(properties["numberOfPassengers"].toString()),
numberOfRooms:
int.tryParse(properties["numberOfRooms"].toString()),
numberOfNights: int.tryParse(properties["numberOfNights"].toString()),
numberOfPassengers: int.tryParse(properties["numberOfPassengers"].toString()),
numberOfRooms: int.tryParse(properties["numberOfRooms"].toString()),
origin: properties["origin"]?.toString(),
startDate: properties["startDate"]?.toString(),
travelClass: properties["travelClass"]?.toString());
break;
default:
await FirebaseAnalytics.instance.logEvent(
name: sanitizeEventName(event.event),
parameters: castParameterType(properties));
name: sanitizeEventName(event.event),
parameters: castParameterType(properties),
);
break;
}
} catch (error) {
Expand All @@ -213,8 +209,15 @@ class FirebaseDestination extends DestinationPlugin {

@override
Future<RawEvent?> screen(ScreenEvent event) async {
FirebaseAnalytics.instance
.logScreenView(screenClass: event.name, screenName: event.name);
// Transform and cast properties to the required format
final transformedProperties = recurseMapper(event.properties, mappings);
final parameters = castParameterType(transformedProperties as Map<String, Object?>);

FirebaseAnalytics.instance.logScreenView(
screenClass: event.name,
screenName: event.name,
parameters: parameters,
);
return event;
}

Expand Down
60 changes: 37 additions & 23 deletions packages/plugins/plugin_firebase/lib/properties.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,28 +46,42 @@ Map<String, Object> castParameterType(Map<String, Object?> properties) {
class AnalyticsEventItemJson extends AnalyticsEventItem {
AnalyticsEventItemJson(Map<String, Object?> json)
: super(
affiliation: json['affiliation'].toString(),
currency: json['currency'].toString(),
coupon: json['coupon'].toString(),
creativeName: json['creativeName'].toString(),
creativeSlot: json['creativeSlot'].toString(),
discount: num.tryParse(json['discount'].toString()),
index: int.tryParse(json['index'].toString()),
itemBrand: json['itemBrand'].toString(),
itemCategory: json['itemCategory'].toString(),
itemCategory2: json['itemCategory2'].toString(),
itemCategory3: json['itemCategory3'].toString(),
itemCategory4: json['itemCategory4'].toString(),
itemCategory5: json['itemCategory5'].toString(),
itemId: json['itemId'].toString(),
itemListId: json['itemListId'].toString(),
itemListName: json['itemListName'].toString(),
itemName: json['itemName'].toString(),
itemVariant: json['itemVariant'].toString(),
locationId: json['locationId'].toString(),
price: num.tryParse(json['price'].toString()),
promotionId: json['promotionId'].toString(),
promotionName: json['promotionName'].toString(),
quantity: int.tryParse(json['quantity'].toString()),
affiliation: json['affiliation']?.toString(),
currency: json['currency']?.toString(),
coupon: json['coupon']?.toString(),
creativeName: json['creativeName']?.toString(),
creativeSlot: json['creativeSlot']?.toString(),
discount: _parseNum(json['discount']),
index: _parseInt(json['index']),
itemBrand: json['itemBrand']?.toString(),
itemCategory: json['itemCategory']?.toString(),
itemCategory2: json['itemCategory2']?.toString(),
itemCategory3: json['itemCategory3']?.toString(),
itemCategory4: json['itemCategory4']?.toString(),
itemCategory5: json['itemCategory5']?.toString(),
itemId: json['itemId']?.toString(),
itemListId: json['itemListId']?.toString(),
itemListName: json['itemListName']?.toString(),
itemName: json['itemName']?.toString(),
itemVariant: json['itemVariant']?.toString(),
locationId: json['locationId']?.toString(),
price: _parseNum(json['price']),
promotionId: json['promotionId']?.toString(),
promotionName: json['promotionName']?.toString(),
quantity: _parseInt(json['quantity']),
);

// Helper to safely parse num values
static num? _parseNum(Object? value) {
if (value == null) return null;
if (value is num) return value;
return num.tryParse(value.toString());
}

// Helper to safely parse int values
static int? _parseInt(Object? value) {
if (value == null) return null;
if (value is int) return value;
return int.tryParse(value.toString());
}
}
14 changes: 7 additions & 7 deletions packages/plugins/plugin_firebase/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: segment_analytics_plugin_firebase
description: The hassle-free way to add Segment analytics to your Flutter app.
version: 1.0.1
version: 1.1.0
homepage: https://github.com/segmentio/analytics_flutter#readme
repository: https://github.com/segmentio/analytics_flutter/tree/main/packages/plugins/plugin_firebase#readme
issue_tracker: https://github.com/segmentio/analytics_flutter/issues
Expand All @@ -10,15 +10,15 @@ environment:
flutter: ">=3.16.0"

dependencies:
firebase_analytics: ^11.3.3
firebase_core: ^3.6.0
firebase_analytics: ^12.0.4
firebase_core: ^4.2.1
flutter:
sdk: flutter
json_annotation: ^4.8.0
segment_analytics: ^1.1.1
json_annotation: ^4.9.0
segment_analytics: ^1.1.10

dev_dependencies:
build_runner: ^2.3.3
build_runner: ^2.10.3
flutter_test:
sdk: flutter
flutter_lints: ^4.0.0
flutter_lints: ^6.0.0