I want to use FirebaseMessagingService to handle push notifications from the server. But there is not called onCreate function at the start. I thought that this service is initialized automatically when the app starts. Also, I started to send testing notification from firebase cloud messaging but it didn't work.
class PushNotificationService: FirebaseMessagingService() {
private lateinit var app: App
override fun onCreate() {
super.onCreate()
App.log("FireBaseMsg: starting service")
app = application as App
}
override fun onMessageReceived(msg: RemoteMessage?) {
super.onMessageReceived(msg)
App.log("FireBaseMsg: onMessageReceived")
val pNotification = msg?.notification
if (pNotification != null){
val title = pNotification.title
val text = pNotification.body
if (!title.isNullOrEmpty() && !text.isNullOrEmpty()){
val p = PushNotification(app, NOTIFICATION_CHANNEL_ID_PUSH, title = title, text = text)
p.fireNotification(NOTIFICATION_ID_PUSH)
}
}
}
override fun onNewToken(token: String) {
App.log("FireBaseMsg: Received token: $token")
//REGISTER TOKEN
app.regPushNotification(token, ::onNewTokenCallback)
}
private fun onNewTokenCallback(err: ApiCallError?){
if (err == null){
app.showToast(app.getString(R.string.notification_push_token_failed))
}
}
}
Manifest:
<service
android:name=".services.PushNotificationService"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
I was in same problem while i am implementing FirebaseMessagingService class
My solution
Manifest.xml
<service
android:name=".MyFirebaseMessagingServices"
android:enabled="true"
android:permission="com.google.android.c2dm.permission.SEND"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
If everything ok in your manifest service section then
Uninistall your application
File -> Invalidate Caches / Restart....
Run your application
Related
i'm trying to send notification from android using retrofit and i followed the offical documentation from firebase.
i setup retrofit with https://fcm.googleapis.com/fcm/send and when i post notifications retrofit returns response but the message dosen't appear in my logs. i think my service is not working after the message was posted.
MainActivity
const val TOPIC = "MyTopic"
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
FirebaseMessaging.getInstance().subscribeToTopic(TOPIC)
val btnSend = findViewById<Button>(R.id.btnSend)
btnSend.setOnClickListener {
FirebaseNotificationData(
NotificationData("Notification title", "Notification message"),
TOPIC
).also {
postNotification(it)
}
}
}
private fun postNotification(notification: FirebaseNotificationData) =
CoroutineScope(Dispatchers.IO).launch {
val response = RetrofitInstance.api.postNotification(notification)
if (response.isSuccessful)
Log.d("Retrofit", "Message was posted")
else
Log.e("Retrofit", response.errorBody().toString())
}
}
Service
class FirebaseNotificationService : FirebaseMessagingService() {
override fun onMessageReceived(message: RemoteMessage) {
super.onMessageReceived(message)
Log.d("onMessageReceived","message received")
}
}
Manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.firebasenotification">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<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.FirebaseNotification">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".FirebaseNotificationService"
android:permission="com.google.android.c2dm.permission.SEND"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
</intent-filter>
</service>
</application>
</manifest>
onMessageReceived is provided for most message types, with the
following exceptions:
Notification messages delivered when your app is in the background. In
this case, the notification is delivered to the device’s system tray.
A user tap on a notification opens the app launcher by default.
Messages with both notification and data payload, when received in the
background. In this case, the notification is delivered to the
device’s system tray, and the data payload is delivered in the extras
of the intent of your launcher Activity.
While testing, make sure the app is in background, when you send FCM notifications.
https://firebase.google.com/docs/cloud-messaging/android/receive
AndroidManifest.xml
<service
android:name=".CustomFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
My service:
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import org.tokend.template.BuildConfig
class CustomFirebaseMessagingService : FirebaseMessagingService() {
private val TAG = CustomFirebaseMessagingService::class.java.name
override fun onMessageReceived(remoteMessage: RemoteMessage?) {
if (BuildConfig.DEBUG)
Log.d(TAG, "onMessageReceived:")
...
}
And when app is running and FCM is received then success called method onMessageReceived
Nice.
But when app is not running then method onMessageReceived is not called.
From server send different message type: data, notification. Not help. Not call onMessageReceived when app is NOT RUNNING
I'm testing some functions with flutter to try to find out if I'm able to handle it and right now it doesn't seem that I would be able to make it.
I've set up a app which should be able to handle incoming text from android intents. With that text I've wanted to open a specific screen of my app and load specific data into the screen.
I've tried so many different approaches that I can't even remember when it worked best and what went wrong.
Right now I have the following code.
AndroidManifest.xml
<application
android:name=".MyApplication"
android:label="My cool App"
android:icon="#mipmap/ic_launcher">
<activity
android:name=".MyFlutterActivity"
android:launchMode="standard"
android:theme="#style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
MyApplication.kt
class MyApplication : FlutterApplication(), PluginRegistrantCallback {
lateinit var flutterEngine: FlutterEngine
override fun registerWith(registry: PluginRegistry) {
FirebaseCloudMessagingPluginRegistrant.registerWith(registry)
}
override fun onCreate() {
super.onCreate()
// Instantiate a FlutterEngine.
flutterEngine = FlutterEngine(this)
// Start executing Dart code to pre-warm the FlutterEngine.
flutterEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
)
// Cache the FlutterEngine to be used by FlutterActivity.
FlutterEngineCache
.getInstance()
.put("my_engine_id", flutterEngine)
FlutterFirebaseMessagingService.setPluginRegistrant(this)
}
As you can see I'm also using the FlutterFirebaseMessagingService to receive notifications, which I'm right now not already sure if it is still working as it already was.
FlutterActivity.kt
class MyFlutterActivity : FlutterActivity() {
private var sharedText: String? = null
override fun provideFlutterEngine(context: Context): FlutterEngine? {
return FlutterEngineCache.getInstance().get("my_engine_id")
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
// Use the GeneratedPluginRegistrant to add every plugin that's in the pubspec.
//GeneratedPluginRegistrant.registerWith(flutterEngine)
handleShareIntent()
MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "com.example.app.shared.data")
.setMethodCallHandler {call: MethodCall , result: MethodChannel.Result ->
if (call.method.contentEquals("getSharedText")) {
result.success(sharedText)
sharedText = null
}
}
}
fun handleShareIntent() {
//val intent = getIntent()
val action = intent.action
val type = intent.type
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type)) {
handleSendText(intent)
}
}
}
fun handleSendText(intent: Intent) {
sharedText = intent.getStringExtra(Intent.EXTRA_TEXT)
}
}
main.dart
static const platform =
const MethodChannel('com.example.app.shared.data');
static Stream<String> get sharedData {
return new Stream<String>.fromFuture(
platform.invokeMethod("getSharedText"));
}
//... inside build
StreamProvider<String>.value(
lazy: true,
value: sharedData,
),
// .. handle inside build
final String sharedData = Provider.of<String>(context);
// .. handle shared Data and open Screen..
I've tried to log every step to find out what's not working.
So I connected my android phone and tried to debug, but didn't found a step where to handle the incoming data, even if the text is successfully handled inside the "handleSendText" method of the FlutterAcitivity.kt.
What even more confused me is, that if i save a dart file / press hot reload, my breakpoint inside the sharedData getter of the main.dart is getting called and from there everything works as it should.
But why do I have to hot reload where it should start itself instead.
Am I'm missing anything or doing wrong at this point?
Any help appreciated.
I have tried every possible answer on SO but nothing has helped.
I want to reset alarms using AlarmManager on device reboot and the code to do exactly that works, but it doesn't when I put it inside the receiver.
I had tried creating a service but that didn't seem to work at all which that was probably incompetence of my part, however I just can't see why this code isn't working.
AndroidManifest:
<manifest
(...)
<uses-permission android:name = "android.permission.RECEIVE_BOOT_COMPLETED" />
(...)
<application
(...)
<receiver
android:name = ".utils.DeviceRebootReceiver">
<intent-filter>
<action android:name = "android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
DeviceRebootReceiver:
class DeviceRebootReceiver : BroadcastReceiver() {
override fun onReceive(context : Context?, intent : Intent?) {
resetAlarms(context)
}
}
fun resetAlarms(context:Context):
fun resetAlarms(context : Context?) {
suspend fun resetAlarmsCoroutine(context : Context) {
val reminders = NotesDatabase.getInstance(context).notesDatabaseDAO.getAllActiveReminders()
reminders.forEach {
if (it.reminderTime > System.currentTimeMillis()) {
createAlarm(it.reminderTime, it.reminderMessage,null,context)
}
}
}
CoroutineScope(Dispatchers.IO).launch {
if (context != null) {
resetAlarmsCoroutine(context)
}
}
}
No need to show the createAlarm() function cause it works fine, BUT since I had seen that AlarmManager could cause problems on reboot I do instantiate it there like so:
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
I am trying to put together just a basic IntentService/BroadcastReceiver combo.
Yes, I know that what is currently there isn't really useful, but I just wanted to get the broadcast running.
The Service receives my initial intent, but the Receiver doesn't get the return Broadcast (debugger). Other answers didn't help me, and I feel like I've tried everything. It has to be something trivial, but I just can't put my finger on it.
Displaying Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val filter = IntentFilter()
filter.addAction(Constants.BROADCAST_ACTION)
filter.addDataScheme("http")
val dsl = DownloadStateReceiver()
LocalBroadcastManager.getInstance(this).registerReceiver(dsl,filter)
buttonLogin.setOnClickListener({
var loginIntent = Intent(this,RawRestJsonPull::class.java)
loginIntent.putExtra("userName",editLogin.text.toString())
loginIntent.putExtra("password",editPassword.text.toString())
this.startService(loginIntent)
})
}
class DownloadStateReceiver : BroadcastReceiver()
{
override fun onReceive(currentContext: Context, incomingIntent: Intent) {
Log.d("?????","d")
}
}
}
Service and the action constants:
class RawRestJsonPull : IntentService("rest" ) {
override fun onHandleIntent(incomingIntent: Intent) {
var outgoingIntent = Intent(Constants.BROADCAST_ACTION)
var status = 0
var userName : String? = incomingIntent.getStringExtra("userName")
var password : String? = incomingIntent.getStringExtra("password")
outgoingIntent.putExtra(Constants.EXTENDED_DATA_STATUS,status).putExtra("userName",userName).
putExtra("password",password)
outgoingIntent.flags = Intent.FLAG_INCLUDE_STOPPED_PACKAGES
LocalBroadcastManager.getInstance(this).sendBroadcast(outgoingIntent)
}
}
class Constants
{
companion object {
val BROADCAST_ACTION = "com.example.hubert1224.xxx.BROADCAST"
val EXTENDED_DATA_STATUS = "com.example.hubert1224.xxx.STATUS"
}
}
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.hubert1224.xxx">
<uses-permission android:name="android.permission.INTERNET" />
<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/AppTheme">
<activity
android:name=".MainActivity"
android:windowSoftInputMode="stateVisible">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".RawRestJsonPull" />
<receiver android:name=".MainActivity$DownloadStateReceiver" />
</application>
</manifest>
Try that
First make your BroadcastReceiver static or it's own class, I am not sure Android can work with non static inner classes.
Second, I am not sure why your receiver intent filter has a
filter.addDataScheme("http")
But you are missing that from the Intent you are firing from your service, if you don't need it, remove it.
Try removing the data scheme http from the filter. 2. Try adding the category default to the filter.