【问题标题】:QuickBlox notifications: push token disappearsQuickBlox 通知:推送令牌消失
【发布时间】:2015-06-10 18:07:58
【问题描述】:

我一直在开发一个使用 QuickBlox 进行聊天的 Android 应用程序。聊天工作正常,但我在为已注销用户推送通知时遇到了困难。

问题是某些设备有时会停止接收通知。它通常可以正常工作几个小时,但随后突然完全停止为该设备工作。完全手动卸载 + 重新安装(然后将用户重新登录到 QuickBlox + GCM)通常可以解决问题。

查看 QuickBlox 管理面板,我可以看到一些订阅丢失了他们的推送令牌。

用户 1 在设备 A 上注册。推送令牌已消失。 http://i.stack.imgur.com/YUkyw.png

用户 1 在设备 B 上注册。推送令牌仍然存在。 http://i.stack.imgur.com/Yu5IQ.png

一旦用户登录到 QuickBlox,我就会向 GCM + QuickBlox 推送消息注册。此代码主要取自 QuickBlox 聊天示例。

聊天服务:

private void loginToChat(final Context context, final QBUser user, final QBEntityCallback callback)
{
    this.qbChatService.login(user, new QBEntityCallbackImpl()
    {
        @Override
        public void onSuccess()
        {

            checkPlayServices(context);

            try
            {
                qbChatService.startAutoSendPresence(AUTO_PRESENCE_INTERVAL_IN_SECONDS);
            }
            catch (SmackException.NotLoggedInException e)
            {
                e.printStackTrace();
            }

            if (callback != null)
            {
                callback.onSuccess();
            }
        }

        @Override
        public void onSuccess(Object result, Bundle params)
        {
            super.onSuccess(result, params);

            checkPlayServices(context);
        }

        @Override
        public void onError(List errors)
        {
            if (callback != null)
            {
                callback.onError(errors);
            }
        }
    });
}


private void checkPlayServices(Context context)
{
    // Register with GCM after the session has been created
    PlayServicesHelper playServicesHelper = new PlayServicesHelper(context);
    playServicesHelper.checkPlayServices();
}

PlayServicesHelper:

public class PlayServicesHelper
{
private static final String PROPERTY_APP_VERSION = "appVersion";
private static final String PROPERTY_REG_ID = "registration_id";
private static final String TAG = "PlayServicesHelper";
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;

private GoogleCloudMessaging googleCloudMessaging;
private Context activity;
private String regId;

private String projectNumber;

public PlayServicesHelper(Context activity)
{
    this.activity = activity;
    this.projectNumber = activity.getString(R.string.gcm_project_number);
    checkPlayService();
}

private void checkPlayService()
{
    // Check device for Play Services APK. If check succeeds, proceed with
    // GCM registration.
    if (checkPlayServices())
    {
        googleCloudMessaging = GoogleCloudMessaging.getInstance(activity);
        regId = getRegistrationId();

        if (regId.isEmpty())
        {
            registerInBackground();
        }
    }
    else
    {
        Log.i(TAG, "No valid Google Play Services APK found.");
    }
}

/**
 * Check the device to make sure it has the Google Play Services APK. If
 * it doesn't, display a dialog that allows users to download the APK from
 * the Google Play Store or enable it in the device's system settings.
 */
public boolean checkPlayServices()
{
    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(activity);
    if (resultCode != ConnectionResult.SUCCESS)
    {
        if (GooglePlayServicesUtil.isUserRecoverableError(resultCode))
        {
            GooglePlayServicesUtil.getErrorDialog(resultCode, activity, PLAY_SERVICES_RESOLUTION_REQUEST).show();
        }
        return false;
    }
    return true;
}

/**
 * Gets the current registration ID for application on GCM service.
 * <p/>
 * If result is empty, the app needs to register.
 *
 * @return registration ID, or empty string if there is no existing
 * registration ID.
 */
private String getRegistrationId()
{
    final SharedPreferences prefs = getGCMPreferences();
    String registrationId = prefs.getString(PROPERTY_REG_ID, "");
    if (registrationId.isEmpty())
    {
        Log.i(TAG, "Registration not found.");
        return "";
    }
    // Check if app was updated; if so, it must clear the registration ID
    // since the existing regID is not guaranteed to work with the new
    // app version.
    int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);

    int currentVersion = getAppVersionCode();
    if (registeredVersion != currentVersion)
    {
        Log.i(TAG, "App version changed.");
        return "";
    }
    return registrationId;
}

/**
 * Registers the application with GCM servers asynchronously.
 * <p/>
 * Stores the registration ID and app versionCode in the application's
 * shared preferences.
 */
private void registerInBackground()
{
    new AsyncTask<Void, Void, String>()
    {
        @Override
        protected String doInBackground(Void... params)
        {
            String msg = "";
            try
            {
                if (googleCloudMessaging == null)
                {
                    googleCloudMessaging = GoogleCloudMessaging.getInstance(activity);
                }
                regId = googleCloudMessaging.register(projectNumber);
                msg = "Device registered, registration ID=" + regId;

                // You should send the registration ID to your server over HTTP, so it
                // can use GCM/HTTP or CCS to send messages to your app.
                Handler h = new Handler(activity.getMainLooper());
                h.post(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        subscribeToPushNotifications(regId);
                    }
                });

                // Persist the regID - no need to register again.
                storeRegistrationId(regId);
            }
            catch (IOException ex)
            {
                msg = "Error :" + ex.getMessage();
                // If there is an error, don't just keep trying to register.
                // Require the user to click a button again, or perform
                // exponential back-off.
            }
            return msg;
        }

        @Override
        protected void onPostExecute(String msg)
        {
            Log.i(TAG, msg + "\n");
        }
    }.execute(null, null, null);
}

/**
 * @return Application's {@code SharedPreferences}.
 */
private SharedPreferences getGCMPreferences()
{
    return activity.getSharedPreferences(activity.getPackageName(), Context.MODE_PRIVATE);
}

/**
 * Subscribe to Push Notifications
 *
 * @param regId registration ID
 */
private void subscribeToPushNotifications(String regId)
{
    String deviceId;

    final TelephonyManager mTelephony = (TelephonyManager) activity.getSystemService(Context.TELEPHONY_SERVICE);
    if (mTelephony.getDeviceId() != null)
    {
        deviceId = mTelephony.getDeviceId();
    }
    else
    {
        deviceId = Settings.Secure.getString(activity.getContentResolver(), Settings.Secure.ANDROID_ID);
    }

    QBMessages.subscribeToPushNotificationsTask(regId, deviceId, QBEnvironment.PRODUCTION, new QBEntityCallbackImpl<ArrayList<QBSubscription>>()
    {
        @Override
        public void onSuccess(ArrayList<QBSubscription> qbSubscriptions, Bundle bundle)
        {

        }

        @Override
        public void onError(List<String> strings)
        {

        }
    });
}

/**
 * Stores the registration ID and app versionCode in the application's
 * {@code SharedPreferences}.
 *
 * @param regId registration ID
 */
private void storeRegistrationId(String regId)
{
    final SharedPreferences prefs = getGCMPreferences();
    int appVersion = getAppVersionCode();
    SharedPreferences.Editor editor = prefs.edit();
    editor.putString(PROPERTY_REG_ID, regId);
    editor.putInt(PROPERTY_APP_VERSION, appVersion);
    editor.apply();
}

private int getAppVersionCode()
{
    try
    {
        PackageInfo packageInfo = this.activity.getPackageManager().getPackageInfo(this.activity.getPackageName(), 0);
        return packageInfo.versionCode;
    }
    catch (PackageManager.NameNotFoundException e)
    {
        return 0;
    }
}
}

为了允许用户接收通知,我每次应用程序进入后台时将其注销(在 BaseActivity 中使用 onStop),然后在应用程序恢复时重新登录(然后再次启动 PlayServicesHelper)。

ChatService.getInstance().logout(null);

该应用程序还使用 Parse(使用 GCM)进行推送通知,但是当我禁用 Parse 时,问题似乎仍然存在。

会不会是一个用户同时在多台设备上注册造成的?频繁的应用安装(无需手动删除之前的安装)是否会导致此行为?

【问题讨论】:

    标签: android google-cloud-messaging quickblox


    【解决方案1】:

    如果 2 个用户使用同一设备,推送令牌可能会消失

    例如,用户 1 订阅了设备 A 上的推送

    然后用户 2 订阅了设备 A(同一设备)上的推送

    在此之后,只有用户 2 会收到推送,而不是用户 1

    在您的案例中是否有机会拥有这样的逻辑?

    【讨论】:

    • 这是否也会导致用户 2 停止在设备 A 上接收通知?在我的情况下,设备上没有收到任何通知。
    • 那么这有没有可能?
    • 这可能与在设备上经常(卸载)安装和登录/注销有关。我有一台设备,我在其中安装了该应用 + 仅登录过一次,并且该设备在一个多星期后仍在接收通知。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多