Google Cloud Messaging (GCM)

1 篇文章 / 0 new
author
Google Cloud Messaging (GCM)
Google 的service之一, Google Cloud Messaging (GCM) 訊息推播, 主要在讓我們省去架設自己的通訊伺服器, 其運作流程框架如圖
► 首先有Google帳號並啟用 GCM 服務
1. 啟用 Google APIs Consols , 開啟 GCM 服務
,
3. 建立專案, 產生 Server Key
 
► GCM for Android
引用的 api 有兩種, 一為 gcm.jar(非常久性支援,但檔案較小), 一為 google-play-services.jar(google 後續的主推方式, 從SDK Manage 內直接下載), 兩種處理程序幾乎完全相同. 下為使用 play-services 方式
AndroidManifest.xml 必要參數設定
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package=[AppPackage名稱] android:versionCode="1" android:versionName="1.0" >
    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" />
    <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="[AppPackage名稱].permission.C2D_MESSAGE" android:protectionLevel="signature" />
    <uses-permission android:name="[AppPackage名稱].permission.C2D_MESSAGE" />
    <uses-permission android:name="[AppPackage名稱].c2dm.permission.RECEIVE" />
    <application
        android:icon="@drawable/ic_launcher" android:label="@string/app_name" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <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="[AppPackage名稱]" />
            </intent-filter>
        </receiver>
        <service android:name=".GCMIntentService" />
    </application>
</manifest>
GCMBroadcastReceiver.java 接收外部訊息的進入點
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);
    }
}
GCMIntentService.java 處理訊息
public class GCMIntentService extends IntentService {
    public GCMIntentService() {
        super("GCMIntentService");//傳遞名稱用意??
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        Bundle extras = intent.getExtras();//訊息均封裝在此
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        String msgType = gcm.getMessageType(intent);
        if (!extras.isEmpty()) {
            if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(msgType)) {
                Log.d(TAG,"Type[ERROR]: " + msgType + ",body:" + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(msgType)) {
                Log.d(TAG,"Type[DELETED]: " + msgType + ",body:" + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(msgType)) {
                Log.d(TAG,"Type[MESSAGE]: " + msgType + ",body:" + extras.toString());
            }
        }
        GCMBroadcastReceiver.completeWakefulIntent(intent);
    }
}
► GCM Server for PHP
Server 端通常需要兩個程序, 一個讓 Android裝置進行登錄自己的 Registration ID, 這樣 Server 才知道要發送訊息給哪些裝置. 另一個就是發送訊息的程序, 但注意的是目前資料有 4K 限制, 所以當發送的對象多(rID)時, 宜採分批發送避免被 Google GCM捨棄.
訊息發送格式
$url = 'https://android.googleapis.com/gcm/send';// Googlo GCM Server
$fields = array(//資料格式
    'registration_ids' => array('rId','rId'),//對象
    'data' => array("message" => $message ),//訊息
);
$headers = array(//Server Key
    'Content-Type: application/json',
    'Authorization: key=' . $serverKey,//API Key
);
// 向Google GCM Server 發送訊息
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$response = curl_exec($ch);//GCM Server 回覆結果
if ($response === FALSE) {
    die('Problem occurred: ' . curl_error($ch));
}
$info = curl_getinfo($ch);
curl_close($ch);
$state = $info['http_code'];
if ($state == 200) {
    //echo $response . '';
    $json_response = json_decode($response);
    $multicast_id = $json_response->multicast_id;
    $success = $json_response->success;
    $failure = $json_response->failure;
    $canonical_ids = $json_response->canonical_ids;
    echo "GCM request $multicast_id was successful:
";
    echo "$success successful messages
";
    echo "$failure failed messages
";
    echo "$canonical_ids canonical ids
";
    gcm_results($fields['registration_ids'], $json_response->results);
} else if ($state == 400) {
    echo 'GCM JSON error';
} else { // 500 or 503
    echo "GCM error code $state";
}
 
function gcm_results($registration_ids, $results) {
  echo '<b>Result list:</b><hr>';
  foreach ($results as $key => $result) {
    echo 'TargetId=' . $registration_ids[$key] . '
';
    if (isset($result->error) && !empty($result->error)) {
      echo '<b>error=' .$result->error . '</b>'; // 無效ID
    } else {
      echo '<b>Send Ok</b>:'.$result->message_id . '';
    }
  }
}
回覆格式如下(JSON)
{
    "multicast_id":6704309358101356778, "success":1, "failure":1, "canonical_ids":0,
    "results":[
        {"error":"InvalidRegistration"},
        {"message_id":"0:1392177391536659%2bf58953f9fd7ecd"}
    ]
}
►GCM Server for Delphi
const
    sendUrl = 'https://android.googleapis.com/gcm/send';
var
    lRequest: TStringStream;
    response: String;//server 回應內容
    IdSSLIO: TIdSSLIOHandlerSocketOpenSSL;
begin
    //需要 libeay32.dll, ssleay32.dll,至於程式目錄下即可
    IdSSLIO := IdSSLIOHandlerSocketOpenSSL1;
    IdSSLIO.SSLOptions.Method := sslvSSLv3;
    IdSSLIO.SSLOptions.Mode := sslmUnassigned;
    lRequest := TStringStream.Create('{"registration_ids":["rID1","rID2"],"data":{"message":"訊息"}}', TEncoding.UTF8);
    with IdHTTP1 do
    begin
        IOHandler := IdSSLIO;//可直接用元件連接
        ConnectTimeout := 3000;
        HTTPOptions := [hoKeepOrigProtocol,hoForceEncodeParams];//一定要 hoKeepOrigProtocol
        Request.ContentType := 'application/json';
        Request.CharSet := 'UTF-8';
        Request.CustomHeaders.Clear;
        Request.CustomHeaders.Add('Content-Type: application/json');
        Request.CustomHeaders.Add('Authorization: key='+ServerAPIKey);
        Response.CharSet := 'UTF-8';
    end;
    try
        IdHTTP.response := Post(sendUrl, lRequest);
    except
    end;
    lRequest.Free;
    IdHTTP.Disconnect;
end;
OpenSSL http://indy.fulgan.com/SSL/
Free Web Hosting