4242public class CustomPushNotification extends PushNotification {
4343 public static ReactApplicationContext reactApplicationContext ;
4444 final NotificationManager notificationManager ;
45+
46+ // Create a single Gson instance
47+ private static final Gson gson = new Gson ();
4548
4649 public CustomPushNotification (Context context , Bundle bundle , AppLifecycleFacade appLifecycleFacade , AppLaunchHelper appLaunchHelper , JsIOHelper jsIoHelper ) {
4750 super (context , bundle , appLifecycleFacade , appLaunchHelper , jsIoHelper );
@@ -63,9 +66,9 @@ public static void clearMessages(int notId) {
6366 @ Override
6467 public void onReceived () throws InvalidNotificationException {
6568 Bundle received = mNotificationProps .asBundle ();
66- Ejson receivedEjson = new Gson (). fromJson (received .getString ("ejson" , "{}" ), Ejson .class );
69+ Ejson receivedEjson = safeFromJson (received .getString ("ejson" , "{}" ), Ejson .class );
6770
68- if (receivedEjson .notificationType != null && receivedEjson .notificationType .equals ("message-id-only" )) {
71+ if (receivedEjson != null && receivedEjson .notificationType != null && receivedEjson .notificationType .equals ("message-id-only" )) {
6972 notificationLoad (receivedEjson , new Callback () {
7073 @ Override
7174 public void call (@ Nullable Bundle bundle ) {
@@ -78,18 +81,18 @@ public void call(@Nullable Bundle bundle) {
7881
7982 // We should re-read these values since that can be changed by notificationLoad
8083 Bundle bundle = mNotificationProps .asBundle ();
81- Ejson loadedEjson = new Gson (). fromJson (bundle .getString ("ejson" , "{}" ), Ejson .class );
84+ Ejson loadedEjson = safeFromJson (bundle .getString ("ejson" , "{}" ), Ejson .class );
8285 String notId = bundle .getString ("notId" , "1" );
8386
8487 if (notificationMessages .get (notId ) == null ) {
8588 notificationMessages .put (notId , new ArrayList <Bundle >());
8689 }
8790
88- boolean hasSender = loadedEjson .sender != null ;
91+ boolean hasSender = loadedEjson != null && loadedEjson .sender != null ;
8992 String title = bundle .getString ("title" );
9093
9194 // If it has a encrypted message
92- if (loadedEjson .msg != null ) {
95+ if (loadedEjson != null && loadedEjson .msg != null ) {
9396 // Override message with the decrypted content
9497 String decrypted = Encryption .shared .decryptMessage (loadedEjson , reactApplicationContext );
9598 if (decrypted != null ) {
@@ -100,9 +103,9 @@ public void call(@Nullable Bundle bundle) {
100103 bundle .putLong ("time" , new Date ().getTime ());
101104 bundle .putString ("username" , hasSender ? loadedEjson .sender .username : title );
102105 bundle .putString ("senderId" , hasSender ? loadedEjson .sender ._id : "1" );
103- bundle .putString ("avatarUri" , loadedEjson .getAvatarUri ());
106+ bundle .putString ("avatarUri" , loadedEjson != null ? loadedEjson .getAvatarUri () : null );
104107
105- if (loadedEjson .notificationType instanceof String && loadedEjson .notificationType .equals ("videoconf" )) {
108+ if (loadedEjson != null && loadedEjson .notificationType instanceof String && loadedEjson .notificationType .equals ("videoconf" )) {
106109 notifyReceivedToJS ();
107110 } else {
108111 notificationMessages .get (notId ).add (bundle );
@@ -128,7 +131,7 @@ protected Notification.Builder getNotificationBuilder(PendingIntent intent) {
128131 String title = bundle .getString ("title" );
129132 String message = bundle .getString ("message" );
130133 Boolean notificationLoaded = bundle .getBoolean ("notificationLoaded" , false );
131- Ejson ejson = new Gson (). fromJson (bundle .getString ("ejson" , "{}" ), Ejson .class );
134+ Ejson ejson = safeFromJson (bundle .getString ("ejson" , "{}" ), Ejson .class );
132135
133136 notification
134137 .setContentTitle (title )
@@ -145,7 +148,7 @@ protected Notification.Builder getNotificationBuilder(PendingIntent intent) {
145148 notificationDismiss (notification , notificationId );
146149
147150 // if notificationType is null (RC < 3.5) or notificationType is different of message-id-only or notification was loaded successfully
148- if (ejson .notificationType == null || !ejson .notificationType .equals ("message-id-only" ) || notificationLoaded ) {
151+ if (ejson == null || ejson .notificationType == null || !ejson .notificationType .equals ("message-id-only" ) || notificationLoaded ) {
149152 notificationStyle (notification , notificationId , bundle );
150153 notificationReply (notification , notificationId , bundle );
151154
@@ -159,9 +162,9 @@ protected Notification.Builder getNotificationBuilder(PendingIntent intent) {
159162 while (iterator .hasNext ()) {
160163 Bundle not = (Bundle ) iterator .next ();
161164 // get the notification info
162- Ejson notEjson = gson . fromJson (not .getString ("ejson" , "{}" ), Ejson .class );
165+ Ejson notEjson = safeFromJson (not .getString ("ejson" , "{}" ), Ejson .class );
163166 // if already has a notification from same server
164- if (ejson .serverURL ().equals (notEjson .serverURL ())) {
167+ if (ejson != null && notEjson != null && ejson .serverURL ().equals (notEjson .serverURL ())) {
165168 String id = not .getString ("notId" );
166169 // cancel this notification
167170 notificationManager .cancel (Integer .parseInt (id ));
@@ -207,13 +210,15 @@ private void notificationIcons(Notification.Builder notification, Bundle bundle)
207210
208211 int smallIconResId = res .getIdentifier ("ic_notification" , "drawable" , packageName );
209212
210- Gson gson = new Gson ();
211- Ejson ejson = gson .fromJson (bundle .getString ("ejson" , "{}" ), Ejson .class );
213+ Ejson ejson = safeFromJson (bundle .getString ("ejson" , "{}" ), Ejson .class );
212214
213215 notification .setSmallIcon (smallIconResId );
214216
215217 if (Build .VERSION .SDK_INT < Build .VERSION_CODES .N ) {
216- notification .setLargeIcon (getAvatar (ejson .getAvatarUri ()));
218+ String avatarUri = ejson != null ? ejson .getAvatarUri () : null ;
219+ if (avatarUri != null ) {
220+ notification .setLargeIcon (getAvatar (avatarUri ));
221+ }
217222 }
218223 }
219224
@@ -236,7 +241,7 @@ private void notificationChannel(Notification.Builder notification) {
236241 }
237242
238243 private String extractMessage (String message , Ejson ejson ) {
239- if (ejson .type != null && !ejson .type .equals ("d" )) {
244+ if (ejson != null && ejson .type != null && !ejson .type .equals ("d" )) {
240245 int pos = message .indexOf (":" );
241246 int start = pos == -1 ? 0 : pos + 2 ;
242247 return message .substring (start , message .length ());
@@ -291,17 +296,19 @@ private void notificationStyle(Notification.Builder notification, int notId, Bun
291296 String message = data .getString ("message" );
292297 String senderId = data .getString ("senderId" );
293298 String avatarUri = data .getString ("avatarUri" );
294- Ejson ejson = gson . fromJson (data .getString ("ejson" , "{}" ), Ejson .class );
299+ Ejson ejson = safeFromJson (data .getString ("ejson" , "{}" ), Ejson .class );
295300 String m = extractMessage (message , ejson );
296301
297302 if (Build .VERSION .SDK_INT < Build .VERSION_CODES .P ) {
298- messageStyle .addMessage (m , timestamp , ejson .senderName );
303+ String senderName = ejson != null ? ejson .senderName : "Unknown" ;
304+ messageStyle .addMessage (m , timestamp , senderName );
299305 } else {
300306 Bitmap avatar = getAvatar (avatarUri );
301307
308+ String senderName = ejson != null ? ejson .senderName : "Unknown" ;
302309 Person .Builder sender = new Person .Builder ()
303310 .setKey (senderId )
304- .setName (ejson . senderName );
311+ .setName (senderName );
305312
306313 if (avatar != null ) {
307314 sender .setIcon (Icon .createWithBitmap (avatar ));
@@ -369,4 +376,29 @@ private void notificationLoad(Ejson ejson, Callback callback) {
369376 LoadNotification loadNotification = new LoadNotification ();
370377 loadNotification .load (reactApplicationContext , ejson , callback );
371378 }
379+
380+ /**
381+ * Safely parse JSON string to object with error handling.
382+ *
383+ * @param json JSON string to parse
384+ * @param classOfT Target class type
385+ * @param <T> Type parameter
386+ * @return Parsed object, or null if parsing fails
387+ */
388+ private static <T > T safeFromJson (String json , Class <T > classOfT ) {
389+ if (json == null || json .trim ().isEmpty () || json .equals ("{}" )) {
390+ return null ; // no need to create a new instance
391+ }
392+
393+ try {
394+ return gson .fromJson (json , classOfT );
395+ } catch (Exception e ) {
396+ android .util .Log .e (
397+ "CustomPushNotification" ,
398+ "Failed to parse JSON into " + classOfT .getSimpleName () + " (payload redacted)." ,
399+ e
400+ );
401+ return null ;
402+ }
403+ }
372404}
0 commit comments