我一直在开发一款使用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聊天示例。
ChatService:
.bss
PlayServicesHelper:
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();
}
为了允许用户接收通知,我每次应用程序进入后台时都会将其注销(在BaseActivity中使用onStop),然后在应用程序恢复时重新登录(然后再次启动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;
}
}
}
该应用程序还使用Parse(使用GCM)进行推送通知,但是当我禁用Parse时,问题似乎仍然存在。
问题可能是由于一个用户同时在多个设备上注册了吗?频繁安装应用程序(无需手动删除以前的安装)会导致此行为吗?
答案 0 :(得分:1)
如果2个用户使用同一设备
,则推送令牌可能会消失例如,用户1订阅了推送deviceA
然后用户2订阅了推送deviceA(同一设备)
此后只有用户2接收推送,而不是用户1
你的案子中是否有机会拥有这样的逻辑?