I'm sending a push notification from Firebase console to my Android App. But sometimes, after receiving the notification and waiting for a couple of hours, and clicking the notification thereafter, it is not opening the app.
PS: In Samsung devices app is opening after a delay of 30+ seconds but in other devices like Mi or Oneplus, it is not opening at all.
Bug video:
In Samsung device
In Mi device
App manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.baja.app">
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:requestLegacyExternalStorage="true"
android:name=".BajaApplication"
android:allowBackup="false"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="false"
android:theme="#style/AppTheme.Default"
tools:ignore="GoogleAppIndexingWarning">
<activity
android:name=".ui.home.HomeActivity"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter
android:label="#string/app_name"
android:autoVerify="true"
tools:targetApi="m">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with "example://gizmosā -->
<data
android:host="#string/share_host"
android:scheme="https" />
</intent-filter>
</activity>
<activity
android:name=".ui.welcome.WelcomeActivity"
android:screenOrientation="portrait" />
<activity
android:name=".ui.home.alarms.ringer.AlarmRingingActivity"
android:screenOrientation="portrait"
android:launchMode="singleInstance" />
<service
android:name=".media.MediaService"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
<service
android:name=".messaging.BajaFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service
android:name=".ui.welcome.AddressIntentService"
android:exported="false" />
<service
android:name=".media.download.InternalMediaDownloadService"
android:exported="false" />
<service
android:name=".media.download.ExternalMediaDownloadService"
android:exported="false" />
<service android:name=".ui.home.alarms.ringer.AlarmMediaService" />
<receiver android:name=".media.download.DownloadCancelReceiver" />
<receiver
android:name=".ui.home.alarms.AlarmsBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service
android:name=".ui.home.alarms.RescheduleAlarmsService"
android:exported="false" />
<!--
MediaSession, prior to API 21, uses a broadcast receiver to communicate with a
media session. It does not have to be this broadcast receiver, but it must
handle the action "android.intent.action.MEDIA_BUTTON".
Additionally, this is used to resume the service from an inactive state upon
receiving a media button event (such as "play").
-->
<receiver android:name="androidx.media.session.MediaButtonReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver> <!-- Disable crash and analytics reporting for debug builds -->
<meta-data
android:name="firebase_crashlytics_collection_enabled"
android:value="${enableCrashReporting}" />
<meta-data
android:name="firebase_analytics_collection_deactivated"
android:value="${disableAnalyticsReporting}" /> <!-- Set custom default icon and color for request notification -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="#string/default_notification_channel" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#drawable/ic_favicon" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/black" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="#string/app_fileprovider_authority"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
</application>
onMessageReceived method
override fun onMessageReceived(remoteMessage: RemoteMessage) {
val notification: RemoteMessage.Notification = remoteMessage.notification ?: return
val channelId: String = notification.channelId ?: getString(R.string.default_notification_channel)
val (channelCode: Int, #StringRes channelNameRes: Int, #StringRes channelDescRes: Int) =
getNotificationChannelRelatedParams(channelId)
buildAndShowNotification(
notification.title!!,
notification.body!!,
channelId,
notification.imageUrl,
remoteMessage.data,
channelCode,
channelNameRes,
channelDescRes
)
}
Notification builder method
private fun buildAndShowNotification(
title: String,
message: String,
channelId: String,
imageUri: Uri?,
extras: Map<String, String>,
requestCode: Int,
#StringRes channelName: Int,
#StringRes channelDescRes: Int
) {
val defaultSoundUri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val intent: Intent = Intent(this, HomeActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
extras.keys.forEach { key ->
putExtra(key, extras[key])
}
}
val pendingIntent: PendingIntent = PendingIntent.getActivity(this, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val builder: NotificationCompat.Builder = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_favicon)
.setColor(Color.BLACK)
.setContentTitle(title)
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent)
.setStyle(NotificationCompat.BigTextStyle().bigText(message))
applyImageUrl(builder, imageUri)
val manager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
channelId,
getString(channelName),
NotificationManager.IMPORTANCE_DEFAULT
).apply { description = getString(channelDescRes) }
manager.createNotificationChannel(channel)
}
manager.notify(requestCode, builder.build())
}
Checking notification intent in HomeActivity, if notification handled by system tray
onCreate(..){
//statements
// Check if opened with notification
val intentData: Triple<String, String?, Boolean> = if (savedInstanceState == null) {
playFromIntent(intent, appLaunch = true)
} else {
Triple("", null, false)
}
//statements
}
Related
I'm working on an android application and i need alarm manager to fire events at certain times , the code works fine and the notification fires in time but only in one scenario is not working when the screen is off , the device is not waking up and wait for notification to fire up , actually this works in emulators ( i guess because there is no such power saving mode like in some physical devices ) , I've looked up most topics and could not find any solution , any help would be appreciated Thank you .
Firing Alarm Manager
fun fireAlarmManager(context: Context , time : MutableList<Long>){
val intent = Intent(context, AlarmReceiver::class.java)
for (i in 0 until time.size){
if(time[i] > deviceTimeInMillis()){
list.add(time[i])
val pendingIntent = PendingIntent.getBroadcast(context,time[i].toInt(),intent,PendingIntent.FLAG_IMMUTABLE)
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,time[i],pendingIntent)
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP,time[i],pendingIntent)
}
}
}
setDataFromSharedPreferences(list)
}
Broadcast receiver
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context : Context?, intent : Intent?) {
wakeUp(context)
val serviceIntent = Intent(context,OnClearFromRecentServices::class.java)
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
context!!.startForegroundService(serviceIntent)
} else {
context!!.startService(serviceIntent)
}
}
private fun wakeUp(context: Context?) {
val pm = context!!.getSystemService(Context.POWER_SERVICE) as PowerManager
val wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK or PowerManager.FULL_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP, "app::tag")
wakeLock.acquire(60000)
val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
val keyguardLock = keyguardManager.newKeyguardLock("TAG")
keyguardLock.disableKeyguard()
}
}
Alarm Service
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
fireNotification(this)
return START_STICKY
}
Manifest File
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.kotlin.quranapp">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:name=".koin.BaseApplication"
android:allowBackup="true"
android:dataExtractionRules="#xml/data_extraction_rules"
android:fullBackupContent="#xml/backup_rules"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:largeHeap="true"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.QuranApp"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="false"
android:launchMode="singleInstance"
android:screenOrientation="portrait" />
<activity
android:name=".views.SplashActivity"
android:exported="true"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".alarm.AlarmReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
<receiver
android:name=".alarm.PlayerReceiver"
android:exported="false" />
<service android:name=".alarm.services.OnClearFromRecentServices" />
</application>
</manifest>
I am implementing push notification on Android with FirebaseMessagingService for an app that mainly lives in a webview.
The notifications arrives as expected when the app is in foreground, background and closed (wiped away).
Tapping a notification opens the deeplink provided in data.payload.link (after parsing the JSON in data.payload) when the app is in forground and background but not when closed.
In case the app is closed - the app gets started and shows up but the deeplink is not loaded like when the app is in foreground/background.
The payload I send to the Firebase API looks as follows:
admin
.messaging()
.send({
data: {
payload: JSON.stringify({
link: link || "",
}),
},
notification,
android: {
notification: {
click_action: "OPEN_DEEPLINK_FROM_PUSH_NOTIFICATION",
},
priority: "normal",
},
token: recipient,
})
The onMessageReceived() is implemented as follows:
public void onMessageReceived(RemoteMessage remoteMessage) {
if (remoteMessage == null) return;
Map<String, String> data = remoteMessage.getData();
String payload = (String) data.values().toArray()[0];
String link = null;
JSONObject jObject = null;
try {
jObject = new JSONObject(payload);
link = jObject.getString("link");
} catch (Exception e) {
Log.e(PUSH_NOTIFICATION, "ERROR: " + e.getMessage());
return;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(link));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_stat_ic_notification)
.setContentTitle(remoteMessage.getNotification().getTitle())
.setContentText(remoteMessage.getNotification().getBody())
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(notificationId, builder.build());
notificationId = ++notificationId;
}
The androidManifest.xml looks like:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.myapp" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_GPS" />
<uses-permission android:name="android.permission.ACCESS_ASSISTED_GPS" />
<uses-permission android:name="android.permission.ACCESS_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.AppCompat" >
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#drawable/ic_stat_ic_notification" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/colorNotification" />
<activity
android:name="com.myapp.app.mobile.MainActivity"
android:launchMode="singleTask"
android:configChanges="orientation|screenSize"
android:theme="#style/Theme.AppCompat.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="OPEN_DEEPLINK_FROM_PUSH_NOTIFICATION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter android:label="">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http"
android:host="app.myapp.com" />
</intent-filter>
<intent-filter android:label="">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https"
android:host="app.myapp.com" />
</intent-filter>
<intent-filter android:label="">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http"
android:host="app.myapp.ch" />
</intent-filter>
<intent-filter android:label="">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https"
android:host="app.myapp.ch" />
</intent-filter>
</activity>
<service
android:name="com.myapp.app.mobile.MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
</manifest>
Opening deeplinks when an app is not running is handled in onPageFinished() of my WebViewClient instance (what works for openening deeplinks eg. from email when the app is not running):
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
Intent intent = getIntent();
String action = intent.getAction();
Uri data = intent.getData();
if(intent.getData() != null){
openDeeplink(intent);
}
}
I am wondering why this logic does not work in case of tapping a notification when the app was not running?
Any suggestions are welcome.
As firebese the docs describe here: https://firebase.google.com/docs/cloud-messaging/android/receive the data is delivered within the extras of the intent. This also applies for apps that are NOT running. I think the docs are not precise enough in this matter.
The following fix did the trick in this case:
public void onPageFinished(WebView view, String url) {
Intent intent = getIntent();
if(intent.getData() != null || intent.getExtras() != null){
openDeeplink(intent);
}
I'm trying to receive propertly a message from FireBase when my app is in background but not working anithing. I've seen some Stackoverflow problems like mine but not working anything.
Could anyone help me to find the problem?
I need to do it when my app is in background but not working.
here AndoridManifest.xml
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-feature android:name="android.hardware.type.watch" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#android:style/Theme.DeviceDefault"
tools:targetApi="ice_cream_sandwich">
<service
android:name=".MyfirebaseMessagingService" android:exported="false" >
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service
android:name=".MyFirebaseInstanceIDService" android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
<uses-library
android:name="com.google.android.wearable"
android:required="true" />
<!--
Set to true if your app is Standalone, that is, it does not require the handheld
app to run.
-->
<meta-data
android:name="com.google.android.wearable.standalone"
android:value="true" />
<!-- [START fcm_default_channel] -->
<!-- [START fcm_default_channel] -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="#string/default_notification_channel_id" />
<activity
android:name=".MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<!--<action android:name="android.intent.action.VIEW" />-->
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="gizmos"
android:scheme="example" />
</intent-filter>
</activity>
</application>
MyfirebaseMessagingService.java:
public class MyfirebaseMessagingService extends FirebaseMessagingService {
public static String TAG = "MyFirebaseMsgService";
private LocalBroadcastManager broadcaster;
#Override
public void onCreate() {
super.onCreate();
createNotificationChannel();
broadcaster = LocalBroadcastManager.getInstance(this);
}
#Override
public void onDestroy() {
super.onDestroy();
}
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String channelId = getString(R.string.default_notification_channel_id);
CharSequence name = getString(R.string.default_notification_channel_id);
String description = getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(channelId, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
Intent home = new Intent(getApplicationContext(), MainActivity.class);
home.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(home);
// 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());
Intent intent = new Intent("Data");
intent.putExtra("messageFromCloud", remoteMessage.getNotification().getBody());
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
broadcaster.sendBroadcast(intent);
if (intent.getExtras() != null)
{
RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");
for (String key : intent.getExtras().keySet())
{
builder.addData(key, intent.getExtras().get(key).toString());
}
onMessageReceived(builder.build());
}
}
}
}
If you want use MainActivity as Activity ofNotification click activity then you need to code like:
<activity
android:name=".MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="gizmos"
android:scheme="example" />
</intent-filter>
</activity>
It will be automatically redirect to MainAcitivity on Notification click.
You need to mention The messaging file in manifest but this is not only the solution for open an activity through notification you need to write into intent in Messaging files.
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
For manifest write this code:
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/colorAccent" />
<service
android:name=".MyFirebaseMessagingService"
android:permission=""
tools:ignore="ExportedService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
You need to declare it as service because notification is the part of service and run in application background when you application became closed.
i'm not able to receive GCM messages on devices running android below lollipop.
Push messages works on android 5, 6 and 7.
I really don't know why ... There is my app code:
Manifest:
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="25"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<permission android:name="sbntt.android.xenoss.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="sbntt.android.xenoss.permission.C2D_MESSAGE" />
<application
android:name="android.support.multidex.MultiDexApplication"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="sbntt.android.xenoss" />
</intent-filter>
</receiver>
<service
android:name="sbntt.android.xenoss.GCMPushReceiverService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service
android:name=".GCMRegistrationIntentService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<service
android:name=".GCMTokenRefreshListenerService"
android:exported="false">
</service>
</application>
GCMPushReceiverService class
#Override
public void onMessageReceived(String from, Bundle data) {
String message = data.getString("message");
if (Settings.preference != null) {
if (Settings.preference.getBoolean("notifications", true)) {
sendNotification(message);
}
} else {
sendNotification(message);
}
}
private void sendNotification(String message) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
int requestCode = 0;
PendingIntent pendingIntent = PendingIntent.getActivity(this, requestCode, intent, PendingIntent.FLAG_ONE_SHOT);
Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder noBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_menu_youtube)
.setContentTitle("TITLE")
.setContentText(message)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.setSound(sound)
.setDefaults(Notification.DEFAULT_ALL)
.setPriority(Notification.PRIORITY_HIGH);
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, noBuilder.build());
}
Registration works fine!
Thanks for your help.
GCM need to be updated Play Service on devices . you can notify users to update Play Service or use less play service version in your project .
I am trying to get started with Parse push notification on Android, but I could not find any way to implement my own BroadcastReceiver which would perform action in response to a push notification.
In their "getting started", they give a program sample where the receiver and the intent service is contained in the jar file (and not implemented in the code, so that I could try and play with it). A similar question has been asked here, but it's two years old and the answer has 11 downvotes.
There are a few other blog posts, e.g. as in here, but none of them work properly (the one in that link was two years old).
So please kindly suggest a step by step way to implement the same.
EDIT:
I tried the code as suggested by droidx. But it does not work. I am sending my AndroidManifest.xml (rest of the code is exactly as he suggested):
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.rahulserver.parsenotificationdemo" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!--
IMPORTANT: Change "com.parse.starter.permission.C2D_MESSAGE" in the lines below
to match your app's package name + ".permission.C2D_MESSAGE".
-->
<permission android:protectionLevel="signature"
android:name="com.rahulserver.parsenotificationdemo.permission.C2D_MESSAGE" />
<uses-permission android:name="com.rahulserver.parsenotificationdemo.permission.C2D_MESSAGE" />
<application
android:name=".ParseNotification"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.parse.PushService" />
<receiver android:name="com.parse.ParseBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
</intent-filter>
</receiver>
<receiver android:name=".MyCustomParsePushReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.parse.push.intent.RECEIVE" />
<action android:name="com.parse.push.intent.DELETE" />
<action android:name="com.parse.push.intent.OPEN" />
</intent-filter>
</receiver>
<receiver android:name="com.parse.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<!--
IMPORTANT: Change "com.parse.starter" to match your app's package name.
-->
<category android:name="com.rahulserver.parsenotificationdemo" />
</intent-filter>
</receiver>
</application>
</manifest>
Here's an example!
public class ParseCustomBroadcastReceiver extends ParsePushBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
JSONObject json = new JSONObject(intent.getExtras().getString("com.parse.Data"));
Log.d(TAG, json.getString("alert").toString());
final String notificationTitle = json.getString("title").toString();
final String notificationContent = json.getString("alert").toString();
final String uri = json.getString("uri");
Intent resultIntent = null;
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
resultIntent = new Intent(context, HomeScreen.class);
stackBuilder.addParentStack(HomeScreen.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
//Customize your notification - sample code
NotificationCompat.Builder builder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.mipmap.ic_notification_icon)
.setContentTitle(notificationTitle)
.setContentText(notificationContent);
int mNotificationId = 001;
NotificationManager mNotifyMgr =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotifyMgr.notify(mNotificationId, builder.build());
} catch (JSONException e) {
Log.d(TAG, e.getMessage());
}
}
}
Following this guide, replace android name for the receiver to the path of your custom broadcastreceiver
<receiver
android:name=".receivers.ParseCustomBroadcastReceiver"
android:exported="false" >
<intent-filter>
<action android:name="com.parse.push.intent.RECEIVE" />
<action android:name="com.parse.push.intent.DELETE" />
<action android:name="com.parse.push.intent.OPEN" />
</intent-filter>
</receiver>
In your application class, make sure to have subscribed to Parse Push like this
Parse.initialize(this, ParseUtils.PARSE_APPLICATION_ID_DEV, ParseUtils.PARSE_CLIENT_KEY_DEV);
ParseObject.registerSubclass(Article.class);
ParsePush.subscribeInBackground("", new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
Log.d(TAG, "successfully subscribed to the broadcast channel.");
} else {
Log.e(TAG, "failed to subscribe for push", e);
}
}
});
Update:
The above broadcast receiver expects to send a json object notification from parse dashboard usually consists of three name value pairs:
{ "alert": "Alert message", "title": "Title", "uri": "bla bla" }
When you use only plain string for eg: hello world! in parse push dashboard, internally it goes as only alert tag. something like this : {"alert" : "hello world!, "title" = null/"", "uri" = null/""}
The broadcast receiver code above doesn't have this null checks, so it's caught in the catch with exception No title/uri.
So you can add some null checks based on what you are expecting from the push notification.
Something like this:
JSONObject json = new JSONObject(intent.getExtras().getString("com.parse.Data"));
Log.d(TAG, json.getString("alert").toString());
if (json.has("title")) {
notificationTitle = json.getString("title").toString();
}
if (json.has("alert")) {
notificationAlert = json.getString("alert").toString();
}
if(json.has("uri")) {
notificationURI = json.getString("uri");
}
Then set appropriate contentTitle and contentText in notification
NotificationCompat.Builder builder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(notificationAlert)
.setContentText(notificationAlert);
Hope this helps!