fanmeter-sdk-reactnative
v4.0.0
Published
Pluggable's Fanmeter for React Native apps
Downloads
31
Readme
Pluggable's Fanmeter Plugin for React Native apps
The Fanmeter plugin is the one responsible for enabling Fanmeter in any mobile application. It is a simple plug-&-play plugin that makes available a set of methods that can be used to allow users to participate in activations such as the FAN OF THE MATCH.
Fully-automatized vs Manual Fanmeter
There are two possible types of integration. One is fully-automatized and uses a default native view that is launched to your users for them to participate in Fanmeter - it also launches and delivers push notifications as soon as the event starts and finishes. If, on the other hand, you wish to create your own Fanmeter view, you will follow a manual approach.
- Fully-automatized Fanmeter: you want everything automated (including a default Fanmeter view). You should also integrate with FCM to handle received notifications that start the event (in summary, you'll need to use the execute, launchFanmeterNotification and, optionally, the launchFanmeterView methods);
- Manual Fanmeter: you want to handle the conditions yourself and develop your own view (just start calling the startService, stopService, and isServiceRunning methods).
Pre-Conditions
Meta-Data
For Android, push permission is required so that a notification is shown to the user so that he knows that a foreground service is running. Also, note that the Location permission is needed for the fans to participate in the geo-restricted events. Hence, you need to ask for such permissions.
For iOS, add the Background Modes capability and enable Location Updates. Also, you must open your Info.plist file and add the following code at the bottom of the file:
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>location</string>
<string>remote-notification</string>
</array>
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
<key>PreciseLocationRequired</key>
<string>This event is geo-restricted. Access to the precise location during the event is required!</string>
</dict>
<key>NSLocationAlwaysUsageDescription</key>
<string>Location is required to participate in geo-restricted fan events!</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>GPS is required to collect data to classify your celebration during the event! </string>
Note that, for Android only, Fanmeter is required to use a Data Sync foreground service to communicate non-intrusive sensor data with Pluggable's server. Since API 34 of Android, when publishing an app that uses such services, you are required to fill a Policy Declaration where you must justify the need for such services. In Fanmeter's case, when filling such policy, you will be asked the question "What tasks require your app to use the FOREGROUND_SERVICE_DATA_SYNC permission?".
There, you should:
- Select the option OTHER in Other tasks;
- Provide the following video link:
https://youtu.be/w4d7Pgksok0
- Provide the following description:
Fanmeter is an Android SDK, incorporated in this app, that uses a Data Sync foreground service to communicate non-intrusive sensor data with Pluggable's servers, which are used to quantify the engagement of the user in real-time. The foreground service must start as soon as the user opts to participate in the event (so that it can collect and communicate data) and must keep running until the user himself decides to terminate his/her participation.
Push Notifications
Before using this plugin, if you want a fully-automated experience, you should guarantee that your app already integrates with React Native Firebase and then with Firebase Cloud Messaging (FCM). The steps are as follows:
Create a new Firebase project. Note that current versions of firebase-ios-sdk have a minimum Xcode requirement of 14.1, which implies a minimum macOS version of 12.5 (macOS Monterey);
Install the React Native Firebase "app" module to the root of the React Native project with NPM:
npm install --save @react-native-firebase/app
. The@react-native-firebase/app
module must be installed before using any other Firebase service;Android Setup - a configuration file must be downloaded and added to the project:
- On the Firebase console, add a new Android application and enter the projects details. The "Android package name" must match the local projects package name which can be found inside of the manifest tag within the /android/app/src/main/AndroidManifest.xml file within the project;
- Download the
google-services.json
file and place it inside of the project at the following location: /android/app/google-services.json; - To allow Firebase on Android to use the credentials, the google-services plugin must be enabled on the project. This requires modification to two files in the Android directory. First, add the google-services plugin as a dependency inside of the /android/build.gradle file:
buildscript { dependencies { // ... other dependencies classpath 'com.google.gms:google-services:4.3.15' } }
- Lastly, execute the plugin by adding the following to the /android/app/build.gradle file:
apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' // <- Add this line
iOS Setup - to allow the iOS app to securely connect to the Firebase project, a configuration file must be downloaded and added to the project, and you must enable frameworks in CocoaPods:
- On the Firebase console, add a new iOS application and enter your projects details. The "Apple bundle ID" must match your local project bundle ID. The bundle ID can be found within the "General" tab when opening the project with Xcode;
- Download the
GoogleService-Info.plist
file; - Using Xcode, open the projects /ios/{projectName}.xcodeproj file (or /ios/{projectName}.xcworkspace if using Pods) and right click on the project name and "Add files" to the project. Select the downloaded
GoogleService-Info.plist
file from your computer, and ensure the Copy items if needed checkbox is enabled; - To allow Firebase on iOS to use the credentials, the Firebase iOS SDK must be configured during the bootstrap phase of your application. To do this, open your /ios/{projectName}/AppDelegate.mm file (or AppDelegate.m if on older react-native), and add the following:
#import "AppDelegate.h" #import <Firebase.h> // <- Add this line // ... - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Add me --- \/ [FIRApp configure]; // <- Add this line // Add me --- /\ // ... } // ...
- Beginning with firebase-ios-sdk v9+ (react-native-firebase v15+) you must tell CocoaPods to use frameworks. Open the file ./ios/Podfile and add the following line inside your targets (right after the line calling the react native Podfile function to get the native modules config):
target 'reactnativeapp' do config = use_native_modules! use_frameworks! :linkage => :static # <- Add this line $RNFirebaseAsStaticFramework = true # <- Add this line (see next point) ... # Note that if you have use_frameworks! enabled, Flipper will not work and # you should disable the next line. #:flipper_configuration => flipper_config, # <- COMMENT this line ...
- To use Static Frameworks on iOS, you also need to manually enable this for the project with the following global to your ./ios/Podfile file:
# right after `use_frameworks! :linkage => :static` $RNFirebaseAsStaticFramework = true
Once the above steps have been completed, the React Native Firebase library must be linked to the project and the application needs to be rebuilt. Users on React Native 0.60+ automatically have access to "autolinking", requiring no further manual installation steps. To automatically link the package, rebuild your project (for manual linking, if you're using an older version of React Native without autolinking support, or wish to integrate into an existing project, you can follow the manual installation steps for iOS and Android):
# Android apps npm run android # iOS apps cd ios/ pod install --repo-update cd .. npm run ios
You can now install the messaging module by running:
# Install the messaging module npm install @react-native-firebase/messaging # If you're developing your app using iOS, run this command cd ios/ && pod install cd .. npm run ios
iOS Setup - iOS requires further configuration before you can start receiving and sending messages through Firebase. Read the documentation and follow the steps on how to setup iOS with Firebase Cloud Messaging.
NOTE: FCM via APNs does not work on iOS Simulators. To receive messages & notifications a real device is required. The same is recommended for Android. Also, for iOS, React-Native-Firebase uses use_frameworks
, which has compatibility issues with Flipper, Hermes, and Fabric.
NOTE 2: In iOS foreground notification are not displayed. If it is needed you can use a package for local notifications.
Set up the Fanmeter Plugin in your React Native App
Install the Plugin
After configuring your app to integrate with FCM, you are ready to use this plugin to properly engage with your fans! To install the Fanmeter Package just run in the root of the project:
npm install fanmeter-sdk-reactnative
Once the above steps have been completed, the React Native Firebase library must be linked to your project and your application needs to be rebuilt. Users on React Native 0.60+ automatically have access to "autolinking", requiring no further manual installation steps. To automatically link the package, rebuild your project:
# Android apps npm run android # iOS apps cd ios/ pod install --repo-update
OPTIONAL: For iOS, if you want to display push notifications while your app is in the foreground, you must allow that specific scenario:
- In your app's AppDelegate.h file:
// Import the native iOS UserNotifications package #import <UserNotifications/UserNotifications.h> // <- Add this line // Extend the UNUserNotificationCenterDelegate class @interface AppDelegate : RCTAppDelegate<UNUserNotificationCenterDelegate> // <- Update this line
- In your app's AppDelegate.mm file:
// Import the native iOS UserNotifications package #import <UserNotifications/UserNotifications.h> // <- Add this line // ... - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // ... [UNUserNotificationCenter currentNotificationCenter].delegate = self; // <- Add this line // ... } // ... // Function to implement to display foreground push notifications - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler { completionHandler(UNNotificationPresentationOptionAlert|UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound); }
Note that for Android, to customize the used notification icon just add the desired icon in the Android's drawable folder and name it ic_push_app_icon. Otherwise, a default icon, not related to your app, will be used.
Method initialize
The initialize
method is mandatory for both fully-automatized and manual scenarios. It is responsible for initializing the SDK and must be invoked before using any other method (a possible approach is to invoke it in the main app process).
import {
initialize,
...
} from 'fanmeter-sdk-reactnative';
const COMPANY_NAME: string = 'your_company_name';
const COMPANY_KEY: string = 'your_company_key';
const EXTERNAL_USER_ID: string = 'your_user_id';
const EXTERNAL_TOKEN_ID: string = 'the_id_of_the_device';
const EXTERNAL_USER_EMAIL: string | null = '[email protected]';
const FCM_TOKEN: string | null = 'the_fcm_token';
const TICKET_NUMBER: string | null = 't-1234';
const TICKET_STAND: string | null = null;
const REGULATION_URL: string | null = null;
const NOTIFICATION_CLASS_RESPONSE: string | null = null;
const FANMETER_LOG: boolean | null = true;
// ...
// When the Fanmeter SDK is initialized, it initializes all company and user data.
initialize(
COMPANY_NAME,
COMPANY_KEY,
EXTERNAL_USER_ID,
EXTERNAL_TOKEN_ID,
EXTERNAL_USER_EMAIL,
FCM_TOKEN,
TICKET_NUMBER,
TICKET_STAND,
REGULATION_URL,
FANMETER_LOG
)
Where:
- COMPANY_NAME, is the name of your company in Fanmeter;
- COMPANY_KEY, your company's license key;
- EXTERNAL_USER_ID, the user identifier in your db (can be the username, the uuid, ...);
- EXTERNAL_TOKEN_ID, the individual smartphone identifier (allows for the same account in different devices);
- EXTERNAL_USER_EMAIL, the user's email. Nullable;
- FCM_TOKEN, the FCM token id of the user. Nullable;
- TICKET_NUMBER, the user's ticket number - used for additional analytics. Nullable;
- TICKET_STAND, the stand where the user is - used for additional analytics. Nullable;
- REGULATION_URL, the URL to the regulation for your events. Nullable;
- FANMETER_LOG, enables additional logging.
Fully-automatized Fanmeter
After initializing the Plugin, you are now ready to start calling Fanmeter. In particular, if you want to automate the entire process, this library exposes three methods, that must be called as demonstrated below. In particular:
execute
, launches the SDK Fanmeter default's view as soon as a notification is clicked by the user;launchFanmeterNotification
, launches a local notification to the user, which is required by Android when the app is in the foreground;launchFanmeterView
, launches the SDK Fanmeter default's view. It can be associated with a button or banner in your app, redirecting the user to the Fanmeter native view, allowing users without notification permissions to participate in the event. It will open the Fanmeter view with the event with the closest date to the current date.
The execute
method is used for backgrounded processes and will open the default Fanmeter view to the user. On the other hand, the launchFanmeterNotification
method launches a local notification when the Android app is in a foreground state. An example is as follows, used in your .tsx files as demonstrated in the next lines.
import {
...
execute,
launchFanmeterNotification,
launchFanmeterView
} from 'fanmeter-sdk-reactnative';
// To listen to messages in the foreground, call the onMessage method inside of your application code.
// Code executed via this handler has access to React context.
useEffect(() => {
messaging().onMessage(async remoteMessage => {
const notificationData = remoteMessage.data as {[key: string]: any};
launchFanmeterNotification(
notificationData,
NOTIFICATION_CLASS_RESPONSE
);
});
}, []);
useEffect(() => {
// When the application is opened from a quit state, check whether an initial notification is available.
messaging().getInitialNotification().then(remoteMessage => {
if(remoteMessage) {
const notificationData = remoteMessage.data as {[key: string]: any};
execute(
notificationData,
NOTIFICATION_CLASS_RESPONSE
);
}
});
// When the application is running, but in the background.
messaging().onNotificationOpenedApp(remoteMessage => {
const notificationData = remoteMessage.data as {[key: string]: any};
execute(
notificationData,
NOTIFICATION_CLASS_RESPONSE
);
});
}, []);
Where:
- notificationData, is the remote data received with the notification;
- NOTIFICATION_CLASS_RESPONSE, the name of the class that is being instantiated when the user clicks the notification - example: "com.company.activities.SearchActivity" (null opens the app's default view).
Finally, the launchFanmeterView
method should be called on a button click, redirecting users to Fanmeter's default view. It can, p.e., be associated with a button/banner in your app, redirecting the user to the Fanmeter native view, allowing users without notification permissions to participate in the event. It will open the Fanmeter view with the event with the closest date to the current date.
launchFanmeterView();
These functions return the following values:
- 1, success;
- -80, no GPS/PUSH permissions;
- -81, GPS disabled;
- -82, invalid event coordinates;
- -89, SDK not initialized;
- -91, invalid notification data;
- -92, invalid company license;
- -93, invalid event;
- -94, event not happening now;;
- -95, invalid external user data;
- -96, failed to get event data;
- -97, failed to start the Fanmeter service;
You are also required to subscribe the user to a FCM topic so that he/she can receive event notifications. This can be done, for example, as follows:
// Subscribe to a topic.
messaging().subscribeToTopic('football_senior').then(() => console.log('Subscribed to topic: football_senior!'));
Manual Fanmeter
If you want full control and implement your own UI, this library exposes three methods, that must be called as demonstrated below. In particular:
startService
, starts the Fanmeter service that enables Fanmeter for your client's device during a particular event;stopService
, stops the Fanmeter service. The service will, still, terminate automatically as soon as the event ends. This returns 1, if success, otherwise an error code;isServiceRunning
, used to check the current status of the Fanmeter service. Returns 1, if the service is running, otherwise 0.
The startService
method is used to start the Fanmeter service and should be called as follows (associated, for example, to a particular button):
import {
...
startService,
stopService,
isServiceRunning
} from 'fanmeter-sdk-reactnative';
// ...
// You should manage the events to get their name programmatically instead of an hardcoded string.
const event_title = "Round 1 - 2024/2025 Season"
startService(
event_title,
NOTIFICATION_CLASS_RESPONSE
);
Where:
- event_title, is the name of the event the user will participate when the start service is called;
- NOTIFICATION_CLASS_RESPONSE, the name of the class that is being instantiated when the user clicks the notification - example: "com.company.activities.SearchActivity" (null opens the app's default view).
This method returns the following values:
- 1, success;
- -80, no GPS/PUSH permissions;
- -81, GPS disabled;
- -82, invalid event coordinates;
- -89, SDK not initialized;
- -91, invalid notification data;
- -92, invalid company license;
- -93, invalid event;
- -94, event not happening now;;
- -95, invalid external user data;
- -96, failed to get event data;
- -97, failed to start the Fanmeter service;
The stopService
method is used to stop the Fanmeter service (can be toggled with the previous method). Even if the user does not explicitly stop the service, it will automatically stop as soon as the event finishes. This returns 1, if success, otherwise an error code.
stopService();
Finally, the isServiceRunning
method is used to check the current status of the Fanmeter service. This returns 1, if the service is running, otherwise 0.
isServiceRunning();
Additional info
Other important methods are to request user permission to be able to send notifications and request GPS permission. Also, get the user token and listen for changes to get the user FCM_TOKEN and update it when it changes.
In addition, please note that FCM via APNs does not work on iOS Simulators. To receive messages and notifications a real device is required. The same is recommended for Android.
In particular, if you need to know the FCM token ID associated with each user device:
// Get user's FCM token.
messaging().getToken().then(token => {
console.log('TOKEN is:', token);
FCM_TOKEN = token;
});
// Listen to whether the token changes
messaging().onTokenRefresh(token => {
console.log('TOKEN refreshed to:', token);
FCM_TOKEN = token;
});
For full compatibility, attention to the used versions of XCODE, SWIFT and COCOAPODS. Recommended versions are XCODE=15, SWIFT=5.9, and COCOAPODS=1.14.2. For more info visit https://pluggableai.xyz/ or send your feedback to [email protected].