I'm trying to extend the FCM service, and broadcast to the MainActivity upon onNewToken() being called. onNewToken() is indeed called, but the onReceive() method is not. As far as I know, I do not need to define anything else in the manifest, since this is a local broadcast. These are my classes:
MainActivity.kt
package com.reali.app.mymessagingapp
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v4.content.LocalBroadcastManager
import android.widget.TextView
import com.google.android.gms.tasks.OnCompleteListener
import com.reali.app.mymessagingapp.MyFirebaseMessagingService.Companion.TOKEN_REFRESHED_EVENT
import com.google.firebase.iid.FirebaseInstanceId
import com.google.firebase.iid.InstanceIdResult
class MainActivity : AppCompatActivity() {
private lateinit var broadcastReceiver: BroadcastReceiver
private lateinit var tvTitle: TextView
private lateinit var tvToken: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tvTitle = findViewById(R.id.tvTitle)
tvToken = findViewById(R.id.tvToken)
broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
tvTitle.text = resources.getString(R.string.token_refreshed)
refreshTokenText()
}
}
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, IntentFilter(TOKEN_REFRESHED_EVENT))
refreshTokenText()
}
private fun refreshTokenText() {
FirebaseInstanceId.getInstance().instanceId.addOnCompleteListener(OnCompleteListener<InstanceIdResult> { task ->
if (!task.isSuccessful) {
return#OnCompleteListener
}
val token = task.result?.token
tvToken.text = token
})
}
}
MyFirebaseMessagingService.kt
package com.reali.app.mymessagingapp
import android.content.Intent
import android.util.Log
import com.google.firebase.messaging.FirebaseMessagingService
class MyFirebaseMessagingService : FirebaseMessagingService()
{
companion object {
const val TOKEN_REFRESHED_EVENT = "token_refreshed_event"
}
override fun onNewToken(token: String?) {
Log.d("MyFcmMessagingService", "Refreshed token: " + token!!)
applicationContext.sendBroadcast(Intent(TOKEN_REFRESHED_EVENT))
}
}
Broadcasts sent via Context.sendBroadcast() are not local broadcasts, that's why you're not receiving them.
You need to use LocalBroadcastManager for the sending as well.
Instead of the following:
applicationContext.sendBroadcast(Intent(TOKEN_REFRESHED_EVENT))
You should do something like this:
LocalBroadcastManager.getInstance(this)
.sendBroadcast(Intent(TOKEN_REFRESHED_EVENT))
Also, do not forget to unregister your receiver when appropriate to avoid memory leaks:
// most likely in onDestroy() (since the registration is in onCreate())
LocalBroadcastManager.getInstance(this)
.unregisterReceiver(broadcastReceiver)
Related
I am working on an android application and currently binding to my location service from which i receive location updates while inside the activity, and i wanted to do so from inside a composable after a user has finished the authentication proces
I haven't tested this, but feel free to try, if required it could be adapted for remote services that expose a Messenger. Anyway here's the gist:
package com.example.app
import android.app.Service
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Binder
import android.os.IBinder
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisallowComposableCalls
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
#Composable
inline fun <reified BoundService : Service, reified BoundServiceBinder : Binder> rememberBoundLocalService(
crossinline getService: #DisallowComposableCalls BoundServiceBinder.() -> BoundService,
): BoundService? {
val context: Context = LocalContext.current
var boundService: BoundService? by remember(context) { mutableStateOf(null) }
val serviceConnection: ServiceConnection = remember(context) {
object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
boundService = (service as BoundServiceBinder).getService()
}
override fun onServiceDisconnected(arg0: ComponentName) {
boundService = null
}
}
}
DisposableEffect(context, serviceConnection) {
context.bindService(Intent(context, BoundService::class.java), serviceConnection, Context.BIND_AUTO_CREATE)
onDispose { context.unbindService(serviceConnection) }
}
return boundService
}
Then:
package com.example.app
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import kotlin.random.Random
class RandomNumberService : Service() {
private val binder = LocalBinder()
private val randomNumberGenerator = Random(seed = 100)
val randomNumber: Int
get() = randomNumberGenerator.nextInt()
inner class LocalBinder : Binder() {
val service: RandomNumberService
get() = this#RandomNumberService
}
override fun onBind(intent: Intent): IBinder = binder
}
#Composable
fun RandomNumberServiceExample() {
val randomNumberService = rememberBoundLocalService<RandomNumberService, RandomNumberService.LocalBinder> { service }
Text(
text = randomNumberService?.randomNumber?.toString().orEmpty(),
)
}
If it works I'll update this answer.
I want to inject a class in Service. Lets have a look at the code below:
class DeviceUtil #Inject constructor() {
...
}
#AndroidEntryPoint
class LocationUpdateService : Service() {
#Inject
lateinit var deviceUtil: DeviceUtil
...
}
#Inject lateinit var deviceUtil: DeviceUtil is working fine in Activity but not working in Service.
Its giving the error: kotlin.UninitializedPropertyAccessException: lateinit property deviceUtil has not been initialized
For those dummies like me. As said by OP in the comments, a full example on how you can inject object in your service like so:
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import com.yourapp.services.UserService
#AndroidEntryPoint
class MyService: Service() {
#Inject lateinit var userService: UserService
override fun onCreate() {
super.onCreate()
userService.getUserList()
.subscribe { userList -> Log.d("tag", "users: $userList") }
}
override fun onBind(intent: Intent?): IBinder? {
return object: Binder() {
// ...
}
}
}
As for the service you're injecting make sure it has the #Inject annotation in its constructor like so:
class UserService #Inject() constructor() {
// ...
}
I am having an unresolved reference error in my class when building this code. I need help to pinpoint the error.
This is the error
e: .../app/src/main/java/com/example/auth_onboarding/QualtricsFeedback.kt: (37, 50): Unresolved reference: #QualtricsFeedback
(37,50) refers to the last line where this#QualtricsFeedback was called.
This is the code
package com.example.auth_onboarding
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.qualtrics.digital.IQualtricsCallback
import com.qualtrics.digital.Qualtrics
import com.qualtrics.digital.TargetingResult
class QualtricsFeedback : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_qualtrics_feedback)
setSupportActionBar(findViewById(R.id.toolbar))
Qualtrics.instance().initialize("some_key", "some_other_key", "some_other_key_2", this);
val fab =
findViewById<View>(R.id.fab) as FloatingActionButton
fab.setOnClickListener {view ->
fun onClick(view: View?) {
Qualtrics.instance().evaluateTargetingLogic(MyCallback())
}
}
}
private class MyCallback : IQualtricsCallback {
override fun run(targetingResult: TargetingResult) {
if (targetingResult.passed()) {
Qualtrics.instance().display(this#QualtricsFeedback)
}
}
}
}
I've tried .display(QualtricsFeedback.this) but that doesnt work. I've also tried just .display(QualtricsFeedback).
Are there any suggestions of what I could try?
Change to this, you should add inner to class in Kotlin it means an inner class can reference to the outer class
private inner class MyCallback : IQualtricsCallback {
override fun run(targetingResult: TargetingResult) {
if (targetingResult.passed()) {
Qualtrics.instance().display(this#QualtricsFeedback)
}
}
}
I'm using firebase_messaging in my flutter application.
To handle background messages with firebase messaging in pub they suggested to create new Application.java file and replace java file name in AndroidManifest file.
In my application i'm using kotlin and i already implemented some native code in MainActivity.kt
So how to write this code in kotlin.
package io.flutter.plugins.firebasemessagingexample;
import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService;
public class Application extends FlutterApplication implements PluginRegistrantCallback {
#Override
public void onCreate() {
super.onCreate();
FlutterFirebaseMessagingService.setPluginRegistrant(this);
}
#Override
public void registerWith(PluginRegistry registry) {
GeneratedPluginRegistrant.registerWith(registry);
}
}
it is mandatory to replace MainActivity to Application in AndroidManifest file?
Here is the working background notification kotlin code:
package com.example.yourapp
import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
import io.flutter.plugins.GeneratedPluginRegistrant
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService
class Application : FlutterApplication(), PluginRegistrantCallback {
override fun onCreate() {
super.onCreate()
FlutterFirebaseMessagingService.setPluginRegistrant(this);
}
override fun registerWith(registry: PluginRegistry?) {
io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin.registerWith(registry?.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"));
}
}
Here is the Kotlin code for the new firebase cloud messaging version:
package id.your.app
import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
import io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingBackgroundService
// import io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingPlugin
class Application : FlutterApplication(), PluginRegistrantCallback {
override fun onCreate() {
super.onCreate()
FlutterFirebaseMessagingBackgroundService.setPluginRegistrant(this)
}
override fun registerWith(registry: PluginRegistry?) {
// FlutterFirebaseMessagingPlugin.registerWith(registry?.registrarFor("io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingPlugin"))
}
}
While I'm turning off internet connection on the phone I have an exception
Cannot evaluate the expression: : Backend Internal error: Exception during code generation
Cause: Can not generate outer receiver value for class <closure-StartViewModel$fetchCurrentWeek$1>
When internet is on, everething works fine!
Exception appears in function fetchCurrentWeek, on line
val currentWeek = WeekSource(ApiFactory.rozkladKpiApi).getCurrentWeek()
StartViewModel.kt
package andy.schedulekpi.ui.fragments.start
import android.content.SharedPreferences
import androidx.lifecycle.MutableLiveData
import andy.schedulekpi.network.api.ApiFactory
import andy.schedulekpi.network.sources.GroupSource
import andy.schedulekpi.network.sources.SourcesFactory
import andy.schedulekpi.network.sources.WeekSource
import andy.schedulekpi.ui.fragments.base.BaseViewModel
import andy.schedulekpi.utils.SHARED_PREFERENCES_GROUP
import kotlinx.coroutines.*
class StartViewModel : BaseViewModel() {
// TODO: Implement the ViewModel
private val source = SourcesFactory.weekSource
val mCurrentWeek : MutableLiveData<Int> = MutableLiveData()
fun fetchCurrentWeek() {
scope.launch {
val currentWeek = WeekSource(ApiFactory.rozkladKpiApi).getCurrentWeek()
mCurrentWeek.postValue(currentWeek)
}
}
fun getGroupFromSharedPreferences(sharedPreferences: SharedPreferences) : String {
return sharedPreferences.getString(SHARED_PREFERENCES_GROUP, "null")!!
}
fun isGroupCachedInSharedPreferences(sharedPreferences: SharedPreferences) : Boolean {
return sharedPreferences.contains(SHARED_PREFERENCES_GROUP)
}
}
Image:
image of debugger: https://ibb.co/fNSLZZM