2014年7月26日 星期六

Android-GCM( Google Cloud Messaging ) Client端 創建

說到GCM就想到推播功能
但是說到這裡,大多能參考的教學版本不符時事
因為自從4.X以上版本直接用google-play-services的Library
本人也被GCM服務搞得一頭霧水
如果本人提供的方法有問題,歡迎指教

參考來源 : 官方連結
話不多說,開始來動手做吧

package 為 com.example.gcm


  1. 匯入google-play-services_lib並在加入目標專案底下




  2. 增加AndroidManifest.xml內容

    若package不同,請改紅字部分

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.gcm"
        android:versionCode="1"
        android:versionName="1.0" >
    
        <uses-sdk
            android:minSdkVersion="9"
            android:targetSdkVersion="19" />
        <!-- Start -->
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.GET_ACCOUNTS" />
        <uses-permission android:name="android.permission.WAKE_LOCK" />
        <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
        <permission
            android:name="com.example.gcm.permission.C2D_MESSAGE"
            android:protectionLevel="signature" />
        <uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" />
        <!-- The end -->
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity android:name="DemoActivity" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <!-- Start -->
            <meta-data
                android:name="com.google.android.gms.version"
                android:value="@integer/google_play_services_version" />
            <receiver
                android:name=".GcmBroadcastReceiver"
                android:permission="com.google.android.c2dm.permission.SEND" >
                <intent-filter>
                    <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                    <category android:name="com.example.gcm" />
                </intent-filter>
            </receiver>
            <service android:name=".GcmIntentService" />
            <!-- The end -->
        </application>
    
    </manifest>
    
  3. DemoActivity.java

    ID記得改
    package com.example.gcm;
    
    import java.io.IOException;
    import java.util.concurrent.atomic.AtomicInteger;
    
    import android.app.Activity;
    import android.content.Context;
    import android.content.SharedPreferences;
    import android.content.pm.PackageInfo;
    import android.content.pm.PackageManager.NameNotFoundException;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.util.Log;
    import android.widget.TextView;
    
    import com.google.android.gms.common.ConnectionResult;
    import com.google.android.gms.common.GooglePlayServicesUtil;
    import com.google.android.gms.gcm.GoogleCloudMessaging;
    
    public class DemoActivity extends Activity{
    
        public static final String EXTRA_MESSAGE = "message";
        public static final String PROPERTY_REG_ID = "registration_id";
        private static final String PROPERTY_APP_VERSION = "appVersion";
        private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
    
        /*project id*/
        String SENDER_ID = "1234567890";
        static final String TAG = "GCMDemo";
    
        TextView mDisplay;
        GoogleCloudMessaging gcm;
        AtomicInteger msgId = new AtomicInteger();
        SharedPreferences prefs;
        Context context;
    
        String regid;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mDisplay = (TextView) findViewById(R.id.display);
    
            context = getApplicationContext();
    
            // Check device for Play Services APK. If check succeeds, proceed with
            //  GCM registration.
            if (checkPlayServices()) {
                gcm = GoogleCloudMessaging.getInstance(this);
                regid = getRegistrationId(context);
                Log.d("tag","gcm run"+regid);
                if (regid.isEmpty()) {
                    registerInBackground();
                }
            } else {
                Log.i(TAG, "No valid Google Play Services APK found.");
            }
    
        }
    
        private String getRegistrationId(Context context) {
            final SharedPreferences prefs = getGCMPreferences(context);
            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 = getAppVersion(context);
            if (registeredVersion != currentVersion) {
                Log.i(TAG, "App version changed.");
                return "";
            }
            return registrationId;
        }
    
        private SharedPreferences getGCMPreferences(Context context) {
            // This sample app persists the registration ID in shared preferences, but
            // how you store the regID in your app is up to you.
            return getSharedPreferences(DemoActivity.class.getSimpleName(),
                    Context.MODE_PRIVATE);
        }
    
        private static int getAppVersion(Context context) {
            try {
                PackageInfo packageInfo = context.getPackageManager()
                        .getPackageInfo(context.getPackageName(), 0);
                return packageInfo.versionCode;
            } catch (NameNotFoundException e) {
                // should never happen
                throw new RuntimeException("Could not get package name: " + e);
            }
        }
    
    
        private class RunTask extends AsyncTask<Void,Void,String>{
            @Override
            protected String doInBackground(Void... params) {
                String msg = "";
                try {
                    if (gcm == null) {
                        gcm = GoogleCloudMessaging.getInstance(context);
                    }
                    regid = gcm.register(SENDER_ID);
                    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.
                    // The request to your server should be authenticated if your app
                    // is using accounts.
                    sendRegistrationIdToBackend();
    
                    // For this demo: we don't need to send it because the device
                    // will send upstream messages to a server that echo back the
                    // message using the 'from' address in the message.
    
                    // Persist the regID - no need to register again.
                    storeRegistrationId(context, 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;
            }
    
        }
    
        private void registerInBackground() {
            new RunTask().execute(null, null, null);
    
        }
    
        private void sendRegistrationIdToBackend() {
            // Your implementation here.
        }
    
        private void storeRegistrationId(Context context, String regId) {
            final SharedPreferences prefs = getGCMPreferences(context);
            int appVersion = getAppVersion(context);
            Log.i(TAG, "Saving regId on app version " + appVersion);
            SharedPreferences.Editor editor = prefs.edit();
            editor.putString(PROPERTY_REG_ID, regId);
            editor.putInt(PROPERTY_APP_VERSION, appVersion);
            editor.commit();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            checkPlayServices();
        }
    
        private boolean checkPlayServices() {
            int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
            if (resultCode != ConnectionResult.SUCCESS) {
                if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
                    GooglePlayServicesUtil.getErrorDialog(resultCode, this,
                            PLAY_SERVICES_RESOLUTION_REQUEST).show();
                } else {
                    Log.i(TAG, "This device is not supported.");
                    finish();
                }
                return false;
            }
            return true;
        }
    
    }
    
    
  4. GcmBroadcastReceiver.java

    package com.example.gcm;
    
    import android.app.Activity;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.support.v4.content.WakefulBroadcastReceiver;
    
    public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            // Explicitly specify that GcmIntentService will handle the intent.
            ComponentName comp = new ComponentName(context.getPackageName(),
                    GcmIntentService.class.getName());
            // Start the service, keeping the device awake while it is launching.
            startWakefulService(context, (intent.setComponent(comp)));
            setResultCode(Activity.RESULT_OK);
        }
    
    }
    
  5. GcmIntentService.java


    package com.example.gcm;
    
    import static com.example.gcm.DemoActivity.TAG;
    import android.app.IntentService;
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.os.SystemClock;
    import android.support.v4.app.NotificationCompat;
    import android.util.Log;
    
    import com.google.android.gms.gcm.GoogleCloudMessaging;
    
    public class GcmIntentService extends IntentService {
    
        public static final int NOTIFICATION_ID = 1;
        private NotificationManager mNotificationManager;
        NotificationCompat.Builder builder;
    
        public GcmIntentService() {
            super("GcmIntentService");
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            Bundle extras = intent.getExtras();
            GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
            // The getMessageType() intent parameter must be the intent you received
            // in your BroadcastReceiver.
            String messageType = gcm.getMessageType(intent);
    
            if (!extras.isEmpty()) {  // has effect of unparcelling Bundle
                /*
                 * Filter messages based on message type. Since it is likely that GCM
                 * will be extended in the future with new message types, just ignore
                 * any message types you're not interested in, or that you don't
                 * recognize.
                 */
                if (GoogleCloudMessaging.
                        MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
                    sendNotification("Send error: " + extras.toString());
                } else if (GoogleCloudMessaging.
                        MESSAGE_TYPE_DELETED.equals(messageType)) {
                    sendNotification("Deleted messages on server: " +
                            extras.toString());
                    // If it's a regular GCM message, do some work.
                } else if (GoogleCloudMessaging.
                        MESSAGE_TYPE_MESSAGE.equals(messageType)) {
                    // This loop represents the service doing some work.
                    for (int i=0; i<5; i++) {
                        Log.i(TAG, "Working... " + (i+1)
                                + "/5 @ " + SystemClock.elapsedRealtime());
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                        }
                    }
                    Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());
                    // Post notification of received message.
                    sendNotification("Received: " + extras.toString());
                    Log.i(TAG, "Received: " + extras.toString());
                }
            }
            // Release the wake lock provided by the WakefulBroadcastReceiver.
            GcmBroadcastReceiver.completeWakefulIntent(intent);
        }
    
        // Put the message into a notification and post it.
        // This is just one simple example of what you might choose to do with
        // a GCM message.
        private void sendNotification(String msg) {
            mNotificationManager = (NotificationManager)
                    this.getSystemService(Context.NOTIFICATION_SERVICE);
    
            PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                    new Intent(this, DemoActivity.class), 0);
    
            NotificationCompat.Builder mBuilder =
                    new NotificationCompat.Builder(this)
            .setSmallIcon(R.drawable.ic_launcher)
            .setContentTitle("GCM Notification")
            .setStyle(new NotificationCompat.BigTextStyle()
            .bigText(msg))
            .setContentText(msg);
    
            mBuilder.setContentIntent(contentIntent);
            mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
        }
    
    }
    
    
  6. 記得DemoActivity有一行紅色ID需求嗎?

    Google Developers Console : 位置
    只需創立一個專案就可以
    String SENDER_ID = "1234567890";  (改為您自己的ID)




    請用自己的Google帳號去申請一個專案( 這不用申請API Key )
  7. Google Developers Console 開通 GCM

  8. 執行程式

歡迎轉載,請註明出處。

1 則留言: