Android C2DM Push Notification

Я разрабатываю одно приложение, и в этом приложении мне нужно реализовать push-уведомления. Может ли кто-нибудь предложить, как мне следует внедрять push-уведомления? Если бы мне предоставили хороший учебник, это было бы здорово!

Спасибо.

Ответ 1

//Вызов при запуске приложения

public void StartRegistrationNotification()
    {

        Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
        registrationIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0));
        registrationIntent.putExtra("sender", "[email protected]");
        this.startService(registrationIntent);  

}

//изменение в файле манифеста

<receiver android:name="com.ReceiverC2DM"
        android:permission="com.google.android.c2dm.permission.SEND">
        <!-- Receive the actual message -->
        <intent-filter>

            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <category android:name="yourpackagename" />
        </intent-filter>
        <!-- Receive the registration id -->
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            <category android:name="yourpackagename" />
        </intent-filter>
    </receiver>
    <permission android:name="yourpackagename.permission.C2D_MESSAGE"
    android:protectionLevel="signature" />
<uses-permission android:name="yourpackagename.permission.C2D_MESSAGE" />
<!-- This app has permission to register and receive message -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

//ReceiverC2DM.java.....

public class ReceiverC2DM extends BroadcastReceiver {

    private static String KEY = "c2dmPref";
    private static String REGISTRATION_KEY = "registrationKey";
    private Context context;

    // wakelock
    private static final String WAKELOCK_KEY = "C2DM_FAX";
    private static PowerManager.WakeLock mWakeLock;

    @Override
    public void onReceive(Context context, Intent intent) {
        this.context = context;

        runIntentInService(context, intent);

        if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {
            handleRegistration(context, intent);
        } else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
            handleMessage(context, intent);
        }
     }

    private void handleRegistration(Context context, Intent intent) {
        String registration = intent.getStringExtra("registration_id");
        Log.e("registration :","registration :"+registration);

        if (intent.getStringExtra("error") != null) {
            // Registration failed, should try again later.
            Log.d("c2dm", "registration failed");
            String error = intent.getStringExtra("error");
            if(error == "SERVICE_NOT_AVAILABLE"){
                Log.d("c2dm", "SERVICE_NOT_AVAILABLE");
            }else if(error == "ACCOUNT_MISSING"){
                Log.d("c2dm", "ACCOUNT_MISSING");
            }else if(error == "AUTHENTICATION_FAILED"){
                Log.d("c2dm", "AUTHENTICATION_FAILED");
            }else if(error == "TOO_MANY_REGISTRATIONS"){
                Log.d("c2dm", "TOO_MANY_REGISTRATIONS");
            }else if(error == "INVALID_SENDER"){
                Log.d("c2dm", "INVALID_SENDER");
            }else if(error == "PHONE_REGISTRATION_ERROR"){
                Log.d("c2dm", "PHONE_REGISTRATION_ERROR");
            }
        } else if (intent.getStringExtra("unregistered") != null) {
            // unregistration done, new messages from the authorized sender will be rejected
            Log.d("c2dm", "unregistered");

        } else if (registration != null) {
            Log.d("c2dm", registration);
            Editor editor =
                context.getSharedPreferences(KEY, Context.MODE_PRIVATE).edit();
            editor.putString(REGISTRATION_KEY, registration);
            editor.commit();
           // Send the registration ID to the 3rd party site that is sending the messages.
           // This should be done in a separate thread.
           // When done, remember that all registration is done.
        }
    }


    private void handleMessage(Context context, Intent intent)
    {

     String message = intent.getExtras().getString("payload");
     String key = intent.getExtras().getString("collapse_key");
     Log.e("","accountName : " +accountName);
     Log.e("","message : " +message);    
          Intent startActivity = new Intent(); 
            startActivity.setClass(context, NotificationAlert.class); 
            startActivity.setAction(NotificationAlert.class.getName()); 
            startActivity.setFlags( 
                    Intent.FLAG_ACTIVITY_NEW_TASK 
                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);      
            startActivity.putExtra("Title", "Hello");
            startActivity.putExtra("Message", message);
            context.startActivity(startActivity);   

        //Do whatever you want with the message         
    }

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

//Серверная сторона... Новое тестовое приложение

ServerSimulator.java

private SharedPreferences prefManager;
private final static String AUTH = "authentication";

private static final String UPDATE_CLIENT_AUTH = "Update-Client-Auth";

public static final String PARAM_REGISTRATION_ID = "registration_id";

public static final String PARAM_DELAY_WHILE_IDLE = "delay_while_idle";

public static final String PARAM_COLLAPSE_KEY = "collapse_key";

private static final String UTF8 = "UTF-8";

// Registration is currently hardcoded
private final static String YOUR_REGISTRATION_STRING = "put registration key";

private SharedPreferences prefs;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    prefManager = PreferenceManager.getDefaultSharedPreferences(this);
}




public void getAuthentification(View view) {
    SharedPreferences prefs = PreferenceManager
            .getDefaultSharedPreferences(this);

    HttpClient client = new DefaultHttpClient();
    HttpPost post = new HttpPost(
            "https://www.google.com/accounts/ClientLogin");

    try {

        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
        nameValuePairs.add(new BasicNameValuePair("Email", "[email protected]"));
        nameValuePairs.add(new BasicNameValuePair("Passwd","....."));
        nameValuePairs.add(new BasicNameValuePair("accountType", "GOOGLE"));
        nameValuePairs.add(new BasicNameValuePair("source",
                "Google-cURL-Example"));
        nameValuePairs.add(new BasicNameValuePair("service", "ac2dm"));

        post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
        HttpResponse response = client.execute(post);
        BufferedReader rd = new BufferedReader(new InputStreamReader(
                response.getEntity().getContent()));

        String line = "";
        while ((line = rd.readLine()) != null) {
            Log.e("HttpResponse", line);
            if (line.startsWith("Auth=")) {
                Editor edit = prefManager.edit();
                edit.putString(AUTH, line.substring(5));
                edit.commit();
                String s = prefManager.getString(AUTH, "n/a");
                Toast.makeText(this, s, Toast.LENGTH_LONG).show();
            }

        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void showAuthentification(View view) {
    String s = prefManager.getString(AUTH, "n/a");
    Toast.makeText(this, s, Toast.LENGTH_LONG).show();
}

public void sendMessage(View view) {
    try {
        Log.e("Tag", "Started");
        String auth_key = prefManager.getString(AUTH, "n/a");
        // Send a sync message to this Android device.
        StringBuilder postDataBuilder = new StringBuilder();
        postDataBuilder.append(PARAM_REGISTRATION_ID).append("=")
                .append(YOUR_REGISTRATION_STRING);

        // if (delayWhileIdle) {
        // postDataBuilder.append("&").append(PARAM_DELAY_WHILE_IDLE)
        // .append("=1");
        // }
        postDataBuilder.append("&").append(PARAM_COLLAPSE_KEY).append("=")
                .append("0");

        postDataBuilder.append("&").append("data.payload").append("=")
                .append(URLEncoder.encode("Fax Sent ... Test Push Notification ....", UTF8));

        Log.e("postDataBuilder ","postDataBuilder :" + postDataBuilder.toString());

        byte[] postData = postDataBuilder.toString().getBytes(UTF8);

        // Hit the dm URL.

        URL url = new URL("https://android.clients.google.com/c2dm/send");

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type",
                "application/x-www-form-urlencoded;charset=UTF-8");
        conn.setRequestProperty("Content-Length",
                Integer.toString(postData.length));
        conn.setRequestProperty("Authorization", "GoogleLogin auth="
                + auth_key);

        OutputStream out = conn.getOutputStream();
        out.write(postData);
        out.close();

        int responseCode = conn.getResponseCode();

        Log.e("Tag", String.valueOf(responseCode));
        // Validate the response code

        if (responseCode == 401 || responseCode == 403) {
            // The token is too old - return false to retry later, will
            // fetch the token
            // from DB. This happens if the password is changed or token
            // expires. Either admin
            // is updating the token, or Update-Client-Auth was received by
            // another server,
            // and next retry will get the good one from database.
            Log.e("C2DM", "Unauthorized - need token");
        }

        // Check for updated token header
        String updatedAuthToken = conn.getHeaderField(UPDATE_CLIENT_AUTH);
        if (updatedAuthToken != null && !auth_key.equals(updatedAuthToken)) {
            Log.i("C2DM",
                    "Got updated auth token from datamessaging servers: "
                            + updatedAuthToken);
            Editor edit = prefManager.edit();
            edit.putString(AUTH, updatedAuthToken);
        }

        String responseLine = new BufferedReader(new InputStreamReader(
                conn.getInputStream())).readLine();

        // NOTE: You *MUST* use exponential backoff if you receive a 503
        // response code.
        // Since App Engine task queue mechanism automatically does this
        // for tasks that
        // return non-success error codes, this is not explicitly
        // implemented here.
        // If we weren't using App Engine, we'd need to manually implement
        // this.
        if (responseLine == null || responseLine.equals("")) {
            Log.i("C2DM", "Got " + responseCode
                    + " response from Google AC2DM endpoint.");
            throw new IOException(
                    "Got empty response from Google AC2DM endpoint.");
        }

        String[] responseParts = responseLine.split("=", 2);
        if (responseParts.length != 2) {
            Log.e("C2DM", "Invalid message from google: " + responseCode
                    + " " + responseLine);
            throw new IOException("Invalid response from Google "
                    + responseCode + " " + responseLine);
        }

        if (responseParts[0].equals("id")) {
            Log.i("Tag", "Successfully sent data message to device: "
                    + responseLine);
        }

        if (responseParts[0].equals("Error")) {
            String err = responseParts[1];
            Log.w("C2DM",
                    "Got error response from Google datamessaging endpoint: "
                            + err);
            // No retry.
            throw new IOException(err);
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}   

Ответ 2

C2DM устарел и был заменен на Google Cloud Messaging для Android (GCM). Инструкция Google:

Важно: C2DM официально устарел по состоянию на 26 июня 2012 года. Это означает, что C2DM прекратил прием новых пользователей и квоту Запросы. Никакие новые функции не будут добавлены в C2DM. Однако приложения, использующие C2DM продолжит работу. Существующие разработчики C2DM поощряются для перехода на новую версию C2DM, называемую Cloud Cloud Messaging для Android (GCM). См. Документ миграции C2DM-to-GCM для получения дополнительной информации. Информация. Разработчики должны использовать GCM для новой разработки.

Существует учебный демонстрационный пример для GCM, а также для migration из C2DM.