以下圖片畫面僅供參考,畫面會隨Google改版而有所變更。
1. 申請Key和ProjectID的網址
https://console.developers.google.com
2. 取得 金鑰
專案 -> 憑證
新增憑證 -> API 金鑰 -> 伺服器金鑰
推播需建立伺服器憑證
此金鑰是推播訊息發送端使用的。
3. 取得專案編號 ProjectID
專案 -> 首頁 -> 右手邊區塊的ID後面的數字編號
也就是下圖紅框內的數字(不同的專案,會有不同的ID)
此ID是推播訊息接收端使用的,也就是要打入Android程式碼中的編號
4. Android 程式
AndroidManifest.xml
<!-- 開網路 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 接收 GCM 用 -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- 用來連接到 Google Services -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 需要使用 Google 帳戶資訊(4.0.4以下版本需要使用者帳戶) -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!-- 收到訊息時保持 CPU 休眠 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- 紅色部份,請換成 package name -->
<permission android:name="com.app.name.permission.C2D_MESSAGE" android:protectionLevel="signature" /><uses-permission android:name="com.app.name.permission.C2D_MESSAGE" />
<application>
<activity android:name="..............................">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 允許 GCMBroadcastReceiver 接收處理來自 GCM 所 SEND 出來的 RECEIVE 跟 REGISTRATION 這兩個 Intent -->
<receiver android:name="com.google.android.gcm.GCMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<!-- 紅色部份,請換成 package name -->
<category android:name="com.app.name" />
</intent-filter>
</receiver>
<!-- 繼承自 GCMBaseIntentService 的類別, 若由 GCMBroadcastReceiver 呼叫則不能改類別名 -->
<service android:name=".GCMIntentService" />
</application>
5. Android程式 手機訊息設定
建立 GCMIntentService.java
package com.app.name;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.app.name.R;
import com.google.android.gcm.GCMBaseIntentService;
public class GCMIntentService extends GCMBaseIntentService {
public GCMIntentService() {
super( ProjectID );
}
@SuppressWarnings("deprecation") //沒加會有警告訊息
private static void generateNotification(Context context, String message) {
long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
//這裡可以設定推播通知的icon
Notification notification = new Notification(R.drawable.appicon, message, when);
//這裡可以設定推播通知的標題
String title = Title;
//這裡可以設定當點選推播通知的時候要開起哪支程式
Intent notificationIntent = new Intent(context, MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, title, message, intent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.defaults |= Notification.DEFAULT_SOUND;
notification.defaults |= Notification.DEFAULT_VIBRATE;
notificationManager.notify(0, notification);
}
protected void onError(Context arg0, String arg1) { }
protected void onMessage(Context arg0, Intent arg1) {
Log.d("GCM", "RECIEVED A MESSAGE");
generateNotification(arg0, arg1.getStringExtra("message"));
}
protected void onRegistered(Context arg0, String arg1) { }
protected void onUnregistered(Context arg0, String arg1) { }
}
6. Android程式 手機註冊
手機註冊取回Google Token,並登錄 ProjectID
(1)需搭配Thread使用
(2)不會100%成功,所以需搭配迴圈或遞迴來重覆執行
//取得Google token
private String Token = "";
private void getRun()
{
Message msg2 = new Message ( ) ;
GCMRegistrar.checkDevice(this);
GCMRegistrar.checkManifest(this);
if (GCMRegistrar.isRegistered(this)) {
Log.d("info", GCMRegistrar.getRegistrationId(this));
}
try
{
//目前失敗最高七次,取回空白
Token = GCMRegistrar.getRegistrationId(this);
//Thread 使用註記
msg2.what = GUI_OK2;
MainActivity.this.myMessageHandler.sendMessage ( msg2 ) ;
}
catch(Exception e)
{
Toast.makeText(MainActivity.this, "Ex."+ e.getMessage(), Toast.LENGTH_LONG).show();
}
if (Token.equals("")) {
//將步驟3取得的ProjectID,放進來
GCMRegistrar.register(this, ProjectID );
Log.d("info", GCMRegistrar.getRegistrationId(this));
} else {
Log.d("info", "already registered as" + Token);
}
//這裡的regId就是前面server端所需的裝置ID
}
7. 把取到的Token記錄,想辦法存到資料庫,並且和使用者帳號有關連。
8. 編寫伺服器端的發送程式
using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
namespace PUSH
{
public static class AndroidGSM
{
private static string BrowserAPIKey = "AIzaSyCviYfVwvXXXXXXXXXXXXXXXXXXXXXXXE"; // Server App key
private static string tickerText = "ProjectTestGCM"; //registration_ids http ticker
private static string contentTitle = "ProjectTestGCM"; //registration_ids http title
//private static string sSource_sms = "APP_ProjectTest";
/// <summary>
/// Android 推播程式
/// </summary>
/// <param name="token"></param>
/// <param name="msg"></param>
public static void SendAndroid(string token, string msg)
{
RunSend(token, msg);
}
/// <summary>
/// Android 推播解析
/// </summary>
/// <param name="id">這裡請填入要傳送的裝置ID</param>
private static void RunSend(string id, string message)
{
/*
* { "registration_ids": [ "{0}" ], "data": {"tickerText":"{1}", "contentTitle":"{2}", "message": "{3}"}}
*/
string response = "";
string postData =
"{ \"registration_ids\": [ \""
+ id + "\" ], \"data\": {\"tickerText\":\""
+ tickerText + "\", \"contentTitle\":\""
+ contentTitle + "\", \"message\": \""
+ message + "\"}}";
//十次機會,如果十次都錯,那就放棄發送吧!
for (int i = 0; i < 10; i++)
{
response = "";
string err = "";
response = SendGCMNotification(BrowserAPIKey, postData, out err);
if (err.Length == 0)
{
break;
}
else
{
Thread.Sleep(500); //回傳錯誤,暫停0.5秒
Console.Write(" ...");
}
}
Console.WriteLine(response);
}
/// <summary>
/// Android GCM功能
/// </summary>
/// <param name="apiKey"></param>
/// <param name="postData"></param>
/// <param name="ermsg"></param>
/// <param name="postDataContentType"></param>
/// <returns></returns>
private static string SendGCMNotification(string apiKey, string postData, out string ermsg, string postDataContentType = "application/json")
{
ermsg = "";
ServicePointManager.ServerCertificateValidationCallback
+= new RemoteCertificateValidationCallback(ValidateServerCertificate);
// MESSAGE CONTENT
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// CREATE REQUEST
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://android.googleapis.com/gcm/send");
Request.Method = "POST";
Request.KeepAlive = false;
Request.ContentType = postDataContentType;
Request.Headers.Add(string.Format("Authorization: key={0}", apiKey));
Request.ContentLength = byteArray.Length;
Stream dataStream = Request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
// SEND MESSAGE
string error = "";
try
{
WebResponse Response = Request.GetResponse();
HttpStatusCode ResponseCode = ((HttpWebResponse)Response).StatusCode;
if (ResponseCode.Equals(HttpStatusCode.Unauthorized) || ResponseCode.Equals(HttpStatusCode.Forbidden))
{
ermsg = error = "Unauthorized - need new token";
}
else if (!ResponseCode.Equals(HttpStatusCode.OK))
{
ermsg = error = "Response from web service isn't OK";
}
StreamReader Reader = new StreamReader(Response.GetResponseStream());
string responseLine = Reader.ReadToEnd();
Reader.Close();
return responseLine;
}
catch (Exception e)
{
ermsg = error = e.ToString();
}
return error;
}
public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
}
}
}
9. 完成。
{ "registration_ids": [ "{0}" ] , "data": {"tickerText":"{1}", "contentTitle":"{2}", "message": "{3}"}}
同一訊息,要同時傳送給n個行動裝置時
針成上面的 JSON 中的 registration_ids 去修改 ( 一次上限1000個 )
例如:
一個行動裝置時:
"registration_ids": [ "A0001" ]
兩個行動裝置時
"registration_ids": [ "A0001" , "A0002" ]
多個行動裝置時
"registration_ids": [ "A0001" , "A0002".... "A000n" ]
{
"registration_ids": [
"APA91bGcMdbuJ3ghvRNpvUhL69MMag2uofIMnWSbPeVUpts17a6DTDnZmxcMAuRK6vn34AUb9gNiJ74cM-Y1_Lw7BZkwBhqM3oRyz6Z98HYxWymhuO_SdAsavYM9JtodPLEC02zbaJBD"
,
"APA91bHBib2OQ0RSPknW2xKxm3p2aK7R9sUP0CFcMGFgX9pi1r6FEQRlaAOcvJa_FWdgIl-OrY-nSBrYD7jqRFULae1bhW06F_QMc7czHdEwj7KaC9vfa75XIZYFvDTnHTcaQbpEfXWB"
],
"data": {"tickerText":"ticker", "contentTitle":"title", "message": "測試訊息"}
}
上面的是同時發送給兩個行動裝置的完整JSON
{
"multicast_id":9999992091979545599,
"success":2,
"failure":0,
"canonical_ids":0,
"results":[
{"message_id":"0:9495592993591952%ba5925e9f9fd9ecd"}, {"message_id":"0:9495592993590356%ba5925e9f9fd9ecd"}
]
}
上面是由上面測試的JSON,,同時發送給兩個行動裝置
由GOOGLE回傳兩個都成功的結果
{
"multicast_id":9999992091979545599,"
success":1,
"failure":1,
"canonical_ids":0,
"results":[
{"message_id":"0:1447573717077899%ba7327e2f7fd7ecd"},
{"error":"InvalidRegistration"}
]
}
上面是由上面測試的JSON,同時發送給兩個行動裝置
由GOOGLE回傳一個成功,一個失敗的結果