1

I am building an android firebase chat app that doesn't require a server setup, I've already built everything for it and found a couple of YouTube tutorials on how to do what I'm having trouble with right now, I'm trying to get the app itself to send a push notification to the device its sending the message to, I'm using Volley to send the notification, the problem that I'm facing is the other device is not getting or showing the notification, can you please tell me what I'm doing wrong and how to fix it?

build.gradle

implementation 'com.google.firebase:firebase-auth:20.0.4'
implementation 'com.google.firebase:firebase-database:19.7.0'
implementation platform('com.google.firebase:firebase-bom:27.0.0')
implementation 'com.google.firebase:firebase-analytics'
implementation 'com.google.firebase:firebase-messaging:20.0.1'
implementation 'com.android.volley:volley:1.1.1'

AndroidManifest

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

...

<service
   android:name=".MyFirebaseMessagingService"
   android:permission="com.google.android.c2dm.permission.SEND">
   <intent-filter>
       <action android:name="com.google.firebase.MESSAGING_EVENT" />
       <action android:name="com.google.android.c2dm.intent.RECEIVE" />
   </intent-filter>
</service>
<service
   android:name=".MyFirebaseInstanceIDService">
   <intent-filter>
       <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
   </intent-filter>
</service>

MyFirebaseInstanceIDService

public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {

    private static final String TAG = "mFirebaseIIDService";

    @Override
    public void onTokenRefresh() {
        FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
        final String token = FirebaseInstanceId.getInstance().getToken();
        FirebaseInstallations.getInstance().getToken(false)
                .addOnCompleteListener(new OnCompleteListener<InstallationTokenResult>() {
                    @Override
                    public void onComplete(@NonNull Task<InstallationTokenResult> task) {
                        FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
                        FirebaseMessaging.getInstance().subscribeToTopic(user.getUid());
                        Log.i("TAG", "onTokenRefresh completed with token: " + task.getResult().getToken());
                    }
                });
    }
}

MyFirebaseMessagingService

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    private final String ADMIN_CHANNEL_ID = "admin_channel";

    @Override
    public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
        final Intent intent = new Intent(this, MainActivity.class);
        NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
        int notificationID = new Random().nextInt(85-65);

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            setupChannels(notificationManager);
        }

        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this , 0, intent,
                PendingIntent.FLAG_ONE_SHOT);

        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, ADMIN_CHANNEL_ID)
                .setContentTitle(remoteMessage.getData().get("title"))
                .setContentText(remoteMessage.getData().get("message"))
                .setAutoCancel(true)
                .setSound(notificationSoundUri)
                .setContentIntent(pendingIntent);

        notificationManager.notify(notificationID, notificationBuilder.build());
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    private void setupChannels(NotificationManager notificationManager){
        CharSequence adminChannelName = "New notification";
        String adminChannelDescription = "Device to device notification";

        NotificationChannel adminChannel;
        adminChannel = new NotificationChannel(ADMIN_CHANNEL_ID, adminChannelName, NotificationManager.IMPORTANCE_HIGH);
        adminChannel.setDescription(adminChannelDescription);
        adminChannel.enableLights(true);
        adminChannel.setLightColor(Color.RED);
        adminChannel.enableVibration(true);
        if (notificationManager != null) {
            notificationManager.createNotificationChannel(adminChannel);
        }
    }
}

MessageActivity

final private String FCM_API = "https://fcm.googleapis.com/fcm/send";
final private String serverKey = "key=MY_KEY";
final private String contentType = "application/json";
final String TAG = "NOTIFICATION TAG";

...

sendBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        String msg = msg_editText.getText().toString();
        if (!msg.equals("")) {
            sendMessage(fuser.getUid(), userid, msg);
            JSONObject notification = getStructure(fuser.getUid(), userid, msg);
            sendNotification(notification);
        }

        msg_editText.setText("");
    }
});

...

private JSONObject getStructure(String senderId, String receiverId, String msg) {
    JSONObject notification = new JSONObject();
    JSONObject notificationBody = new JSONObject();
    try {
        notificationBody.put("title", "App Test");
        notificationBody.put("message", "This is a test notification from the app");

        notification.put("to", "/topics/" + receiverId);
        notification.put("data", notificationBody);
    } catch (JSONException e) {
        e.printStackTrace();
    }
    return notification;
}

...

private void sendNotification(JSONObject notification) {

    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(FCM_API, notification,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject response) {
                    Log.i(TAG, "onResponse: " + response.toString());
                }
        }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Toast.makeText(MessageActivity.this, "Request error", Toast.LENGTH_SHORT).show();
            Log.i(TAG, "onErrorResponse: Didn't work");
        }
    }) {
        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Map<String, String> params = new HashMap<>();
            params.put("Authorization", serverKey);
            params.put("Content-Type", contentType);
            return params;
        }
    };

    MySingleton.getInstance(getApplicationContext()).addToRequestQueue(jsonObjectRequest);

}

MySingleton

public class MySingleton {

    private static MySingleton instance;
    private RequestQueue requestQueue;
    private Context ctx;

    public MySingleton(Context ctx) {
        this.ctx = ctx;
        requestQueue = getRequestQueue();
    }

    public static synchronized MySingleton getInstance(Context context) {
        if (instance == null) {
            instance = new MySingleton(context);
        }
        return instance;
    }

    public RequestQueue getRequestQueue() {
        if (requestQueue == null) {
            requestQueue = Volley.newRequestQueue(ctx.getApplicationContext());
        }
        return requestQueue;
    }

    public <T> void addToRequestQueue(Request<T> req) {
        getRequestQueue().add(req);
    }
}
tareq masri
  • 23
  • 1
  • 5
  • Please include the minimal code relevant to the problem, not your entire app for others to debug. See http://stackoverflow.com/help/mcve – Kato Apr 27 '21 at 23:27
  • *firebaser here* Calls to the FCM REST API require that you specify the FCM **server** key in your code. As its name implies, this key should only be used in server-side code, or in an otherwise trusted environment. The reason for this is that anyone who has the FCM server key can send whatever message they want to all of your users. By including this key in your Android app, a malicious user can find it and you're putting your users at risk. See https://stackoverflow.com/a/37993724 for a better solution. – Frank van Puffelen Apr 27 '21 at 23:29

0 Answers0