2015-05-31 4 views
2

Я работаю над Android-приложением, которое использует QuickBlox для общения. Чат работает нормально, но я сталкиваюсь с трудностями с push-уведомлениями для выведенных из системы пользователей.Уведомления QuickBlox: push token исчезает

Проблема в том, что некоторые устройства иногда перестают получать уведомления. Он часто отлично работает в течение нескольких часов, но затем внезапно полностью перестает работать на этом устройстве. Полная ручная деинсталляция + переустановка (которая затем регистрирует пользователя снова в QuickBlox + GCM) обычно решает проблему.

Глядя на панель администратора QuickBlox, я вижу, что некоторые подписки теряют токен.

Пользователь 1 зарегистрирован на устройстве A. Токовый токен исчез. http://i.stack.imgur.com/YUkyw.png

Пользователь 1 зарегистрирован на устройстве B. Тоновый токен присутствует. http://i.stack.imgur.com/Yu5IQ.png

Я регистрирую сообщения GCM + QuickBlox после входа пользователя в QuickBlox. Этот код был в основном взят из образца чата QuickBlox.

ChatService:

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; 
    } 
} 
} 

Чтобы разрешить пользователю получать уведомления, я регистрирую его каждый раз, когда приложение переходит в фоновом режиме (с использованием OnStop в BaseActivity) и затем войдите в систему, когда приложение возобновится (что снова запускает PlayServicesHelper).

ChatService.getInstance().logout(null); 

Приложение также использует Разбор (с ГКМ) для уведомления толчка, но проблема по-прежнему казалось, происходит, когда я отключил Анализировать.

Возможно, проблема связана с тем, что один пользователь зарегистрирован на нескольких устройствах одновременно? Могут ли частые установки приложений (без ручного удаления предыдущей установки) привести к такому поведению?

ответ

1

Нажмите маркер может исчезнуть, если 2 пользователи используют один и тот же прибор

, например, пользователь 1 подписались на толчков на deviceA

Затем пользователь 2 подписался на наталкивает на deviceA (то же самое устройство)

После этого только пользователь 2 будет получать нажатие, а не пользователь 1

Есть ли вероятность иметь такую ​​логику в вашем случае?

+0

Может ли это заставить пользователя 2 прекратить прием уведомлений на устройстве A? В моем случае на устройство не поступает никаких уведомлений. –

+0

Так что это возможный случай или нет? –

+0

Это может быть связано с (un) установкой и входом/выходом в систему очень часто на устройстве. У меня есть устройство, в котором я установил приложение +, зарегистрированное только один раз, и что он все еще получает уведомления более чем через неделю. –

Смежные вопросы