@pluggableai/fanmeter-sdk
by pluggableai | v3.1.0
Pluggable's Fanmeter Plugin for NativeScript apps
npm i --save @pluggableai/fanmeter-sdk

@pluggableai/fanmeter-sdk

Pluggable's Fanmeter Plugin for NativeScript apps

npm install @pluggableai/fanmeter-sdk

Note that, for Android only, Fanmeter is required to use a Data Sync foreground service to communicate non-intrusive sensor motion 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:

  1. Select the option OTHER in Other tasks;
  2. Provide the following video link:
https://youtu.be/w4d7Pgksok0
  1. 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 motion data with Pluggable's servers, which are used to quantify the engagement of the user in real-time. The foreground service must start as soons as the user opts to participate in the event (so that it can collect and communicate motion data) and must keep running until the user himself decides to terminate his/her participation.

Pre-conditions [Integrate with FCM]

Before using this plugin you should guarantee that your app already integrates with NativeScript Firebase and then with Firebase Cloud Messaging (FCM). The steps are quite easy to follow.

  1. Install the @nativescript/firebase-core plugin (a plugin to initialize FirebaseApp in your app) by running the following command in the root directory of your project (this plugin must be installed before using any other Firebase service).
npm install @nativescript/firebase-core
  1. 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 the nativescript.config.ts file;
  • Download the google-services.json file and place it inside the project at the following location: /App_Resources/Android/src/google-services.json.
  1. 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:
  • 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 or inside the nativescript.config.ts file;;
  • Download the GoogleService-Info.plist file and place it inside the project at the following location: /App_Resources/iOS/GoogleService-Info.plist;
  • Then, a set of steps are required for you to obtain an auth key .p8 file (APNs authentication key) to send push notification to Apple devices. If you don't already have an APNs authentication key, make sure to create one in the Apple Developer Member Center. Then, inside your project in the Firebase console, select the gear icon, select Project Settings, and then select the Cloud Messaging tab. In APNs authentication key under "Apple app configuration", click the Upload button. Browse to the location where you saved your key, select it, and click Open. Add the key ID for the key (available in the Apple Developer Member Center) and click Upload.

  1. Instantiate Firebase and initialize a default app (for example, in the /app/app.ts file):
import { firebase } from '@nativescript/firebase-core'
const defaultApp = await firebase().initializeApp()
  1. You can now install the messaging module by running:
npm install @nativescript/firebase-messaging
  1. Then, add the SDK by importing the @nativescript/firebase-messaging module. You should import this module once in your app, ideally in the main file (e.g. app.ts or main.ts).
import '@nativescript/firebase-messaging'
  1. 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.
  • Here note that one of the steps of the above tutorial is incomplete. In particular, the one to Allow processing received a background push notification. You should open app/App_Resources/iOS/Info.plist and add the following code at the bottom:
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>location</string>
<string>remote-notification</string>
</array>
<key>NSLocationAlwaysUsageDescription</key>
<string>GPS is required to collect data to classify your celebration during the event! </string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>GPS is required to collect data to classify your celebration during the event! </string>
  1. Note that for both Android and iOS apps, the GPS permission is needed for the fans to participate in events (due to geo-restricted events).

  2. You can then rebuild the project by running in the root's terminal:

ns clean
ns build android
ns build ios

NOTE: Firebase Messaging in NativeScript MUST be called as soon as possible in your App's initialization process, otherwise it will no be able to detect and handle notifications and notification clicks. Please, make sure you implement all the required methods as soon as your app inits.

Fanmeter Usage

After configuring your app to integrate with FCM, you are ready to use this plugin to properly engage with your fans! The Fanmeter Native Script plugin is fully automated.

  1. First install the Fanmeter Package, which exposes three new methods, by running, in the root of the project:
npm install @pluggableai/fanmeter-sdk
  1. The pluggableExecute method is used to launch the SDK as soon as a notification is tapped by the user. It accepts a set of parameters, including:

    • externalUserId, the user identifier in the company's db - can be the username, the uuid, or other;
    • externalTokenId, the individual smartphone identifier (allows for same accounts in different devices);
    • notificationData, a map containing data coming from the notification;
    • externalUserEmail, the user's email (optional);
    • fcmToken, the FCM token id (mandatory for fully autonomous events);
    • ticketNumber, the ticket number of the user (optional);
    • ticketStand, the stand where the given user is (optional);
    • notificationClassResponse, the name of the class that is being instantiated when the user clicks the notification - example: "com.company.activities.SearchActivity" (null opens a default view);
    • log, enables additional logging (optional).

    It also returns the following values:

    • 1: SUCCESS;
    • -80: No GPS/PUSH Permissions; -81: GPS Disabled; -82: Invalid event coordinates;
    • -92: Invalid License; -93: Invalid Event; -94: Invalid event dates; -95: externalUserId or externalTokenId are empty; -96: Failed to get event details; -97: Failed to start background service.
...
import { FanmeterSdk } from '@pluggableai/fanmeter-sdk';
...

let EXTERNAL_USER_ID = 'your_user_id';
let EXTERNAL_TOKEN_ID = 'the_id_of_the_device';
let EXTERNAL_USER_EMAIL = '[email protected]';
let FCM_TOKEN = 'the_fcm_token';
let TICKET_NUMBER = null;
let TICKET_STAND = null;
let NOTIFICATION_CLASS_RESPONSE = null;
let FANMETER_LOG = true;

let COMPANY_NAME = 'your_company_name';
let LICENSE_KEY = 'your_company_key';

const defaultApp = async function () {
console.log('defaultApp function started');
await firebase().initializeApp();
console.log('Firebase Initialized');
};
defaultApp();

// ...

const setFirebaseInits = async function () {

firebase().messaging().onNotificationTap((message) => {
let result = FanmeterSdk.pluggableExecute(
EXTERNAL_USER_ID,
EXTERNAL_TOKEN_ID,
message.data,
EXTERNAL_USER_EMAIL,
FCM_TOKEN,
TICKET_NUMBER,
TICKET_STAND,
NOTIFICATION_CLASS_RESPONSE,
FANMETER_LOG
);
console.log('Fanmeter Notification Tap: ' + result);
});

}
  1. The pluggableExecuteWithLocalNotification method is used to tell the SDK to launch a local notification to the user, which is required by Android to launch push notifications when the app is in the foreground. It accepts a set of parameters, including:

    • externalUserId, the user identifier in the company's db - can be the username, the uuid, or other;
    • externalTokenId, the individual smartphone identifier (allows for same accounts in different devices);
    • notificationData, a map containing data coming from the notification;
    • externalUserEmail, the user's email (optional);
    • fcmToken, the FCM token id (mandatory for fully autonomous events);
    • ticketNumber, the ticket number of the user (optional);
    • ticketStand, the stand where the given user is (optional);
    • notificationClassResponse, the name of the class that is being instantiated when the user clicks the notification - example: "com.company.activities.SearchActivity" (null opens a default view);
    • log, enables additional logging (optional).

    It also returns the following values:

    • 1: SUCCESS;
    • -80: No GPS/PUSH Permissions; -81: GPS Disabled; -82: Invalid event coordinates;
    • -92: Invalid License; -93: Invalid Event; -94: Invalid event dates; -95: externalUserId or externalTokenId are empty; -96: Failed to get event details; -97: Failed to start background service.
// ...

const setFirebaseInits = async function () {
// Allows you to always display notifications while the application is in the foreground.
firebase().messaging().showNotificationsWhenInForeground = true

firebase().messaging().onNotificationTap((message) => {
// ...
});

firebase().messaging().onMessage(async (remoteMessage) => {
let result = FanmeterSdk.pluggableExecuteWithLocalNotification(
EXTERNAL_USER_ID,
EXTERNAL_TOKEN_ID,
remoteMessage.data,
EXTERNAL_USER_EMAIL,
FCM_TOKEN,
TICKET_NUMBER,
TICKET_STAND,
NOTIFICATION_CLASS_RESPONSE,
FANMETER_LOG
);
console.log('Fanmeter Message: ' + result);
});

}
  1. The pluggableLaunchFanmeterView method is used to tell the SDK to launch the Fanmeter native view. For example, it can be associated with a button in the company's 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, accepting a set of parameters, including:

    • companyName, the name of the company requesting to start the service;
    • licenseKey, the company key requesting to start the service;
    • externalUserId, the user identifier in the company's db - can be the username, the uuid, or other;
    • externalTokenId, the individual smartphone identifier (allows for same accounts in different devices);
    • externalUserEmail, the user's email (optional);
    • fcmToken, the FCM token id (mandatory for fully autonomous events);
    • ticketNumber, the ticket number of the user (optional);
    • ticketStand, the stand where the given user is (optional);
    • log, enables additional logging (optional).

    It also returns the following values:

    • 1: SUCCESS;
    • -80: No GPS/PUSH Permissions; -81: GPS Disabled; -82: Invalid event coordinates;
    • -92: Invalid License; -93: Invalid Event; -94: Invalid event dates; -95: externalUserId or externalTokenId are empty; -96: Failed to get event details; -97: Failed to start background service.
// ...

launchNativeView() {
let result = FanmeterSdk.pluggableLaunchFanmeterView(
COMPANY_NAME,
LICENSE_KEY,
EXTERNAL_USER_ID,
EXTERNAL_TOKEN_ID,
EXTERNAL_USER_EMAIL,
FCM_TOKEN,
TICKET_NUMBER,
TICKET_STAND,
FANMETER_LOG
);
console.log('Launch Fanmeter Native View: ' + result);
}
  1. It's equally mandatory to subscribe the user to specific topic so that they receive event notifications.
// Subscribe user to a specific topic.
firebase().messaging().subscribeToTopic('football_senior').then(() => {
console.log('Subscribed to topic: football_senior')
});
  1. Other important methods are 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.
// Request user permission
async function requestUserPermission() {
const authStatus = await firebase()
.messaging()
.requestPermission({
ios: {
alert: true
}
})
const enabled =
authStatus === AuthorizationStatus.AUTHORIZED ||
authStatus === AuthorizationStatus.PROVISIONAL

console.log('Authorization status: ', authStatus)
if (enabled) {
const didRegister = await firebase().messaging().registerDeviceForRemoteMessages().then(() => {
// Init Firebase and calling the below methods
setFirebaseInits();
});
}
}

requestUserPermission()
// Get user token 
firebase().messaging().getToken().then(token => {
console.log('User token: ', token)
FCM_TOKEN = token
//saveTokenToDatabase(token)
});

// Listen to user token changes
firebase().messaging().onToken(token => {
console.log('User token changed to: ', token)
FCM_TOKEN = token
//saveTokenToDatabase(token)
});

NOTE: For Android, to customize the used notification icon, just add the desired icon in the Android's drawble folder and name it ic_push_app_icon. Otherwise, a default icon, not related to your app, will be used.

More info

  • 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 give us feedback to [email protected].

License

Copyright 2024 PLUGGABLE, LDA (aka PluggableAI)

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.