Professional Documents
Culture Documents
Push Notification - Overview
Push Notification - Overview
Push Notification
Last updated by | Millisande Bath | Dec 22, 2023 at 9:54 AM GMT
Introduction
We can differentiate 3 types of push notifications as shown in Figure 1.
Only the first two use cases will send push notifications via the Salesforce Marketing Cloud.
https://dev.azure.com/bp-digital/bp_pulse/_wiki/wikis/bp_pulse/104605/Push-Notification 1/15
2/26/24, 3:01 PM Push Notification - Overview
We can use the React native push notification library to implement local push notifications (
https://github.com/zo0r/react-native-push-notification ).
Setup
Install the package
iOS - Follow the installation instructions for PushNotificationIOS
Android - Manually update the AndroidManifest.xml (as per installation instruction ) in order to use
Scheduled Notifications.
Mobile app
Schedule a local push notification.
Use can click at the link of the notification to launch the mobile app.
References:
The high-level design is shown in Figure 1. Salesforce IDP will provide data feed (e.g. user ID, contact ID) to
the Salesforce Marketing Cloud.
1. Scheduled push notification. Scheduled messages are sent to a group of users for specific events. We
may want to notify the users (of specific postcode) about maintenance activities or faulty issues.
2. Real-time push notification. Apollo XI EV Experience Platform can send a real-time notification to the
user about charging events, promotion et.
https://dev.azure.com/bp-digital/bp_pulse/_wiki/wikis/bp_pulse/104605/Push-Notification 2/15
2/26/24, 3:01 PM Push Notification - Overview
TBC
https://dev.azure.com/bp-digital/bp_pulse/_wiki/wikis/bp_pulse/104605/Push-Notification 3/15
2/26/24, 3:01 PM Push Notification - Overview
Ability to pass ContactId/PersonAccountId into SFMC to identify records and avoid the creation of
duplicates.
IOS - Developer creates two iOS Apple Push Notification service SSL Certificates (One for sandbox and
one for production). These certificates establish a secure connection between Marketing Cloud, Apple
and your app.
Android - Developer has to retrieve the Legacy Server Key and Sender ID from Google Firebase.
Android: https://github.com/salesforce-marketingcloud/MarketingCloudSDK-Android
iOS: https://github.com/salesforce-marketingcloud/MarketingCloudSDK-iOS
reactNative: https://github.com/salesforce-marketingcloud/react-native-marketingcloudsdk
The SFMC will provide the following configurations parameters to be configured in the SDK:
Access Token
App ID
App Endpoint
Account MID
For more implementation details, please refer to Mobile Push Notifications Implementation Guide. There is
also a Salesforce Marketing Cloud React Native plugin.
Enabling Permissions
iOS implementations also require an additional step and you will need to ensure your mobile app is
requesting users to allow push notifications, this does not happen automatically in iOS as it does in Android.
There will be a design decision on when to best ask for permission.
It is also important to note that the initial implementation will only cover the basic push notifications. To be
able to use Geo-location or Inbox messaging you will need to ensure your app is asking for users
permissions and that your SDK is updated to include the following functions;
Contact Key
When the SDK adds contacts to Marketing Cloud, it will assign a random unique ID for unidentified app
users. Unless you are asking your users to register when they download the app Marketing Cloud will create
https://dev.azure.com/bp-digital/bp_pulse/_wiki/wikis/bp_pulse/104605/Push-Notification 4/15
2/26/24, 3:01 PM Push Notification - Overview
new/duplicate users. And even if you do ask your users to register, the SDK will not automatically set the
correct contact key.
To prevent this from happening you will need your developers to add
These functions hold off adding contacts to Marketing Cloud until you have been able to set the contact key,
which you can do by returning the Contact Key when verifying a user’s login credentials. We believe that this
setting of the Contact key is done when a Pulse user accepts marketing consents. The contact key is not the
same as the salesforce or authentication id. It is stored in salesforce in the Salesforce Core database account
object as the field PersonContactId
${idpInstanceUrl}/services/data/v48.0/sobjects/User/${userId}
@Chay Carnell is able to look up their consents data with a request to two endpoints:
GET https://bp-idp-pp.bpglobal.com/services/apexrest/UserConsent
This second request returned the following object for his user:
{
"attributes": {
"type": "REIDP_User_Consent__c",
"url": "/services/data/v44.0/sobjects/REIDP_User_Consent__c/a0L4K00000E08SiUAJ"
},
"Id": "a0L4K00000E08SiUAJ",
"OwnerId": "0054K000007ZoMVQA0",
"IsDeleted": false,
"Name": "UC108269526",
"CurrencyIsoCode": "USD",
"CreatedDate": "2023-07-24T06:48:13.000+0000",
"CreatedById": "0054K000007ZoMVQA0",
"LastModifiedDate": "2023-07-24T06:48:13.000+0000",
"LastModifiedById": "0054K000007ZoMVQA0",
"SystemModstamp": "2023-07-24T06:48:13.000+0000",
"Contact__c": "0034K00000mY8r7QAC",
"REIDP_App_Name__c": "chargemaster"
}
We are working on how we can retrieve the data using CIP authenticated endpoints.
The current version of the contact api does not include returning the Contact ID
https://dev.azure.com/bp-digital/bp_pulse/_wiki/wikis/bp_pulse/104605/Push-Notification 5/15
2/26/24, 3:01 PM Push Notification - Overview
You will not be able to send a push notification if you have not acquired the system/push token. This token
is generated by the OS vendor when an app user agrees to enable push notifications and is checked at the
time of sending by either Google or Apple. We need to implement SFPushNotificationManager class
following the Mobile Push Notifications Implementation Guide.
Launch app
/ieeo-identitymgmt-b2c/papi/${apiVersion}/identity/user
Return
/iecm-contactmgmt-b2c/papi/${apiVersion}/contact
Return (contactId)
set Device Id
Return
Return
Return
Return
You need to write the below code which is inside double star(**) in onCreate() method
https://dev.azure.com/bp-digital/bp_pulse/_wiki/wikis/bp_pulse/104605/Push-Notification 6/15
2/26/24, 3:01 PM Push Notification - Overview
@Override
public void onCreate() {
super.onCreate();
// If you opted-in for the New Architecture, we enable the TurboModule system
ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
SoLoader.init(this, /* native exopackage */ false);
return null;
}), initializationStatus -> {
Log.e("TAG", "STATUS " + initializationStatus);
if (initializationStatus.getStatus() == 1) {
Log.e("TAG", "STATUS SUCCESS");
}
return null;
});**
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
To write the above code, you need to import the below packages -
import com.salesforce.marketingcloud.MarketingCloudConfig;
import com.salesforce.marketingcloud.notifications.NotificationCustomizationOptions;
import com.salesforce.marketingcloud.notifications.NotificationManager;
import com.salesforce.marketingcloud.notifications.NotificationMessage;
import com.salesforce.marketingcloud.sfmcsdk.SFMCSdk;
import com.salesforce.marketingcloud.sfmcsdk.SFMCSdkModuleConfig;
import android.util.Log;
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
Open the android/ build.gradle file and add the following under buildscript -> dependencies
go further down and add the below code under allprojects -> repositories -
maven {
//Add SalesForce Marketing Cloud SDK repository
url "https://salesforce-marketingcloud.github.io/MarketingCloudSDK-Android/repository"
}
https://dev.azure.com/bp-digital/bp_pulse/_wiki/wikis/bp_pulse/104605/Push-Notification 7/15
2/26/24, 3:01 PM Push Notification - Overview
In the FE, either you can create a provider or handler, here I create a handler for testing purpose. I give the
handler name PushNotificationHandler.tsx (Path -
src/components/PushNotificationHandler/PushNotificationHandler.tsx)
https://dev.azure.com/bp-digital/bp_pulse/_wiki/wikis/bp_pulse/104605/Push-Notification 8/15
2/26/24, 3:01 PM Push Notification - Overview
useEffect(() => {
updatePushData();
if (isAndroid) {
requestNotificationPermission();
}
}, []);
useEffect(() => {
// Manually update a contact key,it should be during login, which should be similar in BE
MCReactModule.setContactKey('<GET & SET CONTACT KEY WHILE LOGIN>');
updateContactKey('Added contact key');
}, []);
useEffect(() => {
MCReactModule.getDeviceId().then(val => {
setDeviceId(val || '');
console.log('device id', val);
});
}, []);
//---Attribute---
const updateAttributes = async (msg?: string) => {
https://dev.azure.com/bp-digital/bp_pulse/_wiki/wikis/bp_pulse/104605/Push-Notification 9/15
2/26/24, 3:01 PM Push Notification - Overview
return Promise.resolve()
.then(MCReactModule.getAttributes)
.then(val => {
setAttributes(val || {});
console.log(val);
console.info(msg);
return val;
});
};
useEffect(() => {
// set the attributes for personalisation
MCReactModule.setAttribute('bp_pulse_App_Language', '<LOCALISATION>');
MCReactModule.setAttribute('bp_pulse_App_Locale', '<LOCALISATION>');
MCReactModule.setAttribute('bp_pulse_Marketing_Optin', '1');
MCReactModule.setAttribute('Contact_Key', '<GET & SET CONTACT KEY WHILE LOGIN>');
MCReactModule.setAttribute('FirstName', '<NAME OF THE USER>');
updateAttributes('Attribute added');
}, []);
return null;
};
.......
........
<OutageProvider>
<FavouritesProvider>
<AnalyticsMiddleware />
<LaunchHandler />
**<PushNotificationHandler />**
<App />
</FavouritesProvider>
</OutageProvider>
..........
.........
Note- "react-native": "0.68.5" POST_NOTIFICATION not present in node_modules, for that we need to create
patch-package-
In order to fix this I had to create a patch using patch-package along with postinstall and update my current
PermissionAndroid files to support in my case POST_NOTIFICATIONS given I'm using react-native 0.68.5. So I
went ahead and updated these 2 files as detailed below:
/node_modules/react-native/Libraries/PermissionsAndroid/NativePermissionsAndroid.js
...
| 'android.permission.POST_NOTIFICATIONS';
...
/node_modules/react-native/Libraries/PermissionsAndroid/PermissionsAndroid.js
...
POST_NOTIFICATIONS: 'android.permission.POST_NOTIFICATIONS', <- added this
...
POST_NOTIFICATIONS: string, <- added this
....
https://dev.azure.com/bp-digital/bp_pulse/_wiki/wikis/bp_pulse/104605/Push-Notification 10/15
2/26/24, 3:01 PM Push Notification - Overview
After this change the PermissionsAndroid module from react-native started to work again as expected
without getting any permission is null error.
BTW also don't forget to include the respective permission on the AndroidManifest, in my case was: <uses-
permission android:name="android.permission.POST_NOTIFICATIONS" />
Finally be sure to set the compileSdkVersion and the targetSdkVersion to 33 for the permission prompt to
show up...
downstream-provider-
local/infrastructure/cloudinformation/stacks/services/unversioned/notificationsStack/lambda/pushNotification
sTrigger/index.ts
In the index.ts file, we write the below code to connect SFMC auth and rest API by using lambda function -
https://dev.azure.com/bp-digital/bp_pulse/_wiki/wikis/bp_pulse/104605/Push-Notification 11/15
2/26/24, 3:01 PM Push Notification - Overview
import {
APIGatewayProxyEvent,
APIGatewayProxyResult,
Context,
} from 'aws-lambda';
import axios, { AxiosRequestConfig } from 'axios';
/**
* CALL THE EVENT BASED SFMC API TO SEND PUSH NOTIFICATION
* @param accessToken
*/
async function callEventBasedRestApiSF(accessToken: string):
Promise<string> {
const restApiUrl = SFMC_EVENT_NOTIFICATION_API;
const requestBody = {
contactKey: SFMC_CONTACT_KEY,
EventDefinitionKey: EVENT_DEFINITION_KEY_PAYMENT_FAILURE,
Data: {
ContactKey: SFMC_CONTACT_KEY,
DateInserted: new Date().toISOString(),
},
};
https://dev.azure.com/bp-digital/bp_pulse/_wiki/wikis/bp_pulse/104605/Push-Notification 12/15
2/26/24, 3:01 PM Push Notification - Overview
method: 'POST',
url: restApiUrl,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`,
},
data: requestBody,
};
try {
const response = await axios(config);
console.log('Event notification REST API Response:', response.data);
return "EVENT_SUCCESS";
} catch (error) {
console.error('Event notification error calling REST API:', error);
return "EVENT_ERROR";
}
}
if (accessToken) {
const responseMsg= await callEventBasedRestApiSF(accessToken);
return response(200, `event response', ${responseMsg}`);
} else {
return response(400, `auth response', ${accessToken}`);
}
} catch (error) {
console.error(`Error creating push message:', ${error}`);
return response(400, `Error creating event push message:', ${error}`);
}
}
interface IBody {
userId?: string;
messageId?: number;
logTraceId?: string;
}
export function parseJson(json: string): IBody {
try {
return JSON.parse(json);
} catch (e) {
console.error('Failed to parse json:', e);
return { userId: undefined, messageId: undefined, logTraceId: undefined };
}
}
);
🚨
console.error(
` logTraceId ${logTraceId} - Error: userId or messageId is missing:userId: ${userId}, messageId: ${
console.info(
`logTraceId: ${logTraceId} - Received event with userId: ${userId}, messageId: ${messageId}`,
);
return createPushMessage();
};
https://dev.azure.com/bp-digital/bp_pulse/_wiki/wikis/bp_pulse/104605/Push-Notification 13/15
2/26/24, 3:01 PM Push Notification - Overview
To run the above lambda locally, we need to change run-local.ts file event part -
event: {
body: "{\"userId\": \"userId\",\"messageId\": 1}"
},
the above code only for testing purpose and on that path we need to run yarn start
Furthermore, we also need to create one API to call it, for that we create one controller & route (Path -
downstream-provider-local/unversioned/controllers/controller.ts) -
export default {
qaTokensRequest,
notificationsRequest,
};
router.post('/qaTokens', lambdaController.qaTokensRequest);
router.post('/notifications', lambdaController.notificationsRequest);
module.exports = router;
https://dev.azure.com/bp-digital/bp_pulse/_wiki/wikis/bp_pulse/104605/Push-Notification 14/15
2/26/24, 3:01 PM Push Notification - Overview
....
const userRoutes = require('./user-api/routes/routes');
const dataSapRoutes = require('./data-api/routes/sap');
const batchPendingDeletionDateRoutes = require('./wallet-api/routes/routes');
const unversionedRoutes = require('./unversioned/routes/routes'); <- add this
...
....
app.use('/data/sap/', dataSapRoutes);
app.use('/wallet', batchPendingDeletionDateRoutes);
app.use('/unversioned/', unversionedRoutes); <- add this
....
....
batch_pending_deletion_delete: `${walletServicePath}/batchPendingDeletionDelete/index.ts`,
qa_tokens: `${unversionedInfrastructureLambdaPath}/qaTokens/lambdas/tokenProxyLambda/index.js`,
push_notifications: `${unversionedInfrastructureLambdaPath}/notificationsStack/lambdas/pushNotificationsT
......
Push (message)
https://dev.azure.com/bp-digital/bp_pulse/_wiki/wikis/bp_pulse/104605/Push-Notification 15/15