3

Hello to all in community. I get message from title of this post during executing RUN command in my app.

First .kt file (MyTaxiApplication.kt):

package com.innomalist.taxi.common

import android.app.Activity
import android.app.Application
import androidx.appcompat.app.AppCompatDelegate
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ProcessLifecycleOwner
import com.google.firebase.FirebaseApp
import com.google.firebase.iid.FirebaseInstanceId
import com.innomalist.taxi.common.components.BaseActivity
import com.innomalist.taxi.common.networking.socket.interfaces.ConnectionError
import com.innomalist.taxi.common.networking.socket.interfaces.RemoteResponse
import com.innomalist.taxi.common.networking.socket.interfaces.SocketNetworkDispatcher
import com.innomalist.taxi.common.utils.AlertDialogBuilder
import com.innomalist.taxi.common.utils.LoadingDialog
import com.innomalist.taxi.common.utils.MyPreferenceManager
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

class MyTaxiApplication: Application(), LifecycleObserver {
    private var currentActivity: BaseActivity? = null

    override fun onCreate() {
        FirebaseApp.initializeApp(applicationContext)
        val nightMode = AppCompatDelegate.MODE_NIGHT_NO
        AppCompatDelegate.setDefaultNightMode(nightMode)
        ProcessLifecycleOwner.get().lifecycle.addObserver(this)
        super.onCreate()
    }


    fun getCurrentActivity(): Activity {
        return currentActivity!!
    }

    fun setCurrentActivity(mCurrentActivity: BaseActivity?) {
        currentActivity = mCurrentActivity
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onMoveToForeground() {
        if(currentActivity is BaseActivity && !(currentActivity as BaseActivity).shouldReconnect) return
        val token = MyPreferenceManager.getInstance(this).token ?: return
        if(SocketNetworkDispatcher.currentNamespace == null)  return
        if(currentActivity != null) LoadingDialog.display(currentActivity!!)
        FirebaseInstanceId.getInstance().instanceId.addOnCompleteListener { fb ->
            SocketNetworkDispatcher.instance.connect(SocketNetworkDispatcher.currentNamespace!!, token, fb.result!!.token) {
                when(it) {
                    is RemoteResponse.Success -> {
                        LoadingDialog.hide()
                        currentActivity?.onReconnected()
                    }

                    is RemoteResponse.Error -> {
                        GlobalScope.launch(Main) {
                            if(it.error == ConnectionError.TokenVerificationError)
                                return@launch
                            AlertDialogBuilder.show(currentActivity!!, getString(R.string.error_message_reconnection_failed, it.error.rawValue),AlertDialogBuilder.DialogButton.OK) {
                                currentActivity!!.finishAffinity()
                            }
                        }
                    }
                }
            }
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onMoveToBackground() {
        SocketNetworkDispatcher.instance.disconnect()
    }
}

Second .kt file (SocketNetworkDispatcher.kt):

package com.innomalist.taxi.common.networking.socket.interfaces

import android.content.Context
import android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR
import android.util.Log
import com.google.android.gms.maps.model.LatLng
import com.innomalist.taxi.common.Config
import com.innomalist.taxi.common.models.ChatMessage
import com.innomalist.taxi.common.models.Request
import com.innomalist.taxi.common.utils.Adapters
import com.innomalist.taxi.common.utils.AlertDialogBuilder
import com.squareup.moshi.Json
import io.socket.client.IO
import io.socket.client.Manager.EVENT_ERROR
import io.socket.client.Socket
import io.socket.engineio.client.Socket.EVENT_ERROR
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.json.JSONObject

class SocketNetworkDispatcher : NetworkDispatcher {
    companion object {
        var instance = SocketNetworkDispatcher()
        var currentNamespace: Namespace? = null
    }
    var socket: Socket? = null
    var onNewMessage: ((ChatMessage) -> Unit)? = null
    var onArrived: ((Int) -> Unit)? = null
    var onStarted: ((Request) -> Unit)? = null
    var onTravelInfo: ((LatLng) -> Unit)? = null
    var onNewRequest: ((Request) -> Unit)? = null
    var onFinished: ((FinishResult) -> Unit)? = null
    var onCancel: ((Int) -> Unit)? = null
    var onCancelRequest: ((Int) -> Unit)? = null
    var onDriverAccepted: ((Request) -> Unit)? = null
    var onPaid: ((Int) -> Unit)? = null

    override fun dispatch(event: String, params: Array<Any>?, completionHandler: (RemoteResponse<Any, SocketClientError>) -> Unit) {
        if(socket == null) {
            return
        }
        socket!!.emit(event, params) {
            if ((it.size > 1)) {
                completionHandler(RemoteResponse.createError(SocketClientError.InvalidAckParamCount))
                return@emit
            }
            if ((it.isEmpty())) {
                GlobalScope.launch(Dispatchers.Main) {
                    completionHandler(RemoteResponse.createSuccess(EmptyClass()))
                }
                return@emit
            }
            completionHandler(RemoteResponse.createSuccess(it[0]))
        }
    }

    fun connect(namespace: Namespace, token: String, notificationId: String, completionHandler: (RemoteResponse<Boolean, ConnectionError>) -> Unit) {
        val options = IO.Options()
        currentNamespace = namespace
        options.reconnection = true
        options.query = "token=$token&os=android&ver=60&not=$notificationId"
        socket = IO.socket("${Config.Backend}${namespace.rawValue}", options)
        socket!!.on(Socket.EVENT_CONNECT) {
            completionHandler(RemoteResponse.createSuccess(true))
        }
        val on = socket!!.on(Socket.EVENT_ERROR) {
            //socket!!.disconnect()
            if (it.isEmpty()) {
                completionHandler(RemoteResponse.createError(ConnectionError.ErrorWithoutData))
            } else if (it[0] is JSONObject) {
                Log.e("Error message", (it[0] as JSONObject)["message"] as String)
                completionHandler(RemoteResponse.createError(ConnectionError.TokenVerificationError))
            } else if (it[0] is String) {
                val knownError = ConnectionError(rawValue = it[0] as String)
                if (knownError != null) {
                    completionHandler(RemoteResponse.createError(knownError))
                } else {
                    completionHandler(RemoteResponse.createError(ConnectionError.Unknown))
                }
            } else {
                completionHandler(RemoteResponse.createError(ConnectionError.NotDecodableError))
            }
        }
        socket!!.on("cancelRequest") { item ->
                GlobalScope.launch(Dispatchers.Main) {
                    onCancelRequest?.invoke(item[0] as Int)
                }
            }
        // Driver Events
        socket!!.on("requestReceived") { item ->
            val travel = Adapters.moshi.adapter(Request::class.java).fromJson(item[0].toString())
            GlobalScope.launch(Dispatchers.Main) {
                onNewRequest?.invoke(travel!!)
            }
        }
        socket!!.on("messageReceived") { item ->
            val message = Adapters.moshi.adapter<ChatMessage>(ChatMessage::class.java).fromJson(item[0].toString())
            onNewMessage?.invoke(message!!)
        }
        socket!!.on("cancelTravel") {
            GlobalScope.launch(Dispatchers.Main) {
                onCancel?.invoke(0)
            }
        }
        socket!!.on("paid") {
            GlobalScope.launch(Dispatchers.Main) {
                onPaid?.invoke(0)
            }
        }
        socket!!.on("arrived") {
            GlobalScope.launch(Dispatchers.Main) {
                onArrived?.invoke(0)
            }
        }
        socket!!.on("started") { item ->
            val travel = Adapters.moshi.adapter<Request>(Request::class.java).fromJson(item[0].toString())
            GlobalScope.launch(Dispatchers.Main) {
                onStarted?.invoke(travel!!)
            }
        }
        socket!!.on("travelInfoReceived") { item ->
            val json = item[0] as JSONObject
            val lng = json.getDouble("x")
            val lat = json.getDouble("y")
            val loc = LatLng(lat, lng)
            GlobalScope.launch(Dispatchers.Main) {
                onTravelInfo?.invoke(loc)
            }
        }
        socket!!.on("Finished") { item ->
            GlobalScope.launch(Dispatchers.Main) {
                if(item[1] is Int) {
                    onFinished?.invoke(FinishResult(item[0] as Boolean, (item[1] as Int).toDouble()))
                } else {
                    onFinished?.invoke(FinishResult(item[0] as Boolean, item[1] as Double))

                }
            }
        }
        socket!!.on("driverAccepted") { item ->
            val travel = Adapters.moshi.adapter<Request>(Request::class.java).fromJson(item[0].toString())
            GlobalScope.launch(Dispatchers.Main) {
                onDriverAccepted?.invoke(travel!!)
            }
        }
        socket!!.connect()
    }

    fun disconnect() {
        socket?.disconnect()
    }
}

enum class Namespace(val rawValue: String) {
    Driver("drivers"), Rider("riders")
}

enum class ConnectionError(val rawValue: String) {
    @Json(name = "VersionOutdated")
    VersionOutdated("VersionOutdated"),
    @Json(name="NotFound")
    NotFound("NotFound"),
    @Json(name="NotFound")
    Blocked("Blocked"),
    @Json(name="RegistrationIncomplete")
    RegistrationIncomplete("RegistrationIncomplete"),
    @Json(name="TokenVerificationError")
    TokenVerificationError("TokenVerificationError"),
    @Json(name="NotDecodableError")
    NotDecodableError("NotDecodableError"),
    @Json(name="Unknown")
    Unknown("Unknown"),
    @Json(name="ErrorWithoutData")
    ErrorWithoutData("ErrorWithoutData");

    fun showAlert(context: Context) {
        AlertDialogBuilder.show(context, this.toString(), AlertDialogBuilder.DialogButton.OK, null)
    }

    companion object {
        operator fun invoke(rawValue: String) = values().firstOrNull { it.rawValue == rawValue }

    }
}

data class FinishResult(
        val paid: Boolean,
        val remainingAmount: Double
)

enum class SocketClientError(val rawValue: String) {
    InvalidAckParamCount("InvalidAckParamCount"), RequestTimeout("RequestTimeout");

    companion object {
        operator fun invoke(rawValue: String) = values().firstOrNull { it.rawValue == rawValue }
    }

    val localizedDescription: String
        get() {
            return when (this) {
                InvalidAckParamCount -> "Result parameter count is more than one. It's unexpected."
                RequestTimeout -> "Request Timeout"
            }
        }
}

DEBUG - ERROR Screeenshoot:

Debugger error message

app-level build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    ext.kotlin_version = '1.4.31'
    repositories {
        maven { url "https://maven.google.com" }
        jcenter()
        google()
        maven { url 'https://plugins.gradle.org/m2/'}
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.1.3'
        classpath 'com.google.gms:google-services:4.3.8'
        classpath 'com.google.firebase:firebase-crashlytics-gradle:2.6.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        maven { url "https://maven.google.com" }
        jcenter()
        mavenCentral()
        google()
        maven { url "https://jitpack.io" }
        maven {
            url "https://cardinalcommerce.bintray.com/android"
            credentials {
                username 'braintree-team-sdk@cardinalcommerce'
                password '220cc9476025679c4e5c843666c27d97cfb0f951'
            }
        }
    }
}
task clean(type: Delete) {
    delete rootProject.buildDir
}

I know this is depreciated, and that I need to replace depreciated with Firebase Installation or Messaging - but I really don't have a clue from where to strat, because this is not my code, I bought this and developers just vanished and left me with this.

I'm not good in Android/Kotlin development, but I'm web developer - so any guidance will do me good.

Thank you very much all...

EDIT

I tried import of dependencies related to firebase messaging and installation and tried to replace obsolete code with suggestions from Firebase documentation, but every time I get another, new error.

Eager2Learn
  • 153
  • 4
  • 19
  • 2
    This page should be pretty much all that's needed: https://firebase.google.com/docs/cloud-messaging/android/client#sample-register – Frank van Puffelen Jun 02 '21 at 23:29
  • @FrankvanPuffelen man, I was at that page whole day :) problem is that code I wrote above is not mine, so I don't know how to start with editing. I need someone just to give me some example how to change obsolete instance with active one. – Eager2Learn Jun 02 '21 at 23:44
  • Could you include your app-level build.gradle? – Ryan M Jun 03 '21 at 08:54
  • @RyanM My question is closed even I added all info, including app.gradle, as you asked for – Eager2Learn Jun 03 '21 at 15:11
  • I'm not sure why the last voter voted to close, that information isn't shown to me. That said, it looks like you aren't importing any Firebase libraries other than Crashlytics, which definitely isn't the one you want for this. Take a look at [this section](https://firebase.google.com/docs/cloud-messaging/android/client#add_firebase_sdks_to_your_app) of the page Frank linked above and give that a try. – Ryan M Jun 03 '21 at 15:18
  • Alternately, see https://stackoverflow.com/q/50579660/208273 – Ryan M Jun 03 '21 at 15:19
  • @RyanM Thank you man I will try and give you feedback here about work. Thank you once more – Eager2Learn Jun 03 '21 at 15:23

2 Answers2

4

FirebaseInstanceId is depricated, you can read more here

Firebase Instance ID has been replaced with FirebaseInstallations for app instance identifiers and FirebaseMessaging.getToken() for FCM registration tokens.

That said, replace this FirebaseInstanceId.getInstance().instanceId with FirebaseInstallations.getInstance().id. Your First.kt will be updated to:


    @OnLifecycleEvent(Lifecycle.Event.ON_START)
        fun onMoveToForeground() {
            if(currentActivity is BaseActivity && !(currentActivity as BaseActivity).shouldReconnect) return
            val token = MyPreferenceManager.getInstance(this).token ?: return
            if(SocketNetworkDispatcher.currentNamespace == null)  return
            if(currentActivity != null) LoadingDialog.display(currentActivity!!)
// Replace FirebaseInstanceId with FirebaseInstallations
            FirebaseInstallations.getInstance().id.addOnCompleteListener { fb ->
    
     if (!fb.isSuccessful){
                return@addOnCompleteListener
            }
                SocketNetworkDispatcher.instance.connect(SocketNetworkDispatcher.currentNamespace!!, token, fb.result) {
                    when(it) {
                        is RemoteResponse.Success -> {
                            LoadingDialog.hide()
                            currentActivity?.onReconnected()
                        }
    
                        is RemoteResponse.Error -> {
                            GlobalScope.launch(Main) {
                                if(it.error == ConnectionError.TokenVerificationError)
                                    return@launch
                                AlertDialogBuilder.show(currentActivity!!, getString(R.string.error_message_reconnection_failed, it.error.rawValue),AlertDialogBuilder.DialogButton.OK) {
                                    currentActivity!!.finishAffinity()
                                }
                            }
                        }
                    }
                }
            }
        }

To get the token FirebaseInstallations.getInstance().getToken(false).result.token

mementoGuy
  • 391
  • 2
  • 8
  • The `MyPreferenceManager.getInstance(this).token` doesn't exist now, and what you have today returns you a Task that needs to be waited to. An easy way to overcome it is : https://stackoverflow.com/a/69786426/878126 – android developer Jan 13 '22 at 09:39
2

I once encountered this kind of error and I add this line of code to android/build.gradle:

ext {
    ...
    firebaseMessagingVersion = "21.1.0"
}

Hope it works for you too!