If you’re strugling to send Android push notifications from your server, specially with the bizillion libraries, dependencies, graddle nuances and error rabbit holes.. know you’re not alone, and also be aware that there is another way to do this without all that library hell.
This method will grab Google credentials and then push notifications to Firebase from a java server. Sure, it still uses some libraries, but all these can be grabbed as simple jars from Maven, or the traditionall Gradle implementation way, but they wont, in turn, download a bunch of incompatible dependency libs. Also, it will be a lot easier to adapt this code to any other language like Python, PHP, etc .. specially if you ask AI.
You should already have your project im firebase and able to receive push noficitions from the firebase messaging website, also, you need to have your service-account-key.json file in hand.
Please keep in mind this is a very raw code, you’ll need to modify it to access your credentials and to send messages to multiple receivers.
import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import com.google.gson.reflect.TypeToken; import org.jose4j.jws.AlgorithmIdentifiers; import org.jose4j.jws.JsonWebSignature; import org.jose4j.jwt.JwtClaims; import org.jose4j.lang.JoseException; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.lang.reflect.Type; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.util.Base64; import java.util.Map; public class NotificationManager { //these come from the serviceaccountkey.json final String project_id = "*****"; final String client_email = "firebase-adminsdk-fbsvc@*****.iam.gserviceaccount.com"; final String private_key_id = "******"; //please remove -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY----- from private_key final String private_key = "*****"; String cachedAccessToken = ""; long tokenExpirationTime = 0; private static final String TOKEN_URI = "https://oauth2.googleapis.com/token"; public NotificationManager(){ System.out.println("NotificationManager created"); } public sendPushNotification(String title, String message, String extra, String deviceToken){ //you more likely send this via params title = "New message"; message = "hello world"; extra = "extradata"; deviceToken = "****"; //this token arrives to each Android device on app launch. Pass it to the server //lets not block the main thread new Thread(new sendPushNotificationRunnable(title, message, extra, deviceToken)).start(); } class sendPushNotificationRunnable implements Runnable{ String title, msg, extra, deviceToken; public sendPushNotificationRunnable(String title, String msg, String extra, String deviceToken) { this.title = title; this.msg = msg; this.extra = extra; this.deviceToken = deviceToken; } public void run() throws RuntimeException { String accessToken = getAccessToken(); sendNotification(accessToken); } public String getAccessToken(){ //here we will ask Google Cloud for Firebase credentials, and return them as a String String newAccessToken = cachedAccessToken; long currentTimeSeconds = System.currentTimeMillis() / 1000; //if last token is still valid, we will skip all this and return the cached one if (cachedAccessToken.equals("") || currentTimeSeconds > tokenExpirationTime - 300) { JwtClaims claims = new JwtClaims(); claims.setIssuer(client_email); claims.setSubject(client_email); claims.setAudience(TOKEN_URI); claims.setIssuedAtToNow(); claims.setExpirationTimeMinutesInTheFuture(60); claims.setStringClaim("scope", "https://www.googleapis.com/auth/firebase.messaging"); JsonWebSignature jws = new JsonWebSignature(); jws.setPayload(claims.toJson()); jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); jws.setHeader("kid", private_key_id); String pemContent = private_key.replaceAll("\\s", ""); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(pemContent)); String jwsKey = ""; try { KeyFactory keyFactory = KeyFactory.getInstance("RSA"); jws.setKey(keyFactory.generatePrivate(keySpec)); jwsKey = jws.getCompactSerialization(); } catch (NoSuchAlgorithmException | InvalidKeySpecException | JoseException e) { throw new RuntimeException(e); } if(!jwsKey.equals("")){ HttpURLConnection connection = null; try { URL url = new URL(TOKEN_URI); String requestBody = "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=" + jwsKey; byte[] postData = requestBody.getBytes(StandardCharsets.UTF_8); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); connection.setDoOutput(true); connection.setRequestProperty("Content-Length", String.valueOf(postData.length)); System.out.println("Sending token exchange request to " + TOKEN_URI + "..."); // Write the request body try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) { wr.write(postData); wr.flush(); } int responseCode = connection.getResponseCode(); StringBuilder response = new StringBuilder(); // Read the response try (BufferedReader in = new BufferedReader( new InputStreamReader( (responseCode == HttpURLConnection.HTTP_OK) ? connection.getInputStream() : connection.getErrorStream(), StandardCharsets.UTF_8))) { String inputLine; while ((inputLine = in.readLine()) != null) { response.append(inputLine); } } String responseBody = response.toString(); if (responseCode == HttpURLConnection.HTTP_OK) { Gson gson = new Gson(); Type typeOfHashMap = new TypeToken<Map<String, Object>>() {}.getType(); Map<String, Object> tokenResponseMap; try { tokenResponseMap = gson.fromJson(responseBody, typeOfHashMap); } catch (JsonSyntaxException e) { throw new IOException("Failed to parse token response JSON: " + e.getMessage() + "\nResponse: " + responseBody, e); } cachedAccessToken = (String) tokenResponseMap.get("access_token"); long expiresIn = ((Double)tokenResponseMap.get("expires_in")).longValue(); tokenExpirationTime = (System.currentTimeMillis() / 1000) + expiresIn; System.out.println("Access Token obtained successfully. Expires in " + expiresIn + " seconds."); newAccessToken = cachedAccessToken; } else { throw new IOException("Failed to get access token. Status: " + responseCode + ", Response: " + responseBody); } } catch (IOException e) { System.out.println("Token error: " + e.getMessage()); } finally { if (connection != null) { connection.disconnect(); } } } } return newAccessToken; } public void sendNotification(String accessToken){ //Here we will finally access Firebase using the Google Access token, //and submit a payload with the notification if (!FirebaseToken.equals("")) { try { URL url = new URL("https://fcm.googleapis.com/v1/projects/"+project_id+"/messages:send"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/json; UTF-8"); connection.setRequestProperty("Authorization", "Bearer " + accessToken); connection.setUseCaches(false); connection.setDoOutput(true); if (!deviceToken.equals("")) { String jsonPayload = ( "{'message': {"+ "'token':'"+deviceToken+"',"+ "'data':{'title':'"+title+"','body':'"+msg+"','extra':'"+extra+"},"+ "'android':{'priority':'HIGH'}}}" ).replace("'","\""); try (OutputStream os = connection.getOutputStream()) { byte[] input = jsonPayload.getBytes(StandardCharsets.UTF_8); os.write(input, 0, input.length); } int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { System.out.println("Notification was send"); } else { String errorResponse = new String(connection.getErrorStream().readAllBytes(), StandardCharsets.UTF_8); System.out.println("Notification error: " + errorResponse); } } connection.disconnect(); }catch(Exception e){ System.out.println("Notification error: " + e.getMessage()); e.printStackTrace(); } } } } }