androidkotlinsocket.ioforeground-service

socket-io android doesn't work with pro-guard enabled


I'm trying to start android foreground service for real-time connection with my server using Socket-IO android native client and it works when i run the application with debug mode but when i run it with with release mode only connect event executes and other events won't work

Service.kt

class MyService() : Service() {


    private val notifBuilder = NotificationCompat.Builder(this, ongoingChannelId)
        .setSmallIcon(R.drawable.ic_notification_offline)
        .setPriority(NotificationCompat.PRIORITY_MIN)
        .setOngoing(true)


    override fun onCreate() {
        Log.e(TAG, "onCreate: Service ONCREATE")
        notificationIntent = Intent(this, MainActivity::class.java)
        pendingIntent = PendingIntent.getActivity(
            applicationContext,
            0, notificationIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT),
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
        )
        notifBuilder.setContentIntent(pendingIntent)
            .setOnlyAlertOnce(true)
            .setContentTitle(getString(R.string.app_name))

        super.onCreate()
    }


    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.e(TAG, "onStartCommand: ")
        createNotificationChannel()
        startForeground(onGoingNotificationId, notifBuilder.build())
        startSocket()
        return START_STICKY
    }


    private fun startSocket() {
        if (!socketStarted) {
            socketStarted = true
            socket.on(Socket.EVENT_CONNECT) {
                Log.e(TAG, "onStartCommand: ${Socket.EVENT_CONNECT}")
                notifBuilder.setContentText("Connected to Server")
                NotificationManagerCompat.from(this)
                    .notify(onGoingNotificationId, notifBuilder.build())
                socket.emit(
                    SOCKET_EVENT_LOGIN,
                    "my token"
                )
                if (this::pingTimerTask.isInitialized)
                    pingTimerTask.cancel()
                pingTimerTask = object : TimerTask() {
                    override fun run() {
                        Log.e(TAG, "run: Pinging ".plus(socket.connected()))
                        if (socket.connected())
                            socket.emit(
                                SOCKET_EVENT_PING,
                                "my token"
                            )
                    }
                }

                pingTimer = if (!this::pingTimer.isInitialized)
                    Timer(true)
                else {
                    pingTimer.cancel()
                    pingTimer.purge()
                    Timer(true)
                }
                pingTimer.schedule(pingTimerTask, 2000, 10000)

            }
            socket.on(Socket.EVENT_CONNECT_ERROR) {
                Log.e(TAG, "onStartCommand: ${Socket.EVENT_CONNECT_ERROR}")
                notifBuilder.setContentText("Connection error to Server")
                    .setSmallIcon(R.drawable.ic_notification_offline)
                NotificationManagerCompat.from(this)
                    .notify(onGoingNotificationId, notifBuilder.build())
                pingTimer.cancel()
            }
            socket.on(Socket.EVENT_DISCONNECT) {
                Log.e(TAG, "onStartCommand: ${Socket.EVENT_DISCONNECT}")
                notifBuilder.setContentText("Disconnected from Server")
                notifBuilder.setOngoing(false)
                    .setSmallIcon(R.drawable.ic_notification_offline)
                NotificationManagerCompat.from(this)
                    .notify(onGoingNotificationId, notifBuilder.build())
                pingTimer.cancel()
            }
            socket.on(SOCKET_EVENT_ONLINE, loginListener)
            socket.connect()
        }
    }

    @SuppressLint("MissingPermission")
    private val loginListener = Emitter.Listener { res ->
        Log.e(TAG, "loginListener: Pinged")
        val date = System.currentTimeMillis()
        val dateFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
        val dateStr: String = dateFormat.format(date)
        notifBuilder.setContentText("Last Ping was $dateStr")
            .setSmallIcon(R.drawable.ic_notification_online)
        NotificationManagerCompat.from(this).notify(onGoingNotificationId, notifBuilder.build())

    }

}

So i expect to get a loginlistener event everytime i ping the server

and i start the service like this

serviceIntent = Intent(requireContext(), MyService::class.java)
ContextCompat.startForegroundService(requireContext(),serviceIntent)

Solution

  • I defined my model class in the proguard file.

    -keep class com.example.model.** { *; }

    If you are using SSL, this may be the reason. It's work fine like that :

    val socket = IO.socket(socketUrl, SocketOptionsSSL.getOptions())
    socketConnect()
    
    private fun socketConnect() {
    val obj = JSONObject()
    obj.put("type", "client")
    obj.put("userId", "XXXX")
    socket.emit("roomConnect", obj)
    socket.on("tableupdate", onSocketTableStateChange())
    socket.connect()
    }
    private fun onSocketTableStateChange(): Emitter.Listener {
    return object : Emitter.Listener {
    override fun call(vararg args: Any?) {
    try {
    val socketData = Gson().fromJson(args[0].toString(), SocketDataClass::class.java)
    } catch (e: Exception) {
    }
    }
    }
    }
    

    SocketOptionsSSL

    public class SocketOptionsSSL {
    
    public static IO.Options getOptions() {
    
    
        HostnameVerifier hostnameVerifier = new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            @Override
            public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
    
            }
    
            @Override
            public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
    
            }
    
            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[0];
            }
        }};
    
        X509TrustManager trustManager = (X509TrustManager) trustAllCerts[0];
    
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .hostnameVerifier(hostnameVerifier)
                .build();
        try {
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, null);
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            okHttpClient = null;
            okHttpClient = new OkHttpClient.Builder()
                    .hostnameVerifier(hostnameVerifier)
                    .sslSocketFactory(sslSocketFactory, trustManager)
                    .build();
        } catch (Exception e) {
            Logger.INSTANCE.d("SocketSSL", "Options çekilirken hata oluştu.");
    
        }
    
        IO.Options opts = new IO.Options();
        opts.callFactory = okHttpClient;
        opts.webSocketFactory = okHttpClient;
    
        return opts;
    }
    }