Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add getters and observer for onesignal ID and external ID #1627

Merged
merged 15 commits into from
Mar 12, 2024
Merged
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
16 changes: 16 additions & 0 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,22 @@ The User namespace is accessible via `OneSignal.User` and provides access to use
| `OneSignal.User.removeTag("KEY")` | _Remove the data tag with the provided key from the current user._ |
| `OneSignal.User.removeTags(["KEY_01", "KEY_02"])` | _Remove multiple tags with the provided keys from the current user._ |
| `OneSignal.User.getTags()` | _Returns the local tags for the current user._|
| `OneSignal.User.addEventListener("change", (event: UserChangedState) => void)`<br><br>**_See below for usage_** | _Add a User State callback which contains the nullable onesignalId and externalId. The listener will be fired when these values change._|
| `await OneSignal.User.getOnesignalId()` | _Returns the OneSignal ID for the current user, which can be null if it is not yet available._|
| `await OneSignal.User.getExternalId()` | _Returns the External ID for the current user, which can be null if not set._|

### User State Listener

```typescript
const listener = (event: UserChangedState) => {
console.log("User changed: " + (event));
};

OneSignal.User.addEventListener("change", listener);
// Remove the listener
OneSignal.User.removeEventListener("change", listener);
```

## Push Subscription Namespace

The Push Subscription namespace is accessible via `OneSignal.User.pushSubscription` and provides access to push subscription-scoped functionality.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ of this software and associated documentation files (the "Software"), to deal
import com.onesignal.user.subscriptions.IPushSubscriptionObserver;
import com.onesignal.user.subscriptions.PushSubscriptionState;
import com.onesignal.user.subscriptions.PushSubscriptionChangedState;
import com.onesignal.user.state.UserState;
import com.onesignal.user.state.UserChangedState;
import com.onesignal.user.state.IUserStateObserver;
import org.json.JSONException;

import java.util.HashMap;
Expand All @@ -82,6 +85,7 @@ of this software and associated documentation files (the "Software"), to deal
public class RNOneSignal extends ReactContextBaseJavaModule implements
IPushSubscriptionObserver,
IPermissionObserver,
IUserStateObserver,
LifecycleEventListener,
INotificationLifecycleListener{
private ReactApplicationContext mReactApplicationContext;
Expand All @@ -90,6 +94,7 @@ public class RNOneSignal extends ReactContextBaseJavaModule implements
private boolean oneSignalInitDone;
private boolean hasSetPermissionObserver = false;
private boolean hasSetPushSubscriptionObserver = false;
private boolean hasSetUserStateObserver = false;

private HashMap<String, INotificationWillDisplayEvent> notificationWillDisplayCache;
private HashMap<String, INotificationWillDisplayEvent> preventDefaultCache;
Expand Down Expand Up @@ -162,6 +167,7 @@ public void onClick(INotificationClickEvent event) {
private void removeObservers() {
this.removePermissionObserver();
this.removePushSubscriptionObserver();
this.removeUserStateObserver();
}

private void removeHandlers() {
Expand Down Expand Up @@ -676,6 +682,53 @@ public void removeAliases(ReadableArray aliasLabels) {
OneSignal.getUser().removeAliases(RNUtils.convertReadableArrayIntoStringCollection(aliasLabels));
}

@ReactMethod
public void getOnesignalId(Promise promise) {
String onesignalId = OneSignal.getUser().getOnesignalId();
if (onesignalId.isEmpty()) {
onesignalId = null;
}
promise.resolve(onesignalId);
jennantilla marked this conversation as resolved.
Show resolved Hide resolved

}

@ReactMethod
public void getExternalId(Promise promise) {
String externalId = OneSignal.getUser().getExternalId();
if (externalId.isEmpty()) {
externalId = null;
}
promise.resolve(externalId);
}

@ReactMethod
public void addUserStateObserver() {
if (!hasSetUserStateObserver) {
OneSignal.getUser().addObserver(this);
hasSetUserStateObserver = true;
}
}

@Override
public void onUserStateChange(UserChangedState state) {
try {
sendEvent("OneSignal-userStateChanged",
RNUtils.convertHashMapToWritableMap(
RNUtils.convertUserChangedStateToMap(state)));
Log.i("OneSignal", "sending user state change event");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocker, avoid using android.util.Log - since it looks like we are using that a lot already, we can refactor in the future.
The reason is similar to this PR done for ios: OneSignal/OneSignal-iOS-SDK#1219

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for flagging! Refactoring will happen in a future PR.

} catch (JSONException e) {
e.printStackTrace();
}
}

@ReactMethod
public void removeUserStateObserver() {
if (hasSetUserStateObserver) {
OneSignal.getUser().removeObserver(this);
hasSetUserStateObserver = false;
}
}

/** Added for NativeEventEmitter */
@ReactMethod
public void addListener(String eventName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import com.onesignal.user.subscriptions.IPushSubscription;
import com.onesignal.user.subscriptions.PushSubscriptionState;
import com.onesignal.user.subscriptions.PushSubscriptionChangedState;
import com.onesignal.user.state.UserState;
import com.onesignal.user.state.UserChangedState;

import org.json.JSONArray;
import org.json.JSONException;
Expand Down Expand Up @@ -197,6 +199,25 @@ public static HashMap<String, Object> convertPushSubscriptionStateToMap(PushSubs
return hash;
}

public static HashMap<String, Object> convertUserStateToMap(UserState user) {
HashMap<String, Object> hash = new HashMap<>();

if (user.getExternalId() != null && !user.getExternalId().isEmpty()) {
hash.put("externalId", user.getExternalId());
}
else {
hash.put("externalId", JSONObject.NULL);
}
if (user.getOnesignalId() != null && !user.getOnesignalId().isEmpty()) {
hash.put("onesignalId", user.getOnesignalId());
}
else {
hash.put("onesignalId", JSONObject.NULL);
}

return hash;
}

public static HashMap<String, Object> convertPushSubscriptionChangedStateToMap(PushSubscriptionChangedState state) {
HashMap<String, Object> hash = new HashMap<>();
hash.put("current", convertPushSubscriptionStateToMap(state.getCurrent()));
Expand All @@ -205,6 +226,13 @@ public static HashMap<String, Object> convertPushSubscriptionChangedStateToMap(P
return hash;
}

public static HashMap<String, Object> convertUserChangedStateToMap(UserChangedState state) {
HashMap<String, Object> hash = new HashMap<>();
hash.put("current", convertUserStateToMap(state.getCurrent()));

return hash;
}

public static HashMap<String, Object> convertJSONObjectToHashMap(JSONObject object) throws JSONException {
HashMap<String, Object> hash = new HashMap<>();

Expand Down
22 changes: 20 additions & 2 deletions examples/RNOneSignalTS/src/OSButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,8 @@ class OSButtons extends React.Component<Props> {
});

const getTagsButton = renderButtonView('Get tags', async () => {
const tags = await OneSignal.User.getTags();
loggingFunction('Tags:', tags);
const tags = await OneSignal.User.getTags();
loggingFunction('Tags:', tags);
});

const setLanguageButton = renderButtonView('Set Language', () => {
Expand Down Expand Up @@ -342,6 +342,22 @@ class OSButtons extends React.Component<Props> {
},
);

const getOnesignalIdButton = renderButtonView(
'Get OneSignal Id',
async () => {
const onesignalId = await OneSignal.User.getOnesignalId();
loggingFunction('OneSignal Id: ', onesignalId);
},
);

const getExternalIdButton = renderButtonView(
'Get External Id',
async () => {
const externalId = await OneSignal.User.getExternalId();
loggingFunction('External Id:', externalId);
},
);

return [
loginButton,
logoutButton,
Expand All @@ -359,6 +375,8 @@ class OSButtons extends React.Component<Props> {
removeAliasButton,
addAliasesButton,
removeAliasesButton,
getOnesignalIdButton,
getExternalIdButton,
];
}

Expand Down
4 changes: 4 additions & 0 deletions examples/RNOneSignalTS/src/OSDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ class OSDemo extends React.Component<Props, State> {
OneSignal.Notifications.addEventListener('permissionChange', (granted) => {
this.OSLog('OneSignal: permission changed:', granted);
});

OneSignal.User.addEventListener('change', (event) => {
this.OSLog('OneSignal: user changed: ', event);
});
}

OSLog = (message: string, optionalArg: any = null) => {
Expand Down
3 changes: 1 addition & 2 deletions ios/RCTOneSignal/RCTOneSignal.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
#import "../OneSignalFramework.h"
#endif

@interface RCTOneSignal : NSObject <OSPushSubscriptionObserver, OSNotificationPermissionObserver, OSInAppMessageLifecycleListener, OSInAppMessageClickListener, OSNotificationClickListener>

@interface RCTOneSignal : NSObject <OSPushSubscriptionObserver, OSNotificationPermissionObserver, OSInAppMessageLifecycleListener, OSInAppMessageClickListener, OSNotificationClickListener, OSUserStateObserver>
+ (RCTOneSignal *) sharedInstance;

@end
25 changes: 25 additions & 0 deletions ios/RCTOneSignal/RCTOneSignal.m
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,31 @@ - (void)sendEvent:(NSString *)eventName withBody:(NSDictionary *)body {
[RCTOneSignalEventEmitter sendEventWithName:eventName withBody:body];
}

- (void)onUserStateDidChangeWithState:(OSUserChangedState * _Nonnull)state {
NSString *onesignalId = state.current.onesignalId;
NSString *externalId = state.current.externalId;

NSMutableDictionary *currentDictionary = [NSMutableDictionary dictionary];

if (onesignalId.length > 0) {
[currentDictionary setObject:onesignalId forKey:@"onesignalId"];
}
else {
[currentDictionary setObject:[NSNull null] forKey:@"onesignalId"];
}

if (externalId.length > 0) {
[currentDictionary setObject:externalId forKey:@"externalId"];
}
else {
[currentDictionary setObject:[NSNull null] forKey:@"externalId"];
}

NSDictionary *result = @{@"current": currentDictionary};

[self sendEvent:OSEventString(UserStateChanged) withBody:result];
}

- (void)onPushSubscriptionDidChangeWithState:(OSPushSubscriptionChangedState * _Nonnull)state {
NSMutableDictionary *result = [NSMutableDictionary new];

Expand Down
3 changes: 2 additions & 1 deletion ios/RCTOneSignal/RCTOneSignalEventEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
typedef NS_ENUM(NSInteger, OSNotificationEventTypes) {
PermissionChanged,
SubscriptionChanged,
UserStateChanged,
NotificationWillDisplayInForeground,
NotificationClicked,
InAppMessageClicked,
Expand All @@ -24,7 +25,7 @@ typedef NS_ENUM(NSInteger, OSNotificationEventTypes) {
InAppMessageDidDismiss,
};

#define OSNotificationEventTypesArray @[@"OneSignal-permissionChanged",@"OneSignal-subscriptionChanged",@"OneSignal-notificationWillDisplayInForeground",@"OneSignal-notificationClicked",@"OneSignal-inAppMessageClicked", @"OneSignal-inAppMessageWillDisplay", @"OneSignal-inAppMessageDidDisplay", @"OneSignal-inAppMessageWillDismiss", @"OneSignal-inAppMessageDidDismiss"]
#define OSNotificationEventTypesArray @[@"OneSignal-permissionChanged",@"OneSignal-subscriptionChanged",@"OneSignal-userStateChanged",@"OneSignal-notificationWillDisplayInForeground",@"OneSignal-notificationClicked",@"OneSignal-inAppMessageClicked", @"OneSignal-inAppMessageWillDisplay", @"OneSignal-inAppMessageDidDisplay", @"OneSignal-inAppMessageWillDismiss", @"OneSignal-inAppMessageDidDismiss"]

#define OSEventString(enum) [OSNotificationEventTypesArray objectAtIndex:enum]

Expand Down
32 changes: 32 additions & 0 deletions ios/RCTOneSignal/RCTOneSignalEventEmitter.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ @implementation RCTOneSignalEventEmitter {
BOOL _hasListeners;
BOOL _hasSetSubscriptionObserver;
BOOL _hasSetPermissionObserver;
BOOL _hasSetUserStateObserver;
BOOL _hasAddedNotificationClickListener;
BOOL _hasAddedNotificationForegroundLifecycleListener;
BOOL _hasAddedInAppMessageClickListener;
Expand Down Expand Up @@ -310,6 +311,13 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body {
}

// OneSignal.User namespace methods
RCT_EXPORT_METHOD(addUserStateObserver) {
if (!_hasSetUserStateObserver) {
[OneSignal.User addObserver:[RCTOneSignal sharedInstance]];
_hasSetUserStateObserver = true;
}
}

RCT_EXPORT_METHOD(addPushSubscriptionObserver) {
if (!_hasSetSubscriptionObserver) {
[OneSignal.User.pushSubscription addObserver:[RCTOneSignal sharedInstance]];
Expand Down Expand Up @@ -365,6 +373,30 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body {
resolve(tags);
}

RCT_REMAP_METHOD(getOnesignalId,
getOnesignalIdResolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
NSString *onesignalId = OneSignal.User.onesignalId;

if (onesignalId == nil || [onesignalId length] == 0) {
resolve([NSNull null]); // Resolve with null if nil or empty
} else {
resolve(onesignalId);
}
}

RCT_REMAP_METHOD(getExternalId,
getExternalIdResolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
NSString *externalId = OneSignal.User.externalId;

if (externalId == nil || [externalId length] == 0) {
resolve([NSNull null]); // Resolve with null if nil or empty
} else {
resolve(externalId);
}
}

RCT_EXPORT_METHOD(addAlias:(NSString *)label :(NSString *)id) {
[OneSignal.User addAliasWithLabel:label id:id];
}
Expand Down
2 changes: 2 additions & 0 deletions src/events/EventManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import NotificationWillDisplayEvent from './NotificationWillDisplayEvent';
import {
PERMISSION_CHANGED,
SUBSCRIPTION_CHANGED,
USER_STATE_CHANGED,
NOTIFICATION_WILL_DISPLAY,
NOTIFICATION_CLICKED,
IN_APP_MESSAGE_CLICKED,
Expand All @@ -20,6 +21,7 @@ import OSNotification from '../OSNotification';
const eventList = [
PERMISSION_CHANGED,
SUBSCRIPTION_CHANGED,
USER_STATE_CHANGED,
NOTIFICATION_WILL_DISPLAY,
NOTIFICATION_CLICKED,
IN_APP_MESSAGE_CLICKED,
Expand Down
1 change: 1 addition & 0 deletions src/events/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export const IN_APP_MESSAGE_WILL_DISMISS = 'OneSignal-inAppMessageWillDismiss';
export const IN_APP_MESSAGE_DID_DISMISS = 'OneSignal-inAppMessageDidDismiss';
export const PERMISSION_CHANGED = 'OneSignal-permissionChanged';
export const SUBSCRIPTION_CHANGED = 'OneSignal-subscriptionChanged';
export const USER_STATE_CHANGED = 'OneSignal-userStateChanged';
Loading
Loading