Android push notifications , fcm - java

I'm develop java rest api service and i need to make push notifications to android devices. I'm not really sure how to do it properly, my code is
public class FcmNotif {
public final static String AUTH_KEY_FCM = "My key";
public final static String API_URL_FCM = "https://fcm.googleapis.com/fcm/send";
// userDeviceIdKey is the device id you will query from your database
public void pushFCMNotification(String userDeviceIdKey, String title, String message) throws Exception {
String authKey = AUTH_KEY_FCM; // You FCM AUTH key
String FMCurl = API_URL_FCM;
URL url = new URL(FMCurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization", "key=" + authKey);
conn.setRequestProperty("Content-Type", "application/json");
JsonObject json = new JsonObject();
json.addProperty("to", userDeviceIdKey.trim());
JsonObject info = new JsonObject();
info.addProperty("title", title); // Notification title
info.addProperty("body", message); // Notification body
info.addProperty("image", "https://lh6.googleusercontent.com/-sYITU_cFMVg/AAAAAAAAAAI/AAAAAAAAABM/JmQNdKRPSBg/photo.jpg");
info.addProperty("type", "message");
json.add("data", info);
System.out.println(json.toString());
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(json.toString());
wr.flush();
conn.getInputStream();
// System.out.println(url.getH);
}
public static void main(String[] args) throws Exception {
FcmNotif fcmN=new FcmNotif();
fcmN.pushFCMNotification("user id ", "myFirstMessage", "hello");
System.out.println("Done");
}
}
AUTH_KEY_FCM i get from https://developers.google.com/mobile/add "Server API Key" and userDeviceIdKey its id that i get from running this code in android studio
String android_id = Settings.Secure.getString(getApplicationContext().getContentResolver(),
Settings.Secure.ANDROID_ID);
Maybe i don't understand smth clearly, whan am i doing wrong?
Response error
java.io.IOException: Server returned HTTP response code: 401 for URL: https://fcm.googleapis.com/fcm/send
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1840)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
at com.gmoika.FcmNotif.makeRequest(FcmNotif.java:88)
at com.gmoika.FcmNotif.main(FcmNotif.java:111)

You can use Pushraven to send push notifications to android devices via fcm.
https://github.com/Raudius/Pushraven
Add the jar and do :
Pushraven.setKey(my_key);
Notification raven = new Notification();
raven.title("MyTitle")
.text("Hello World!")
.color("#ff0000")
.to(client_key);
Pushraven.push(raven);
raven.clear();
For more detail documentation and jar file go to the link provided.
The jar implements everything that needs to be done to send fcm push notifications.

Currently, you're only supposed to generate a valid Server Key by creating a Firebase Project, from there, go to Project Settings > Cloud Messaging tab. New Server API keys generated through the Google Dev Console is expected to not work for GCM/FCM, if it does, the behavior is not guaranteed -- you may receive a 401 error.
The value for userDeviceIdKey is supposed to be generated on the client side (usually) by calling getToken(). See Registration Token.

Related

Can't get FCM payload message on Android app after website publish on Openshift

I have a JSP Servlet Web application, when customer enter one entry using web application the application generate the FCM payload message to Android application.
It's all working fine when I tested it on my local environment, but now I published the website on OPENSHIFT and try to enter one entry using website.
Now I am unable to get the FCM payload message on my Android app. What could be the problem? My android app is not published on Google play store yet.
I used all required code i.e.
public final static String AUTH_KEY_FCM="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
public final static String API_URL_FCM = "https://fcm.googleapis.com/fcm/send";
It works fine on any machine but after publishing the website on OPENSHIFT it's not send any message to Android app.
// This class is created to send data payload to the FCM to Android app....
public class SendDataPayload {
// Method to send Notifications from server to client end.
public final static String AUTH_KEY_FCM = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
public final static String API_URL_FCM = "https://fcm.googleapis.com/fcm/send";
// userDeviceIdKey is the device id you will query from your database
public void pushFCMNotification(String userDeviceIdKey, int y_Id, String f_name, String l_name, String m_number,
String puja_name, String puja_date, String puja_time, String p_address, String p_landmark, String p_taluka,
String p_district, String p_pincode) throws Exception {
String authKey = AUTH_KEY_FCM; // Your FCM AUTH key
String FMCurl = API_URL_FCM;
URL url = new URL(FMCurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization", "key=" + authKey);
conn.setRequestProperty("Content-Type", "application/json");
JSONObject json = new JSONObject();
json.put("to", userDeviceIdKey.trim()); // device token...
// JSONObject info = new JSONObject();
// info.put("title", "xyz"); // Notification title
// info.put("body", "my message body is here!!!");
// // Notification body
String timeStamp = new SimpleDateFormat("dd/MM/yyyy hh:mm a").format(Calendar.getInstance().getTime());
String date = timeStamp;
JSONObject data = new JSONObject();
String first_name_ = URLEncoder.encode(f_name, "UTF-8");
String last_name_ = URLEncoder.encode(l_name, "UTF-8");
String santrika_sandesh = URLEncoder.encode("msg-MY", "UTF-8");
String M_number = URLEncoder.encode(m_number, "UTF-8");
String Puja_name = URLEncoder.encode(puja_name, "UTF-8");
String Puja_date = URLEncoder.encode(puja_date, "UTF-8");
String Puja_time = URLEncoder.encode(puja_time, "UTF-8");
String P_address = URLEncoder.encode(p_address, "UTF-8");
String P_landmark = URLEncoder.encode(p_landmark, "UTF-8");
String P_taluka = URLEncoder.encode(p_taluka, "UTF-8");
String P_district = URLEncoder.encode(p_district, "UTF-8");
data.put("key1", santrika_sandesh); // DataPayload
data.put("key2", date); // DataPayload
data.put("y_Id", y_Id);
data.put("f_name", first_name_); // Yajman first name
data.put("l_name", last_name_);
data.put("m_number", M_number);
data.put("puja_name", Puja_name);
data.put("puja_date", Puja_date);
data.put("puja_time", Puja_time);
data.put("puja_add", P_address);
data.put("puja_landmark", P_landmark);
data.put("puja_tal", P_taluka);
data.put("puja_dist", P_district);
data.put("puja_pincode", p_pincode);
// send notification and payload data to FCM....
// json.put("notification", info);
json.put("data", data);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(json.toString());
wr.flush();
conn.getInputStream();
}
}
See https://firebase.google.com/docs/cloud-messaging/send-message#http_response
FCM will send back http response with success or error.
FCM response Example {"multicast_id":************,"success":1,"failure":1,"canoni‌cal_ids":0,"results"‌​:[{"error":"NotRegis‌​tered"},{"message_id‌​":"0:***********"}]}
In code below fcmServerResponse.toString() is response from FCM.Print it in webpage so can see the error or success message.
StringBuilder fcmServerResponse = new StringBuilder();
BufferedReader in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
fcmServerResponse.append(inputLine);
}
fcmServerResponse.toString()//This is response from FCM

Firebase Cloud Messaging- Group of devices

I try to create a group of devices in Firebase Cloud Messaging and I got an ioexception "https://android.googleapis.com/gcm/googlenotification".
I have several questions about it:
What I need to put in fields: senderId, registrationId, idToken?
How I change this part of code to create a group and not add to group?
Where I need to put "authorization", "key=AIzaS..."?
Code:
public String addNotificationKey(
String senderId, String userEmail, String registrationId, String idToken)
throws IOException, JSONException {
URL url = new URL("https://android.googleapis.com/gcm/googlenotification");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setDoOutput(true);
// HTTP request header
con.setRequestProperty("project_id", senderId);
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
con.setRequestMethod("POST");
con.connect();
// HTTP request
JSONObject data = new JSONObject();
data.put("operation", "add");
data.put("notification_key_name", userEmail);
data.put("registration_ids", new JSONArray(Arrays.asList(registrationId)));
data.put("id_token", idToken);
OutputStream os = con.getOutputStream();
os.write(data.toString().getBytes("UTF-8"));
os.close();
// Read the response into a string
InputStream is = con.getInputStream();
String responseString = new Scanner(is, "UTF-8").useDelimiter("\\A").next();
is.close();
// Parse the JSON string and return the notification key
JSONObject response = new JSONObject(responseString);
return response.getString("notification_key");
}
For #3:
con.setRequestProperty("Authorization", "key=AIzaS...");
What I need to put in fields: senderId, registrationId, idToken?
See their definitions in Credentials.
Sender ID can be found in your Firebase Console. Go to Project Settings, then Cloud Messaging tab.
Registration token is generated on your client app side. See the corresponding setup documentation depending on the client app type here.
idToken is (AFAIK) only used on the client app side. See the (Android) documentation here.
How I change this part of code to create a group and not add to group?
Change
data.put("operation", "add");
to
data.put("operation", "create");
Where I need to put "authorization", "key=AIzaS..."?
See Puf's answer.

FileNotFoundException on getInputStream from GAE address

I'm doing an Android app with an API with Python. The API is on a Google App Engine cloud and everything works fine when I tested it with Postman.
I'm trying to do a Login with a POST method. That method returns json with the user information I keep getting that error: FileNotFoundException
Here is some of my code:
try{
String account = params[0].get(0);
String password = params[0].get(1);
URL url = new URL("http", WEB_SERVICE_URL, PORT, REST_LOGIN);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(CONNECTION_TIMEOUT);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
httpURLConnection.setRequestProperty("Content-Type", "application/json");
httpURLConnection.setRequestProperty("Accept", "application/json");
JSONObject json = jsonParser.serialJsonLogin(nomCompte, motPasse);
osw = new OutputStreamWriter(httpURLConnection.getOutputStream(),"UTF-8");
osw.write(json.toString());
osw.flush();
String body = readStream(httpURLConnection.getInputStream());
osw.close();
Log.i(TAG, "Return : " + body);
user = jsonParser.deserializeJsonUser(body);
}catch (Exception e) {
mException = e;
}finally {
if (mHttpURLConnection != null) {
mHttpURLConnection.disconnect();
}
}
return user;
At: String body = readStream(httpURLConnection.getInputStream()); I'm getting a java.io.FileNotFoundException: http://10.0.2.2:8080/login
My readStream method is fine, I tested it. If I look in my Google App Engine logs, I can see that there is no 404, or anything wrong. If I find the user I get a 201 if not a 403. So even if the error says FileNotFound, I see status code which means that actually the URL is right.
UPDATE: My API was giving me a 201 and getInputStream apparently doesn't work on 201 status. Changed my return status to 200 in my API and it works fine.

GCM Push Notifications are not delivered to devices

We (Panos and Rainer - see the comments down) have a server and several Android devices.
We want to send push notifications from our server via GCM to the Android devices.
Now we make a post request to the GCM server. The GCM server response is that all is fine (success==1 and even the message-id)!
BUT the push notification(s) are never delivered to the devices.
If we use the same data and the Chrome addon Postman - the notifications are delivered immediately.
We tried all lot of different solutions. We get always the feedback of the GCM server that all is ok - but the push notifications aren't send.
We also tried this one:
https://github.com/googlesamples/google-services/blob/master/android/gcm/gcmsender/src/main/java/gcm/play/android/samples/com/gcmsender/GcmSender.java
You might also post the URL you use. There is a new GCM enpoint which looks like the following:
https://gcm-http.googleapis.com/gcm/send
I am not yet sure what's causing the issues on your side. But the following is tested and working:
public class Main {
public static void main(String[] args) {
// write your code here
try {
String url = "https://gcm-http.googleapis.com/gcm/send";
URL obj = new URL(url);
HttpsURLConnectionImpl conn = (HttpsURLConnectionImpl) obj.openConnection();
conn.setRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty ("Authorization", "key=***");
String title = "Short title";
String body = "A body :D";
String token = "****";
String data = "{ \"notification\": { \"title\": \"" + title +"\", \"body\": \"" + body + "\" }, \"to\" : \"" + token + "\", \"priority\" : \"high\" }";
OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
out.write(data);
out.close();
String text = getText(new InputStreamReader(conn.getInputStream()));
System.out.println(text);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getText(InputStreamReader in) throws IOException {
StringBuilder sb=new StringBuilder();
BufferedReader br = new BufferedReader(in);
String read;
while((read=br.readLine()) != null) {
sb.append(read);
}
br.close();
return sb.toString();
}
}
This is the data used for the Postman request which is working without any problem.
Rainer already mentioned that we tried several implementations on the Java side and it seems that we are always able to communicate with the service and receive a response which seems to look correct so far:
{
"multicast_id":7456542468425129822,
"success":1,
"failure":0,
"canonical_ids":0,
"results":
[{
"message_id":"0:1457548597263237%39c590d7f9fd7ecd"
}]
}
Not sure if I'm on the right track but do you mean downstream HTTP messages (plain text)?
Tried to send the following JSON to the service (from Postman) which results again in a positive response but this time the notification did not reach the device (just to make that clear, at the moment there is no app on the device listening actively for incoming notifications -> first of all we just want to ensure that they generally arrive on the device):
{
"data":
{
"score": "5x1",
"time": "15:10"
},
"to" : "SECRET-DEVICE-TOKEN"
}
Thanks to all of you trying to help here but to be honest, this issue is really frustrating. Communicating with an interface\service which seems not to be able to return a useful response in case the request contains maybe evil stuff which will finally prevent GCM from sending the push notification to the device, feels like a pain in the ass. If Postman would also fail I would say ok, you can not be so stupid :-)
Here are some quick'n dirty implementations we have already used.
Example
try
{
URL url = new URL(apiUrl);
HttpsURLConnection conn = (HttpsURLConnection);//also tried HttpURLConnection
url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", "key="+apiKey);
conn.setDoOutput(true);
String json = "{\"priority\":\"high\",\"notification\":{\"title\":\"Some title\",\"text\":\"Some text\"},\"to\":\""+deviceToken+"\"}";
OutputStream os = conn.getOutputStream();
os.write(json.getBytes());
os.flush();
}
catch(Exception exc)
{
System.out.println("Error while trying to send push notification: "+exc);
}
Example
HttpClient httpClient = HttpClientBuilder.create().build();
try
{
HttpPost request = new HttpPost(apiUrl);
StringEntity params =new StringEntity("{\"priority\":\"high\",\"notification\":{\title\":\"Some title\",\"text\":\"Some text\"},\"to\":\""+deviceToken+"\"}");
request.addHeader("Content-Type", "application/json");
request.addHeader("Authorization", "key="+apiKey);
request.setEntity(params);
HttpResponse response = httpClient.execute(request);
// check response
System.out.println(response.getStatusLine().toString());
}catch (Exception exc) {
System.out.println("Error while trying to send push notification: "+exc);
} finally {
httpClient.getConnectionManager().shutdown(); //Deprecated
}
Example
try
{
String charset = "UTF-8";
URLConnection connection = new URL(apiUrl).openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Accept-Charset", charset);
connection.setRequestProperty("Content-Type", "application/json;charset=" + charset);
connection.setRequestProperty("Authorization", "key="+apiKey);
String param = "{\"priority\":\"high\",\"notification\":{\"title\":\"Some title\",\"text\":\"Some text\"},\"to\":\""+deviceToken+"\"}";
try (OutputStream output = connection.getOutputStream())
{
output.write(param.getBytes(charset));
}
InputStream response = connection.getInputStream();
}
catch(Exception exc)
{
System.out.println("Error while trying to send push notification: "+exc);
}
Example
try
{
// prepare JSON
JSONObject jGcmData = new JSONObject();
JSONObject jData = new JSONObject();
jData.put("message", "{ \"data\": {\"score\": \"5x1\",\"time\": \"15:10\"},\"to\" : \""+deviceToken+"\"}");
jGcmData.put("to", deviceToken);
jGcmData.put("data", jData);
// Create connection to send GCM Message request.
URL url = new URL("https://android.googleapis.com/gcm/send");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Authorization", "key=" + apiKey);
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestMethod("POST");
conn.setDoOutput(true);
// Send GCM message content.
OutputStream outputStream = conn.getOutputStream();
outputStream.write(jGcmData.toString().getBytes());
// Read GCM response.
InputStream inputStream = conn.getInputStream();
String resp = IOUtils.toString(inputStream);
System.out.println(resp);
} catch (IOException e) {
System.out.println("Unable to send GCM message. "+e);
}
Mike, with your example it's working also on our side. After comparing your implementation with the on eon our side, the only real difference I found is the used URL!!
Somehow the URL used in our Java implementation was https://android.googleapis.com/gcm/send
Seems that https://gcm-http.googleapis.com/gcm/send is the right one which by the way was also used for our Postman tests.
But why on hell is the URL from our failed tests still somehowe valid and returns a response!?
Setting the priority to high in the json resolved the issue for me.
'registration_ids' => $id,
'priority' => 'high',
'data' => $load
For our case, the clients Android devices had intermittent internet connection issue, that is, network dropouts thus causing notification delivery failed. We resolved the reliability issue with the following JAVA GCM code:
gcmPayload.setTime_to_live(messageExpiryTime); //in seconds. Set notification message expiry to give user time to receive it in case they have intermittent internet connection, or phone was off
gcmPayload.setPriority("high");
and APNS code:
ApnsService apnsService = APNS.newService().withCert(certificateStream, configurations.getApnPassword()).withProductionDestination().build();
PayloadBuilder payloadBuilder = APNS.newPayload();
...
payloadBuilder.instantDeliveryOrSilentNotification(); //same as content-available=true
String payload = payloadBuilder.build();
Integer now = (int)(new Date().getTime()/1000);
//use EnhancedApnsNotification to set message expiry time
for(String deviceToken : deviceTokens) {
EnhancedApnsNotification notification = new EnhancedApnsNotification(EnhancedApnsNotification.INCREMENT_ID() /* Next ID */,
now + messageExpiryTime /* Expiry time in seconds */,
deviceToken /* Device Token */,
payload);
apnsService.push(notification);
}
Also, remember to consider time zone if your backend server time is different to the client mobile app time.

Getting HTTP audio and then playing it back in android

I have a API that takes a string and converts in into audio when I do a HTTP get in android. I want to be able to play it back when I recieve it but I don't know how to do this. Can someone help me. Here is my code so far:
public static String getHTML(String urlToRead) throws Exception {
StringBuilder result = new StringBuilder();
URL url = new URL(urlToRead);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");

Categories