{"id":16444383,"url":"https://github.com/relateddigital/react-native-related-digital","last_synced_at":"2026-04-01T17:25:55.244Z","repository":{"id":40587167,"uuid":"343378073","full_name":"relateddigital/react-native-related-digital","owner":"relateddigital","description":"Mobile notifications and analytics","archived":false,"fork":false,"pushed_at":"2026-03-18T10:34:52.000Z","size":4522,"stargazers_count":32,"open_issues_count":1,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2026-03-19T01:41:40.173Z","etag":null,"topics":["analytics","javascript","push-notifications","react-native","relateddigital"],"latest_commit_sha":null,"homepage":"https://www.relateddigital.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/relateddigital.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-03-01T10:36:23.000Z","updated_at":"2026-03-18T10:04:10.000Z","dependencies_parsed_at":"2025-12-18T23:07:15.980Z","dependency_job_id":null,"html_url":"https://github.com/relateddigital/react-native-related-digital","commit_stats":{"total_commits":61,"total_committers":3,"mean_commits":"20.333333333333332","dds":0.06557377049180324,"last_synced_commit":"6d3712352656f880ac0e768f3b01ddc401cbdb47"},"previous_names":[],"tags_count":87,"template":false,"template_full_name":null,"purl":"pkg:github/relateddigital/react-native-related-digital","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/relateddigital%2Freact-native-related-digital","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/relateddigital%2Freact-native-related-digital/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/relateddigital%2Freact-native-related-digital/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/relateddigital%2Freact-native-related-digital/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/relateddigital","download_url":"https://codeload.github.com/relateddigital/react-native-related-digital/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/relateddigital%2Freact-native-related-digital/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31290537,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["analytics","javascript","push-notifications","react-native","relateddigital"],"created_at":"2024-10-11T09:24:14.657Z","updated_at":"2026-04-01T17:25:55.218Z","avatar_url":"https://github.com/relateddigital.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/relateddigital/relateddigital-flutter/master/screenshots/related-digital-logo.svg\" width=\"400px;\"/\u003e\n\u003c/p\u003e\n\n[![npm package](https://img.shields.io/npm/v/react-native-related-digital?color=gree\u0026label=npm%20package)](https://www.npmjs.com/package/react-native-related-digital)\n\n\u003c!-- TOC start (generated with https://github.com/derlin/bitdowntoc) --\u003e\n\n- [Supported versions](#supported-versions)\n- [Installation](#installation)\n- [Platform Integrations](#platform-integrations)\n  - [Android](#android)\n  - [IOS](#ios)\n  - [App Groups](#app-groups)\n    - [Errors and Solutions](#errors-and-solutions)\n  - [Recommendations](#recommendations)\n  - [Search Recommendations](#search-recommendations)\n  - [Story](#story)\n  - [App Banner](#app-banner)\n  - [Request Permission](#request-permission)\n    - [Provisional Push (iOS Only)](#provisional-push-ios-only)\n  - [Request and Send IDFA (iOS Only)](#request-and-send-idfa-ios-only)\n  - [Request Location Permission](#request-location-permission)\n  - [Geofencing Interval (Android Only)](#geofencing-interval-android-only)\n  - [Sending Location Status Information](#sending-location-status-information)\n  - [Spin to win \\\u0026 Scratch to win](#spin-to-win--scratch-to-win)\n  - [User Anonymization](#user-anonymization)\n  - [Using Push Notification Messages](#using-push-notification-messages)\n  - [Get User Data](#get-user-data)\n- [Usage](#usage)\n\n\u003c!-- TOC end --\u003e\n\n## Supported versions\n\n**\"react\": \"\u003e=16.8.6\"**\n\n**\"react-native\": \"\u003e=0.60.0\"**\n\n## Installation\n* Install prerequisites.\n```\nnpm i @react-native-async-storage/async-storage\n```\n```\nyarn add @react-native-async-storage/async-storage\n```\n* Install package.\n```\nnpm i react-native-related-digital\n```\n```\nyarn add react-native-related-digital\n```\n* Install pods (IOS only).\n```\n$ cd ios\n$ pod install\n```\n\n## Platform Integrations\n\n### Android\n* Create a Firebase project and register your app. Download google-services.json file and place it in `android/app` folder.\n* Add below line to your `android/build.gradle` file's both repositories sections. If you are going to do Huawei integration, add the `agconnect-services.json` file to the same location.\n```gradle\nmavenCentral()\nmaven {\n    url 'http://developer.huawei.com/repo/'\n    allowInsecureProtocol = true\n}\n```\n* Add below lines to your `android/build.gradle` file's dependencies section.\n```gradle\nclasspath 'com.google.gms:google-services:4.3.10'\nclasspath 'com.huawei.agconnect:agcp:1.6.5.300'\n```\n* Change your `minSdkVersion` to 23.\n* Change your `compileSdkVersion` and `targetSdkVersion` to 34.\n* Add below lines to your `android/app/build.gradle` file's bottom.\n```gradle\napply plugin: 'com.google.gms.google-services'\napply plugin: 'com.huawei.agconnect'\n```\n* Add below line to your `android/app/build.gradle` file's defaultConfig section.\n```gradle\nmultiDexEnabled true\n```\n* Add below line to your `android/app/build.gradle` file's dependencies section.\n```gradle\nimplementation 'org.jetbrains:annotations:16.0.2'\n```\n* Add below code to your `AndroidManifest.xml` file's `application` section to receive notifications when the app is foreground.\n```xml\n\u003cservice\n    android:name=\"euromsg.com.euromobileandroid.service.EuroFirebaseMessagingService\"\n    android:exported=\"false\"\u003e\n    \u003cintent-filter\u003e\n        \u003caction android:name=\"com.google.firebase.MESSAGING_EVENT\" /\u003e\n    \u003c/intent-filter\u003e\n\u003c/service\u003e\n```\n\n* If you are going to do Huawei integration, add the following lines to the file.\n```xml\n\u003cservice\n    android:name=\"euromsg.com.euromobileandroid.service.EuroHuaweiMessagingService\"\n    android:exported=\"false\"\u003e\n    \u003cintent-filter\u003e\n      \u003caction  android:name=\"com.huawei.push.action.MESSAGING_EVENT\"  /\u003e\n    \u003c/intent-filter\u003e\n\u003c/service\u003e\n```\n\n* In order to send push to Huawei devices, you need to follow the steps in the link from the Huawei Developer panel.\nhttps://developer.huawei.com/consumer/en/doc/HMS-Plugin-Guides-V1/config-agc-0000001050178043-V1\n\n* Add below code to your `AndroidManifest.xml` file's `application` section to enable geofence capability.\n```xml\n\u003cservice\n    android:name=\"com.visilabs.gps.geofence.GeofenceTransitionsIntentService\"\n    android:enabled=\"true\"\n    android:permission=\"android.permission.BIND_JOB_SERVICE\" /\u003e\n\n\u003creceiver\n    android:name=\"com.visilabs.gps.geofence.VisilabsAlarm\"\n    android:exported=\"false\" /\u003e\n\n\u003creceiver\n    android:name=\"com.visilabs.gps.geofence.GeofenceBroadcastReceiver\"\n    android:enabled=\"true\"\n    android:exported=\"true\" /\u003e\n```\n* Modify your `MainApplication.java` or `MainApplicaiton.kt` as below to init library. Change geofenceEnabled parameter as you want.\n\n#### Java\n```java\nimport com.visilabs.Visilabs;\nimport euromsg.com.euromobileandroid.EuroMobileManager;\nimport euromsg.com.euromobileandroid.enums.RDNotificationPriority;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Build;\nimport org.jetbrains.annotations.Nullable;\n```\n```java\n@Override\npublic Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) {\n    if (Build.VERSION.SDK_INT \u003e= 34 \u0026\u0026 getApplicationInfo().targetSdkVersion \u003e= 34) {\n        return super.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);\n    } else {\n        return super.registerReceiver(receiver, filter);\n    }\n}\n\n@Override\npublic void onCreate() {\n  // ...\n\n  initEuroMessage();\n}\n\nprivate void initEuroMessage() {\n    String appAlias = \"demo-alias\";\n    String huaweiAppAlias = \"demo-alias-huawei\";\n    String organizationId = \"OID\";\n    String siteId = \"SID\";\n    String datasource = \"datasource\";\n    String channel = \"Android\";\n    String segmentUrl = \"http://lgr.visilabs.net\";\n    String realtimeUrl = \"http://rt.visilabs.net\";\n    String targetUrl = \"http://s.visilabs.net/json\";\n    String actionUrl = \"http://s.visilabs.net/actjson\";\n    String geofenceUrl = \"http://s.visilabs.net/geojson\";\n\n    Visilabs.CreateAPI(organizationId, siteId, segmentUrl,\n            datasource, realtimeUrl, channel, this, targetUrl, actionUrl, 30000, geofenceUrl, true, \"reactnative\");\n\n    EuroMobileManager euroMobileManager = EuroMobileManager.init(appAlias, huaweiAppAlias, this);\n    \n    // optional\n    euroMobileManager.setPushIntent(\"com.pushsdk.MainActivity\", this);\n    euroMobileManager.setNotificationTransparentSmallIcon(R.drawable.ic_launcher, this);\n    euroMobileManager.setNotificationTransparentSmallIconDarkMode(R.drawable.ic_launcher, this);\n    euroMobileManager.useNotificationLargeIcon(true);\n    euroMobileManager.setNotificationLargeIcon(R.drawable.ic_launcher, this);\n    euroMobileManager.setNotificationLargeIconDarkMode(R.drawable.ic_launcher, this);\n    euroMobileManager.setNotificationColor(\"#d1dbbd\");\n    euroMobileManager.setChannelName(\"Channel\", this);\n    euroMobileManager.setNotificationPriority(RDNotificationPriority.NORMAL, this); // Set to HIGH for push notifications to appear as temporary banners\n}\n```\n\n#### Kotlin\n\n```kotlin\nimport com.visilabs.Visilabs;\nimport euromsg.com.euromobileandroid.EuroMobileManager;\nimport euromsg.com.euromobileandroid.enums.RDNotificationPriority;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Build;\nimport org.jetbrains.annotations.Nullable;\n```\n```kotlin\noverride fun registerReceiver(receiver: BroadcastReceiver?, filter: IntentFilter?): Intent? {\n  return if (Build.VERSION.SDK_INT \u003e= 34 \u0026\u0026 applicationInfo.targetSdkVersion \u003e= 34) {\n      super.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED)\n  } else {\n      super.registerReceiver(receiver, filter)\n  }\n}\n\noverride fun onCreate() {\n  // ...\n  \n  initEuroMessage()\n}\n\nprivate fun initEuroMessage() {\n    val appAlias = \"demo-alias\"\n    val huaweiAppAlias = \"demo-alias-huawei\"\n    val organizationId = \"OID\"\n    val siteId = \"SID\"\n    val datasource = \"datasource\"\n    val channel = \"Android\"\n    val segmentUrl = \"http://lgr.visilabs.net\"\n    val realtimeUrl = \"http://rt.visilabs.net\"\n    val targetUrl = \"http://s.visilabs.net/json\"\n    val actionUrl = \"http://s.visilabs.net/actjson\"\n    val geofenceUrl = \"http://s.visilabs.net/geojson\"\n\n    Visilabs.CreateAPI(\n        organizationId,\n        siteId,\n        segmentUrl,\n        datasource,\n        realtimeUrl,\n        channel,\n        this,\n        targetUrl,\n        actionUrl,\n        30000,\n        geofenceUrl,\n        true,\n        \"reactnative\")\n\n    val euroMobileManager = EuroMobileManager.init(appAlias, huaweiAppAlias, this)\n    // Optional settings\n    euroMobileManager.setPushIntent(\"com.pushsdk.MainActivity\", this)\n    euroMobileManager.setNotificationTransparentSmallIcon(R.mipmap.ic_launcher, this)\n    euroMobileManager.setNotificationTransparentSmallIconDarkMode(R.mipmap.ic_launcher, this)\n    euroMobileManager.useNotificationLargeIcon(true)\n    euroMobileManager.setNotificationLargeIcon(R.mipmap.ic_launcher, this)\n    euroMobileManager.setNotificationLargeIconDarkMode(R.mipmap.ic_launcher, this)\n    euroMobileManager.setNotificationColor(\"#d1dbbd\")\n    euroMobileManager.setChannelName(\"Channel\", this)\n    euroMobileManager.setNotificationPriority(RDNotificationPriority.NORMAL, this)\n}\n```\n\n* If you want to track installed apps, call below method.\n```javascript\n  await visilabsApi.sendTheListOfAppsInstalled()\n```\nAlso, add one of the below sections to your `AndroidManifest.xml`\n\n**Option 1**\n```xml\n\u003cmanifest package=\"com.example.myApp\"\u003e\n    \u003cqueries\u003e\n        \u003cpackage android:name=\"com.example.app1\" /\u003e\n        \u003cpackage android:name=\"com.example.app2\" /\u003e\n    \u003c/queries\u003e\n\u003c/manifest\u003e\n```\n\n**Option 2**\n```xml\n\u003cuses-permission android:name=\"android.permission.QUERY_ALL_PACKAGES\" \ntools:ignore=\"QueryAllPackagesPermission\" /\u003e\n```\n* Add below listener to be able to handle carousel push notification's item click.\n```javascript\n  addEventListener('carouselItemClicked', async (carouselItemInfo) =\u003e {\n    console.log('carouselItemInfo is ', carouselItemInfo)\n  }, euroMessageApi)\n```\n\n### IOS\n* Enable **Push Notifications** and **Background Modes-\u003eRemote Notifications** capabilities.\n\n#### Objective-C\n* Add `Empty.swift` file to your project as the sdk contains Swift code and xcode requires at least one empty swift file in each target.\n\n**AppDelegate.mm**\n```objective-c\n// other codes...\n#import \"RelatedDigitalPushModule.h\"\n#import \u003cUserNotifications/UserNotifications.h\u003e\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions\n{\n  // other codes...\n  \n  UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];\n  center.delegate = self;\n  \n  [RelatedDigitalPushModule initRelatedDigital:@\"organization_id\" profileId:@\"profile_id\" dataSource:@\"datasource\" appAlias:@\"rdgencallariostest\" inAppNotificationsEnabled:true requestTimeoutSeconds:30 geofenceEnabled:false askLocationPermmissionAtStart:false maxGeofenceCount:20 isIDFAEnabled:false loggingEnabled:true];\n\n  return // other codes...\n}\n\n- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings\n{\n [RelatedDigitalPushModule didRegisterUserNotificationSettings:notificationSettings];\n}\n\n- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken\n{\n [RelatedDigitalPushModule didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];\n}\n\n- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo\nfetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler\n{\n  [RelatedDigitalPushModule didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];\n}\n\n- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error\n{\n [RelatedDigitalPushModule didFailToRegisterForRemoteNotificationsWithError:error];\n}\n\n-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler\n{\n  completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);\n}\n\n// other codes...\n```\n\n#### Swift\n\n**AppDelegate.swift**\n```swift\n// other codes...\nimport UserNotifications\nimport react_native_related_digital\n\n@main\nclass AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {\n  // other codes...\n\n  // 🔔 Push Notification delegate settings\n  let center = UNUserNotificationCenter.current()\n  center.delegate = self\n\n  // 🔔 Related Digital init\n  RelatedDigitalPushModule.initRelatedDigital(\n    \"organization_id\", // OID\n    profileId: \"profile_id\", // SID\n    dataSource: \"datasource\",\n    appAlias: \"app_alias\",\n    inAppNotificationsEnabled: true,\n    requestTimeoutSeconds: 30,\n    geofenceEnabled: false,\n    askLocationPermmissionAtStart: false,\n    maxGeofenceCount: 20,\n    isIDFAEnabled: true,\n    loggingEnabled: true,\n    deliveredBadge: true\n  )\n\n  return true\n}\n\n// MARK: - Push Notification Delegate Methods\nfunc application(_ application: UIApplication, didRegister notificationSettings: UIUserNotificationSettings) {\n  RelatedDigitalPushModule.didRegister(notificationSettings)\n}\nfunc application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {\n  RelatedDigitalPushModule.didRegisterForRemoteNotifications(withDeviceToken: deviceToken)\n}\nfunc application(_ application: UIApplication,\n                 didReceiveRemoteNotification userInfo: [AnyHashable : Any],\n                 fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -\u003e Void) {\n  RelatedDigitalPushModule.didReceiveRemoteNotification(userInfo, fetchCompletionHandler: completionHandler)\n}\nfunc application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {\n  RelatedDigitalPushModule.didFailToRegisterForRemoteNotificationsWithError(error)\n}\nfunc userNotificationCenter(_ center: UNUserNotificationCenter,\n                            willPresent notification: UNNotification,\n                            withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -\u003e Void) {\n  completionHandler([.sound, .alert, .badge])\n}\n// other codes...\n```\n\n* Add `NSUserTrackingUsageDescription` to your `Info.plist` file to be able to use AdvertisingTrackingID on iOS 14 and later. If you don't want to use it, set `isIDFAEnabled` to `false` among the `initRelatedDigital` parameters.\n* If you have any issues while building the app due to `_swift_getFunctionReplacement` or any swift related errors, try editing your project's (not target) `Library Search Paths` and remove `$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)` line.\n* If you are going to use in app notifications feature, add below lines to your project target's `Build Phases`-\u003e`Copy Bundle Resources` section. Select `Create folder references` when prompted.\n  * `Pods/VisilabsIOS/Sources/TargetingAction/InAppNotification/Views/VisilabsMiniNotificationViewController.xib`\n  * `Pods/VisilabsIOS/Sources/TargetingAction/InAppNotification/Views/VisilabsFullNotificationViewController.xib`\n  * `Pods/VisilabsIOS/Sources/TargetingAction/drawer/drawerView.xib`\n  * `Pods/VisilabsIOS/Sources/TargetingAction/InAppNotification/BannerView/BannerView.xib`\n  * `Pods/VisilabsIOS/Sources/TargetingAction/InAppNotification/BannerView/BannerCollectionViewCell.xib`\n* #### To enable rich notification capabilites like showing image or video;\n1. Add `Notification Service Extension` target to your project and name it `RelatedDigitalNotificationService`. Change this service's target iOS version to 10.0. Then change newly added `NotificationService.m` file contents with the following:\n(Don't forget to enter your app name instead of `APP_ALIAS`)\n```objective-c\n#import \"NotificationService.h\"\n#import \"RelatedDigitalNotificationService.h\"\n\n@interface NotificationService ()\n\n@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);\n@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;\n\n@end\n\n@implementation NotificationService\n\n- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {\n    self.contentHandler = contentHandler;\n    self.bestAttemptContent = [request.content mutableCopy];\n    \n  [RelatedDigitalNotificationService didReceiveNotificationRequest:@\"APP_ALIAS\" withBestAttemptContent:self.bestAttemptContent withContentHandler:self.contentHandler];\n}\n\n- (void)serviceExtensionTimeWillExpire {\n    // Called just before the extension will be terminated by the system.\n    // Use this as an opportunity to deliver your \"best attempt\" at modified content, otherwise the original push payload will be used.\n  [RelatedDigitalNotificationService didReceiveNotificationRequest:@\"APP_ALIAS\" withBestAttemptContent:self.bestAttemptContent withContentHandler:self.contentHandler];\n}\n\n@end\n```\n2. Add below lines to your Podfile's root level.\n```\ntarget 'RelatedDigitalNotificationService' do\n  pod 'react-native-related-digital', :path =\u003e '../node_modules/react-native-related-digital'\n  \n  use_native_modules!\nend\n\n# Post Install processing for RelatedDigitalNotificationService causing errors\ndef notification_service_post_install(installer)\n  installer.pods_project.targets.each do |target|\n    target.build_configurations.each do |config|\n      config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'NO'\n    end\n  end\nend\n```\n3. Modify Podfile and have the following in main target section.\n```\npost_install do |installer|\n  notification_service_post_install(installer)\n  # Other post install function calls\nend\n```\n4. Add `Empty.swift` file to your RelatedDigitalNotificationService target as the sdk contains Swift code and xcode requires at least one empty swift file in each target.\n5. Make sure your deployment target is ios 10.\n```\nplatform :ios, '10.0'\n```\n6. Execute `pod install` then run.\n* #### To enable push notification carousel;\n1. Add `Notification Content Extension` target to your project and name it `RelatedDigitalNotificationContent`. Change this service's target iOS version to 11.0. Remove newly added files under RelatedDigitalNotificationContent except Info.plist. Then add EMNotificationViewController.swift file with the following content.\n```swift\nimport UIKit\nimport UserNotifications\nimport UserNotificationsUI\nimport Euromsg\n\n@objc(EMNotificationViewController)\nclass EMNotificationViewController: UIViewController, UNNotificationContentExtension {\n    \n    let carouselView = EMNotificationCarousel.initView()\n    var completion: ((_ url: URL?, _ bestAttemptContent: UNMutableNotificationContent?) -\u003e Void)?\n    \n    var notificationRequestIdentifier = \"\"\n    \n    func didReceive(_ notification: UNNotification) {\n        notificationRequestIdentifier = notification.request.identifier\n        Euromsg.configure(appAlias: \"APP_ALIAS\", launchOptions: nil, enableLog: true, deliveredBadge: true)\n        carouselView.didReceive(notification)\n    }\n    func didReceive(_ response: UNNotificationResponse, completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -\u003e Void) {\n        carouselView.didReceive(response, completionHandler: completion)\n\n    }\n    override func loadView() {\n        completion = { [weak self] url, bestAttemptContent in\n            if let identifier = self?.notificationRequestIdentifier {\n                UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [identifier])\n                UNUserNotificationCenter.current().getDeliveredNotifications(completionHandler: { notifications in\n                    bestAttemptContent?.badge =  NSNumber(value: notifications.count)\n                })\n            }\n            if let url = url {\n                if #available(iOSApplicationExtension 12.0, *) {\n                    self?.extensionContext?.dismissNotificationContentExtension()\n                }\n                self?.extensionContext?.open(url)\n            } else {\n                if #available(iOSApplicationExtension 12.0, *) {\n                    self?.extensionContext?.performNotificationDefaultAction()\n                }\n            }\n        }\n        carouselView.completion = completion\n        carouselView.delegate = self\n        self.view = carouselView\n    }\n}\n\n/**\n Add if you want to track which carousel element has been selected\n */\nextension EMNotificationViewController: CarouselDelegate {\n    \n    func selectedItem(_ element: EMMessage.Element) {\n        // Add your work...\n        print(\"Selected element is =\u003e \\(element)\")\n    }\n    \n}\n```\n2. Add or replace the following lines in newly added `RelatedDigitalNotificationContent/Info.plist`\n```\n\u003ckey\u003eNSExtension\u003c/key\u003e\n\u003cdict\u003e\n  \u003ckey\u003eNSExtensionAttributes\u003c/key\u003e\n  \u003cdict\u003e\n    \u003ckey\u003eUNNotificationExtensionUserInteractionEnabled\u003c/key\u003e\n    \u003ctrue/\u003e\n    \u003ckey\u003eUNNotificationExtensionDefaultContentHidden\u003c/key\u003e\n    \u003cfalse/\u003e\n    \u003ckey\u003eUNNotificationExtensionCategory\u003c/key\u003e\n    \u003cstring\u003ecarousel\u003c/string\u003e\n    \u003ckey\u003eUNNotificationExtensionInitialContentSizeRatio\u003c/key\u003e\n    \u003creal\u003e1\u003c/real\u003e\n  \u003c/dict\u003e\n  \u003ckey\u003eNSExtensionPrincipalClass\u003c/key\u003e\n  \u003cstring\u003eRelatedDigitalNotificationContent.EMNotificationViewController\u003c/string\u003e\n  \u003ckey\u003eNSExtensionPointIdentifier\u003c/key\u003e\n  \u003cstring\u003ecom.apple.usernotifications.content-extension\u003c/string\u003e\n\u003c/dict\u003e\n```\n3. Add below lines to your Podfile's root level.\n```\ntarget 'RelatedDigitalNotificationContent' do\n  use_native_modules!\n  \n  pod 'Euromsg', '\u003e= 2.0.0'\nend\n```\n4. In Xcode, select `RelatedDigitalNotificationContent` target and add below files to `Build Phases`-\u003e`Copy Bundle Resources` section. Select `Create folder references` when prompted.\n    * `Pods/Euromsg/Sources/Euromsg/Classes/EMNotificationCarousel/CarouselCell.xib`\n    * `Pods/Euromsg/Sources/Euromsg/Classes/EMNotificationCarousel/EMNotificationCarousel.xib`\n5. Make sure your deployment target is ios 10.\n```\nplatform :ios, '10.0'\n```\n6. Execute `pod install` then run.\n\n### App Groups\n\nEnable `App Groups` Capability for your targets. App Groups allow your app to execute code when a notification is recieved, even if your app is not active. This is required for Related Digital's analytics features and to store and access notification payloads of the last 30 days.\n\n- In your Main App Target go to `Signing \u0026 Capabilities \u003e All`. \n- Click `+ Capability` if you do not have App Groups in your app yet.\n- Select App Groups.\n- Under App Groups click the `+` button.\n- Set the `App Groups` container to be `group.BUNDLE_ID.relateddigital` where `BUNDLE_ID` is the same as set in `Bundle Identifier`.\n- Press OK.\n- In the NotificationServiceExtension Target\n- Go to `Signing \u0026 Capabilities \u003e All`\n- Click `+ Capability` if you do not have App Groups in your app yet.\n- Select App Groups\n- In the NotificationContentExtension Target go to `Signing \u0026 Capabilities` \u003e All`.\n- Click `+ Capability`.\n- Select App Groups\n- Under App Groups click the `+` button.\n- Set the `App Groups` container to be `group.BUNDLE_ID.relateddigital` where `BUNDLE_ID` is the same as your Main App Target `Bundle Identifier`. Do Not Include `NotificationServiceExtension` and `NotificationContentExtension`.\n- Press OK\n\n![App Groups](https://raw.githubusercontent.com/relateddigital/euromessage-ios/master/screenshots/appgroups.png)\n\n![App Groups Name](https://raw.githubusercontent.com/relateddigital/euromessage-ios/master/screenshots/appgroups-name.png)\n\n\n#### Errors and Solutions\n  If you are getting errors regarding the firebase app, update all Define Module parameters to YES as shown in the screenshots.\n  \n  ![Pods Defines Module](https://raw.githubusercontent.com/relateddigital/euromessage-ios/master/screenshots/podsdefinesmodule.png)\n  ![Main Target Defines Module](https://raw.githubusercontent.com/relateddigital/euromessage-ios/master/screenshots/maintargetdefinesmodule.png)\n  ![Service Target Defines Module](https://raw.githubusercontent.com/relateddigital/euromessage-ios/master/screenshots/servicetargetdefinesmodule.png)\n  ![Content Target Defines Module](https://raw.githubusercontent.com/relateddigital/euromessage-ios/master/screenshots/contenttargetdefinesmodule.png)\n\n### Recommendations\n\nTo view recommendations, use `visilabsApi.getRecommendations(zoneId, productCode, properties, filters)` method.\n\n```json\n{\n    \"recommendations\": [\n        {\n            \"attr1\": \"420494\",\n            \"attr10\": \"\",\n            \"attr2\": \"\",\n            \"attr3\": \"\",\n            \"attr4\": \"\",\n            \"attr5\": \"\",\n            \"attr6\": \"\",\n            \"attr7\": \"\",\n            \"attr8\": \"\",\n            \"attr9\": \"\",\n            \"brand\": \"Related Digital\",\n            \"code\": \"1159092\",\n            \"comment\": 0,\n            \"cur\": \"TRY\",\n            \"dcur\": \"TRY\",\n            \"dest_url\": \"https://relateddigital.com/example-product?OM.zn=You%20Viewed-w60\u0026OM.zpc=1159092\",\n            \"discount\": 0,\n            \"dprice\": 5.25,\n            \"freeshipping\": false,\n            \"img\": \"https://cdn.relateddigital.com/example.png\",\n            \"price\": 5.25,\n            \"qs\": \"OM.zn=You Viewed-w60\u0026OM.zpc=1159092\",\n            \"rating\": 0,\n            \"samedayshipping\": false,\n            \"title\": \"Titiz TP-115 Yeşil Ayakkabı\"\n        }\n    ],\n    \"title\": \"Display You Viewed\"\n}\n```\n\nAfter clicking on each product, run the following function with the `qs` parameter. This parameter is included in the response returned from the `getRecommendations` function.\n```js\nvisilabsApi.trackRecommendationClick(qs)\n```\n\nMore information [Rmc Docs](https://relateddigital.atlassian.net/wiki/spaces/RMCKBT/pages/1746403404/React+Native+-+Recommendations)\n\n\n### Search Recommendations\n\nSearch recommendations are handled by the `visilabsApi.searchRecommendation(keyword: string, searchType: string): Promise\u003cany\u003e;` method of SDK. You have to pass 2 mandatory arguments which are `keyword` and `searchType` to `searchRecommendation` method. Value of `searchType` parameter can be acquired from the RMC panel. The value of `searchType` is defined in the search widget page's **Search Type** combo box.\n\nThe return type of the `searchRecommendation` method is a JSON object. The JSON object contains 4 containers which are `brandContainer`, `categoryContainer`, `productAreaContainer`, and `searchContainer`. An example of the return type is shown below.\n\n```json\n{\n  \"brandContainer\": {\n    \"isActive\": false,\n    \"popularBrands\": [\n      {\n        \"name\": \"Brand Name\"\n      }\n    ],\n    \"title\": \"\",\n    \"report\": {\n      \"click\": \"OM.zn=search-1\u0026OM.zpc=search-brand\",\n      \"impression\": \"OM.zdn=search-1\u0026OM.zcp=search-web\"\n    }\n  },\n  \"categoryContainer\": {\n    \"isActive\": true,\n    \"popularCategories\": [\n      {\n        \"name\": \"Book\"\n      },\n      {\n        \"name\": \"Laptop\"\n      },\n      {\n        \"name\": \"SSD\"\n      }\n    ],\n    \"report\": {\n      \"click\": \"OM.zn=search-1\u0026OM.zpc=search-category\",\n      \"impression\": \"OM.zdn=search-1\u0026OM.zcp=search-web\"\n    }\n  },\n  \"productAreaContainer\": {\n    \"changeTitle\": false,\n    \"products\": [\n      {\n        \"brandName\": \"Visilabs\",\n        \"code\": \"123\",\n        \"currency\": \"TRY\",\n        \"discountCurrency\": \"TRY\",\n        \"discountPrice\": 1499.99,\n        \"imageUrl\": \"https://www.visilabs.com/123.jpg\",\n        \"name\": \"Product Name 123\",\n        \"price\": 2999.99,\n        \"url\": \"https://www.visilabs.com/123\"\n      },\n      {\n        \"brandName\": \"Euromessage\",\n        \"code\": \"124\",\n        \"currency\": \"TRY\",\n        \"discountCurrency\": \"TRY\",\n        \"discountPrice\": 1499.99,\n        \"imageUrl\": \"https://www.visilabs.com/124.jpg\",\n        \"name\": \"Product Name 124\",\n        \"price\": 2999.99,\n        \"url\": \"https://www.visilabs.com/124\"\n      }\n    ],\n    \"searchResultMessage\": \"\",\n    \"report\": {\n      \"click\": \"OM.zn=search-1\u0026OM.zpc=search-productarea\",\n      \"impression\": \"OM.zdn=search-1\u0026OM.zcp=search-web\"\n    }\n  },\n  \"searchContainer\": {\n    \"isActive\": true,\n    \"popularSearches\": [\n      {\n        \"name\": \"Product Name 123\"\n      },\n      {\n        \"name\": \"Scifi Books\"\n      },\n      {\n        \"name\": \"Visilabs\"\n      }\n    ],\n    \"report\": {\n      \"click\": \"OM.zn=search-1\u0026OM.zpc=search-word\",\n      \"impression\": \"OM.zdn=search-1\u0026OM.zcp=search-web\"\n    }\n  }\n}\n```\n\nAn example of how to use the `searchRecommendation` method is shown below.\n\n```js\nlet searchKeyword = \"shoe\";\nlet searchType = \"web\";\n\nlet productSearchResults = [];\nlet categorySearchResults = [];\nlet brandSearchResults = [];\nlet popularSearchSearchResults = [];\n\n\nlet products = [];\nlet categories = [];\nlet brands = [];\nlet popularSearches = [];\n\nconst searchRecommendationResponse = await visilabsApi.searchRecommendation(searchKeyword, searchType);\n\n\n// productAreaContainer\nconst productAreaContainer = searchRecommendationResponse.productAreaContainer;\nconst productAreaContainerProducts = productAreaContainer.products;\nconst productAreaContainerReport = productAreaContainer.report;\n\nproductAreaContainerProducts.forEach(productObject =\u003e {\n  const productName = productObject.name;\n  products.push(productObject);\n  productSearchResults.push({ name: productName, report: productAreaContainerReport });\n});\n\n// categoryContainer\nconst categoryContainer = searchRecommendationResponse.categoryContainer;\nconst categoryContainerPopularCategories = categoryContainer.popularCategories;\nconst categoryContainerReport = categoryContainer.report;\n\ncategoryContainerPopularCategories.forEach(categoryObject =\u003e {\n  const categoryName = categoryObject.name;\n  categories.push(categoryObject);\n  categorySearchResults.push({ name: categoryName, report: categoryContainerReport });\n});\n\n// brandContainer\nconst brandContainer = searchRecommendationResponse.brandContainer;\nconst brandContainerPopularBrands = brandContainer.popularBrands;\nconst brandContainerReport = brandContainer.report;\n\nbrandContainerPopularBrands.forEach(brandObject =\u003e {\n  const brandName = brandObject.name;\n  brands.push(brandObject);\n  brandSearchResults.push({ name: brandName, report: brandContainerReport });\n});\n\n// searchContainer\nconst searchContainer = searchRecommendationResponse.searchContainer;\nconst searchContainerPopularSearches = searchContainer.popularSearches;\nconst searchContainerReport = searchContainer.report;\n\nsearchContainerPopularSearches.forEach(popularSearchObject =\u003e {\n  const popularSearchName = popularSearchObject.name;\n  popularSearches.push(popularSearchObject);\n  popularSearchSearchResults.push({ name: popularSearchName, report: searchContainerReport });\n});\n```\n\nTo report the clicks of search recommendations you need to call the `trackSearchRecommendationClick` method with the `report` property of container objects. For example, if you want to report the click of a product, you need to call the `trackSearchRecommendationClick` method with the `report` property of the container.\n\n```js\nlet products = [];\nlet searchKeyword = \"shoe\";\nlet searchType = \"web\";\nconst searchRecommendationResponse = await visilabsApi.searchRecommendation(searchKeyword, searchType);\n\n\n// productAreaContainer\nconst productAreaContainer = searchRecommendationResponse.productAreaContainer;\nconst productAreaContainerProducts = productAreaContainer.products;\nconst productAreaContainerReport = productAreaContainer.report;\n\nproductAreaContainerProducts.forEach(productObject =\u003e {\n  const productName = productObject.name;\n  products.push(productObject);\n});\n\nvisilabsApi.trackSearchRecommendationClick(productAreaContainer.report);\n```\n\n\n\n### Story\nFollow the step below to add a countdown to your stories.\n\n**iOS**\n\nAdd below lines to your project target's `Build Phases`-\u003e`Copy Bundle Resources` section. Select `Create folder references` when prompted.\n  * `Pods/VisilabsIOS/Sources/TargetingAction/Story/Views/timerView/timerView.xib`\n\n**Android**\n\nNo special installation required\n\n**Usage**\n\nTo add story view to your app, import `RDStoryView` and use as below:\n```jsx\nimport { RDStoryView } from 'react-native-related-digital'\n...\n...\n\u003cRDStoryView\n  actionId={'1'} // optional\n  onItemClicked={(data) =\u003e { \n    console.log('Story data', data)\n  }}\n  style={{ flex: 1 }}\n/\u003e\n```\n\n\n### App Banner\n\n**iOS**\n\nAdd below lines to your project target's `Build Phases`-\u003e`Copy Bundle Resources` section. Select `Create folder references` when prompted.\n  * `Pods/VisilabsIOS/Sources/TargetingAction/InAppNotification/BannerView/BannerView.xib`\n  * `Pods/VisilabsIOS/Sources/TargetingAction/InAppNotification/BannerView/BannerCollectionViewCell.xib`\n\n**Android**\n\nNo special installation required\n\n**Usage**\n\nTo add banner view to your app, import `RDBannerView` and use as below:\n```jsx\nimport { RDBannerView } from 'react-native-related-digital'\n...\n...\n\u003cRDBannerView\n  properties={{\n    // 'OM.inapptype': 'banner_carousel',\n  }}\n  onRequestResult={isAvailable =\u003e \n    console.log('Related Digital - Banners', isAvailable)\n  }\n  onItemClicked={data =\u003e \n    console.log('Related Digital - Banner data', data)\n  }\n  style={{\n    flex: 1,\n  }}\n/\u003e\n```\n\n`onRequestResult` response\n```js\n{ \"isAvailable\": true } // or false\n```\n\n`onItemClicked` response\n```js\n{ \"bannerLink\": \"URL\" }\n```\n\n### Request Permission\nIt is used to request notification permission from the user. On iOS devices, a prompt asking for permission to receive notifications will appear. On Android devices, if Android 13 (API 33) or a higher version is used, a similar prompt will be displayed. In lower versions, permission is assumed to be granted by default.\nIt should be called every time the application is launched.\n\n**IMPORTANT NOTE**: The notification permission here indicates whether permission has been granted from the device. If your user turns off notification permission from your application's account settings, the permission status here will not change. Therefore, you should check the permission information managed by the user from their account settings on your side. Otherwise, notifications may be sent to users without permission.\nFor example;\n```javascript\npushPermitRequest = async (isProvisional) =\u003e {\n    const pushPermit = await requestPermissions(isProvisional)\n    console.log(\"Device Push Permit\",pushPermit);\n    if (\n        user.pushPermit == true // If permission has been granted before\n        || // or\n        typeof user.pushPermit === 'undefined' // If no definition has been made regarding the permission status\n      ) {\n        euroMessageApi.setUserProperties({pushPermit: pushPermit ? 'Y' : 'N'}).then(() =\u003e {\n          euroMessageApi.subscribe(this.state.token)\n        })\n    }\n  }\n```\n#### Provisional Push (iOS Only)\nTo use provisional push feature on iOS, call `requestPermissions` method with parameter `false`\n```javascript\nconst isProvisional = true\nrequestPermissions(isProvisional)\n```\n### Request and Send IDFA (iOS Only)\nYou can call the `requestIDFA` function whenever you want to show `App Tracking Transparency` prompt to request IDFA and send the value to Visilabs servers. If you are going to use this function, you should set the `isIDFAEnabled` parameter to `false` in the initial parameters.\n```javascript\nrequestIDFA()\n```\n### Request Location Permission\nIf you have set the (iOS only)`askLocationPermmissionAtStart` parameter in `initRelatedDigital` to false in the `AppDelegate.m` file, you can request location permission wherever you want with this function.\n```javascript\nrequestLocationPermission()\nrequestLocationPermissionWithPopup(title,message,positiveButton,negativeButton) // only android\nrequestBackgroundLocationPermission() // only android\nrequestBackgroundLocationPermissionWithPopup(foregroundTitle, foregroundMessage, backgroundTitle, backgroundMessage, positiveButton, negativeButton) // only android\n```\n### Geofencing Interval (Android Only)\n(Android only) You can change the geofence location update interval with the `setGeofencingIntervalInMinute` function.\n```javascript\nsetGeofencingIntervalInMinute(15)\n```\n### Sending Location Status Information\nYou can call the `sendLocationPermission` method to to send the location permission status of your users to Visilabs servers and use this information on the panel later.\n```javascript\nawait visilabsApi.sendLocationPermission()\n```\nThis information is sent with the `OM.locpermit` parameter and can take one of the following 3 values:\n\n* \"always\" : Location permission is obtained while the application is open and closed.\n* \"appopen\" : Location permission is only obtained when the app is open.\n* \"none\" : Location permission is not obtained.\n\n### Spin to win \u0026 Scratch to win\nTo use these features, call `customEvent` method with the page name you created on RMC dashboard.\n```javascript\nvisilabsApi.customEvent('*spintowin*', {\n  'OM.pv': '77',\n  'OM.pn': 'Nectarine Blossom \u0026 Honey Body \u0026 Hand Lotion',\n  'OM.ppr': '39'\n})\n\nvisilabsApi.customEvent('*scratchtowin*', {\n  'OM.pv': '77',\n  'OM.pn': 'Nectarine Blossom \u0026 Honey Body \u0026 Hand Lotion',\n  'OM.ppr': '39'\n})\n```\n\n### User Anonymization\n\nTo anonymize a user, you should first call one of the following functions, `setUserProperty` or `setUserProperties`, as shown below:\n```javascript\nlet userData = {\n  // ...other properties\n  \"SetAnonymous\": true \n}\neuroMessageApi.setUserProperties(userData)\n\n// OR\n\nawait euroMessageApi.setUserProperty('SetAnonymous', 'true')\n```\nAfter the set operation is completed, you must save the changes by calling the `subscribe` function:\n```javascript\neuroMessageApi.subscribe(this.state.token)\n```\n\n**IMPORTANT NOTE**: If you do not set the `SetAnonymous` parameter back to `false`, the user will remain anonymous indefinitely.\n\n\n### Using Push Notification Messages\nYou can access payload list of last 30 days if you have completed iOS `NotificationServiceExtension` and `App Groups` setup. Using `getPushMessages` method you can access these payloads. Android does not require special installation.\n\nWhen sending a notification, if you add the `pushCategory` parameter to the custom parameters field, you can retrieve the category parameter you sent for the respective push within the payload. This process will enable you to categorize your notifications. Example values include `transactional`, `order`, `bulk`, `campaign`, `reco`, etc.\n\n```javascript\nconst getPushMessages = async () =\u003e {\n    const messages = await euroMessageApi.getPushMessages()\n    console.log('messages', messages)\n}\n\n// pushId optional. If a pushId is sent, it will mark only the relevant push as read. If no parameters are sent, it will mark all notifications as read.\nconst readPushMessages = async (pushId) =\u003e { \n  const result = await euroMessageApi.readPushMessages(pushId)\n    console.log('READ Push Messages', JSON.stringify(result))\n}\n\n// pushId is optional. If a PushId is provided, only the corresponding notification will be removed from the notification center. If no parameters are sent, all notifications will be cleared from the OS notification center.\n// Note: pushId should be sent in the payload for iOS, and notificationId for Android.\nconst deletePushMessages = async (pushId) =\u003e {\n  const result = await euroMessageApi.deletePushNotificationsFromNotificationCenter(pushId)\n  console.log('DELETE Push Messages', JSON.stringify(result))\n}\n\n// pushId is optional. If a PushId is provided, only the corresponding notification will be removed from the LOCAL notification center. If no parameters are sent, all notifications will be cleared from the LOCAL notification center.\n// Note: The pushId included in the payload should be sent as a parameter value for all operating systems.\nconst deletLocalPushMsg = async (pushId) =\u003e {\n  const result = await euroMessageApi.deletePushMessages(pushId)\n  console.log('DELETE Push Messages', JSON.stringify(result))\n  }\n```\nMessages are sorted by date. The most recent message is displayed at the top of the list.\n```json\n// Android response\n[\n  {\n    \"altUrl\": \"\",\n    \"date\": \"2025-03-27 17:02:19\",\n    \"emPushSp\": \"D9DED6935B934325972EF0A4EC814AB3|2CCE03D672E4492EB6C85CDBD8AB9D5E|05F46A9218A04757AD2AA802D4B0FD49|2164102|1|0|true|false|0|0|3215470e-067b-49cc-b48c-3c2637a16bd6\",\n    \"email\": \"Baris.arslan@euromsg.com\",\n    \"extraData\": {\n      \"map\": {\n        \"altUrl\": \"\",\n        \"badgeCount\": \"0\",\n        \"expiredate\": \"912345678\",\n        \"pushType\": \"Text\",\n        \"test\": \"true\",\n        \"utm_campaign\": \"campaign\",\n        \"utm_medium\": \"medium\",\n        \"utm_source\": \"source\"\n      }\n    },\n    \"keyID\": \"Baris.arslan@euromsg.com\",\n    \"mediaUrl\": \"\",\n    \"message\": \"baris test\",\n    \"notificationId\": 1889709228,\n    \"openDate\": \"\",\n    \"params\": {\n      \"emPushSp\": \"CF203B70D23C40DF84167C339648CC94\",\n      \"mediaUrl\": \"\",\n      \"message\": \"baris test\",\n      \"pushId\": \"f6e9e487-126e-4805-a3ef-bcf0e5df3ca0\",\n      \"silent\": \"false\",\n      \"sound\": \"\",\n      \"title\": \"baris test\",\n      \"url\": \"\"\n    },\n    \"pushId\": \"f6e9e487-126e-4805-a3ef-bcf0e5df3ca0\",\n    \"pushType\": \"Text\",\n    \"pushCategory\": \"x campaign\",\n    \"silent\": \"false\",\n    \"sound\": \"\",\n    \"status\": \"D\",\n    \"title\": \"baris test\",\n    \"url\": \"\"\n  }\n]\n\n// iOS response\n[\n    {\n      \"aps\": {\n        \"category\": \"rmc\",\n        \"alert\": {\n          \"title\": \"Message Title\",\n          \"body\": \"Message body\"\n        }\n      },\n      \"altUrl\": \"\",\n      \"url\": \"\",\n      \"utm_medium\": \"medium\",\n      \"openedDate\": \"\",\n      \"emPushSp\": \"CF203B70D23C40DF84167C339648CC94\",\n      \"mediaUrl\": \"https:\\/\\/raw.githubusercontent.com\\/relateddigital\\/euromessage-ios\\/master\\/screenshots\\/appgroups-name.png\",\n      \"utm_source\": \"source\",\n      \"email\": \"Baris.arslan@euromsg.com\",\n      \"status\": \"D\",\n      \"utm_campaign\": \"campaign\",\n      \"pushType\": \"Image\",\n      \"keyID\": \"Baris.arslan@euromsg.com\",\n      \"deepLink\": \"\",\n      \"pushId\": \"75dff035-295d-4a3d-969a-2a9f4d89d9df\",\n      \"formattedDateString\": \"2025-03-27 16:05:22\",\n      \"customExpireDate\": \"912345678\", // custom\n      \"customParameter\": \"test\",  // custom\n      \"pushCategory\": \"x campaign\", // custom\n    }\n] \n```\n\n\n### Get User Data\nYou can use `getUserAllData` method to access user data.\n```javascript\nimport {getUserAllData} from 'react-native-related-digital'\n...\n...\n...\n getUser = async () =\u003e {\n    const result = await getUserAllData();\n    console.log(\"ALL Storage Data\", result);\n    console.log(\"Visilabs - Exvisitorid\", result.visilabs.exVisitorId);\n    console.log(\"Euromsg - Keyid\", result.euromsg.extra.Keyid);\n    console.log(\"Euromsg - Email\", result.euromsg.extra.Email);\n    console.log(\"JS Euromsg - Keyid\", result.js.euromsgsubextra?.Keyid);\n    console.log(\"JS Euromsg - Email\", result.js.euromsgsubextra?.Email);\n}\n```\nResponse\n```json\n{\n    \"euromsg\": {\n        \"appKey\": \"rniostestapp\",\n        \"appVersion\": \"1.0\",\n        \"deviceName\": \"iPhone 14 Pro\",\n        \"deviceType\": \"x86_64\",\n        \"extra\": {\n            \"ConsentSource\": \"HS_MOBIL\",\n            \"ConsentTime\": \"2022-11-12 10:00:00\",\n            \"Email\": \"baris.arslan@euromsg.com\",\n            \"Keyid\": \"1234-B-5678\",\n            \"PushPermit\": \"Y\",\n            \"RecipientType\": \"BIREYSEL\"\n        },\n        \"firstTime\": 0,\n        \"identifierForVendor\": \"57BA15B3-9B97-4B2D-AB21-211DDE7D56C6\",\n        \"local\": \"tr-US\",\n        \"method\": \"POST\",\n        \"osName\": \"iOS\",\n        \"osVersion\": \"16.2\",\n        \"path\": \"subscription\",\n        \"prodBaseUrl\": \".euromsg.com\",\n        \"sdkVersion\": \"2.6.6\",\n        \"subdomain\": \"pushs\"\n    },\n    \"js\": {\n        \"euromsgsub\": {\n            \"advertisingIdentifier\": \"\",\n            \"appKey\": \"rniostestapp\",\n            \"appVersion\": \"1.0\",\n            \"carrier\": \"\",\n            \"deviceName\": \"iPhone 14 Pro\",\n            \"deviceType\": \"x86_64\",\n            \"extra\": {\n                \"ConsentSource\": \"HS_MOBIL\",\n                \"ConsentTime\": \"2022-11-12 10:00:00\",\n                \"Email\": \"baris.arslan@euromsg.com\",\n                \"Keyid\": \"1234-B-5678\",\n                \"PushPermit\": \"Y\",\n                \"RecipientType\": \"BIREYSEL\"\n            },\n            \"firstTime\": 1,\n            \"identifierForVendor\": \"57BA15B3-9B97-4B2D-AB21-211DDE7D56C6\",\n            \"local\": \"tr-US\",\n            \"os\": \"ios\",\n            \"osVersion\": \"16.2\",\n            \"sdkVersion\": \"2.4.1\",\n            \"token\": null\n        },\n        \"euromsgsubextra\": {\n            \"ConsentSource\": \"HS_MOBIL\",\n            \"ConsentTime\": \"2022-11-12 10:00:00\",\n            \"Email\": \"baris.arslan@euromsg.com\",\n            \"Keyid\": \"1234-B-5678\",\n            \"PushPermit\": \"Y\",\n            \"RecipientType\": \"BIREYSEL\"\n        },\n        \"expiresubscribecheckdate\": 1681132339166\n    },\n    \"visilabs\": {\n        \"apiver\": \"IOS\",\n        \"appVersion\": \"1.0\",\n        \"channel\": \"IOS\",\n        \"cookieId\": \"6EA1D2E6-74CF-4A61-A845-D297BCEE0108\",\n        \"exVisitorId\": \"1234-B-5678\",\n        \"mappl\": \"true\",\n        \"sdkVersion\": \"3.9.0\",\n        \"userAgent\": \"Mozilla/5.0 (iPhone; CPU iPhone OS 16_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148\",\n        \"vchannel\": \"IOS\"\n    }\n}\n```\n\n\n## Usage\n```jsx\nimport React, { useState, useEffect } from 'react';\nimport {\n  SafeAreaView,\n  StyleSheet,\n  ScrollView,\n  Button,\n  View,\n  ActivityIndicator,\n  Platform\n} from 'react-native';\n\nimport { addEventListener, removeEventListener, requestPermissions, requestIDFA, EuroMessageApi, VisilabsApi, setApplicationIconBadgeNumber, logToConsole, RDStoryView, RecommendationAttribute, RecommendationFilterType, requestLocationPermission, setGeofencingIntervalInMinute } from 'react-native-related-digital'\n\nconst App = () =\u003e {\n  const [loading, setLoading] = useState(false)\n\n  const appAlias = 'alias'\n\n  const siteId = \"SID\";\n  const organizationId = \"OID\";\n  const dataSource = \"datasource\";\n\n  const euroMessageApi = new EuroMessageApi(appAlias)\n  const visilabsApi = new VisilabsApi(appAlias, siteId, organizationId, dataSource)\n\n  useEffect(() =\u003e {\n    logToConsole(true)\n\n    addExtra()\n    addListeners()\n\n    return () =\u003e removeListeners()\n  }, [])\n\n  const addListeners = () =\u003e {\n\n    addEventListener('register', async (token) =\u003e {\n      const subscribeResult = await euroMessageApi.subscribe(token)\n\n      visilabsApi.register(token, (result) =\u003e {\n        \n      })\n    }, (notificationPayload) =\u003e {\n      console.log('notification payload', notificationPayload)\n    }, euroMessageApi, visilabsApi)\n\n    addEventListener('registrationError', async (registrationError) =\u003e {\n      console.log('registrationError is ', registrationError)\n    }, euroMessageApi)\n\n    addEventListener('carouselItemClicked', async (carouselItemInfo) =\u003e {\n      console.log('carouselItemInfo is ', carouselItemInfo)\n    }, euroMessageApi)\n  }\n\n  const addExtra = async () =\u003e {\n    // IYS parameters\n    // await euroMessageApi.setUserProperty('ConsentTime', '2021-06-05 10:00:00')\n    // await euroMessageApi.setUserProperty('RecipientType', 'BIREYSEL')\n    // await euroMessageApi.setUserProperty('ConsentSource', 'HS_MOBIL')\n\n    // Single\n    // await euroMessageApi.setUserProperty('Email', EMAIL)\n    // await euroMessageApi.setUserProperty('keyid', KEYID)\n    // await euroMessageApi.setUserProperty('PushPermit', 'Y')\n\n    // Or Object\n    let userData = {\n      \"KeyId\":KEYID,\n      \"Email\":EMAIL,\n      \"PushPermit\":\"Y\" // Y=active, N=passive\n    }\n    return euroMessageApi.setUserProperties(userData)\n  }\n\n  const login = async () =\u003e {\n    addExtra().then(() =\u003e\n      euroMessageApi.subscribe(token)\n    );\n  }\n\n  const setBadgeNumber = () =\u003e {\n    const number = 3\n    setApplicationIconBadgeNumber(number)\n  }\n\n  const sendCustomEvent = () =\u003e {\n    visilabsApi.customEvent('*', {\n      'id': '1',\n      'name': 'Product Name'\n    })\n  }\n\n  const getRecommendations = async () =\u003e {\n    try {\n      const zoneId = '6'\n      const productCode = ''\n\n      const properties =  {\n        \"OM.cat\":\"65\" // Category code\n      }\n\n      // optional\n      const filters = [{\n        attribute: RecommendationAttribute.PRODUCTCODE,\n        filterType: RecommendationFilterType.equals,\n        value: '78979,21312,45345'\n      }]\n\n      const recommendations = await visilabsApi.getRecommendations(zoneId, productCode, properties, filters)\n      console.log('recommendations', recommendations)\n    }\n    catch (e) {\n      console.log('recommendations error', e)\n    }\n  }\n\n  const showMailSubscriptionForm = () =\u003e {\n    visilabsApi.customEvent('*pagename*', {\n      'OM.pv': '77',\n      'OM.pn': 'Product',\n      'OM.ppr': '39'\n    })\n  }\n\n  const getFavoriteAttributeActions = async () =\u003e {\n    try {\n      const actionId = '474'\n\n      const favoriteAttrs = await visilabsApi.getFavoriteAttributeActions(actionId)\n      console.log('favoriteAttributeActions', favoriteAttrs)\n    }\n    catch (e) {\n      console.log('favoriteAttributeActions error', e)\n    }\n  }\n\n  const showSpinToWin = () =\u003e {\n    visilabsApi.customEvent('*pragma_spintowin*', {\n      'OM.pv': '77',\n      'OM.pn': 'Nectarine Blossom \u0026 Honey Body \u0026 Hand Lotion',\n      'OM.ppr': '39'\n    })\n  }\n\n  const trackInstalledApps = async () =\u003e {\n    // android only\n    await visilabsApi.sendTheListOfAppsInstalled()\n  }\n\n  const showScratchToWin = () =\u003e {\n    visilabsApi.customEvent('*pragma_scratch*', {\n      'OM.pv': '77',\n      'OM.pn': 'Nectarine Blossom \u0026 Honey Body \u0026 Hand Lotion',\n      'OM.ppr': '39'\n    })\n  }\n\n  const sendLocationPermissionEvent = async () =\u003e {\n    await visilabsApi.sendLocationPermission()\n  }\n\n  const getPushMessages = async () =\u003e {\n    const messages = await euroMessageApi.getPushMessages()\n    console.log('messages', messages)\n  }\n\n  const getUser = async () =\u003e {\n    const user = await visilabsApi.getUser()\n    console.log('USER DATA', user)\n  }\n\n  const pushPermitRequest = async (isProvisional) =\u003e {\n    const pushPermit = await requestPermissions(isProvisional)\n    console.log(\"Device Push Permit\",pushPermit);\n    if (\n        user.pushPermit == true // If permission has been granted before\n        || // or\n        typeof user.pushPermit === 'undefined' // If no definition has been made regarding the permission status\n      ) {\n      euroMessageApi.setUserProperties({pushPermit: pushPermit ? 'Y' : 'N'}).then(() =\u003e {\n        euroMessageApi.subscribe(this.state.token)\n      })\n    }\n  }\n\n  const removeListeners = () =\u003e {\n    removeEventListener('register')\n    removeEventListener('registrationError')\n    removeEventListener('carouselItemClicked')\n  }\n\n  return (\n    \u003c\u003e\n      \u003cSafeAreaView\u003e\n        {\n          loading ?\n          \u003cActivityIndicator \n            size='large'\n            animating={loading} /\u003e :\n          \u003cScrollView\n            contentInsetAdjustmentBehavior=\"automatic\"\n            style={styles.scrollView}\u003e\n            \u003cRDStoryView\n              actionId={'1'} // optional\n              onItemClicked={(data) =\u003e {\n                console.log('Story data', data)\n              }}\n              style={{ flex: 1 }}\n            /\u003e\n            \u003cButton \n              title='REQUEST PERMISSONS'\n              onPress={() =\u003e {\n                const isProvisional = false\n                pushPermitRequest(isProvisional)\n              }} \n            /\u003e\n            \u003cButton\n              title='REQUEST IDFA'\n              onPress={() =\u003e {\n                requestIDFA()\n              }}\n            /\u003e\n            \u003cButton\n              title='REQUEST LOCATION PERMISSION'\n              onPress={() =\u003e {\n                requestLocationPermission()\n              }}\n            /\u003e\n            \u003cButton\n              title='LOGIN/SIGNUP'\n              onPress={() =\u003e {\n                login()\n              }}\n            /\u003e\n            \u003cButton \n              title='SET BADGE NUMBER TO 3 (IOS)'\n              onPress={() =\u003e {\n                setBadgeNumber()\n              }} \n            /\u003e\n            \u003cButton \n              title='SEND CUSTOM EVENT'\n              onPress={() =\u003e {\n                sendCustomEvent()\n              }} \n            /\u003e\n            \u003cButton\n              title='GET RECOMMENDATIONS'\n              onPress={async () =\u003e {\n                await getRecommendations()\n              }}\n            /\u003e\n            \u003cButton\n              title='SHOW MAIL FORM'\n              onPress={() =\u003e {\n                showMailSubscriptionForm()\n              }}\n            /\u003e\n\n            \u003cButton\n              title='GET FAVORITE ATTRIBUTE ACTIONS'\n              onPress={async () =\u003e {\n                await getFavoriteAttributeActions()\n              }}\n            /\u003e\n\n            \u003cButton\n                title='SPIN TO WIN'\n                onPress={() =\u003e {\n                  showSpinToWin()\n                }}\n              /\u003e\n\n            \u003cButton\n                title='SCRATCH TO WIN'\n                onPress={() =\u003e {\n                  showScratchToWin()\n                }}\n              /\u003e\n\n              \u003cButton\n                title='TRACK INSTALLED APPS'\n                onPress={() =\u003e {\n                  trackInstalledApps()\n                }}\n              /\u003e\n\n              \u003cButton\n                title='SEND LOCATION PERMISSION'\n                onPress={() =\u003e {\n                  sendLocationPermissionEvent()\n                }}\n              /\u003e\n\n              \u003cButton\n                title='GET PUSH MESSAGES'\n                onPress={() =\u003e {\n                  getPushMessages()\n                }}\n              /\u003e\n\n              \u003cButton\n                title='GET USER DATA'\n                onPress={() =\u003e {\n                  getUser()\n                }}\n              /\u003e\n\n          \u003c/ScrollView\u003e\n        }\n      \u003c/SafeAreaView\u003e\n    \u003c/\u003e\n  );\n};\n\nconst styles = StyleSheet.create({\n  scrollView: {\n    backgroundColor: '#FFF',\n    padding: 20\n  },\n  divider: {\n    height: 20\n  }\n});\n\nexport default App;\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frelateddigital%2Freact-native-related-digital","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frelateddigital%2Freact-native-related-digital","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frelateddigital%2Freact-native-related-digital/lists"}