各位Android安卓開發者大家好,首先在與大家分享文章之前,小黑人在此先向大家拜個早年,祝大家新年快樂,事事順利!
哈,去年小黑人寫作文章的進度有比較緩慢一點,在此先跟大家說聲抱歉,但是我們都要向前看齊,去年已經過去了,新的一年要好好把握,所以小黑人決定今年的第一篇文章就獻給許多App軟體都必備的"推播"機制!
首先,在分享推播文章之前,我們先了解"推播"到底是什麼?
推播其實就是Google提供的GCM伺服器(Google Cloud Messaging)用來讓後端與行動裝置進行訊息的發送與接收,所以我們的手機狀態列上常常會顯示例如最新消息或優惠訊息等資訊,那我們手機端要怎麼運用GCM來接收後台發送的推播訊息呢?就讓我們繼續看下去吧~
好,在我們開始撰寫推播的接收程式前,我們要先將GCM的Library導入我們的專案中,這樣我們才可以運用GCM本身的內部推播機制,所以一開始會碰到的問題是GCM的Library在哪呢?
答案就是在"Google Play
Services"裡,大家不用上網找這個Library在哪裡,其實在你的電腦裡就可以找到,首先步驟是:開啟Android SDK Manager(就是Update SDK版本的地方),開啟後往下滑動到最底部會有一個Extras資料夾,展開Extras資料夾後裡面會有一個Google Play Services,看到這個項目就不用懷疑在左方打勾然後進行安裝就可以囉,接下來安裝下載完成後檔案會存在SDK的資料夾裡,我們再把檔案抓出來導入到我們的專案裡就完成囉。
Google Play Services的Library位置 : 你的Android SDK路徑\sdk\extras\google\google_play_services\libproject裡的google-play-services_lib專案,將這個專案import到你的專案列表裡。
目前導入google-play-services_lib專案後,這個專案和您的開發專案還沒有任何關係,所以您要在您的專案裡引用google-play-services_lib專案,步驟是:在您的專案上按右鍵,點選Properties,開啟視窗後左側列表點選Android,在下方Library區域裡按Add,將google-play-services_lib加入就可以囉。
好,前置作業都完成後,接下來就要正式開始撰寫推播的接收程式囉!
1. 首先,開啟AndroidManifest.xml進行撰寫,加入下方的權限設定與Application內的資訊。(其實Google有提供GCM的實作範例,裡面範例都寫的很清楚,小黑人也是跟著範例實作)
權限部分加入 :
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<permission android:name="您的Package Name.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="您的Package Name.permission.C2D_MESSAGE" />
<uses-permission
android:name="com.google.android.c2dm.permission.RECEIVE" />
Application內加入 :
<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="您的Package Name" />
</intent-filter>
</receiver>
<service android:name=".GcmIntentService" />
放入這些程式碼,AndroidManifest的部分就完成囉!
2. 建立GcmBroadcastReceiver.java,這個class算是在接收GCM的呼叫,收到通知後啟動Service。
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver
{
@Override
public void onReceive(Context context, Intent
intent)
{
ComponentName comp =
new ComponentName(context.getPackageName(), GcmIntentService.class.getName());
startWakefulService(context,
(intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
3. 建立GcmIntentService.java,這個class算是收到GCM的呼叫通知後,解析傳來的通知訊息。
public class GcmIntentService extends IntentService
{
public static final int NOTIFICATION_ID = 1;
private NotificationManager
mNotificationManager;
NotificationCompat.Builder builder;
public static final String TAG = "GCM Demo";
public GcmIntentService()
{
super("GcmIntentService");
}
@Override
protected void onHandleIntent(Intent intent)
{
//解析收到的文字訊息再傳入sendNotification進行顯示
Bundle extras =
intent.getExtras();
GoogleCloudMessaging
gcm = GoogleCloudMessaging.getInstance(this);
String messageType =
gcm.getMessageType(intent);
if
(!extras.isEmpty())
{
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());
}
else if
(GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType))
{
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());
sendNotification("Received:
" + extras.toString());
Log.i(TAG, "Received:
" + extras.toString());
}
}
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
//設定Notification要顯示的資訊與點擊Notification要開啟的頁面
private void sendNotification(String msg)
{
mNotificationManager
= (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent
contentIntent = PendingIntent.getActivity(this, 0,new Intent(this,
MainActivity.class) , 0);
NotificationCompat.Builder
mBuilder =
new
NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("要顯示的標題名稱")
.setStyle(new
NotificationCompat.BigTextStyle()
.bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID,
mBuilder.build());
}
}
4. 最後一個步驟,上方新增的兩個class都是屬於接收到訊息後要做的事,現在這個步驟是要向GCM註冊這支行動裝置,如果沒有註冊這個動作的話,GCM根本不知道要向哪個行動裝置進行推播發送,所以向GCM註冊裝置是一個很重要的環節。
首先在要做註冊的Activity裡添加註冊程式碼,小黑人以MainActivity作為範例。
public class MainActivity extends Activity
{
//只要把您的GCM註冊ID填入,其他部分皆一樣
private String SENDER_ID = "您GCM的註冊ID";
private static final String TAG = "GCM
:";
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 static final int
PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
private GoogleCloudMessaging gcm;
private AtomicInteger msgId = new
AtomicInteger();
private Context context = this;
private String regid;
@Override
protected void onCreate(Bundle
savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//確認是否已註冊過裝置,將這段放入您欲註冊的位置
if (checkPlayServices())
{
gcm = GoogleCloudMessaging.getInstance(this);
regid = getRegistrationId(context);
if
(regid.isEmpty())
{
registerInBackground();
}
}
else
{
Log.i(TAG, "No valid Google Play Services
APK found.");
}
}
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;
}
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();
}
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
"";
}
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 void registerInBackground()
{
new 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;
sendRegistrationIdToBackend();
storeRegistrationId(context,
regid);
}
catch (IOException ex)
{
msg = "Error :" + ex.getMessage();
}
return msg;
}
@Override
protected void onPostExecute(String msg)
{
}
}.execute(null, null, null);
}
private static int getAppVersion(Context
context)
{
try
{
PackageInfo packageInfo =
context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
}
catch (NameNotFoundException e)
{
throw new RuntimeException("Could not get
package name: " + e);
}
}
private SharedPreferences
getGcmPreferences(Context context)
{
return
getSharedPreferences(MainActivity.class.getSimpleName(),
Context.MODE_PRIVATE);
}
private void sendRegistrationIdToBackend()
{
//裝置向GCM註冊完畢時進入
}
}
以上為行動裝置向GCM註冊的分享文章,跟Google提供的範例程式一樣,小黑人也只是把程式碼貼上而已,只需要把GCM ID更換和註冊完畢後要做的動作變更,其他部分皆沒有修改。
以上4大步驟就是行動裝置接收GCM推播訊息的流程,雖然整體看起來蠻多程式碼的,但是需要修改的程式碼卻只有一小部分,大部分都只要將程式碼貼上即可,註冊動作與接收動作完成就可以收到GCM的推播通知囉,大家可以試試看在App裡加入推播機制~
謝謝大家,如有任何問題都可以和小黑人一起交流討論!
☆小黑人☆
請問
回覆刪除我的Android SDK Manager裡面的Extras資料夾沒有一個Google Play Services,那這樣我要去哪裡找這個檔案??
您好,根據您的提問小黑人與您解答,
刪除如果Android SDK Manager裡的Extras沒有Google Play Services的話,
那可能是您ADT(Android Developer Tools)的版本比較舊版,
導致Android SDK Manager無法Update到一些附加開發工具,
所以您需要先更新ADT再進行Google Play Services下載的動作。
ADT的更新步驟如下 :
Eclipse上方工具列選擇"Help" → 點選"Install New Software" →
輸入"https://dl-ssl.google.com/android/eclipse/" → 更新"Developer Tools"。
感謝您的提問。
作者已經移除這則留言。
刪除作者已經移除這則留言。
刪除請問我照了程式碼後出現:
刪除MainActivity.java:
GooglePlayServicesUtil 無法解析
GooglePlayServicesUtil 無法解析
GoogleCloudMessaging 無法解析成類型
CPTabActivity 無法解析成類型
您好,根據您的提問小黑人與您解釋,
刪除無法解析的狀況應該是Google Play Services專案沒有導入進來,
導入Google Play Services專案步驟是:在您的專案上按右鍵,點選Properties,開啟視窗後左側列表點選Android,在下方Library區域裡按Add,將google-play-services_lib加入就可以囉,
最後CPTabActivity 這個要更改成MainActivity,這是小黑人不小心把MainActivity名稱更改到,
以上您可以再試試看。
感謝您的留言!
作者已經移除這則留言。
刪除作者已經移除這則留言。
刪除作者已經移除這則留言。
刪除看完這篇學到很多
回覆刪除可以請問一下CPTabActivity.class
是再做甚麼的嗎
您好,非常感謝您的支持 ^^
刪除根據您的提問小黑人與您解釋,
CPTabActivity.class其實就是MainActivity.class,
小黑人可能不小心按到把Main改成別的字串...
感謝您的提醒與留言,謝謝!
作者已經移除這則留言。
回覆刪除請問GCM registration id 第4步驟註冊的部分,是自動註冊的嗎?
回覆刪除如果是自動註冊要怎麼取得?
您好,很抱歉這麼久才回覆您,
刪除根據您的提問小黑人與您解釋,
應該是說您要先至GCM後台註冊一個推播裝置服務,然後GCM就會產生一個ID,這個ID就是所謂手機端的註冊ID。
感謝您的提問!
請問這程式碼完成後,基本執行會出現什麼結果??
回覆刪除首先在要做註冊的Activity裡添加註冊程式碼,小黑人以MainActivity作為範例。
如果像上述程式碼跟您建立在同個地方也可以??
我開啟程式後,什麼事情都沒發生,我是用HTTP來傳送。
您好,很抱歉這麼久才回覆您,
刪除根據您的提問小黑人與您解釋,
主要關鍵步驟是"您GCM的註冊ID",應該是說您要先至GCM後台註冊一個推播裝置服務,然後GCM就會產生一個ID,這個ID就是所謂手機端的註冊ID,然後手機端在正常的情況下是都不會有任何狀況發生,直到GCM後台有發送出推播訊息後手機端才會藉由ID來接收並顯示推播訊息。
感謝您的提問!
您好~
回覆刪除我用了您的程式一切都沒問題也能安裝成.apk
但是在手機中開啟程式後,沒有任何反應也沒有得到registration_id
我有哪邊步驟錯誤還是少做了甚麼??
您好,很抱歉這麼久才回覆您,
刪除根據您的提問小黑人與您解釋,
主要關鍵步驟是"您GCM的註冊ID",應該是說您要先至GCM後台註冊一個推播裝置服務,然後GCM就會產生一個ID,這個ID就是所謂手機端的註冊ID,然後手機端在正常的情況下是都不會有任何狀況發生,直到GCM後台有發送出推播訊息後手機端才會藉由ID來接收並顯示推播訊息。
感謝您的提問!
請問為什麼我把google-play-services_lib專案匯入後
回覆刪除CPU使用率 直接飆到100% 然後celipse 就出現GC錯誤
.記憶體不足的問題,試過重新安裝google-play-services了
您好,照著版主教學實作後,裝置一直沒有收到推播的訊息。
回覆刪除要如何才會接收到推播的訊息呢?感謝版主回覆。
小黑人你好,最近也要來實作GCM,不過卡在"import android.support.v4.content.WakefulBroadcastReceiver;"
回覆刪除是不是該class被Google給取消掉了?!