Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions __mocks__/react-native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ const mockRNOneSignal = {
addOutcomeWithValue: vi.fn(),
displayNotification: vi.fn(),
preventDefault: vi.fn(),
trackEvent: vi.fn(),
};

const mockPlatform = {
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ dependencies {

// api is used instead of implementation so the parent :app project can access any of the OneSignal Java
// classes if needed. Such as com.onesignal.NotificationExtenderService
api 'com.onesignal:OneSignal:5.4.2'
api 'com.onesignal:OneSignal:5.6.0'

testImplementation 'junit:junit:4.12'
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ of this software and associated documentation files (the "Software"), to deal
package com.onesignal.rnonesignalandroid;

import android.content.Context;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.Promise;
Expand Down Expand Up @@ -754,4 +755,12 @@ public void addListener(String eventName) {
public void removeListeners(int count) {
// Keep: Required for RN built in Event Emitter Calls.
}

@ReactMethod
public void trackEvent(String name, @Nullable ReadableMap properties) {
OneSignal.getUser()
.trackEvent(
name,
properties != null ? RNUtils.convertReadableMapToMap(properties) : new java.util.HashMap<>());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,70 @@ public static HashMap<String, String> convertReadableMapIntoStringMap(ReadableMa
return stringMap;
}

public static Map<String, Object> convertReadableMapToMap(ReadableMap readableMap) {
Map<String, Object> map = new HashMap<>();
ReadableMapKeySetIterator iterator = readableMap.keySetIterator();

while (iterator.hasNextKey()) {
String key = iterator.nextKey();
ReadableType type = readableMap.getType(key);
Object value = convertValue(type, readableMap, key);
if (value != null) {
map.put(key, value);
}
}

return map;
}

public static List<Object> convertReadableArrayToList(ReadableArray readableArray) {
List<Object> list = new ArrayList<>();

for (int i = 0; i < readableArray.size(); i++) {
ReadableType type = readableArray.getType(i);
Object value = convertValue(type, readableArray, i);
if (value != null) {
list.add(value);
}
}

return list;
}

private static Object convertValue(ReadableType type, ReadableMap map, String key) {
switch (type) {
case Boolean:
return map.getBoolean(key);
case Number:
return map.getDouble(key);
case String:
return map.getString(key);
case Map:
return convertReadableMapToMap(map.getMap(key));
case Array:
return convertReadableArrayToList(map.getArray(key));
default:
return null;
}
}

private static Object convertValue(ReadableType type, ReadableArray array, int index) {
switch (type) {
case Boolean:
return array.getBoolean(index);
case Number:
return array.getDouble(index);
case String:
return array.getString(index);
case Map:
return convertReadableMapToMap(array.getMap(index));
case Array:
return convertReadableArrayToList(array.getArray(index));
default:
return null;
}
}

public static HashMap<String, Object> convertPermissionToMap(boolean granted) {
HashMap<String, Object> hash = new HashMap<>();

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ spotless {
java {
target 'android/**/*.java', 'examples/RNOneSignalTS/android/app/src/**/*.java'
targetExclude '**/build/**'
palantirJavaFormat('2.28.0')
palantirJavaFormat('2.85.0')
removeUnusedImports()
trimTrailingWhitespace()
endWithNewline()
Expand Down
25 changes: 24 additions & 1 deletion examples/RNOneSignalTS/OSButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Text, View } from 'react-native';
import { Platform, Text, View } from 'react-native';
import { OneSignal } from 'react-native-onesignal';
import { renderButtonView } from './Helpers';
// Remove: import {Text, Divider} from '@react-native-material/core';
Expand Down Expand Up @@ -396,11 +396,34 @@ const OSButtons: React.FC<Props> = ({ loggingFunction, inputFieldValue }) => {
},
);

const trackEventButton = renderButtonView('Track Event', () => {
loggingFunction('Tracking event: ', 'ReactNative');
const platform = Platform.OS; // This will be 'ios' or 'android'
OneSignal.User.trackEvent(`ReactNative-${platform}-noprops`);
OneSignal.User.trackEvent(`ReactNative-${platform}`, {
someNum: 123,
someFloat: 3.14159,
someString: 'abc',
someBool: true,
someObject: {
abc: '123',
nested: {
def: '456',
},
ghi: null,
},
someArray: [1, 2],
someMixedArray: [1, '2', { abc: '123' }, null],
someNull: null,
});
});

return [
loginButton,
logoutButton,
addEmailButton,
removeEmailButton,
trackEventButton,
sendTagWithKeyButton,
deleteTagWithKeyButton,
addTagsButton,
Expand Down
34 changes: 17 additions & 17 deletions examples/RNOneSignalTS/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8,48 +8,48 @@ PODS:
- hermes-engine (0.82.1):
- hermes-engine/Pre-built (= 0.82.1)
- hermes-engine/Pre-built (0.82.1)
- OneSignalXCFramework (5.2.16):
- OneSignalXCFramework/OneSignalComplete (= 5.2.16)
- OneSignalXCFramework/OneSignal (5.2.16):
- OneSignalXCFramework (5.4.0):
- OneSignalXCFramework/OneSignalComplete (= 5.4.0)
- OneSignalXCFramework/OneSignal (5.4.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalExtension
- OneSignalXCFramework/OneSignalLiveActivities
- OneSignalXCFramework/OneSignalNotifications
- OneSignalXCFramework/OneSignalOSCore
- OneSignalXCFramework/OneSignalOutcomes
- OneSignalXCFramework/OneSignalUser
- OneSignalXCFramework/OneSignalComplete (5.2.16):
- OneSignalXCFramework/OneSignalComplete (5.4.0):
- OneSignalXCFramework/OneSignal
- OneSignalXCFramework/OneSignalInAppMessages
- OneSignalXCFramework/OneSignalLocation
- OneSignalXCFramework/OneSignalCore (5.2.16)
- OneSignalXCFramework/OneSignalExtension (5.2.16):
- OneSignalXCFramework/OneSignalCore (5.4.0)
- OneSignalXCFramework/OneSignalExtension (5.4.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalOutcomes
- OneSignalXCFramework/OneSignalInAppMessages (5.2.16):
- OneSignalXCFramework/OneSignalInAppMessages (5.4.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalNotifications
- OneSignalXCFramework/OneSignalOSCore
- OneSignalXCFramework/OneSignalOutcomes
- OneSignalXCFramework/OneSignalUser
- OneSignalXCFramework/OneSignalLiveActivities (5.2.16):
- OneSignalXCFramework/OneSignalLiveActivities (5.4.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalOSCore
- OneSignalXCFramework/OneSignalUser
- OneSignalXCFramework/OneSignalLocation (5.2.16):
- OneSignalXCFramework/OneSignalLocation (5.4.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalNotifications
- OneSignalXCFramework/OneSignalOSCore
- OneSignalXCFramework/OneSignalUser
- OneSignalXCFramework/OneSignalNotifications (5.2.16):
- OneSignalXCFramework/OneSignalNotifications (5.4.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalExtension
- OneSignalXCFramework/OneSignalOutcomes
- OneSignalXCFramework/OneSignalOSCore (5.2.16):
- OneSignalXCFramework/OneSignalOSCore (5.4.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalOutcomes (5.2.16):
- OneSignalXCFramework/OneSignalOutcomes (5.4.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalUser (5.2.16):
- OneSignalXCFramework/OneSignalUser (5.4.0):
- OneSignalXCFramework/OneSignalCore
- OneSignalXCFramework/OneSignalNotifications
- OneSignalXCFramework/OneSignalOSCore
Expand Down Expand Up @@ -1828,8 +1828,8 @@ PODS:
- React-RCTFBReactNativeSpec
- ReactCommon/turbomodule/core
- SocketRocket
- react-native-onesignal (5.2.17):
- OneSignalXCFramework (= 5.2.16)
- react-native-onesignal (5.3.0):
- OneSignalXCFramework (= 5.4.0)
- React (< 1.0.0, >= 0.13.0)
- react-native-safe-area-context (5.6.2):
- boost
Expand Down Expand Up @@ -2768,7 +2768,7 @@ SPEC CHECKSUMS:
fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
glog: 5683914934d5b6e4240e497e0f4a3b42d1854183
hermes-engine: 273e30e7fb618279934b0b95ffab60ecedb7acf5
OneSignalXCFramework: 8ed6648481bee0bd973a138fecd80331b798524f
OneSignalXCFramework: 95b6391df5a91b448003149c1a633ade42ceca1e
RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669
RCTDeprecation: f17e2ebc07876ca9ab8eb6e4b0a4e4647497ae3a
RCTRequired: e2c574c1b45231f7efb0834936bd609d75072b63
Expand Down Expand Up @@ -2802,7 +2802,7 @@ SPEC CHECKSUMS:
React-logger: 500f2fa5697d224e63c33d913c8a4765319e19bf
React-Mapbuffer: 06d59c448da7e34eb05b3fb2189e12f6a30fec57
React-microtasksnativemodule: d1ee999dc9052e23f6488b730fa2d383a4ea40e5
react-native-onesignal: 3b6cd199ec0db87166ef7fb595715627a35b3244
react-native-onesignal: 68c8423063cc8ead827e09bc71d139c14850feaf
react-native-safe-area-context: c00143b4823773bba23f2f19f85663ae89ceb460
React-NativeModulesApple: 46690a0fe94ec28fc6fc686ec797b911d251ded0
React-oscompat: 95875e81f5d4b3c7b2c888d5bd2c9d83450d8bdb
Expand Down
5 changes: 5 additions & 0 deletions ios/RCTOneSignal/RCTOneSignalEventEmitter.m
Original file line number Diff line number Diff line change
Expand Up @@ -628,4 +628,9 @@ - (void)removeUserStateObserver {
}
}

RCT_EXPORT_METHOD(trackEvent : (NSString *)name withProperties : (
NSDictionary *_Nullable)properties) {
[OneSignal.User trackEventWithName:name properties:properties];
}

@end
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-onesignal",
"version": "5.2.17",
"version": "5.3.0",
"description": "React Native OneSignal SDK",
"files": [
"dist",
Expand Down
2 changes: 1 addition & 1 deletion react-native-onesignal.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ Pod::Spec.new do |s|
# pod 'React', :path => '../node_modules/react-native/'

# The Native OneSignal-iOS-SDK XCFramework from cocoapods.
s.dependency 'OneSignalXCFramework', '5.2.16'
s.dependency 'OneSignalXCFramework', '5.4.0'
end
44 changes: 43 additions & 1 deletion src/helpers.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import type { NativeModule } from 'react-native';
import type { MockInstance } from 'vitest';
import { isNativeModuleLoaded, isValidCallback } from './helpers';
import {
isNativeModuleLoaded,
isObjectSerializable,
isValidCallback,
} from './helpers';

describe('helpers', () => {
let errorSpy: MockInstance;
Expand Down Expand Up @@ -58,4 +62,42 @@ describe('helpers', () => {
expect(result).toBe(true);
});
});

describe('isObjectSerializable', () => {
test.each([
{ description: 'an empty object', value: {} },
{ description: 'an object with string values', value: { key: 'value' } },
{ description: 'an object with number values', value: { count: 42 } },
{ description: 'an object with boolean values', value: { active: true } },
{ description: 'an object with null values', value: { data: null } },
{
description: 'a nested object',
value: { outer: { inner: 'value' } },
},
{
description: 'an object with array values',
value: { items: [1, 2, 3] },
},
])('should return true for $description', ({ value }) => {
expect(isObjectSerializable(value)).toBe(true);
});

test.each([
{ description: 'null', value: null },
{ description: 'undefined', value: undefined },
{ description: 'a string', value: 'string' },
{ description: 'a number', value: 123 },
{ description: 'a boolean', value: true },
{ description: 'an array', value: [1, 2, 3] },
{ description: 'a function', value: () => {} },
])('should return false for $description', ({ value }) => {
expect(isObjectSerializable(value)).toBe(false);
});

test('should return false for objects with circular references', () => {
const circular: Record<string, unknown> = {};
circular.self = circular;
expect(isObjectSerializable(circular)).toBe(false);
});
});
});
15 changes: 15 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,18 @@ export function isNativeModuleLoaded(module: NativeModule): boolean {

return true;
}

/**
* Returns true if the value is a JSON-serializable object.
*/
export function isObjectSerializable(value: unknown): boolean {
if (!(typeof value === 'object' && value !== null && !Array.isArray(value))) {
return false;
}
try {
JSON.stringify(value);
return true;
} catch {
return false;
}
}
Loading