How to keep a XMPP connection stable on Android with (a)smack?
Asked Answered
C

6

27

I use asmack-android-7-beem library for Android. I have a background service running, such as my app stays alive. But sooner or later XMPP connection dies without any notice. The server says that the client is still online but no packets are sent or received.

For example the client doesn't receive any presence packets when other clients have a new presence. I have XMPPConnection as an attibute of my main Application class.
I set ConnectionConfiguration config.setReconnectionAllowed(true) before the connection was made.
But reconnection doesn't happen. XMPPConnection connection.isConnected() returns true.

So the client is not aware that connection is actually lost.

Is there any way to keep the connection alive?

Champion answered 26/10, 2012 at 4:1 Comment(2)
Related: #11343420Magnum
isConnected method returns object state, but smack can not handle network connectivity changes you need to write code check you are able to ping server or not, based on that you need to perform futher operations, for more details you can see view my answerHennery
P
12

When using asmack put some code like this in your app to make Dalvik load the ReconnectionManager class and run it's static initialization block:

static {
    try {
        Class.forName("org.jivesoftware.smack.ReconnectionManager");
    } catch (ClassNotFoundException ex) {
        // problem loading reconnection manager
    }
}
Piezoelectricity answered 24/12, 2012 at 13:37 Comment(4)
some explanation to do this?Easel
@Easel this is required to execute static initialization block in ReconnectionManager class, which actually activates it. However I would double-check since it should be initialized by asmack statical initializer anyway (if you use it).Hypothecate
Hi @Martin Konecny. I've been trying to create an XMPPConnection but the the connection fails. The XMPPServer starts OK, though. Could you please look at my question here and see if you can help? thank you in advance.Highway
Using ReconnectionManager on Android is usually not the full solution, as you want to react when the data connectivity changes (e.g. GSM to Wifi switch), and ReconnectionManager is not aware of e.g. Android's NETWORK_CONNECTIVITY_CHANGED intents. Also on newer Smack versions (4.1 or higher), which run on Android, it's no longer required to do the initialization manually: Smack will be fully initialized automatically.Magnum
H
8

Actually There is not any problem with Reconnection manager. First you need to add connection listener to your connection manager.

connection.addConnectionListener(new ConnectionListener() {

                    @Override
                    public void reconnectionSuccessful() {
                        Log.i("","Successfully reconnected to the XMPP server.");

                    }

                    @Override
                    public void reconnectionFailed(Exception arg0) {
                        Log.i("","Failed to reconnect to the XMPP server.");
                    }

                    @Override
                    public void reconnectingIn(int seconds) {
                        Log.i("","Reconnecting in " + seconds + " seconds.");
                    }

                    @Override
                    public void connectionClosedOnError(Exception arg0) {
                        Log.i("","Connection to XMPP server was lost.");
                    }

                    @Override
                    public void connectionClosed() {
                        Log.i("","XMPP connection was closed.");

                    }
                }); 

if any error occurred the connectionClosedOnError(Exception arg0) will automatically called when connection is closed

 public void connectionClosed() {
                        Log.i("","XMPP connection was closed.");
                        //You can manually call reconnection code if you                  want to reconnect on any connection close
                    }

then check it this will call reconnectingin() method and try to reconnect.

Hope so this will help you.

use below code for check connection PingManager pingManager = PingManager.getInstanceFor(connection); pingManager.setPingInterval(5000);

add listner for ping fail handling to handle connection is connected or not because isConnected method is not reliable for check state of connection.

pingManager.registerPingFailedListener(PingFailedListener);

For mobile network connectivity is very big problem so you need to check network connectivity for mobile using broadcast receiver and on data reconnection you can use pingMyServer method to check connection is alive or not, if you are getting ping reply from server, means connection is alive otherwise on ping fail you can reconnect connection manually.

Hennery answered 26/4, 2014 at 6:10 Comment(3)
Hi Mandeep, I followed exactly your answer that it still doesn't work. The connection is just alive for 5 minute roughly. I though I'm missing something. Here is my code: link MainActivity.java Could you take a look at this and tell me whether I did as you? Thank you dropbox.com/s/ze3vjy08m2mymir/MainActivity.java?dl=0 I'm on Android API 16 and aSmack: asmack-android-19-0.8.10.jarColorist
I have the same problem, and using the same .jar, did you figure out why the connection is lost after a while?Spouse
Hi @Silvia.H. I've been trying to create an XMPPConnection but the the connection fails. The XMPPServer starts OK, though. Could you please look at my question here and see if you can help? thank you in advance.Highway
S
3

Here's my code work fine for ReconnectionManager

1) Add addConnectionListener on xmpp connection

XMPPConnectionListener mConnectionListener = new XMPPConnectionListener(username);
connection.addConnectionListener(mConnectionListener);

2) if connection closed then reconnect automatically using ReconnectionManager class

 ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(connection);
 reconnectionManager.enableAutomaticReconnection();
 reconnectionManager.setEnabledPerDefault(true);

3) ConnectionListener for reconnect, connect and authenticated on server. if connection authenticated successfully with server also register PingManager and ServerPingWithAlarmManager class.

public class XMPPConnectionListener implements ConnectionListener {
    String username="";
    public XMPPConnectionListener(String username){
        this.username=username;
    }
    @Override
    public void connected(final XMPPConnection connectionObeject) {

        sendPresenceAvailable();
        Log.d(TAG, "xmpp Connected()");
        connected = true;

    }

    @Override
    public void connectionClosed() {

        Log.d(TAG, "xmpp ConnectionCLosed()");

        isAuthenticatedPreviouly=false;
        connected = false;

        loggedin = false;

    }

    @Override
    public void connectionClosedOnError(Exception arg0) {
        Log.d(TAG, "xmpp ConnectionClosedOnError() :"+System.currentTimeMillis());

        isAuthenticatedPreviouly=false;
        connected = false;

        loggedin = false;
    }

    @Override
    public void reconnectingIn(int arg0) {
        Log.d(TAG, "xmpp reconnectingIn() :"+System.currentTimeMillis());

        loggedin = false;
    }

    @Override
    public void reconnectionFailed(Exception arg0) {
        Log.d(TAG, "xmpp ReconnectionFailed!");
        connected = false;

       // chat_created = false;
        loggedin = false;
        try {
            connection.connect();
        } catch (SmackException | IOException | XMPPException | InterruptedException exception) {
            exception.printStackTrace();
        }
    }

    @Override
    public void reconnectionSuccessful() {
        Log.d(TAG, "xmpp ReconnectionSuccessful");
        connected = true;
        sendPresenceAvailable();
        loggedin = false;
    }

    @Override
    public void authenticated(XMPPConnection connection2, boolean resumed) {

        Log.d(TAG, "xmpp Type Main Authenticated() :" + connection.isAuthenticated());

        if(connection.isAuthenticated()) {

            ServerPingWithAlarmManager.getInstanceFor(connection).setEnabled(true);

            PingManager pingManager = PingManager.getInstanceFor(connection);
            pingManager.setPingInterval(10);

            try {
                pingManager.pingMyServer();
                pingManager.pingMyServer(true,10);
                pingManager.pingServerIfNecessary();
                pingManager.registerPingFailedListener(new PingFailedListener() {
                    @Override
                    public void pingFailed() {
                        Log.d("Ping","pingFailed");
                        disconnect();
                        connect();
                    }
                });

            registerAllListener();
     }
}
Southey answered 2/12, 2017 at 7:51 Comment(0)
D
2

I have the same problem, except that My program run on server side JVM.
I used smack 4.0 in the first place. Then I updated to smack 4.1, but the problem still happened. Finally I found a configuration module: PingManager
After using this, the occurrence of this situation was drop down.

    connection = new XMPPTCPConnection(config);     
    PingManager pingManager = PingManager.getInstanceFor(connection);
    pingManager.setPingInterval(300); // seconds
Dang answered 20/7, 2015 at 6:41 Comment(2)
hi @Dang you need to handle network connectivity if you are writing code for android and add code for handle pingfailedlistener where you have to write reconnection mechanism.Hennery
how can we stop this when app is in background ?Horripilation
L
1

In Smack 4.1, I use ServerPingWithAlarmManager. You can find more details about keeping connection alive ramzandroid blog here.

Leith answered 20/5, 2016 at 18:15 Comment(2)
I can't resolve this class. I'm using compile 'org.igniterealtime.smack:smack-extensions:4.2.0' and compile 'org.igniterealtime.smack:smack-android:4.2.0'Alb
@joao2fast4u: I think it would be on smack-android-extensions, based on this github link: github.com/igniterealtime/Smack/blob/master/…Leith
B
0

For these case you need to handle the disconnection manually I mean you should intercept any disconnection, connection listener notified when you got a disconnection over.

public void connectionClosedOnError(Exception exception)

    import android.util.Log;

    import com.dagm8.core.protocols.ConnectionState;
    import com.dagm8.core.service.XMPPService;
    import com.dagm8.events.ConnectionStateEvent;

    import org.greenrobot.eventbus.EventBus;
    import org.jivesoftware.smack.ConnectionListener;
    import org.jivesoftware.smack.SmackException;
    import org.jivesoftware.smack.XMPPConnection;
    import org.jivesoftware.smack.XMPPException;
    import org.jivesoftware.smack.tcp.XMPPTCPConnection;

    import java.io.IOException;

    import static com.dagm8.core.protocols.ConnectionState.CONNECTED;
    import static com.dagm8.core.protocols.ConnectionState.DISCONNECTED;
    import static com.dagm8.core.protocols.ConnectionState.RECONNECTING;

    /**
     * dagm8-android
     * Created by Bedoy on 8/28/17.
     */

    public class ConnectionController implements ConnectionListener {

        private String TAG = getClass().getCanonicalName();

        private XMPPTCPConnection mConnection;

        public void setConnection(XMPPTCPConnection connection) {
            mConnection = connection;
        }

        public void init(XMPPTCPConnection connection) throws InterruptedException, XMPPException, SmackException, IOException {

            setConnection(connection);

            mConnection.setPacketReplyTimeout(10000);
            mConnection.addConnectionListener(this);
            mConnection.connect();
        }

        @Override
        public void connected(XMPPConnection connection) {
            XMPPService.connectionState = RECONNECTING;

            notifyConnectionState(RECONNECTING);

            try {
                mConnection.login();
            } catch (XMPPException | SmackException | IOException | InterruptedException e) {
                e.printStackTrace();
            }

            Log.i(TAG, "connected()");
        }


        @Override
        public void authenticated(XMPPConnection connection, boolean resumed) {
            XMPPService.connectionState = CONNECTED;

            notifyConnectionState(CONNECTED);

            Log.i(TAG, "authenticated()");
        }

        @Override
        public void connectionClosed() {
            XMPPService.connectionState = DISCONNECTED;

            notifyConnectionState(DISCONNECTED);

            Log.i(TAG, "connectionClosed()");
        }

        @Override
        public void connectionClosedOnError(Exception e) {
            XMPPService.connectionState = DISCONNECTED;

            notifyConnectionState(DISCONNECTED);


            try {
                mConnection.connect();
            } catch (SmackException | IOException | XMPPException | InterruptedException exception) {
                exception.printStackTrace();
            }
            Log.i(TAG, "connectionClosedOnError()");
        }

        @Override
        public void reconnectingIn(int seconds) {
            XMPPService.connectionState = RECONNECTING;

            notifyConnectionState(RECONNECTING);

            Log.i(TAG, "reconnectingIn()");
        }

        @Override
        public void reconnectionSuccessful() {
            XMPPService.connectionState = CONNECTED;

            notifyConnectionState(CONNECTED);

            Log.i(TAG, "reconnectionSuccessful()");
        }

        @Override
        public void reconnectionFailed(Exception e) {
            XMPPService.connectionState = DISCONNECTED;

            notifyConnectionState(DISCONNECTED);

            Log.i(TAG, "reconnectionFailed()");
        }


        private void notifyConnectionState(ConnectionState state) {
            EventBus.getDefault().post((ConnectionStateEvent) () -> state);
        }

        public boolean isAuthenticated()
        {
            return mConnection.isAuthenticated();
        }

        public void login() {
            try {
                mConnection.login();
            } catch (XMPPException | SmackException | IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
Bibliotheca answered 14/9, 2017 at 23:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.