2013年3月27日 星期三

Android GCM 推播

首先先介紹一下GCM的流程:












1.向Google GCM Server 註冊 Registration ID
2.GCM 會回傳 一組獨一無二的Registration ID
3.把Registration ID 傳給我們的User Server
4.User Server 裡用這組ID  傳送訊息給GCM
最後GCM 就會把訊息傳給各個 Android Mobile



一. 申請 

首先GCM 為免費的服務平台、每封訊息最大4KB、訊息的存活最長時間為4週(2419200秒)

1.需要有一個Google 帳號
2.開啟GCM Project    http://developer.android.com/google/gcm/gs.html


















3.記住Sender ID
















4.開啟GCM 服務


















5. 創造一個新的Android API KEY

















二.Client 端  註冊

Libary:Build Path
需要將gcm.jar 放到libs 資料夾
















Java Build Path gcm.jar















1.權限的註冊

(紅字注意 要設定程跟package name 一樣)


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.pushnotification"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />
    
    <permission android:name="com.example.pushnotification.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="com.example.pushnotification.permission.C2D_MESSAGE" /> 

<!-- App receives GCM messages. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- GCM connects to Google Services. -->
<uses-permission android:name="android.permission.INTERNET" /> 
<!-- GCM requires a Google account. -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!-- Keeps the processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK" />    
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <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>
        <service android:name=".GCMIntentService" />
        <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" />
   <category android:name="com.example.pushnotification" />
 </intent-filter>
</receiver>
    </application>

</manifest>

2.建立GCMIntentService物件


public class GCMIntentService extends GCMBaseIntentService {
public static final String SENDER_ID = "123456789";
public GCMIntentService(){
super(SENDER_ID);
}
@Override
protected void onError(Context arg0, String arg1) {
}
@Override//收到傳送過來的訊息 產生一個 Notitfication通知
protected void onMessage(Context arg0, Intent arg1) {            
NotificationManager myNotificationManager = (NotificationManager)arg0.getSystemService(Context.NOTIFICATION_SERVICE);
int icon = R.drawable.ic_launcher;
CharSequence tickerText = "Hello";
long when = System.currentTimeMillis();
Notification myNotification = new Notification(icon,tickerText,when);
Context context = getApplicationContext();
CharSequence contentTitle = "My notification";
CharSequence contentText = "Hello World!";
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
myNotification.icon = R.drawable.ic_launcher;
myNotification.flags = Notification.FLAG_AUTO_CANCEL;
myNotification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
myNotificationManager.notify(1, myNotification);
Log.i("asdf",""+myNotificationManager);
}
        
@Override//註冊ID
protected void onRegistered(Context arg0, String arg1) {
                //arg1 GCM 回傳回來的Registration ID 
        //在此可以將Registration ID 回傳 User Server
Log.i("bbbbbb",arg1);
}
@Override
protected void onUnregistered(Context arg0, String arg1) {
}
}

3. 建立Activity 呼叫 GCMIntentService


public class MainActivity extends Activity {

private Button RegisteringC2DM;
private Button UnregisteringC2DM;

private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById();

Log.i(TAG,"regId = "+regId);
setRegisteringC2DM();
setUnregisteringC2DM();


}
private void findViewById() {
RegisteringC2DM  =(Button)findViewById(R.id.RegisteringC2DM);
UnregisteringC2DM  =(Button)findViewById(R.id.UnregisteringC2DM);
}
private void setRegisteringC2DM() {
RegisteringC2DM.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                                //註冊
                                GCMRegistrar.checkDevice(this);
                GCMRegistrar.checkManifest(this);                 
                String regId = GCMRegistrar.getRegistrationId(this);
                                if(regId.equals("")){
                                      GCMRegistrar.register(MainActivity.this, GCMIntentService.SENDER_ID);   
                                }
Log.i(TAG,"RegisteringC2DM onClick");
}
});
}

private void setUnregisteringC2DM() {
UnregisteringC2DM.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                                //取消註冊
                                Intent unregIntent = new Intent("com.google.android.c2dm.intent.UNREGISTER");
unregIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0)); startService(unregIntent);                                Log.i(TAG,"UnregisteringC2DM onClick");
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}

}



三. Server 端 傳送Message


Libary:Build Path
需要將gcm-server.jar 放到libs 資料夾



















Java Build Path gcm-server.jar
















1.權限的註冊


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.pushnotificationserver"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="16" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.pushnotificationserver.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>
    </application>
</manifest>

2.建立Activity 傳送Message



public class MainActivity extends Activity {
private Button getToken;
private Button sendMessage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getToken = (Button)findViewById(R.id.getToken);
getToken.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable(){
@Override
public void run() {
String devices = "APA91bEFZLsH0Pbbd6u0j8JszJ33pB9zn2WpcPJ6nz0eVGtPwk24IRFvLOHVc1LiljIwxPqfSQOGKLZHKBzeGerSR0FUAXBykUDkR3Dwij9nUgHzJcdMEIG3_fG_Kqq8g8BmLiaXH4AXS2x3X6K";//Client 端的 Registration ID

Sender sender = new Sender("AIzaSyBESI-p6XynQoKvKSt9EKIaIP2lTDZc");// Android API KEY

Message message = new Message.Builder().addData("message", "123456").build();//傳送的訊息
Result result = null;
try {
result = sender.send(message, devices, 5);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (result.getMessageId() != null) {
Log.i("result", "getMessageId = "+result.getMessageId());
String canonicalRegId = result.getCanonicalRegistrationId();
Log.i("canonicalRegId", "canonicalRegId = "+canonicalRegId);
}
}
}).start();
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
















10 則留言:

  1. 請問能給我原始碼嗎? 照的打不知道錯在哪裡 手機一直當機

    回覆刪除
  2. 你可以用模擬器去跑~~不一定要用手機真的去試

    回覆刪除
  3. 請問 假設我們使用GCM推播 一開始要申請的Registration ID 只要開發者(一位)申請下來,就能同時推播多台android手機嗎?,還是"接受推播訊息"者也各自需要申請一組Registration ID 才能接收訊息 ? (假設已把GCM功能做成APP)

    回覆刪除
    回覆
    1. 妳好!! 一開始開發者會去GCM 申請 sender ID 。 之後 各個手機會去申請Registration ID 這是辨別各個手機裝置的ID 。透過傳送給同一個sender ID 多個Registration ID 可以達成同時推播多台機器,置於怎麼同時傳送多個Registration ID 網上有很多範例可以參考

      刪除
    2. 接收訊息的功能 妳可以參考步驟2 跟3 希望對妳有幫助

      刪除
    3. 您好! 那有可能我只申請一組sender ID 然後推播到其他手機裝置(未申請sender ID)嗎?

      刪除
  4. 作者已經移除這則留言。

    回覆刪除
  5. 作者已經移除這則留言。

    回覆刪除
  6. 你好
    我在網路上看見您關於gcm的文章
    我願意支付5000學費請您利用遠端軟體演練一次gcm給我看

    假如可以請於2/6 2200前聯絡在下
    謝謝

    email embedorg@gmail.com
    QQ 2047992324
    wechat jimmyyjlee
    teamviewer 608 410 962
    skype jimmy.yj.lee (李彥儒_tainan)
    LINE ID jimmy168line

    回覆刪除
  7. 不好意思請問一下regId是由clien端向sever端申請然後再把regId存進sever端裡嗎?
    那如果我把clien端的apk放進手機裡,我應該怎麼做才能發送regId的申請呢?

    回覆刪除