我有一个项目作为另一个项目的库,因为我需要将其标记为白色(以及其他合作伙伴的更多项目)。在图书馆项目中,我实施了推送通知系统。我已经将库项目作为一个普通的项目来执行,并且推送工作就像一个魅力。当我将此项目作为另一个项目中的库导入时,我的问题就出现了。接收器永远不会被呼叫。
有一个帖子有相同的问题,但解决方案对我不起作用。我疯了!!!
主要问题是我没有收到来自C2DM的消息。我的代码是下一个:
两个项目的清单(我在两个项目中都有相同的代码)(我使用标签lib_project和app_project清除):
<receiver
android:name="com.lib_project.C2DMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.app_project.android" />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.app_project.android" />
</intent-filter>
</receiver>
和权限:
<uses-permission android:name="com.app_project.android.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission
android:name="com.app_project.android.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
我还在清单中声明了管理推送通知的服务,但它被正确调用。
<service android:name="com.lib_project.android.C2DMReceiver" />
真的,我不知道出了什么问题。我认为没问题但是没有用。提前谢谢。
这是我的班级C2DMBaseReceiver:
public abstract class C2DMBaseReceiver extends IntentService {
private static final String C2DM_RETRY = "com.google.android.c2dm.intent.RETRY";
public static final String REGISTRATION_CALLBACK_INTENT = "com.google.android.c2dm.intent.REGISTRATION";
private static final String C2DM_INTENT = "com.google.android.c2dm.intent.RECEIVE";
// Logging tag
private static final String TAG = "C2DM";
// Extras in the registration callback intents.
public static final String EXTRA_UNREGISTERED = "unregistered";
public static final String EXTRA_ERROR = "error";
public static final String EXTRA_REGISTRATION_ID = "registration_id";
public static final String ERR_SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE";
public static final String ERR_ACCOUNT_MISSING = "ACCOUNT_MISSING";
public static final String ERR_AUTHENTICATION_FAILED = "AUTHENTICATION_FAILED";
public static final String ERR_TOO_MANY_REGISTRATIONS = "TOO_MANY_REGISTRATIONS";
public static final String ERR_INVALID_PARAMETERS = "INVALID_PARAMETERS";
public static final String ERR_INVALID_SENDER = "INVALID_SENDER";
public static final String ERR_PHONE_REGISTRATION_ERROR = "PHONE_REGISTRATION_ERROR";
// wakelock
private static final String WAKELOCK_KEY = "C2DM_LIB";
private static PowerManager.WakeLock mWakeLock;
private final String senderId;
/**
* The C2DMReceiver class must create a no-arg constructor and pass the
* sender id to be used for registration.
*/
public C2DMBaseReceiver(String senderId) {
// senderId is used as base name for threads, etc.
super(senderId);
this.senderId = senderId;
}
/**
* Called when a cloud message has been received.
*/
protected abstract void onMessage(Context context, Intent intent);
/**
* Called on registration error. Override to provide better
* error messages.
*
* This is called in the context of a Service - no dialog or UI.
*/
public abstract void onError(Context context, String errorId);
/**
* Called when a registration token has been received.
*/
public void onRegistered(Context context, String registrationId) throws IOException {
// registrationId will also be saved
}
/**
* Called when the device has been unregistered.
*/
public void onUnregistered(Context context) {
}
@Override
public final void onHandleIntent(Intent intent) {
try {
Context context = getApplicationContext();
if (intent.getAction().equals(REGISTRATION_CALLBACK_INTENT)) {
handleRegistration(context, intent);
} else if (intent.getAction().equals(C2DM_INTENT)) {
onMessage(context, intent);
} else if (intent.getAction().equals(C2DM_RETRY)) {
C2DMessaging.register(context, senderId);
}
} finally {
// Release the power lock, so phone can get back to sleep.
// The lock is reference counted by default, so multiple
// messages are ok.
// If the onMessage() needs to spawn a thread or do something else,
// it should use it's own lock.
mWakeLock.release();
}
}
/**
* Called from the broadcast receiver.
* Will process the received intent, call handleMessage(), registered(), etc.
* in background threads, with a wake lock, while keeping the service
* alive.
*/
static void runIntentInService(Context context, Intent intent) {
if (mWakeLock == null) {
// This is called from BroadcastReceiver, there is no init.
PowerManager pm =
(PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
WAKELOCK_KEY);
}
mWakeLock.acquire();
// Use a naming convention, similar with how permissions and intents are
// used. Alternatives are introspection or an ugly use of statics.
String receiver = context.getPackageName() + ".C2DMReceiver";
intent.setClassName(context, receiver);
context.startService(intent);
}
private void handleRegistration(final Context context, Intent intent) {
final String registrationId = intent.getStringExtra(EXTRA_REGISTRATION_ID);
String error = intent.getStringExtra(EXTRA_ERROR);
String removed = intent.getStringExtra(EXTRA_UNREGISTERED);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "dmControl: registrationId = " + registrationId +
", error = " + error + ", removed = " + removed);
}
if (removed != null) {
// Remember we are unregistered
C2DMessaging.clearRegistrationId(context);
onUnregistered(context);
return;
} else if (error != null) {
// we are not registered, can try again
C2DMessaging.clearRegistrationId(context);
// Registration failed
Log.e(TAG, "Registration error " + error);
onError(context, error);
if ("SERVICE_NOT_AVAILABLE".equals(error)) {
long backoffTimeMs = C2DMessaging.getBackoff(context);
Log.d(TAG, "Scheduling registration retry, backoff = " + backoffTimeMs);
Intent retryIntent = new Intent(C2DM_RETRY);
PendingIntent retryPIntent = PendingIntent.getBroadcast(context,
0 /*requestCode*/, retryIntent, 0 /*flags*/);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.ELAPSED_REALTIME,
backoffTimeMs, retryPIntent);
// Next retry should wait longer.
backoffTimeMs *= 2;
C2DMessaging.setBackoff(context, backoffTimeMs);
}
} else {
try {
onRegistered(context, registrationId);
C2DMessaging.setRegistrationId(context, registrationId);
} catch (IOException ex) {
Log.e(TAG, "Registration error " + ex.getMessage());
}
}
}
}
Ant这个是我的C2DMReceiver:
public class C2DMReceiver extends C2DMBaseReceiver {
public static final String EXTRA_DATETIME = "datetime";
public static final String EXTRA_CAM_ID = "cam_id";
public static final String EXTRA_TYPE = "type";
public static final String GCM_PROJECT_ID = "58312821729";
public static void getC2DMRegistration(Context context){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO){
String id = C2DMessaging.getRegistrationId(context);
if(id.equals(""))
C2DMessaging.register(context, C2DMReceiver.GCM_PROJECT_ID);
else
C2DMReceiver.registerPushDevice(context, id);
Log.d("restored id: " + id);
}
}
public static String getDeviceID(Context context){
String out = null;
try {
TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(TELEPHONY_SERVICE);
out = telephonyManager.getDeviceId();
} catch (Exception e) {
Log.w("Error getting device uid", e);
}
return out;
}
public static void registerPushDevice(Context context, String registrationId){
try {
CameraManager app = null;
if(context instanceof Activity)
{
app = (CameraManager)(((Activity)context).getApplication());
}
else if(context instanceof Service)
{
app = (CameraManager)(((Service)context).getApplication());
}
else if(context instanceof Application)
{
app = (CameraManager)context;
}
if(app != null && app.isLoggedIn())
{
HashMap<String, String> keyValues = new HashMap<String, String>(app.getUserSessionKeys());
keyValues.put("imei", getDeviceID(context));
keyValues.put("registration_id", registrationId);
keyValues.put("application_id", context.getString(R.string.application_id));
keyValues.put("gcm", "true");
new ServerCall(context, Script.MOBILE, Method.ADD_REGISTRATION_ID, keyValues, null)
.execute();
}
} catch (Exception e) {
Log.e("Failed to register C2DM", e);
}
}
public C2DMReceiver() {
super(GCM_PROJECT_ID);
}
@Override
public void onRegistered(Context context, String registrationId) {
Log.i("onRegistered: " + registrationId);
registerPushDevice(context, registrationId);
}
@Override
public void onUnregistered(Context context) {
Log.i("onUnregistered");
}
@Override
public void onError(Context context, String errorId) {
Log.w("onError: " + errorId);
}
@SuppressWarnings("unchecked")
@Override
protected void onMessage(Context context, Intent receiveIntent){
Bundle extras = receiveIntent.getExtras();
CameraManager app = null;
if(context instanceof Activity)
{
app = (CameraManager)(((Activity)context).getApplication());
}
else if(context instanceof Service)
{
app = (CameraManager)(((Service)context).getApplication());
}
else if(context instanceof Application)
{
app = (CameraManager)context;
}
boolean activateNotificationsphone = app.getUserStorage().getBoolean(Constants.PUSH_NOTIFI_ACTIVATE_FROM_PHONE, true);
if(extras != null && activateNotificationsphone)
{
Log.e(""+extras.keySet());
Iterator<String> i = extras.keySet().iterator();
while(i.hasNext())
{
String key = i.next();
if(key.equalsIgnoreCase(Constants.EXTRA_ALARM_MOTION) || key.equalsIgnoreCase(Constants.EXTRA_CAMERA_DOWN) || key.equalsIgnoreCase(Constants.EXTRA_LSU_DOWN))
{
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher, context.getString(R.string.app_name), System.currentTimeMillis());
Intent notificationIntent = new Intent(context, FragmentTabs.class);
String type = key.toUpperCase();
String value = receiveIntent.getStringExtra(key);
String collapse_key = receiveIntent.getStringExtra("collapse_key");
String message = "";
String[] pair = value.split("[:]");
if(pair.length == 2)
{
notificationIntent
.putExtra(EXTRA_TYPE, type)
.putExtra(EXTRA_CAM_ID, pair[0])
.putExtra(EXTRA_DATETIME, pair[1])
.setAction(collapse_key);
Log.e("Type c2dm:"+type);
Log.e("Cam ID c2dm: " + pair[0]);
Log.e("DateTime c2dm: " + pair[1]);
ArrayList<CamerasFeedItem> cameras = null;
XMLObject settings = null;
ArrayList<EventItem> listEvents = null;
User user = null;
try
{
user = (User)Utils.deserializeObject(new File(getFilesDir(), CameraManager.USER_OBJ_FILE));
cameras = (ArrayList<CamerasFeedItem>)Utils.deserializeObject(new File(getFilesDir(), user.getUserId() + "_" + CameraManager.CAMERAS_OBJ_FILE));
settings = (XMLObject)Utils.deserializeObject(new File(getFilesDir(), user.getUserId() + "_" + CameraManager.SETTINGS_OBJ_FILE));
//List of events:
if(user!=null)
{
listEvents = (ArrayList<EventItem>)Utils.deserializeObject(new File(getFilesDir(), user.getUserId() + "_" + CameraManager.LIST_EVENTS_OBJ_FILE));
}
}
catch (Exception e)
{ }
CamerasFeedItem item = null;
if(settings == null || cameras == null || (item = isItemExists(cameras, pair[0])) == null)
{
return;
}
if(type.equals(Constants.EXTRA_ALARM_MOTION))
{
if(settings.getValue("motion", "no").equals("no"))
{
return;
}
GregorianCalendar curTime = new GregorianCalendar();
long offset = curTime.get(Calendar.ZONE_OFFSET) + curTime.get(Calendar.DST_OFFSET);
Calendar c = Calendar.getInstance();
c.setTimeZone(TimeZone.getTimeZone("UTC"));
c.setTimeInMillis(Long.parseLong(pair[1]) + offset);
String when = DateFormat.format("dd-MM-yyyy kk:mm:ss", c).toString();
message = context.getString(R.string.push_motion_on_camera, item.getName(), when);
}
else if(type.equals(Constants.EXTRA_CAMERA_DOWN))
{
if(settings.getValue("cameraDown", "no").equals("no"))
{
return;
}
message = context.getString(R.string.push_camera_is_down, item.getName(), getDownString(pair[1]));
//typeIndex = 1;
}
else if(type.equals(Constants.EXTRA_LSU_DOWN))
{
//typeIndex = 3;
message = "";
}
}
if(!message.equals(""))
{
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_CLEAR_TOP);
notification.defaults |= Notification.DEFAULT_SOUND;
notification.flags |= Notification.FLAG_AUTO_CANCEL;
RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.notification);
contentView.setTextViewText(R.id.title, context.getString(R.string.app_name));
contentView.setTextViewText(R.id.text, message);
notification.contentView = contentView;
notification.contentIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), notificationIntent, 0);
mNotificationManager.notify(collapse_key, (int)Math.random(), notification);
}
return;
}
}
}
}
private CamerasFeedItem isItemExists(ArrayList<CamerasFeedItem> cameras, String id){
for(CamerasFeedItem item: cameras)
{
if(item.getID().equals(id))
{
return item;
}
if(item.isFolderItem())
{
LSUItem lsu = ((FolderItem)item).getLsuItem();
if(lsu != null && lsu.getID().equals(id))
{
return lsu;
}
CamerasFeedItem result = isItemExists(CamerasFeedItem.parse(item), id);
if(result != null)
{
return result;
}
}
}
return null;
}
private String getDownString(String hours){
StringBuilder out = new StringBuilder();
int total = Integer.parseInt(hours);
int m = total / 720;
total = total % 720;
int w = total / 168;
total = total % 168;
int d = total / 24;
total = total % 24;
if(m > 0)
{
out.append(getResources().getQuantityString(R.plurals.push_month, m, m));
out.append(" ");
}
if(w > 0)
{
out.append(getResources().getQuantityString(R.plurals.push_weeks, w, w));
out.append(" ");
}
if(d > 0)
{
out.append(getResources().getQuantityString(R.plurals.push_days, d, d));
out.append(" ");
}
if(total > 0)
{
out.append(getResources().getQuantityString(R.plurals.push_hours, total, total));
out.append(" ");
}
return out.toString().trim();
}
C2DMBroadcastReceiver.java
public class C2DMBroadcastReceiver extends BroadcastReceiver {
@Override
public final void onReceive(Context context, Intent intent) {
// To keep things in one place.
C2DMBaseReceiver.runIntentInService(context, intent);
setResult(Activity.RESULT_OK, null /* data */, null /* extra */);
}
}
最后一个:C2DMessaging:
public class C2DMessaging {
public static final String EXTRA_SENDER = "sender";
public static final String EXTRA_APPLICATION_PENDING_INTENT = "app";
public static final String REQUEST_UNREGISTRATION_INTENT = "com.google.android.c2dm.intent.UNREGISTER";
public static final String REQUEST_REGISTRATION_INTENT = "com.google.android.c2dm.intent.REGISTER";
public static final String LAST_REGISTRATION_CHANGE = "last_registration_change";
public static final String BACKOFF = "backoff";
public static final String GSF_PACKAGE = "com.google.android.gsf";
// package
static final String PREFERENCE = "com.google.android.c2dm";
private static final long DEFAULT_BACKOFF = 30000;
/**
* Initiate c2d messaging registration for the current application
*/
public static void register(Context context, String senderId) {
try {
Intent registrationIntent = new Intent(REQUEST_REGISTRATION_INTENT);
registrationIntent.setPackage(GSF_PACKAGE);
registrationIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT, PendingIntent.getBroadcast(context, 0, new Intent(), 0));
registrationIntent.putExtra(EXTRA_SENDER, senderId);
context.startService(registrationIntent);
} catch (Exception e) {
Log.w("Couldn't use C2DM, check OS version", e);
}
}
/**
* Unregister the application. New messages will be blocked by server.
*/
public static void unregister(Context context) {
Intent regIntent = new Intent(REQUEST_UNREGISTRATION_INTENT);
regIntent.setPackage(GSF_PACKAGE);
regIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT, PendingIntent.getBroadcast(context, 0, new Intent(), 0));
context.startService(regIntent);
}
/**
* Return the current registration id.
*
* If result is empty, the registration has failed.
*
* @return registration id, or empty string if the registration is not complete.
*/
public static String getRegistrationId(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
String registrationId = prefs.getString("dm_registration", "");
return registrationId;
}
public static long getLastRegistrationChange(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
return prefs.getLong(LAST_REGISTRATION_CHANGE, 0);
}
static long getBackoff(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
return prefs.getLong(BACKOFF, DEFAULT_BACKOFF);
}
static void setBackoff(Context context, long backoff) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putLong(BACKOFF, backoff);
editor.commit();
}
// package
static void clearRegistrationId(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putString("dm_registration", "");
editor.putLong(LAST_REGISTRATION_CHANGE, System.currentTimeMillis());
editor.commit();
}
// package
static void setRegistrationId(Context context, String registrationId) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putString("dm_registration", registrationId);
editor.commit();
}
}
答案 0 :(得分:1)
你的问题在于这个方法:
static void runIntentInService(Context context, Intent intent) {
if (mWakeLock == null) {
// This is called from BroadcastReceiver, there is no init.
PowerManager pm =
(PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
WAKELOCK_KEY);
}
mWakeLock.acquire();
// Use a naming convention, similar with how permissions and intents are
// used. Alternatives are introspection or an ugly use of statics.
String receiver = context.getPackageName() + ".C2DMReceiver";
intent.setClassName(context, receiver);
context.startService(intent);
}
在以下行中context.getPackageName()
返回您应用的包(com.app_project.android
)。
String receiver = context.getPackageName() + ".C2DMReceiver";
但是,.C2DMReceiver
位于您的图书馆项目(com.lib_project.android
)中,这就是当您尝试使用应用中的图书馆项目时找不到此课程的原因。
解决这个问题的方法是明确地引用C2DMReceiver
类:
String receiver = C2DMReceiver.class.getName ();