QuickBlox / quickblox-android-sdk

QuickBlox Android SDK includes code snippets with main use cases and framework JAR library.
BSD 3-Clause "New" or "Revised" License
417 stars 697 forks source link

Problems when subscribing to push notifications. (SubscribeService) #455

Closed ghost closed 3 years ago

ghost commented 7 years ago

Environment details

Did this work before?

Expected behavior

Actual behavior

Logs

Steps to reproduce the behavior

Quickblox Usage in app

Project structure:

projectstruct

    MessagesDispatcher getMessagesDispatcher();

    DialogsReceiver getDialogsReceiver();

    NotificationsDispatcher getNotificationsDispatcher();

    Authenticator getAuthenticator();

    ConnectionManager getConnectionManager();

Initializing quickblox

    /**
     * Initialization task. It's done in an {@link AsyncTask because, by default, the
     * Quickblox initialization is done on the UI thread. Blocking  UI until it's finished.
     */
     private class initTask extends AsyncTask<EmptyCallback, Void, EmptyCallback> {
        @Override
        protected EmptyCallback doInBackground(EmptyCallback... params) {
            authenticateApi();
            initApi();
            return params[0];
        }

        @Override
        protected void onPostExecute(final EmptyCallback callback) {
            super.onPostExecute(callback);
            quickbloxConnectionManager.addConnectionListener();
            updateChatEnabled();
            quickbloxAuthenticator.login(credentials.getUsername(), credentials.getPassword(), new EmptyCallback() {
                @Override
                public void onSuccess() {
                    callback.onSuccess();
                }

                @Override
                public void onFailure() {
                    reconnectApi(new EmptyCallback() {
                        @Override
                        public void onSuccess() {
                            callback.onSuccess();
                        }

                        @Override
                        public void onFailure() {

                        }
                    });
                }
            });
        }
    }

-> authenticateApi() :

    /**
     * Authenticates {@link QuickBloxInstantMessaging with the appropriate
     * credentials depending on current product flavor.
     */
    @Override
    public void authenticateApi() {
        if (!BuildConfig.DEBUG_ENABLED) {
            QBSettings.getInstance().setStoringMehanism(StoringMechanism.UNSECURED);
            QBSettings.getInstance().setEndpoints(API_DOMAIN, CHAT_DOMAIN, ServiceZone.PRODUCTION);
            QBSettings.getInstance().init(context, APP_ID, AUTH_KEY, AUTH_SECRET);
            QBSettings.getInstance().setAccountKey(ACCOUNT_KEY);
            QBSettings.getInstance().setEnablePushNotification(true);
            QBSettings.getInstance().setSubscribePushStrategy(SubscribePushStrategy.ALWAYS);
        } else {
            QBSettings.getInstance().setStoringMehanism(StoringMechanism.UNSECURED);
            QBSettings.getInstance().setEndpoints(API_DOMAIN, CHAT_DOMAIN, ServiceZone.PRODUCTION);
            QBSettings.getInstance().init(context, DEV_APP_ID, DEV_AUTH_KEY, DEV_AUTH_SECRET);
            QBSettings.getInstance().setAccountKey(DEV_ACCOUNT_KEY);
            QBSettings.getInstance().setEnablePushNotification(true);
            QBSettings.getInstance().setSubscribePushStrategy(SubscribePushStrategy.ALWAYS);
        }
    }

-> initApi():

    /**
     * Initializes the APIs configurations.
     */
    @Override
    public void initApi() {
        QBChatService.setDebugEnabled(true);
        QBChatService.setDefaultAutoSendPresenceInterval(15);
        QBChatService.ConfigurationBuilder builder = new QBChatService.ConfigurationBuilder();
        builder.setAutojoinEnabled(true);
        builder.setSocketTimeout(200);
        builder.setKeepAlive(true);
        builder.setReconnectionAllowed(true);
        builder.setUseTls(true);
        QBChatService.setConfigurationBuilder(builder);
    }

Using the InstantMessaging instance:

    public InstantMessaging getInstantMessagingApi() throws NotLoggedInException {
        if (instantMessaging == null || !instantMessaging.getAuthenticator().isLoggedIn()) {
            throw new NotLoggedInException("User isn't logged in, can't init Instant Messaging");
        }
        return instantMessaging;
    }

Subscribing to pushes

 /**
     * Authenticates the current user with Quickblox and logs in.
     */
    @Override
    public void login(String username, String password, final EmptyCallback callback) {
        final QBUser qUser = new QBUser(username, Base64Helper.encode(password));
        QBAuth.createSession(qUser).performAsync(new QBEntityCallback<QBSession>() {
            @Override
            public void onSuccess(QBSession qbSession, Bundle bundle) {
                qUser.setId(qbSession.getUserId());
                QBChatService.getInstance().login(qUser, new QBEntityCallback() {
                    @Override
                    public void onSuccess(Object o, Bundle bundle) {
                        getInstantMessaging().getConnectionManager().initManagersListeners();
                        getInstantMessaging().getConnectionManager().subscribeToPushNotifications();
/// code..

-> Subscribe to push notifications::

 /**
     * Subscribes the user to offline push notifications.
     */
    @Override
    public void subscribeToPushNotifications() {
        try {
            if (getInstantMessaging().getAuthenticator().isLoggedIn()) {
                SubscribeService.subscribeToPushes(context, true);
                QBPushManager.getInstance().addListener(new QBPushManager.QBSubscribeListener() {
                    @Override
                    public void onSubscriptionCreated() {
                        Log.d(TAG, "Subscribed to push notifications");
                    }

                    @Override
                    public void onSubscriptionError(Exception e, int i) {
                        Log.d(TAG, "Failed to subscribe to push notifications: " + e.toString());
                    }

                    @Override
                    public void onSubscriptionDeleted(boolean b) {
                        Log.d(TAG, "Subscription deleted to push notifications");
                    }
                });
            }
        } catch (Exception e) {
            Log.d(TAG, e.toString());
        }
    }

-> Check if the user is logged in:


    /**
     * Checks if the current user is logged in.
     *
     * @return true if the user is logged in.
     */
    @Override
    public boolean isLoggedIn() {
        try {
            return QBChatService.getInstance() != null && QBChatService.getInstance().isLoggedIn();
        } catch (Exception e) {
            return false;
        }
    }

Android Oreo problems

 Intent intent = new Intent(context, SubscribeService.class);
            intent.putExtra("extraSubscribe", true);
            context.startService(intent);

EDIT:

tatanka987 commented 7 years ago

hello @PampaZiya, sorry for longtime answer, bug with SubscribeService will be fixer in next release

ghost commented 7 years ago

@tatanka987 Thank you for your reply. Looking forward for the next release.

ghost commented 6 years ago

@tatanka987 @RomanPronin I can confirm there are no more problems with Android O. However, SubscribeService threw 3 exceptions yesterday out of no where:

Error 1 Error 2 Error 3

tatanka987 commented 6 years ago

@PampaZiya please try to reproduce your issues without using proguard. For Error 2 check correct setting of parameter Account Key as stated in the error.

ghost commented 6 years ago

@tatanka987 I was unable to reproduce the problem without proguard. It happens in a burst where many users crash together then it fades away until it happens again in a later time. As for the account key. As you can see in my original post, I am always setting it and every use of the InstantMessagingApi variable requires it to be logged in:

if (getInstantMessaging().getAuthenticator().isLoggedIn()) {

Before using the subscribeToPushes method. Check if logged in:

try { return QBChatService.getInstance() != null && QBChatService.getInstance().isLoggedIn(); } catch (Exception e) { return false; }

As for initializing credentials:

`QBSettings.getInstance().setStoringMehanism(StoringMechanism.UNSECURED);
            QBSettings.getInstance().setEndpoints(API_DOMAIN, CHAT_DOMAIN, ServiceZone.PRODUCTION);
            QBSettings.getInstance().init(context, APP_ID, AUTH_KEY, AUTH_SECRET);
            QBSettings.getInstance().setAccountKey(ACCOUNT_KEY);
            QBSettings.getInstance().setEnablePushNotification(true);
            QBSettings.getInstance().setSubscribePushStrategy(SubscribePushStrategy.ALWAYS);

    private static final String API_DOMAIN = "https://api.quickblox.com";
    private static final String CHAT_DOMAIN = "chat.quickblox.com";`
tatanka987 commented 6 years ago

@PampaZiya I saw your code again. So, you use autosubscription on pushes from our SDK and at the time you subscribes to pushes manually, why? And second - you set endpoins but not set Service Zone, you need call QBSettings.getInstance().setZone(ServiceZone.PRODUCTION); after QBSettings.getInstance().setEndpoints(API_DOMAIN, CHAT_DOMAIN, ServiceZone.PRODUCTION);

When we can see our code in stacktrace we will can faster localize issue and fix it.

ghost commented 6 years ago

@tatanka987 I will try to reproduce the problem without proguard today and I'll get back to you if I was able to reproduce.

I will be adding setZone to today's app release and let you know if that fixes the problem.

Thank you

EDIT:

Is setZone necessary even though I have it set in manifest?

<meta-data android:name="com.quickblox.messages.QB_ENVIRONMENT" android:value="PRODUCTION"/>

tatanka987 commented 6 years ago

I'm looking forward to it

ghost commented 6 years ago

@tatanka987 Btw is this sufficient to remove the obfuscation on the SubscribeService that way the next release will not show UknownSource?

-keep com.quickblox.messages.services.SubscribeService.** { *; }

tatanka987 commented 6 years ago

ok, then exclude all QuickBlox lib

-keep com.quickblox.** { *; }

It is important for us to see our code in stacktrace.

ghost commented 6 years ago

@tatanka987

'Fatal Exception: java.lang.RuntimeException: An error occurred while executing doInBackground() at android.os.AsyncTask$3.done(AsyncTask.java:353) at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383) at java.util.concurrent.FutureTask.setException(FutureTask.java:252) at java.util.concurrent.FutureTask.run(FutureTask.java:271) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764) Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference at com.quickblox.core.a.l.b(Unknown Source:60) at com.quickblox.core.a.l.a(Unknown Source) at com.quickblox.core.a.l.a(Unknown Source:2) at com.quickblox.core.rest.RestRequest.toString(Unknown Source:43) at com.quickblox.core.a.g.a(Unknown Source:17) at com.quickblox.auth.b.m.perform(Unknown Source:10) at com.quickblox.messages.services.SubscribeService.a(Unknown Source:27) at com.quickblox.messages.services.SubscribeService.a(Unknown Source:129) at com.quickblox.messages.services.SubscribeService.b(Unknown Source:12) at com.quickblox.messages.services.SubscribeService.c(Unknown Source:18) at com.quickblox.messages.services.SubscribeService.onHandleWork(Unknown Source:61) at android.support.v4.app.w$a.a(JobIntentService.java:391) at android.support.v4.app.w$a.doInBackground(JobIntentService.java:382) at android.os.AsyncTask$2.call(AsyncTask.java:333) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764)'

From 1 user today. No other occurences

ghost commented 6 years ago

@tatanka987 Here is the log:

Fatal Exception: java.lang.RuntimeException: An error occurred while executing doInBackground() at android.os.AsyncTask$3.done(AsyncTask.java:353) at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383) at java.util.concurrent.FutureTask.setException(FutureTask.java:252) at java.util.concurrent.FutureTask.run(FutureTask.java:271) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764) Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference at com.quickblox.core.helper.ToStringHelper.toStringBuilder(Unknown Source:60) at com.quickblox.core.helper.ToStringHelper.toString(Unknown Source) at com.quickblox.core.helper.ToStringHelper.toString(Unknown Source:2) at com.quickblox.core.rest.RestRequest.toString(Unknown Source:43) at com.quickblox.core.helper.Lo.g(Unknown Source:17) at com.quickblox.auth.session.Query.perform(Unknown Source:10) at com.quickblox.messages.services.SubscribeService.a(Unknown Source:27) at com.quickblox.messages.services.SubscribeService.a(Unknown Source:129) at com.quickblox.messages.services.SubscribeService.b(Unknown Source:12) at com.quickblox.messages.services.SubscribeService.c(Unknown Source:18) at com.quickblox.messages.services.SubscribeService.onHandleWork(Unknown Source:61) at android.support.v4.app.w$a.a(JobIntentService.java:391) at android.support.v4.app.w$a.doInBackground(JobIntentService.java:382) at android.os.AsyncTask$2.call(AsyncTask.java:333) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764)

tatanka987 commented 6 years ago

Is setZone necessary even though I have it set in manifest?

Yes, it is necessary. In manifest you set subscription's environment, but not for endpoints.

We saw your last stacktrace, but it didn't help, please try describe more detailed used API, which methods from SubscribeService do you use, and try describe which possible steps can user does for getting this error.

ghost commented 6 years ago

This exception seems to only happen on Android 8 devices. Many devices on Android 8.

Fatal Exception: java.lang.RuntimeException: An error occurred while executing doInBackground() at android.os.AsyncTask$3.done(AsyncTask.java:353) at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383) at java.util.concurrent.FutureTask.setException(FutureTask.java:252) at java.util.concurrent.FutureTask.run(FutureTask.java:271) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764) Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference at com.quickblox.core.helper.ToStringHelper.toStringBuilder(Unknown Source:60) at com.quickblox.core.helper.ToStringHelper.toString(Unknown Source) at com.quickblox.core.helper.ToStringHelper.toString(Unknown Source:2) at com.quickblox.core.rest.RestRequest.toString(Unknown Source:43) at com.quickblox.core.helper.Lo.g(Unknown Source:17) at com.quickblox.auth.session.Query.perform(Unknown Source:10) at com.quickblox.messages.services.SubscribeService.a(Unknown Source:27) at com.quickblox.messages.services.SubscribeService.a(Unknown Source:129) at com.quickblox.messages.services.SubscribeService.b(Unknown Source:12) at com.quickblox.messages.services.SubscribeService.c(Unknown Source:18) at com.quickblox.messages.services.SubscribeService.onHandleWork(Unknown Source:61) at android.support.v4.app.w$a.a(JobIntentService.java:391) at android.support.v4.app.w$a.doInBackground(JobIntentService.java:382) at android.os.AsyncTask$2.call(AsyncTask.java:333) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764)

@tatanka987 Please check this trace. Android O only

tatanka987 commented 6 years ago

hello @PampaZiya yesterday I spent full day for investigation your issue, I tried to use your code in our tests and our samples, but can't reproduce your issue (I tested on Google Pixel with Android 8.0). Can you init QB framework not in AsyncTask (during initialization don't run any requests on server, only setting needed parameter and UI won't blocked). Try to init QB framework in App.java class of your app like we do this in our samples, you should do this in next order:

QBSettings.getInstance().setStoringMehanism(StoringMechanism.UNSECURED);
QBSettings.getInstance().setLogLevel(LogLevel.DEBUG);
QBSettings.getInstance().init(context, APP_ID, AUTH_KEY, AUTH_SECRET);
QBSettings.getInstance().setAccountKey(ACCOUNT_KEY);
QBSettings.getInstance().setEndpoints(API_DOMAIN, CHAT_DOMAIN, ServiceZone.PRODUCTION);
QBSettings.getInstance().setZone(ServiceZone.PRODUCTION);

//SubscribePushStrategy.ALWAYS - if you want use autosubscription on pushes, in this case you don't need call SubscribeService.subscribeToPushes(context, true);
//SubscribePushStrategy.NEVER - if you will realize subscription on pushes himself
QBSettings.getInstance().setSubscribePushStrategy(SubscribePushStrategy.ALWAYS);
QBSettings.getInstance().setEnablePushNotification(true);

If you want to help us to resolve your issue, try to reproduce it in your app himself and send us full log with error (not stacktrace only).

ghost commented 6 years ago

@tatanka987 Next release will no longer be in a AsyncTask. I re-order my initialization to the ones you provided. I will keep you posted and appreciate your dedication to this issue.

Nikhil-z commented 6 years ago

I am also facing the same issue where my targeted version of the app is Android API level 28. I'm using Quick Blox SDK version 3.8.1.

Does anyone found any solution?

ghost commented 3 years ago

Hello QuickBlox customer,

This is Nikolay from QuickBlox support.

The issue was closed as it is outdated.

Please check the relevant section of our documentation here: https://docs.quickblox.com/docs/android-push-notifications

Also, please update the SDK to the latest version: https://github.com/QuickBlox/quickblox-android-sdk-releases/releases/tag/3.9.11

Additionally, please check our new samples: https://docs.quickblox.com/docs/code-samples#chat-samples

If it is still relevant after reviewing the updated information, feel free to open a new issue.

Have a nice day.