Skip to content

Commit 170b99b

Browse files
authored
feat(messaging): add support for exporting delivery metrics to BigQuery (#9636)
* feat(messaging): automatic export to bigquery * feat(messaging): automatic export to bigquery for web * feat(messaging): export to BigQuery * feat(messaging): export to BigQuery * feat(messaging): export to BigQuery * feat(messaging): export to BigQuery on web * feat(messaging): export to BigQuery on web * feat(messaging): export to BigQuery on web * feat(messaging): revert to old service worker with compat * feat(messaging): revert to old service worker with compat * feat(messaging): revert to old service worker with compat * feat(messaging): export to BigQuery * feat(messaging): export to BigQuery
1 parent 3ab283b commit 170b99b

File tree

16 files changed

+1297
-55
lines changed

16 files changed

+1297
-55
lines changed

docs/cloud-messaging/receive.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,3 +339,71 @@ Here's how to use the second method:
339339
},
340340
}
341341
```
342+
343+
344+
## Enable message delivery data export
345+
346+
You can export your message data into BigQuery for further analysis. BigQuery allows you to analyze the data using BigQuery SQL,
347+
export it to another cloud provider, or use the data for your custom ML models. An export to BigQuery
348+
includes all available data for messages, regardless of message type or whether the message is sent via
349+
the API or the Notifications composer.
350+
351+
To enable the export, first follow the steps [described here](https://firebase.google.com/docs/cloud-messaging/understand-delivery?platform=ios#bigquery-data-export),
352+
then follow these instructions:
353+
354+
### Android
355+
356+
You can use the following code:
357+
```dart
358+
await FirebaseMessaging.instance.setDeliveryMetricsExportToBigQuery(true);
359+
```
360+
361+
### iOS
362+
363+
For iOS, you need to change the `AppDelegate.m` with the following content.
364+
365+
```objective-c
366+
#import "AppDelegate.h"
367+
#import "GeneratedPluginRegistrant.h"
368+
#import <Firebase/Firebase.h>
369+
370+
@implementation AppDelegate
371+
372+
- (BOOL)application:(UIApplication *)application
373+
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
374+
[GeneratedPluginRegistrant registerWithRegistry:self];
375+
// Override point for customization after application launch.
376+
return [super application:application didFinishLaunchingWithOptions:launchOptions];
377+
}
378+
379+
- (void)application:(UIApplication *)application
380+
didReceiveRemoteNotification:(NSDictionary *)userInfo
381+
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
382+
[[FIRMessaging extensionHelper] exportDeliveryMetricsToBigQueryWithMessageInfo:userInfo];
383+
}
384+
385+
@end
386+
```
387+
388+
### Web
389+
390+
For Web, you need to change your service worker in order to use the v9 version of the SDK.
391+
The v9 version needs to be bundled, so you need to use a bundler like `esbuild` for instance
392+
to get the service worker to work.
393+
See [the example app](https://github.com/firebase/flutterfire/blob/master/packages/firebase_messaging/firebase_messaging/example/bundled-service-worker) to see how to achieve this.
394+
395+
Once you've migrated to the v9 SDK, you can use the following code:
396+
397+
``` typescript
398+
import {
399+
experimentalSetDeliveryMetricsExportedToBigQueryEnabled,
400+
getMessaging,
401+
} from 'firebase/messaging/sw';
402+
403+
...
404+
405+
const messaging = getMessaging(app);
406+
experimentalSetDeliveryMetricsExportedToBigQueryEnabled(messaging, true);
407+
```
408+
409+
Don't forget to run `yarn build` in order to export the new version of your service worker to the `web` folder.

packages/firebase_messaging/firebase_messaging/android/src/main/java/io/flutter/plugins/firebase/messaging/FlutterFirebaseMessagingPlugin.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,25 @@ private Task<Map<String, Object>> setAutoInitEnabled(Map<String, Object> argumen
251251
return taskCompletionSource.getTask();
252252
}
253253

254+
private Task<Void> setDeliveryMetricsExportToBigQuery(Map<String, Object> arguments) {
255+
TaskCompletionSource<Void> taskCompletionSource = new TaskCompletionSource<>();
256+
257+
cachedThreadPool.execute(
258+
() -> {
259+
try {
260+
FirebaseMessaging firebaseMessaging =
261+
FlutterFirebaseMessagingUtils.getFirebaseMessagingForArguments(arguments);
262+
Boolean enabled = (Boolean) Objects.requireNonNull(arguments.get("enabled"));
263+
firebaseMessaging.setDeliveryMetricsExportToBigQuery(enabled);
264+
taskCompletionSource.setResult(null);
265+
} catch (Exception e) {
266+
taskCompletionSource.setException(e);
267+
}
268+
});
269+
270+
return taskCompletionSource.getTask();
271+
}
272+
254273
private Task<Map<String, Object>> getInitialMessage() {
255274
TaskCompletionSource<Map<String, Object>> taskCompletionSource = new TaskCompletionSource<>();
256275

@@ -447,6 +466,9 @@ public void onMethodCall(final MethodCall call, @NonNull final Result result) {
447466
case "Messaging#setAutoInitEnabled":
448467
methodCallTask = setAutoInitEnabled(call.arguments());
449468
break;
469+
case "Messaging#setDeliveryMetricsExportToBigQuery":
470+
methodCallTask = setDeliveryMetricsExportToBigQuery(call.arguments());
471+
break;
450472
case "Messaging#requestPermission":
451473
if (Build.VERSION.SDK_INT >= 33) {
452474
// Android version >= Android 13 requires user input if notification permission not set/granted

packages/firebase_messaging/firebase_messaging/example/.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
/build/
3333

3434
# Web related
35-
lib/generated_plugin_registrant.dart
3635

3736
# Symbolication related
3837
app.*.symbols
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { initializeApp } from 'firebase/app';
2+
import {
3+
experimentalSetDeliveryMetricsExportedToBigQueryEnabled,
4+
getMessaging,
5+
isSupported,
6+
onBackgroundMessage
7+
} from 'firebase/messaging/sw';
8+
9+
declare var self: ServiceWorkerGlobalScope;
10+
11+
self.addEventListener('install', (event) => {
12+
console.log(self);
13+
console.log(event);
14+
});
15+
16+
const app = initializeApp({
17+
apiKey: 'AIzaSyAgUhHU8wSJgO5MVNy95tMT07NEjzMOfz0',
18+
authDomain: 'react-native-firebase-testing.firebaseapp.com',
19+
databaseURL: 'https://react-native-firebase-testing.firebaseio.com',
20+
projectId: 'react-native-firebase-testing',
21+
storageBucket: 'react-native-firebase-testing.appspot.com',
22+
messagingSenderId: '448618578101',
23+
appId: '1:448618578101:web:ecaffe2bc4511738',
24+
});
25+
26+
isSupported().then((isSupported) => {
27+
if (isSupported) {
28+
const messaging = getMessaging(app);
29+
30+
experimentalSetDeliveryMetricsExportedToBigQueryEnabled(messaging, true);
31+
32+
onBackgroundMessage(messaging, ({ notification: notification }) => {
33+
const { title, body, image } = notification ?? {};
34+
35+
if (!title) {
36+
return;
37+
}
38+
39+
self.registration.showNotification(title, {
40+
body,
41+
icon: image || '/assets/icons/icon-72x72.png',
42+
});
43+
});
44+
}
45+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"dependencies": {
3+
"firebase": "9"
4+
},
5+
"devDependencies": {
6+
"esbuild": "^0.15.10"
7+
},
8+
"scripts": {
9+
"build": "esbuild firebase-messaging-sw.ts --outdir=../web --bundle --sourcemap --minify --format=esm"
10+
}
11+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"lib": [
4+
"webworker",
5+
"es6"
6+
]
7+
}
8+
}

0 commit comments

Comments
 (0)