I am able to get the device id and save it to my database, and when something happens, I try to send the push notification but it does not get delivered to the phone. Here is what I do in my PHP:
$url = 'https://android.googleapis.com/gcm/send';
$device_ids = array( $device_id );
$headers = array('Authorization: key=' . 'my_api_key',
'Content-Type: application/json');
$t_data = array();
$t_data['message'] = 'Someone commented on your business.';
$t_json = array( 'registration_ids' => $device_ids , 'data' => $t_data );
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Authorization: key=my_id', 'Content-Type: application/json' ) );
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode( $t_json ) );
curl_setopt($ch, CURLOPT_URL, $url);
$result = curl_exec($ch);
if ($result === FALSE)
{
die('Curl failed: ' . curl_error($ch));
}
curl_close($ch);
and here is the result I get from the curl_exec call:
{"multicast_id":8714083978034301091,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1350807053347963%9aab4bd8f9fd7ecd"}]}
One thing I am wondering is whether I have to do something extra in the app like write my own Reciever class?
Thanks!
EDIT:
Here is my GCMIntentService class:
package com.problemio;
import static com.google.android.gcm.GCMConstants.ERROR_SERVICE_NOT_AVAILABLE;
import static com.google.android.gcm.GCMConstants.EXTRA_ERROR;
import static com.google.android.gcm.GCMConstants.EXTRA_REGISTRATION_ID;
import static com.google.android.gcm.GCMConstants.EXTRA_SPECIAL_MESSAGE;
import static com.google.android.gcm.GCMConstants.EXTRA_TOTAL_DELETED;
import static com.google.android.gcm.GCMConstants.EXTRA_UNREGISTERED;
import static com.google.android.gcm.GCMConstants.INTENT_FROM_GCM_LIBRARY_RETRY;
import static com.google.android.gcm.GCMConstants.INTENT_FROM_GCM_MESSAGE;
import static com.google.android.gcm.GCMConstants.INTENT_FROM_GCM_REGISTRATION_CALLBACK;
import static com.google.android.gcm.GCMConstants.VALUE_DELETED_MESSAGES;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import com.google.android.gcm.GCMBaseIntentService;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Log;
import android.widget.Toast;
import utils.GCMConstants;
public class GCMIntentService extends GCMBaseIntentService
{
public GCMIntentService()
{
super(ProblemioActivity.SENDER_ID);
}
#Override
protected void onRegistered(Context ctxt, String regId) {
Log.d(getClass().getSimpleName(), "onRegistered: " + regId);
Toast.makeText(this, regId, Toast.LENGTH_LONG).show();
}
#Override
protected void onUnregistered(Context ctxt, String regId) {
Log.d(getClass().getSimpleName(), "onUnregistered: " + regId);
}
#Override
protected void onMessage(Context ctxt, Intent message) {
Bundle extras=message.getExtras();
for (String key : extras.keySet()) {
Log.d(getClass().getSimpleName(),
String.format("onMessage: %s=%s", key,
extras.getString(key)));
}
}
#Override
protected void onError(Context ctxt, String errorMsg) {
Log.d(getClass().getSimpleName(), "onError: " + errorMsg);
}
#Override
protected boolean onRecoverableError(Context ctxt, String errorMsg) {
Log.d(getClass().getSimpleName(), "onRecoverableError: " + errorMsg);
return(true);
}
}
UPDATE:
Looking at LogCat, it turned out that the message is getting to the device. But the device is not displaying the push notification for some reason.
From the response it seems that the message is delivered. On Android you should have a GCMIntentService class that extends GCMBaseIntentService, to receive the message on the device. You should check the gcm-demo-client that comes in the SDK samples for a good approach on how to implement this on the app. There you only need set the SENDER_ID (your google proyect number) in the CommonUtilities class to receive messages from your server.
More info here.
To generate the notification on the GCMIntentService you can use:
//Issues a notification to inform the user that server has sent a message.
private static void generateNotification(Context context, String message, String title,) {
int icon = R.drawable.logo;
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent notificationIntent = new Intent(context, AnActivity.class);
// set intent so it does not start a new activity
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
Uri defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Notification notification = new NotificationCompat.Builder(context)
.setContentTitle(title)
.setContentText(message)
.setContentIntent(intent)
.setSmallIcon(icon)
.setLights(Color.YELLOW, 1, 2)
.setAutoCancel(true)
.setSound(defaultSound)
.build();
notificationManager.notify(0, notification);
}
Have you also registered the receiver on the manifest? Under the application tag?
<!--
BroadcastReceiver that will receive intents from GCM
services and handle them to the custom IntentService.
The com.google.android.c2dm.permission.SEND permission is necessary
so only GCM services can send data messages for the app.
-->
<receiver
android:name="com.google.android.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<!-- Receives the actual messages. -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<!-- Receives the registration id. -->
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.google.android.gcm.demo.app" />
</intent-filter>
</receiver>
<!--
Application-specific subclass of GCMBaseIntentService that will
handle received messages.
By default, it must be named .GCMIntentService, unless the
application uses a custom BroadcastReceiver that redefines its name.
-->
<service android:name=".GCMIntentService" />
You only need a collapseKey if you are planning to have your messages overwrite the previous message of that type. So if you are sending a message that the app needs to sync you can give it a collapse key so it will only send 1 sync message. The official docs describe how to use it.
While sending notification from GCM Server, which url to be used?
https://android.googleapis.com/gcm/send or
https://gcm-http.googleapis.com/gcm/send
Related
I'm trying to integrate Firebase Cloud Messaging (I use this code, which is mirrored here) with my existing app.
Relevant codes:
service.php
$msg_id = $_POST['id'];
$title = $_POST['title'];
$content = $_POST['content'];
$msg_date = $_POST['date'];
$author = $_POST['author'];
// insert the message into DB
$sql = "INSERT INTO tbl_message(msg_id, title, content, msg_date, author) VALUES ('$msg_id','$title','$content','$msg_date','$author')";
if ($result = mysqli_query($db, $sql)){
$firebase = new Firebase();
$push = new Push();
$payload = array();
$payload['foo'] = '123';
$payload['bar'] = 'xyz';
$push->setTitle($title);
$push->setMessage($content);
$push->setAuthor($author);
$push->setDate($msg_date);
$push->setImage('');
$push->setPayload($payload);
$push->setIsBackground(FALSE);
$resp = '';
$response = '';
$resp = $push->getPush();
$response = $firebase->sendToTopic('global', $resp);
echo $response;
}
Firebase.php
<?php
class Firebase {
// sending push message to single user by firebase reg id
public function send($to, $message) {
$fields = array(
'to' => $to,
//'data' => $message,
'data' => array("message" => $message));
return $this->sendPushNotification($fields);
}
// Sending message to a topic by topic name
public function sendToTopic($to, $message) {
$fields = array(
'to' => '/topics/' . $to,
//'data' => $message,
'data' => array("message" => $message)
);
return $this->sendPushNotification($fields);
}
// sending push message to multiple users by firebase registration ids
public function sendMultiple($registration_ids, $message) {
$fields = array(
'to' => $registration_ids,
//'data' => $message,
'data' => array("message" => $message)
);
return $this->sendPushNotification($fields);
}
// function makes curl request to firebase servers
private function sendPushNotification($fields) {
require_once 'config.php';
// Set POST variables
$url = 'https://fcm.googleapis.com/fcm/send';
$headers = array(
'Authorization: key=' . FIREBASE_API_KEY,
'Content-Type: application/json'
);
// Open connection
$ch = curl_init();
// Set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Disabling SSL Certificate support temporarly
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
// Execute post
$result = curl_exec($ch);
if ($result === FALSE) {
die('Curl failed: ' . curl_error($ch));
}
// Close connection
curl_close($ch);
return $result;
}
}
?>
MainActivity.java
package studio.emcorp.monitoringsiswa;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.google.firebase.messaging.FirebaseMessaging;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private static final String TAG = MainActivity.class.getSimpleName();
private BroadcastReceiver mRegistrationBroadcastReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
;
mRegistrationBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// checking for type intent filter
if (intent.getAction().equals(NotificationConfig.REGISTRATION_COMPLETE)) {
// gcm successfully registered
// now subscribe to `global` topic to receive app wide notifications
FirebaseMessaging.getInstance().subscribeToTopic(NotificationConfig.TOPIC_GLOBAL);
displayFirebaseRegId();
} else if (intent.getAction().equals(NotificationConfig.PUSH_NOTIFICATION)) {
// new push notification is received
String message = intent.getStringExtra("message");
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
//txtMessage.setText(message);
}
}
};
#Override
protected void onResume() {
super.onResume();
// register GCM registration complete receiver
LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver,
new IntentFilter(NotificationConfig.REGISTRATION_COMPLETE));
// register new push message receiver
// by doing this, the activity will be notified each time a new message arrives
LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver,
new IntentFilter(NotificationConfig.PUSH_NOTIFICATION));
// clear the notification area when the app is opened
NotificationUtil.clearNotifications(getApplicationContext());
}
#Override
protected void onPause() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mRegistrationBroadcastReceiver);
super.onPause();
}
}
Sending messages directly from Firebase Console works fine. Now the problem is sending messages via PHP script. Somewhow the server manages to send the message successfuly, e.g:
{"message_id":4732936739964848111}
, and the device receive it:
06-19 09:26:21.590 18604-19560/net.anta40.app.firebasetest
E/MyFirebaseMessagingService: From: /topics/global 06-19 09:26:21.590
18604-19560/net.anta40.app.firebasetest E/MyFirebaseMessagingService:
Data Payload:
{message={"data":{"image":"","is_background":false,"payload":{"bar":"xyz","foo":"123"},"title":"test","message":"mehehehe","timestamp":"2017-06-19
2:26:21"}}} 06-19 09:26:21.600 18604-19560/net.anta40.app.firebasetest
E/MyFirebaseMessagingService: push json:
{"message":{"data":{"timestamp":"2017-06-19
2:26:21","message":"mehehehe","payload":{"bar":"xyz","foo":"123"},"image":"","title":"test","is_background":false}}}
06-19 09:26:21.600 18604-19560/net.anta40.app.firebasetest
E/MyFirebaseMessagingService: Json Exception: No value for data 06-19
09:26:21.720 1098-1098/? D/wpa_supplicant: RX ctrl_iface -
hexdump(len=11): 53 49 47 4e 41 4c 5f 50 4f 4c 4c 06-19 09:26:21.720
1098-1098/? D/wpa_supplicant: wlan0: Control interface command
'SIGNAL_POLL'
but not displayed via notifications. What goes wrong here?
You are sending a data-only payload in your PHP:
public function send($to, $message) {
$fields = array(
'to' => $to,
//'data' => $message,
'data' => array("message" => $message));
return $this->sendPushNotification($fields);
}
Your other methods are also sending the same.
If you're going to use a notification-only payload, you could simply structure it like so:
public function send($to, $message) {
$fields = array(
'to' => $to,
'notification' => array("title" => $title,
"body" => $body));
return $this->sendPushNotification($fields);
}
The difference from sending a message from the Firebase Console is that messages from the console are considered as notification messages.
In Android, each message type is handled differently (see Handling Messages).
Some useful posts:
Issue with FCM notification
Can we push only data message from Firebase Notification console
I'm using Firebase for push notifications. My PHP code is working fine. I'm getting success message, but not receiving the push notification in my Android app for single device and multi device. But using Firebase console for sending notification it's working fine. I got the notification on the Android device. Is there any server configuration that I need to add?
PHP Code:
$yourApiSecret = "AIzaSyDY";
$androidAppId = "traasasadad";
$data = array(
"tokens" => "AAAA_kFbSQ4:APA91bQuMV-nRuTnVNFg0HD2C9PBnWWad",
"notification" => "Hello World!"
);
$data_string = json_encode($data);
$ch = curl_init('https://push.ionic.io/api/v1/push');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'X-Ionic-Application-Id: '.$androidAppId,
'Content-Length: ' . strlen($data_string),
'Authorization: Basic '.base64_encode($yourApiSecret)
)
);
$result = curl_exec($ch);
var_dump($result);
Android Code:
package com.seven77Trades.notification;
/** * Created by ist on 21/3/17. */ import
android.app.NotificationManager; import android.app.PendingIntent;
import android.content.Context; import android.content.Intent; import
android.media.RingtoneManager; import android.net.Uri; import
android.support.v4.app.NotificationCompat; import android.util.Log;
import com.google.firebase.messaging.FirebaseMessagingService; import
com.google.firebase.messaging.RemoteMessage; import
com.seven77Trades.HomeActivity; import com.seven77Trades.R;
public class FirebaseMsgService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
/**
* Called when message is received.
*
* #param remoteMessage Object representing the message received from Firebase Cloud Messaging.
*/
// [START receive_message]
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// [START_EXCLUDE]
// There are two types of messages data messages and notification messages. Data messages are handled
// here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
// traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
// is in the foreground. When the app is in the background an automatically generated notification is displayed.
// When the user taps on the notification they are returned to the app. Messages containing both notification
// and data payloads are treated as notification messages. The Firebase console always sends notification
// messages. For more see:
// [END_EXCLUDE]
// TODO(developer): Handle FCM messages here.
// Not getting messages here? See why this may be:
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
/*Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getColor());
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getSound());
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getTag());
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getClickAction());*/
sendNotification(remoteMessage.getNotification().getBody());
}
// Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated. See sendNotification method below.
}
// [END receive_message]
/**
* Create and show a simple notification containing the received FCM message.
*
* #param messageBody FCM message body received.
*/
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, HomeActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_logo)
.setContentTitle("Firebase")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
} }
Output:
"{"multicast_id":8295856130292351869,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1492611205996022%0296efeff9fd7ecd"}]}"
I got the solution .finally I'm receiving notification in android device.When we are sending notification using API (php,java,python) that time android application getting this request in different method (WakefulBroadcastReceiver) and when we sending using fire base console then request comes different method (FirebaseMessagingService).
Here the BrackPullBroadCastReceiver:
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
public class GcmIntentService extends IntentService {
private Context context;
public GcmIntentService() {
super("GcmIntentService");
}
String imageUrl = "";
#Override
protected void onHandleIntent(Intent intent) {
context = this;
Bundle extras = intent.getExtras();
for (String key: extras.keySet())
{
Log.d (TAG, key + " is a key in the bundle");
Log.d(TAG, extras.get(key) + "");
}
}
}
I think there is some mistake with the target url you can try sending the notification like this:
$url = 'http://fcm.googleapis.com/fcm/send';
$fields =array(
"notification"=> array(
"title" => 'sometitle',
"body" => $message, //Can be any message you want to send
"icon" => $image,
"click_action" => "http://google.com"
),
"registration_ids"=> 'Your android app fcm token',
"data"=> array(
"data" => "something",
)
);
$fields = json_encode ( $fields );
$headers = array (
'Authorization: key=' . "your firebase app key",
'Content-Type: application/json'
);
$ch = curl_init ();
curl_setopt ( $ch, CURLOPT_URL, $url );
curl_setopt ( $ch, CURLOPT_POST, true );
curl_setopt ( $ch, CURLOPT_HTTPHEADER, $headers );
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $fields );
$result = curl_exec ( $ch );
curl_close ( $ch );
Also you can pass custom data in the payload
I'm new to android and I tried to make a simple login test with android http post and php, though I'm unable to send posts with the following code:
package com.yagami.boook.classify;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* Created by allen on 2017/1/1.
*/
public class GetUserInfo extends AsyncTask<String, Integer, String> {
// ProgressDialog dialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
// dialog = ProgressDialog.show(MainActivity.class, "Retrieving User Data", "Please wait...", true);
}
#Override
protected void onPostExecute(String aString) {
super.onPostExecute(aString);
// dialog.dismiss();
}
#Override
protected String doInBackground(String... strings) {
HttpURLConnection connection;
OutputStreamWriter request = null;
URL url = null;
Log.d("A","A");
try {
url = new URL("http://localhost/login.php");
connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
Log.d("B","B");
request = new OutputStreamWriter(connection.getOutputStream());
Log.d("C","C");
request.write(strings[0]);
request.flush();
request.close();
InputStreamReader isr = new InputStreamReader(connection.getInputStream());
BufferedReader reader = new BufferedReader(isr);
String response = reader.readLine();
isr.close();
reader.close();
return response;
} catch (IOException e) {
// Error
}
return null;
}
}
Here is the php file, I tried to print a txt file so I would know if I received anything:
<?php
$email = $_POST['username'];
$password = $_POST['password'];
// echo $username."<br>";
// echo $password."<br>";
$connect = mysql_connect("localhost" , "root" , "112233");
mysql_select_db("classify", $connect);
$data = mysql_query("select * from users where email = '$email'");
$row = mysql_fetch_row($data);
// echo $row[2];
if($row[2] == $password) echo "pass";
else echo "nopass";
$fp = fopen('xxx.txt', 'w');
fwrite($fp , "abc");
fclose($fp);
?>
Here's the log, I added some Log.d into the code so that it would be more easy to understand what's happening. (As you can see the Log.d("C", "C") isn't showing up)
01/01 17:22:50: Launching app
$ adb push C:\Users\allen\Desktop\MyApplication\app\build\outputs\apk\app-debug.apk /data/local/tmp/com.example.allen.myapplication
$ adb shell pm install -r "/data/local/tmp/com.example.allen.myapplication"
Success
$ adb shell am start -n "com.example.allen.myapplication/com.example.allen.myapplication.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Client not ready yet..Waiting for process to come online
Connected to process 3148 on device Nexus_5X_API_25 [emulator-5554]
W/System: ClassLoader referenced unknown path: /data/app/com.example.allen.myapplication-2/lib/x86
I/InstantRun: Instant Run Runtime started. Android package is com.example.allen.myapplication, real application class is null.
W/System: ClassLoader referenced unknown path: /data/app/com.example.allen.myapplication-2/lib/x86
W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
I/OpenGLRenderer: Initialized EGL, version 1.4
D/OpenGLRenderer: Swap behavior 1
E/EGL_emulation: tid 3195: eglSurfaceAttrib(1174): error 0x3009 (EGL_BAD_MATCH)
W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0x99477440, error=EGL_BAD_MATCH
W/IInputConnectionWrapper: finishComposingText on inactive InputConnection
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
01/01 17:24:54: Launching app
W/System: ClassLoader referenced unknown path: /data/data/com.example.allen.myapplication/lib
E/EGL_emulation: tid 3195: eglSurfaceAttrib(1174): error 0x3009 (EGL_BAD_MATCH)
W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0x9947d420, error=EGL_BAD_MATCH
E/EGL_emulation: tid 3195: eglSurfaceAttrib(1174): error 0x3009 (EGL_BAD_MATCH)
W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0x98d37ba0, error=EGL_BAD_MATCH
Hot swapped changes, activity restarted
W/IInputConnectionWrapper: finishComposingText on inactive InputConnection
D/A: A
D/B: B
D/A: A
D/B: B
Have already searched the whole google for debugging but didn't find anything useful, hope it isn't a stupid mistake. Also please notify me if more information is needed.
Thanks in advance!
You are trying to access http://localhost/ from your device or emulator, but your actual web server runs somewhere else. So, for your device this web server is not a localhost.
To make this work, you need to make sure that the device is connected to the same network as your web server, and that the web server is accessible from your device (probable firewall issues, etc.). You then need to find out the IP address of your host inside the network, e.g. 192.168.1.42, and use that IP address in your android code:
// use your valid IP address instead
url = new URL("http://192.168.1.42/login.php");
With this connection, the device will look for a provided IP in your network, and access it, if it is available. Also, note that your IP will probably change, so you'll need to figure out how to make it static.
More on accessing localhost from an Android device here.
I'm getting a notification only in one device that is set as the first token stored the table in mySQL DB and the notification is not sent to the rest of the token numbers. I tried a WHILE loop and stored the token numbers in an array, but it did not work.
Please suggest a solution. Thank you.
Here is my code:
<?php
require "init.php";
$message=$_POST['message'];
$title=$_POST['title'];
$path_to_fcm='https://fcm.googleapis.com/fcm/send';
$server_key="A*************************Q";
$sql="select token from fcm_info";
$result =mysqli_query($con,$sql);
$row=mysqli_fetch_row($result);
$key=$row[0];
$headers = array(
'Authorization:key=' .$server_key,
'Content-Type:application/json'
);
$fields =array('to'=>$key,
'notification'=>array('title'=>$title,'body'=>$message));
$payload =json_encode($fields);
$curl_session =curl_init();
curl_setopt($curl_session,CURLOPT_URL, $path_to_fcm);
curl_setopt($curl_session,CURLOPT_POST, true);
curl_setopt($curl_session,CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl_session,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl_session,CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl_session,CURLOPT_IPRESOLVE, CURLOPT_IPRESOLVE);
curl_setopt($curl_session,CURLOPT_POSTFIELDS, $payload);
$result=curl_exec($curl_session);
curl_close($curl_session);
mysqli_close($con);
?>
Use 'registration_ids' instead of 'to' and pass comma separated multiple registrations ids to use multicast in FCM. Final payload should be like:
{
"registration_ids":["id1","id2",...],
"priority" : "normal",
"data" : {
"title" : "Title",
"message" : "Message to be send",
"icon": "icon_path"
}
}
see https://developers.google.com/cloud-messaging/http-server-ref for more help
////////////////////// FCM START /////////////////////////
$path_to_fcm = "https://fcm.googleapis.com/fcm/send";
$server_key = "your_server_key";
$headers = array(
'Authorization:key=' . $server_key,
'Content-Type:application/json');
$keys = ["key_1", "key_2"];
$fields = array(
"registration_ids" => $keys,
"priority" => "normal",
'notification' => array(
'title' => "title of notification",
'body' => "your notification goes here"
)
);
$payload = json_encode($fields);
$curl_session = curl_init();
curl_setopt($curl_session, CURLOPT_URL, $path_to_fcm);
curl_setopt($curl_session, CURLOPT_POST, true);
curl_setopt($curl_session, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl_session, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_session, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl_session, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_setopt($curl_session, CURLOPT_POSTFIELDS, $payload);
$curl_result = curl_exec($curl_session);
////////////////////// FCM END /////////////////////////
This works for me.
You need to cover the notification sending logic in method and then start the loop & call that method in each iterations pass token and message to the method.
"Please suggest a solution"
I would like to suggest using Services. You're most recommended to read the documention by Android Studio here.
There is a lot to perceive about Services, but at the moment I believe a snippet will be most helpful to you, here is a little code,
Create a class called HelloService
and paste the following code inside with the proper imports*
public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "servicestarting",Toast.LENGTH_SHORT).show();
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
#Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
"This is overhwleming" you might think to yourself. However it's but the contrary.
Example for Services + Firebase
Instead of pushing a message from Firebase, let's say you want to notify a user whenever a modification takes place in one of your databases
first, create databasereference earlier on the Oncreate
mDatabaseLike=FirebaseDatabase.getInstance().getReference().child("Likes");
Go to 'handleMessage Method' and add the following
#Override
public void handleMessage(Message msg) {
mDatabaseLike.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
notifyUserOfDBupdate()
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//stopSelf(msg.arg1);
}
}
Here is the notifyUserOfDBupdate method and how to notify a user
private void notifyUserOfDBupdate() {
//Intents
Intent Pdf_view = new Intent(this, //class to throw the user when they hit on notification\\.class);
PendingIntent pdf_view = PendingIntent.getActivity(this, 0, Pdf_view, 0);
//Notification Manager
NotificationManager nm = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
//The note
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Notification noti = new NotificationCompat.Builder(getApplicationContext())
.setTicker("TickerTitle")
.setContentTitle("content title")
.setSound(soundUri)
.setContentText("content text")
.setContentIntent(pdf_view).getNotification();
//Execution
noti.flags = Notification.FLAG_AUTO_CANCEL;
nm.notify(0, noti);
}
Now run your application once on your real device and a second time on an emulator. Once either one of two modifies your firebase database, the other will be notified instantly.
Modify whichever method you like inside the HandleMessage method. It will be eternal, not unless you make it killable.
kindest regards
i have followed the tutorial for GCM available at the official site:
http://developer.android.com/google/gcm/gs.html
and i have successfully implemented it on my app.. but as i am new on android i have few confusions about GCM i would really appriciate if someone could clear these points.
i wrote a PHP script(found from google) and hardcoded my regisration ID (just for testing) when i run the script i recieve a notification on my device.. but i dont wanna receive a notification rather i want to silently recieve the data and handle it on my device. is it possible?? here is the PHP code:
$regID=$_REQUEST['regID'];
$registatoin_ids=array($regID);
$msg=array("message"=>'HI Wasif');
$url='https://android.googleapis.com/gcm/send';
$fields=array
(
'registration_ids'=>$registatoin_ids,
'data'=>$msg
);
$headers=array
(
'Authorization: key=MY-REG-KEY',
'Content-Type: application/json'
);
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POST,true);
curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch,CURLOPT_POSTFIELDS,json_encode($fields));
$result=curl_exec($ch);
curl_close($ch);
echo $result;
Second point is i want to customize the notification i receive on my device i receive a notification like this...(see picture below) but i want to replace the heading text "GCM Notification" with my app's name and the message should me displayed properly(not like the key,value text) and also change the image of notification... can anybody plz provide a tutorial how to do it in new GoogleCloudMessaging API?? (please dont provide old methods if it is not same for new GoogleCouldMessaging API)
BROADCAST RECEIVER CODE:
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
Hope this link helps : GCM
1) If you don't want to receive notification on device then remove the code of Notification from GCMIntentService class under generateNotification() method.
2) You can provide your app name, app icon by implementing following code in generateNotification() method :
private static void generateNotification(Context context, String message) {
int icon = R.drawable.ic_launcher;
long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(icon, message, when);
String title = context.getString(R.string.app_name);
Intent notificationIntent = new Intent(context, MainActivity.class);
// set intent so it does not start a new activity
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent =
PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, title, message, intent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
// Play default notification sound
notification.defaults |= Notification.DEFAULT_SOUND;
// Vibrate if vibrate is enabled
notification.defaults |= Notification.DEFAULT_VIBRATE;
notificationManager.notify(0, notification);
}
Hope this helps.