diff --git a/Countly.d.ts b/Countly.d.ts index 015e1860..70d6716c 100644 --- a/Countly.d.ts +++ b/Countly.d.ts @@ -63,8 +63,8 @@ interface ResultObject { } interface ErrorObject { error: string | null } -declare module "countly-sdk-react-native-bridge" { - import type CountlyConfig from "countly-sdk-react-native-bridge/CountlyConfig"; +declare module "countly-sdk-react-native-bridge-np" { + import type CountlyConfig from "countly-sdk-react-native-bridge-np/CountlyConfig"; namespace Countly { string; @@ -244,7 +244,7 @@ declare module "countly-sdk-react-native-bridge" { export function disablePushNotifications(): string | void; /** - * @deprecated in 23.02.0 : use 'countlyConfig.pushTokenType' instead of 'pushTokenType'. + * @deprecated in 23.02.0 : use 'countlyConfig.pushTokenType' instead of 'pushTokenType'. FOR PUSH VERSION ONLY * * @param {string} tokenType - Token type * @param {string} channelName - Channel name @@ -257,6 +257,7 @@ declare module "countly-sdk-react-native-bridge" { export function pushTokenType(tokenType: string, channelName: string, channelDescription: string): Promise | string; /** + * @deprecated FOR PUSH VERSION ONLY * * Send push token * @param {object} options - object containing the push token @@ -267,6 +268,8 @@ declare module "countly-sdk-react-native-bridge" { export function sendPushToken(options: { readonly token?: string }): void; /** + * @deprecated FOR PUSH VERSION ONLY + * * This method will ask for permission, enables push notification and send push token to countly server. * * @param {string} customSoundPath - name of custom sound for push notifications (Only for Android) @@ -278,6 +281,7 @@ declare module "countly-sdk-react-native-bridge" { export function askForNotificationPermission(customSoundPath?: string): string | void; /** + * @deprecated FOR PUSH VERSION ONLY * * Set callback to receive push notifications * @param {callback listener } theListener @@ -286,7 +290,7 @@ declare module "countly-sdk-react-native-bridge" { export function registerForNotification(theListener: (theNotification: string) => void): any; // The return type should be adjusted to the actual event subscription type /** - * @deprecated in 23.02.0 : use 'countlyConfig.configureIntentRedirectionCheck' instead of 'configureIntentRedirectionCheck'. + * @deprecated in 23.02.0 : use 'countlyConfig.configureIntentRedirectionCheck' instead of 'configureIntentRedirectionCheck'. FOR PUSH VERSION ONLY * * Configure intent redirection checks for push notification * Should be called before Countly "askForNotificationPermission" @@ -1096,7 +1100,7 @@ declare module "countly-sdk-react-native-bridge" { export default Countly; } -declare module "countly-sdk-react-native-bridge/CountlyConfig" { +declare module "countly-sdk-react-native-bridge-np/CountlyConfig" { /** * * This class holds APM specific configurations to be used with @@ -1195,7 +1199,7 @@ declare module "countly-sdk-react-native-bridge/CountlyConfig" { * Method to give consent for specific features before init * * @param {string[]} consents consents e.g ['location', 'sessions', - * 'attribution', 'push', 'events', 'views', 'crashes', 'users', 'push', + * 'attribution', 'push', 'events', 'views', 'crashes', 'users', * 'star-rating', 'apm', 'feedback', 'remote-config'] */ giveConsent(consents: readonly string[]): CountlyConfig; @@ -1227,6 +1231,8 @@ declare module "countly-sdk-react-native-bridge/CountlyConfig" { enableApm(): CountlyConfig; /** + * @deprecated FOR PUSH VERSION ONLY + * * AdditionalIntentRedirectionChecks are enabled by default. * This method should be used to disable them. */ @@ -1234,7 +1240,8 @@ declare module "countly-sdk-react-native-bridge/CountlyConfig" { /** * Method to set the push token type - * @deprecated + * @deprecated FOR PUSH VERSION ONLY + * * Use setPushTokenType() instead to set pushToken * Use setPushNotificationChannelInformation() instead to set channel information * @@ -1245,6 +1252,8 @@ declare module "countly-sdk-react-native-bridge/CountlyConfig" { pushTokenType(tokenType: TokenType, channelName: string, channelDescription: string): CountlyConfig; /** + * @deprecated FOR PUSH VERSION ONLY + * * Method to set the push token type * NB: ONLY FOR iOS * @@ -1254,6 +1263,8 @@ declare module "countly-sdk-react-native-bridge/CountlyConfig" { setPushTokenType(tokenType: messagingMode): CountlyConfig; /** + * @deprecated FOR PUSH VERSION ONLY + * * Method to set the push channel name and description * NB: ONLY FOR ANDROID * @@ -1263,6 +1274,8 @@ declare module "countly-sdk-react-native-bridge/CountlyConfig" { setPushNotificationChannelInformation(name: string, description: string): CountlyConfig; /** + * @deprecated FOR PUSH VERSION ONLY + * * Method to set the push notification accent color * NB: ONLY FOR ANDROID * @@ -1272,6 +1285,8 @@ declare module "countly-sdk-react-native-bridge/CountlyConfig" { setPushNotificationAccentColor(accentColor: string): CountlyConfig; /** + * @deprecated FOR PUSH VERSION ONLY + * * Method to configure intent redirection check * * @param {string[]} allowedIntentClassNames allowed intent class names diff --git a/Countly.js b/Countly.js index da830e2e..2146ff52 100644 --- a/Countly.js +++ b/Countly.js @@ -34,6 +34,9 @@ Countly.userDataBulk = {}; // userDataBulk interface let _isPushInitialized = false; +const BUILDING_WITH_PUSH_DISABLED = true; +const _pushDisabledMsg = 'Push Notifications are disabled in this flavor. Please use the original Countly React Native SDK if you need to use Push Notifications.'; + /* * Listener for rating widget callback, when callback recieve we will remove the callback using listener. */ @@ -218,6 +221,10 @@ Countly.disablePushNotifications = function () { * @return {string | void} error message or void */ Countly.pushTokenType = function (tokenType, channelName, channelDescription) { + if (BUILDING_WITH_PUSH_DISABLED) { + L.w(`pushTokenType, ${_pushDisabledMsg}`); + return _pushDisabledMsg; + } const message = Validate.String(tokenType, "tokenType", "pushTokenType"); if (message) { return message; @@ -239,6 +246,10 @@ Countly.pushTokenType = function (tokenType, channelName, channelDescription) { * @return {string | void} error message or void */ Countly.sendPushToken = function (options) { + if (BUILDING_WITH_PUSH_DISABLED) { + L.w(`sendPushToken, ${_pushDisabledMsg}`); + return; + } L.d(`sendPushToken, Sending push token: [${JSON.stringify(options)}]`); const args = []; args.push(options.token || ""); @@ -255,6 +266,10 @@ Countly.sendPushToken = function (options) { * @return {string | void} error message or void */ Countly.askForNotificationPermission = function (customSoundPath = "null") { + if (BUILDING_WITH_PUSH_DISABLED) { + L.w(`askForNotificationPermission, ${_pushDisabledMsg}`); + return _pushDisabledMsg; + } if (!_state.isInitialized) { const message = "'init' must be called before 'askForNotificationPermission'"; L.e(`askForNotificationPermission, ${message}`); @@ -272,6 +287,10 @@ Countly.askForNotificationPermission = function (customSoundPath = "null") { * @return {NativeEventEmitter} event */ Countly.registerForNotification = function (theListener) { + if (BUILDING_WITH_PUSH_DISABLED) { + L.w(`registerForNotification, ${_pushDisabledMsg}`); + return; + } L.d("registerForNotification, Registering for notification"); const event = eventEmitter.addListener(pushNotificationCallbackName, theListener); CountlyReactNative.registerForNotification([]); @@ -290,15 +309,19 @@ Countly.registerForNotification = function (theListener) { * @return {string | void} error message or void */ Countly.configureIntentRedirectionCheck = function (allowedIntentClassNames = [], allowedIntentPackageNames = [], useAdditionalIntentRedirectionChecks = true) { + if (BUILDING_WITH_PUSH_DISABLED) { + L.w(`configureIntentRedirectionCheck, ${_pushDisabledMsg}`); + return; + } if (/ios/.exec(Platform.OS)) { - L.e("configureIntentRedirectionCheck, configureIntentRedirectionCheck is not required for iOS"); + L.w("configureIntentRedirectionCheck, configureIntentRedirectionCheck is not required for iOS"); return "configureIntentRedirectionCheck : not required for iOS"; } if (_isPushInitialized) { let message = "'configureIntentRedirectionCheck' must be called before 'askForNotificationPermission'"; - L.e(`configureIntentRedirectionCheck, ${message}`); + L.w(`configureIntentRedirectionCheck, ${message}`); return message; } L.w("configureIntentRedirectionCheck, configureIntentRedirectionCheck is deprecated, use countlyConfig.configureIntentRedirectionCheck instead"); diff --git a/CountlyConfig.js b/CountlyConfig.js index 1f8395d7..46de462b 100644 --- a/CountlyConfig.js +++ b/CountlyConfig.js @@ -1,5 +1,8 @@ import { initialize } from "./Logger.js"; import CountlyConfigApm from "./lib/configuration_interfaces/countly_config_apm.js"; + +const BUILDING_WITH_PUSH_DISABLED = true; + /** * Countly SDK React Native Bridge * https://github.com/Countly/countly-sdk-react-native-bridge @@ -8,7 +11,6 @@ import CountlyConfigApm from "./lib/configuration_interfaces/countly_config_apm. /** * * Config Object for Countly Init - * Should be called before Countly "askForNotificationPermission" * * @param {String} serverURL server url * @param {String} appKey application key @@ -94,7 +96,7 @@ class CountlyConfig { * Method to give consent for specific features before init * * @param {String[]} consents consents e.g ['location', 'sessions', - * 'attribution', 'push', 'events', 'views', 'crashes', 'users', 'push', + * 'attribution', 'events', 'views', 'crashes', 'users', * 'star-rating', 'apm', 'feedback', 'remote-config'] */ giveConsent(consents) { @@ -145,6 +147,9 @@ class CountlyConfig { * This method should be used to disable them. */ disableAdditionalIntentRedirectionChecks() { + if (BUILDING_WITH_PUSH_DISABLED) { + return this; + } this.disableAdditionalIntentRedirectionChecks = true; return this; } @@ -160,6 +165,9 @@ class CountlyConfig { * @param {String} channelDescription channel description */ pushTokenType(tokenType, channelName, channelDescription) { + if (BUILDING_WITH_PUSH_DISABLED) { + return this; + } this.tokenType = tokenType; this.channelName = channelName; this.channelDescription = channelDescription; @@ -174,6 +182,9 @@ class CountlyConfig { * Possible values include 'DEVELOPMENT', 'PRODUCTION', 'ADHOC'. */ setPushTokenType(tokenType) { + if (BUILDING_WITH_PUSH_DISABLED) { + return this; + } this.tokenType = tokenType; return this; } @@ -186,6 +197,9 @@ class CountlyConfig { * @param {String} description channel description */ setPushNotificationChannelInformation(name, description) { + if (BUILDING_WITH_PUSH_DISABLED) { + return this; + } this.channelName = name; this.channelDescription = description; return this; @@ -199,6 +213,9 @@ class CountlyConfig { * example '#000000' */ setPushNotificationAccentColor(accentColor) { + if (BUILDING_WITH_PUSH_DISABLED) { + return this; + } this.accentColor = accentColor; return this; } @@ -210,6 +227,9 @@ class CountlyConfig { * @param {String[]} allowedIntentPackageNames allowed intent package name */ configureIntentRedirectionCheck(allowedIntentClassNames, allowedIntentPackageNames) { + if (BUILDING_WITH_PUSH_DISABLED) { + return this; + } this.allowedIntentClassNames = allowedIntentClassNames; this.allowedIntentPackageNames = allowedIntentPackageNames; return this; diff --git a/README.md b/README.md index c3ebf855..4fb6d059 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Codacy Badge](https://api.codacy.com/project/badge/Grade/2d691b48780b440d915a0cfa059474b1)](https://app.codacy.com/gh/Countly/countly-sdk-react-native-bridge?utm_source=github.com&utm_medium=referral&utm_content=Countly/countly-sdk-react-native-bridge&utm_campaign=Badge_Grade) -# Countly React Native Bridge SDK +# Countly React Native Bridge SDK - No Push This repository contains the Countly React Native Bridge SDK, which can be integrated into React Native mobile applications. The Countly React Native Bridge SDK is intended to be used with [Countly Lite](https://countly.com/lite) or [Countly Enterprise](https://count.ly/product). ## What is Countly? @@ -25,7 +25,6 @@ For an example integration of this SDK, you can have a look [here](https://githu This SDK supports the following features: * [Analytics](https://support.count.ly/hc/en-us/articles/4431589003545-Analytics) -* [Push Notifications](https://support.count.ly/hc/en-us/articles/4405405459225-Push-Notifications) * [User Profiles](https://support.count.ly/hc/en-us/articles/4403281285913-User-Profiles) * [Crash Reports](https://support.count.ly/hc/en-us/articles/4404213566105-Crashes-Errors) * [A/B Testing](https://support.count.ly/hc/en-us/articles/4416496362393-A-B-Testing-) diff --git a/android/build.gradle b/android/build.gradle index e87cd84e..f8304566 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -42,9 +42,4 @@ repositories { dependencies { implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}" implementation 'ly.count.android:sdk:24.4.0' - - // Import the BoM for the Firebase platform - // The BoM version of 28.4.2 is the newest release that will target firebase-messaging version 22 - implementation platform('com.google.firebase:firebase-bom:28.4.2') - implementation "com.google.firebase:firebase-messaging" } diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 7b641bf3..4ed1cecd 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,17 +1,6 @@ - - - - - - - - - - - + \ No newline at end of file diff --git a/android/src/main/java/ly/count/android/sdk/react/CountlyMessagingService.java b/android/src/main/java/ly/count/android/sdk/react/CountlyMessagingService.java deleted file mode 100644 index 97e30cab..00000000 --- a/android/src/main/java/ly/count/android/sdk/react/CountlyMessagingService.java +++ /dev/null @@ -1,79 +0,0 @@ -package ly.count.android.sdk.react; - -import android.app.Application; -import android.content.Context; -import android.content.Intent; -import android.util.Log; - -import com.google.firebase.messaging.FirebaseMessagingService; -import com.google.firebase.messaging.RemoteMessage; - -import ly.count.android.sdk.messaging.CountlyConfigPush; -import ly.count.android.sdk.messaging.CountlyPush; -import ly.count.android.sdk.Countly; - -public class CountlyMessagingService extends FirebaseMessagingService { - - @Override - public void onNewToken(String token) { - super.onNewToken(token); - if(Countly.sharedInstance().isLoggingEnabled()) { - Log.d(Countly.TAG, "[CountlyMessagingService] got new token: " + token); - } - if(Countly.sharedInstance().isInitialized()) { - CountlyPush.onTokenRefresh(token); - } - } - - @Override - public void onMessageReceived(RemoteMessage remoteMessage) { - super.onMessageReceived(remoteMessage); - if(Countly.sharedInstance().isLoggingEnabled()) { - Log.d(Countly.TAG, "[CountlyMessagingService] got new message: " + remoteMessage.getData().toString()); - } - - if(!Countly.sharedInstance().isInitialized()) { - Application application = getApplication(); - if(application == null){ - Log.d(Countly.TAG, "[CountlyMessagingService] getApplication() returns null: application must be non-null to init CountlyPush"); - } - else { - CountlyConfigPush configPush = new CountlyConfigPush(application); - CountlyPush.init(configPush); - } - } - - - // decode message data and extract meaningful information from it: title, body, badge, etc. - CountlyPush.Message message = CountlyPush.decodeMessage(remoteMessage.getData()); - - // if (message != null && message.message().contains("typ")) { - // // custom handling only for messages with specific "typ" keys - // message.recordAction(getApplicationContext()); - // return; - // } - Context context = getApplicationContext(); - if(context == null){ - Log.d(Countly.TAG, "[CountlyMessagingService] getApplicationContext() returns null: context must be non-null to displayNotification"); - return; - } - Boolean result = CountlyPush.displayNotification(context, message, context.getApplicationInfo().icon, null); - if(Countly.sharedInstance().isLoggingEnabled()) { - if (result == null) { - Log.i(Countly.TAG, "[CountlyMessagingService] Message wasn't sent from Countly server, so it cannot be handled by Countly SDK"); - } else if (result) { - Log.i(Countly.TAG, "[CountlyMessagingService] Message was handled by Countly SDK"); - } else { - Log.i(Countly.TAG, "[CountlyMessagingService] Message wasn't handled by Countly SDK because API level is too low for Notification support or because currentActivity is null (not enough lifecycle method calls)"); - } - } - - // 'onNotification' should be called at the end of 'onMessageReceived'. This is due to an unknown issue that prevents showing notifications from the "killed" state for some app/hardware configurations - CountlyReactNative.onNotification(remoteMessage.getData()); - } - - @Override - public void onDeletedMessages() { - super.onDeletedMessages(); - } -} diff --git a/android/src/main/java/ly/count/android/sdk/react/CountlyReactNative.java b/android/src/main/java/ly/count/android/sdk/react/CountlyReactNative.java index 434e5d3e..e6a1c3b8 100644 --- a/android/src/main/java/ly/count/android/sdk/react/CountlyReactNative.java +++ b/android/src/main/java/ly/count/android/sdk/react/CountlyReactNative.java @@ -64,10 +64,6 @@ import com.facebook.react.bridge.WritableNativeArray; import com.facebook.react.bridge.WritableNativeMap; import com.facebook.react.modules.core.DeviceEventManagerModule; -import com.google.android.gms.tasks.Task; -import com.google.android.gms.tasks.OnCompleteListener; -import com.google.firebase.FirebaseApp; -import com.google.firebase.messaging.FirebaseMessaging; class CountlyReactException extends Exception { private final String jsError; @@ -873,35 +869,7 @@ public void askForNotificationPermission(ReadableArray args) { configPush.setAllowedIntentPackageNames(allowedIntentPackageNames); } CountlyPush.init(configPush); - try { - FirebaseApp.initializeApp(context); - FirebaseMessaging firebaseMessagingInstance = FirebaseMessaging.getInstance(); - if (firebaseMessagingInstance == null) { - log("askForNotificationPermission, firebaseMessagingInstance is null", LogLevel.WARNING); - return; - } - Task firebaseMessagingTokenTask = firebaseMessagingInstance.getToken(); - if (firebaseMessagingTokenTask == null) { - log("askForNotificationPermission, firebaseMessagingTokenTask is null", LogLevel.WARNING); - return; - } - - firebaseMessagingTokenTask.addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (!task.isSuccessful()) { - log("askForNotificationPermission, Fetching FCM registration token failed", task.getException(), LogLevel.WARNING); - return; - } - - // Get new FCM registration token - String token = task.getResult(); - CountlyPush.onTokenRefresh(token); - } - }); - } catch (Exception exception) { - log("askForNotificationPermission, Firebase exception", exception, LogLevel.WARNING); - } + log("askForNotificationPermission, firebaseMessagingInstance is null", LogLevel.WARNING); } @ReactMethod diff --git a/example/CountlyRNExample/APM.tsx b/example/CountlyRNExample/APM.tsx index 24173810..bd91d52b 100644 --- a/example/CountlyRNExample/APM.tsx +++ b/example/CountlyRNExample/APM.tsx @@ -1,7 +1,7 @@ import React from "react"; import { ScrollView } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; -import Countly from "countly-sdk-react-native-bridge"; +import Countly from "countly-sdk-react-native-bridge-np"; import CountlyButton from "./CountlyButton"; const successCodes = [100, 101, 200, 201, 202, 205, 300, 301, 303, 305]; diff --git a/example/CountlyRNExample/Configuration.tsx b/example/CountlyRNExample/Configuration.tsx index b6ba1e64..5b6c137c 100644 --- a/example/CountlyRNExample/Configuration.tsx +++ b/example/CountlyRNExample/Configuration.tsx @@ -1,4 +1,4 @@ -import CountlyConfig from "countly-sdk-react-native-bridge/CountlyConfig"; +import CountlyConfig from "countly-sdk-react-native-bridge-np/CountlyConfig"; const COUNTLY_SERVER_KEY = "https://your.server.ly"; const COUNTLY_APP_KEY = "YOUR_APP_KEY"; @@ -12,12 +12,11 @@ const countlyConfig = new CountlyConfig(COUNTLY_SERVER_KEY, COUNTLY_APP_KEY).set // .setDeviceID(Countly.TemporaryDeviceIDString) // Enable temporary id mode // .enableCrashReporting() // Enable crash reporting to report unhandled crashes to Countly // .setRequiresConsent(true) // Set that consent should be required for features to work. -// .giveConsent(['location', 'sessions', 'attribution', 'push', 'events', 'views', 'crashes', 'users', 'push', 'star-rating', 'apm', 'feedback', 'remote-config']) // give consent for specific features before init. +// .giveConsent(['location', 'sessions', 'attribution', 'push', 'events', 'views', 'crashes', 'users', 'star-rating', 'apm', 'feedback', 'remote-config']) // give consent for specific features before init. // .setLocation('TR', 'Istanbul', '41.0082,28.9784', '10.2.33.12') // Set user initial location. // .enableParameterTamperingProtection('salt') // Set the optional salt to be used for calculating the checksum of requested data which will be sent with each request // .pinnedCertificates("count.ly.cer") // It will ensure that connection is made with one of the public keys specified // .setHttpPostForced(false) // Set to "true" if you want HTTP POST to be used for all requests -// .pushTokenType(Countly.messagingMode.DEVELOPMENT, 'ChannelName', 'ChannelDescription') // Set messaging mode for push notifications // .configureIntentRedirectionCheck(['MainActivity'], ['com.countly.demo']) // .setStarRatingDialogTexts('Title', 'Message', 'Dismiss') // .recordDirectAttribution('countly', campaignData) diff --git a/example/CountlyRNExample/Consent.tsx b/example/CountlyRNExample/Consent.tsx index 9beb4c61..22932a6d 100644 --- a/example/CountlyRNExample/Consent.tsx +++ b/example/CountlyRNExample/Consent.tsx @@ -1,7 +1,7 @@ import React from "react"; import { ScrollView } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; -import Countly from "countly-sdk-react-native-bridge"; +import Countly from "countly-sdk-react-native-bridge-np"; import CountlyButton from "./CountlyButton"; const giveConsent = (name: string) => { diff --git a/example/CountlyRNExample/Crashes.tsx b/example/CountlyRNExample/Crashes.tsx index 41d0b657..c1c7cdc9 100644 --- a/example/CountlyRNExample/Crashes.tsx +++ b/example/CountlyRNExample/Crashes.tsx @@ -1,7 +1,7 @@ import React from "react"; import { ScrollView } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; -import Countly from "countly-sdk-react-native-bridge"; +import Countly from "countly-sdk-react-native-bridge-np"; import CountlyButton from "./CountlyButton"; const addCrashLog = () => { diff --git a/example/CountlyRNExample/DeviceID.tsx b/example/CountlyRNExample/DeviceID.tsx index 6cd735d8..0a6bfc60 100644 --- a/example/CountlyRNExample/DeviceID.tsx +++ b/example/CountlyRNExample/DeviceID.tsx @@ -1,7 +1,7 @@ import React from "react"; import { ScrollView } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; -import Countly from "countly-sdk-react-native-bridge"; +import Countly from "countly-sdk-react-native-bridge-np"; import CountlyButton from "./CountlyButton"; import { lightOrange } from "./Constants"; diff --git a/example/CountlyRNExample/Events.tsx b/example/CountlyRNExample/Events.tsx index e6276732..945a4958 100644 --- a/example/CountlyRNExample/Events.tsx +++ b/example/CountlyRNExample/Events.tsx @@ -1,7 +1,7 @@ import React from "react"; import { ScrollView } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; -import Countly from "countly-sdk-react-native-bridge"; +import Countly from "countly-sdk-react-native-bridge-np"; import CountlyButton from "./CountlyButton"; const basicEvent = () => { diff --git a/example/CountlyRNExample/EventsLegacy.tsx b/example/CountlyRNExample/EventsLegacy.tsx index 0f767e6c..6076d4f9 100644 --- a/example/CountlyRNExample/EventsLegacy.tsx +++ b/example/CountlyRNExample/EventsLegacy.tsx @@ -1,7 +1,7 @@ import React from "react"; import { ScrollView } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; -import Countly from "countly-sdk-react-native-bridge"; +import Countly from "countly-sdk-react-native-bridge-np"; import CountlyButton from "./CountlyButton"; interface Segmentation {} diff --git a/example/CountlyRNExample/Feedback.tsx b/example/CountlyRNExample/Feedback.tsx index 7c91ce73..dfbd8a26 100644 --- a/example/CountlyRNExample/Feedback.tsx +++ b/example/CountlyRNExample/Feedback.tsx @@ -2,7 +2,7 @@ import React from "react"; import { ScrollView, StyleSheet, Text, TextInput } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; -import Countly from "countly-sdk-react-native-bridge"; +import Countly from "countly-sdk-react-native-bridge-np"; import CountlyButton from "./CountlyButton"; import { lightOrange } from "./Constants"; diff --git a/example/CountlyRNExample/Home.tsx b/example/CountlyRNExample/Home.tsx index ccd2273f..b6dee151 100644 --- a/example/CountlyRNExample/Home.tsx +++ b/example/CountlyRNExample/Home.tsx @@ -2,7 +2,7 @@ import React from "react"; import { Text, SafeAreaView, ScrollView, Alert } from "react-native"; import CountlyButton from "./CountlyButton"; -import Countly from "countly-sdk-react-native-bridge"; +import Countly from "countly-sdk-react-native-bridge-np"; import countlyConfig from "./Configuration"; import { lightGreen, navigationName } from "./Constants"; @@ -14,17 +14,6 @@ async function initialize() { await Countly.initWithConfig(countlyConfig); // Initialize the countly SDK. Countly.appLoadingFinished(); - - /** - * Push notifications settings - * Should be call after init - */ - Countly.registerForNotification((theNotification: string) => { - const jsonString = JSON.stringify(JSON.parse(theNotification)); - console.log(`Just received this notification data: ${jsonString}`); - Alert.alert(`theNotification: ${jsonString}`); - }); // Set callback to receive push notifications - Countly.askForNotificationPermission("android.resource://com.countly.demo/raw/notif_sample"); // This method will ask for permission, enables push notification and send push token to countly server. } function HomeScreen({ navigation }) { diff --git a/example/CountlyRNExample/Others.tsx b/example/CountlyRNExample/Others.tsx index 5c98e702..0581af41 100644 --- a/example/CountlyRNExample/Others.tsx +++ b/example/CountlyRNExample/Others.tsx @@ -1,7 +1,7 @@ import React from "react"; import { Platform, ScrollView } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; -import Countly from "countly-sdk-react-native-bridge"; +import Countly from "countly-sdk-react-native-bridge-np"; import CountlyButton from "./CountlyButton"; class AttributionKey { @@ -24,10 +24,6 @@ const disableLocation = () => { Countly.disableLocation(); }; -const askForNotificationPermission = () => { - Countly.askForNotificationPermission(); -}; - const setCustomMetrics = () => { const customMetric = { _carrier: "Custom Carrier", @@ -57,7 +53,6 @@ function OthersScreen({ navigation }) { - diff --git a/example/CountlyRNExample/RemoteConfig.tsx b/example/CountlyRNExample/RemoteConfig.tsx index bf05453f..08534cbf 100644 --- a/example/CountlyRNExample/RemoteConfig.tsx +++ b/example/CountlyRNExample/RemoteConfig.tsx @@ -1,7 +1,7 @@ import React from "react"; import { ScrollView } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; -import Countly from "countly-sdk-react-native-bridge"; +import Countly from "countly-sdk-react-native-bridge-np"; import CountlyButton from "./CountlyButton"; const remoteConfigUpdate = () => { diff --git a/example/CountlyRNExample/UserProfiles.tsx b/example/CountlyRNExample/UserProfiles.tsx index 55cec93e..9733545f 100644 --- a/example/CountlyRNExample/UserProfiles.tsx +++ b/example/CountlyRNExample/UserProfiles.tsx @@ -1,7 +1,7 @@ import React from "react"; import { ScrollView } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; -import Countly from "countly-sdk-react-native-bridge"; +import Countly from "countly-sdk-react-native-bridge-np"; import CountlyButton from "./CountlyButton"; interface UserDataPredefined { diff --git a/example/CountlyRNExample/Views.tsx b/example/CountlyRNExample/Views.tsx index 2ede2f46..da08897d 100644 --- a/example/CountlyRNExample/Views.tsx +++ b/example/CountlyRNExample/Views.tsx @@ -1,7 +1,7 @@ import React from "react"; import { ScrollView } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; -import Countly from "countly-sdk-react-native-bridge"; +import Countly from "countly-sdk-react-native-bridge-np"; import CountlyButton from "./CountlyButton"; function ViewsScreen({ navigation }) { diff --git a/example/README.md b/example/README.md index 1e31673d..e7822421 100644 --- a/example/README.md +++ b/example/README.md @@ -43,89 +43,3 @@ Finally you can run: npx react-native run-android # or npx react-native run-ios ``` - -## iOS Push Notification Documentation - -Note: This documentation assumes, that you have created necessary certficate, have proper app bundle id. - -STEP 1: Make sure you have proper app bundle id and team selected. - -STEP 2: Add Capabilities - 1. Push Notification - 2. Background Mode - Remote Notifications - Go into your AwesomeProject/ios dir and open AwesomeProject.xcworkspace workspace. Select the top project "AwesomeProject" ans select the "Signing & Capabilities" tab. Add a 2 new Capabilities using "+" button: - Background Mode capability and tick Remote Notifications. - Push Notifications capability - -STEP 3: Place below code in there respective files. - -### AppDelegate.m - -Add header file -`#import "CountlyReactNative.h"` -`#import ` - -Before `@end` add these method - -// Required for the notification event. You must call the completion handler after handling the remote notification. -- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler -{ - [CountlyReactNative onNotification: userInfo]; - completionHandler(0); -} - -// When app is killed. -- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse*)response withCompletionHandler:(void (^)(void))completionHandler{ - [CountlyReactNative onNotificationResponse: response]; - completionHandler(); -} - -// When app is running. -- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification*)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{ - [CountlyReactNative onNotification: notification.request.content.userInfo]; - completionHandler(0); -} - -### Rich Push Notification - -STEP 1: Creating Notification Service Extension - Editor -> Add Target -> - Make sure `ios` is selected - Make sure `Notification Service Extension` is selected - Click `Next` - Enter Product Name e.g. `CountlyNSE` - Language `Objective-C` - Click `Finish` - It will ask for a modal / popup `Activate “CountlyNSE” scheme?` - Choose `Cancel` - -STEP 2: Adding Compile Source - Under `TARGETS` select `CountlyNSE` - Select `Build Phases` - Expand `Compile Sources` - Drag and Drop `CountlyNotificationService.h` and `CountlyNotificationService.m` file - Note: You may also find this file in `Xcode` under `Pods(Project) -> Pods(Folder) -> Countly` - Note: You may also find this file in `Finder` under `AwesomeProject/ios/Pods/Countly` - Note: You may also find this file in `Xcode` under `AwesomeProject(Project) -> Libraries(Folder) -> countly-sdk-react-native-bridge(Project)->src(Folder)` - Note: You may also find this file in `Finder` under `node_modules/countly-sdk-react-native-bridge/ios/Pods/Countly` - -STEP 3: Updating NotificationService file - Under `AwesomeProject(Project) -> CountlyNSE(Folder) -> NotificationService.m` - Add import header `#import "CountlyNotificationService.h"` - Add the following line at the end of `didReceiveNotificationRequest:withContentHandler:` - - - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler - { - self.contentHandler = contentHandler; - self.bestAttemptContent = [request.content mutableCopy]; - //delete existing template code, and add this line - [CountlyNotificationService didReceiveNotificationRequest:request withContentHandler:contentHandler]; - } - - - Note: Please make sure you configure App Transport Security setting in extension's Info.plist file also, just like the main application. Otherwise media attachments from non-https sources can not be loaded. - - Note: Please make sure you check Deployment Target version of extension target is 10, not 10.3 (or whatever minor version Xcode set automatically). Otherwise users running iOS versions lower than Deployment Target value can not get rich push notifications. - - Note: To send push messages to applications that are Debug build use Countly.messagingMode.DEVELOPMENT, for App Store built ones use Countly.messagingMode.PRODUCTION, and for TestFlight/Ad Hoc builds use Countly.messagingMode.ADHOC. - diff --git a/example/create_app.py b/example/create_app.py index 87bee1bb..61f7de6a 100644 --- a/example/create_app.py +++ b/example/create_app.py @@ -6,7 +6,7 @@ # It is meant to be run from the example folder # It will remove any existing AwesomeProject folder, and create a new one # It will then copy the contents of CountlyRNExample to AwesomeProject -# It will then add countly-sdk-react-native-bridge to dependencies in package.json +# It will then add countly-sdk-react-native-bridge-np to dependencies in package.json # If on iOS, it will run pod install def setup_react_native_app(): @@ -26,17 +26,17 @@ def setup_react_native_app(): # Copy contents of CountlyRNExample to AwesomeProject shutil.copytree("CountlyRNExample", "AwesomeProject", dirs_exist_ok=True) - print("Adding countly-sdk-react-native-bridge to dependencies...") + print("Adding countly-sdk-react-native-bridge-np to dependencies...") # Add countly-sdk-react-native-bridge to dependencies in package.json os.chdir("AwesomeProject") - os.system("npm install --save countly-sdk-react-native-bridge@latest @react-navigation/native react-native-screens react-native-safe-area-context @react-navigation/native-stack") + os.system("npm install --save countly-sdk-react-native-bridge-np@latest @react-navigation/native react-native-screens react-native-safe-area-context @react-navigation/native-stack") # If on iOS, run pod install if platform.system() == "Darwin": print("Running pod install") os.chdir("ios") - os.system("pod install") + os.system("pod install --no-repo-update --verbose") os.chdir("..") if __name__ == "__main__": diff --git a/ios/src/CountlyRNPushNotifications.h b/ios/src/CountlyRNPushNotifications.h deleted file mode 100644 index 60053d7e..00000000 --- a/ios/src/CountlyRNPushNotifications.h +++ /dev/null @@ -1,23 +0,0 @@ -// CountlyRNPushNotifications.h -// -// This code is provided under the MIT License. -// -// Please visit www.count.ly for more information. - -#import "CountlyReactNative.h" -#import - -@interface CountlyRNPushNotifications : NSObject -#ifndef COUNTLY_EXCLUDE_PUSHNOTIFICATIONS -+ (instancetype _Nonnull)sharedInstance; - -- (void)startObservingNotifications; -- (void)stopObservingNotifications; -- (void)recordPushActions; -- (void)askForNotificationPermission; -- (void)registerForNotification; -- (void)setCountlyReactNative:(CountlyReactNative *_Nullable)countlyReactNative; -- (void)onNotification:(NSDictionary *_Nullable)notification; -- (void)onNotificationResponse:(UNNotificationResponse *_Nullable)response; -#endif -@end diff --git a/ios/src/CountlyRNPushNotifications.m b/ios/src/CountlyRNPushNotifications.m deleted file mode 100644 index 0d031d71..00000000 --- a/ios/src/CountlyRNPushNotifications.m +++ /dev/null @@ -1,205 +0,0 @@ -// CountlyRNPushNotifications.m -// -// This code is provided under the MIT License. -// -// Please visit www.count.ly for more information. - -#import "CountlyRNPushNotifications.h" -#import "CountlyCommon.h" -#import "UserNotifications/UserNotifications.h" - -#ifndef COUNTLY_EXCLUDE_PUSHNOTIFICATIONS -NSDictionary *lastStoredNotification = nil; -Result notificationListener = nil; -NSMutableArray *notifications = nil; - -CountlyReactNative *_countlyReactNative = nil; - -typedef NSString *CLYUserDefaultKey NS_EXTENSIBLE_STRING_ENUM; -CLYUserDefaultKey const CLYPushNotificationsKey = @"notificationsKey"; -CLYUserDefaultKey const CLYPushButtonIndexKey = @"notificationBtnIndexKey"; -#endif -@interface CountlyRNPushNotifications () -@end - -@implementation CountlyRNPushNotifications -#ifndef COUNTLY_EXCLUDE_PUSHNOTIFICATIONS -+ (instancetype)sharedInstance { - static CountlyRNPushNotifications *s_sharedInstance; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - s_sharedInstance = self.new; - }); - return s_sharedInstance; -} - -- (instancetype)init { - if (self = [super init]) { - } - - notifications = [[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:CLYPushNotificationsKey]; - return self; -} - -- (void)setCountlyReactNative:(CountlyReactNative *_Nullable)countlyReactNative { - _countlyReactNative = countlyReactNative; -} - -- (void)stopObservingNotifications { - if (UNUserNotificationCenter.currentNotificationCenter.delegate == self) - UNUserNotificationCenter.currentNotificationCenter.delegate = nil; -} - -- (void)startObservingNotifications { - UNUserNotificationCenter.currentNotificationCenter.delegate = self; -} - -- (void)askForNotificationPermission { - dispatch_async(dispatch_get_main_queue(), ^{ - [Countly.sharedInstance askForNotificationPermission]; - }); -} - -- (void)saveListener:(Result)result { - notificationListener = result; -} - -- (void)registerForNotification { - dispatch_async(dispatch_get_main_queue(), ^{ - [self saveListener:^(id _Nullable result) { - [_countlyReactNative notificationCallback:[CountlyRNPushNotifications toJSON:lastStoredNotification]]; - lastStoredNotification = nil; - }]; - if (lastStoredNotification != nil) { - [_countlyReactNative notificationCallback:[CountlyRNPushNotifications toJSON:lastStoredNotification]]; - lastStoredNotification = nil; - } - }); -} - -- (void)recordPushActions { - NSMutableArray *_notifications = [[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:CLYPushNotificationsKey]; - if (_notifications != nil) { - for (NSMutableDictionary *notificationMessage in _notifications) { - [self recordPushAction:notificationMessage]; - } - } - - [[NSUserDefaults standardUserDefaults] removeObjectForKey:CLYPushNotificationsKey]; - [[NSUserDefaults standardUserDefaults] synchronize]; -} - -- (void)recordPushAction:(NSMutableDictionary *)notificationMessage { - if (notificationMessage != nil) { - NSNumber *buttonIndex = notificationMessage[CLYPushButtonIndexKey]; - NSInteger responseBtnIndex = buttonIndex.intValue; - NSMutableDictionary *responseDictionary = [notificationMessage mutableCopy]; - [responseDictionary removeObjectForKey:CLYPushButtonIndexKey]; - - if ([responseDictionary count] > 0) { - - NSDictionary *countlyPayload = responseDictionary[kCountlyPNKeyCountlyPayload]; - NSString *URL = @""; - if (responseBtnIndex == 0) { - URL = countlyPayload[kCountlyPNKeyDefaultURL]; - } else { - URL = countlyPayload[kCountlyPNKeyButtons][responseBtnIndex - 1][kCountlyPNKeyActionButtonURL]; - } - - [Countly.sharedInstance recordActionForNotification:responseDictionary clickedButtonIndex:responseBtnIndex]; - - [self openURL:URL]; - } - } -} - -- (void)openURL:(NSString *)URLString { - if (!URLString) - return; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - [UIApplication.sharedApplication openURL:[NSURL URLWithString:URLString] options:@{} completionHandler:nil]; - }); -} - -// when user open the app by tapping notification in any state. -- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { - [self onNotificationResponse:response]; - - id appDelegate = (id)UIApplication.sharedApplication.delegate; - if ([appDelegate respondsToSelector:@selector(userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:)]) - [appDelegate userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler]; - else - completionHandler(); -} - -// When app is running and notification received -- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler { - [self onNotification:notification.request.content.userInfo]; - NSDictionary *countlyPayload = notification.request.content.userInfo[kCountlyPNKeyCountlyPayload]; - NSString *notificationID = countlyPayload[kCountlyPNKeyNotificationID]; - - if (notificationID) { - UNNotificationPresentationOptions presentationOption = UNNotificationPresentationOptionNone; - if (@available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *)) { - presentationOption = UNNotificationPresentationOptionList | UNNotificationPresentationOptionBanner; - } else { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - presentationOption = UNNotificationPresentationOptionAlert; -#pragma GCC diagnostic pop - } - completionHandler(presentationOption); - } - - id appDelegate = (id)UIApplication.sharedApplication.delegate; - - if ([appDelegate respondsToSelector:@selector(userNotificationCenter:willPresentNotification:withCompletionHandler:)]) - [appDelegate userNotificationCenter:center willPresentNotification:notification withCompletionHandler:completionHandler]; - else - completionHandler(UNNotificationPresentationOptionNone); -} - -- (void)onNotification:(NSDictionary *)notificationMessage { - NSLog(@"The notification %@", [CountlyRNPushNotifications toJSON:notificationMessage]); - if (notificationMessage && notificationListener != nil) { - lastStoredNotification = notificationMessage; - notificationListener(@[ [CountlyRNPushNotifications toJSON:notificationMessage] ]); - } else { - lastStoredNotification = notificationMessage; - } -} - -- (void)onNotificationResponse:(UNNotificationResponse *)response API_AVAILABLE(ios(10.0)) { - NSDictionary *notificationDictionary = response.notification.request.content.userInfo; - NSInteger buttonIndex = 0; - if ([response.actionIdentifier hasPrefix:kCountlyActionIdentifier]) { - buttonIndex = [[response.actionIdentifier stringByReplacingOccurrencesOfString:kCountlyActionIdentifier withString:@""] integerValue]; - } - if (!CountlyCommon.sharedInstance.hasStarted) { - if (notifications == nil) { - notifications = [[NSMutableArray alloc] init]; - } - NSMutableDictionary *mutableNotification = [notificationDictionary mutableCopy]; - mutableNotification[CLYPushButtonIndexKey] = [NSNumber numberWithInteger:buttonIndex]; - [notifications insertObject:mutableNotification atIndex:[notifications count]]; - [[NSUserDefaults standardUserDefaults] setObject:notifications forKey:CLYPushNotificationsKey]; - [[NSUserDefaults standardUserDefaults] synchronize]; - } - [self onNotification:notificationDictionary]; -} - -+ (NSString *)toJSON:(NSDictionary *)json { - NSError *error; - NSData *jsonData = [NSJSONSerialization dataWithJSONObject:json options:NSJSONWritingPrettyPrinted error:&error]; - - if (!jsonData) { - NSLog(@"Got an error: %@", error); - return [NSString stringWithFormat:@"{'error': '%@'}", error]; - } else { - NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; - return jsonString; - } -} -#endif - -@end diff --git a/ios/src/CountlyReactNative.m b/ios/src/CountlyReactNative.m index 62ce9978..0bc17eed 100644 --- a/ios/src/CountlyReactNative.m +++ b/ios/src/CountlyReactNative.m @@ -1,3 +1,4 @@ +#define COUNTLY_EXCLUDE_PUSHNOTIFICATIONS #import #import #import @@ -24,8 +25,11 @@ @interface CountlyFeedbackWidget () + (CountlyFeedbackWidget *)createWithDictionary:(NSDictionary *)dictionary; @end +BOOL BUILDING_WITH_PUSH_DISABLED = true; + NSString *const kCountlyReactNativeSDKVersion = @"24.4.0"; NSString *const kCountlyReactNativeSDKName = @"js-rnb-ios"; +NSString *const kCountlyReactNativeSDKNameNoPush = @"js-rnbnp-ios"; CLYPushTestMode const CLYPushTestModeProduction = @"CLYPushTestModeProduction"; @@ -86,6 +90,7 @@ + (BOOL)requiresMainQueueSetup [self populateConfig:jsonOutput]; CountlyCommon.sharedInstance.SDKName = kCountlyReactNativeSDKName; + CountlyCommon.sharedInstance.SDKName = BUILDING_WITH_PUSH_DISABLED ? kCountlyReactNativeSDKNameNoPush : kCountlyReactNativeSDKName; CountlyCommon.sharedInstance.SDKVersion = kCountlyReactNativeSDKVersion; #ifndef COUNTLY_EXCLUDE_PUSHNOTIFICATIONS diff --git a/package.json b/package.json index 1a613167..3f2920a8 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "countly-sdk-react-native-bridge", + "name": "countly-sdk-react-native-bridge-np", "version": "24.4.0", "author": "Countly (https://count.ly/)", "bugs": { @@ -9,7 +9,7 @@ "test": "jest" }, "deprecated": false, - "description": "Countly is an innovative, real-time, open source mobile analytics and push notifications platform.", + "description": "Countly is an innovative, real-time, open source mobile analytics platform.", "homepage": "https://github.com/Countly/countly-sdk-react-native-bridge", "keywords": [ "countly",