簡體   English   中英

接收推送通知到庫項目(lib項目中的Android C2DM)

[英]Receive Push Notifications into library project (Android C2DM in a lib project)

我有一個項目作為另一個項目的庫,因為我需要對其加上白標(還有其他合作伙伴的更多項目)。 在圖書館項目中,我已經實現了推送通知系統。 我已將圖書館項目作為普通項目執行,而推送工作就像一個魅力。 我將這個項目作為另一個項目中的庫導入時,會發生我的問題。 永遠不會調用接收方。

有一個帖子有同樣的問題,但是解決方案對我不起作用。 我快瘋了!!!

Android C2DM和lib項目

主要問題是我沒有收到來自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());
        }
    }
}

}

螞蟻這是我的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 */);        
  }
}

最后一個:C2DM消息:

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();

  }
}

您的問題在於此方法:

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 ();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM