2012年4月27日 星期五

C2DM Server(for PHP) (3)

更新:2013/04/01

發現有很多人搜尋到這篇,C2DM已經更名為GCM(Google Cloud Messaging for Android)

幫大家到找一個比較詳細的說明及操作,大家參考吧


參考資料:

http://www.androidhive.info/2012/10/android-push-notifications-using-google-cloud-messaging-gcm-php-and-mysql/

=========================================================================================================================================


Server 這一端不管用什麼Server都可以,可以使用Google App Engine(GAE)或是PHP都可以

如果使用GAE可以參考KEN YANG  http://blog.kenyang.net/2012/03/android-c2dm-sever.html


這裡主要以PHP為主,在C2DM我們需要前面提到SENDER_ID的Email和密碼

因為需要透過驗證得到Auth,透過那個Auth將訊息傳送出去,接下來實作。


我Google了一下發現有人已經有提供C2DM-PHP   https://github.com/lytsing/c2dm-php

不過我使用過後發現不曉得是改版過後還是什麼問題,導致現在這個版本在讀取Auth時

會出現get auth token error錯誤,無法傳送訊息


因此我自己改寫了一下在這裡下載


我稍為節省了一個步驟,在一開始就先把基本資料輸入進去

$c2dm = new c2dm($useremail ,$useremail_passwd , $long_registration_id);

在這邊就會先去跟 https://www.google.com/accounts/ClientLogin 抓你的 auth

錯誤也會在這裡顯示

接著

$c2dm->sendMessage(1,"Hello World!!");

就可以把你的訊息傳送出去,就完成了


其中c2dm.php要注意一下 94行
'data.message'    => $message //TODO: Add your data here.

data.message是data.[key],所以你Android MESSAGE_KEY_ONE 裡的字串是要一樣的
也就是說如果要改變數,PHP和Android兩邊的變數名稱要一樣


大功告成





有興趣可以到以下的參考連結:
http://blog.kenyang.net/2011/12/android-c2dm.html                 :)
http://blog.kenyang.net/2011/12/android-c2dm_22.html           :P
http://blog.kenyang.net/2012/03/android-c2dm-sever.html        :D
http://blog.kenyang.net/2012/03/android-c2dm-android.html     XD






C2DM Sign Up (2)

更新:2013/04/01

發現有很多人搜尋到這篇,C2DM已經更名為GCM(Google Cloud Messaging for Android)

幫大家到找一個比較詳細的說明及操作,大家參考吧


參考資料:

http://www.androidhive.info/2012/10/android-push-notifications-using-google-cloud-messaging-gcm-php-and-mysql/

=========================================================================================================================================


在C2DM 需要到官方去註冊你的App


比較重要
  1. 1.Package name of your Android app * 
  2. Role (sender) account email *
第1個是要和你剛剛Android App Package一樣,第二個也是跟Android 的SENDER_ID一樣
這兩項一定要對,否則可能會有問題。








有興趣可以到以下的參考連結:
http://blog.kenyang.net/2011/12/android-c2dm.html                 :)
http://blog.kenyang.net/2011/12/android-c2dm_22.html           :P
http://blog.kenyang.net/2012/03/android-c2dm-sever.html        :D
http://blog.kenyang.net/2012/03/android-c2dm-android.html     XD

C2DM Android建置 (1)

更新:2013/04/01

發現有很多人搜尋到這篇,C2DM已經更名為GCM(Google Cloud Messaging for Android)

幫大家到找一個比較詳細的說明及操作,大家參考吧


參考資料:

http://www.androidhive.info/2012/10/android-push-notifications-using-google-cloud-messaging-gcm-php-and-mysql/

=========================================================================================================================================



C2DM(Cloud to Device Messaging)GCM(Google Cloud Messaging for Android)

是Google還蠻新的技術,可以透過雲端傳訊到你的手機,詳細說明可以到官網看

https://developers.google.com/android/c2dm/


這項技術需要一些元件,一些限制

Android:  要在2.2以上的手機,且手機需要一個Google帳戶使用者
C2DM Server:  需要去官方去做認證(中間的溝通)
Server:  開發者的Server,主要可以從Server發送訊息出去


Manifest設定
首先先將Android的Manifest做設定,先設定好權限

<!-- Only this application can receive the messages and registration result --> 
<permission android:name="com.example.myapp.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="com.example.myapp.permission.C2D_MESSAGE" />

<!-- This app has permission to register and receive message -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

<!-- Send the registration id to the server -->
<uses-permission android:name="android.permission.INTERNET" />

在<application>裡面加入下面

<service android:name=".C2DMReceiver" />

<!-- Only C2DM servers can send messages for the app. If permission is not set - any other app can generate it --> 
<receiver android:name="com.google.android.c2dm.C2DMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND">
  <!-- Receive the actual message -->
  <intent-filter>
      <action android:name="com.google.android.c2dm.intent.RECEIVE" />
      <category android:name="com.example.myapp" />
  </intent-filter>
  <!-- Receive the registration id -->
  <intent-filter>
      <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
      <category android:name="com.example.myapp" />
  </intent-filter>
</receiver>

*紅色這邊要注意一下裡面的紅字粗體需要和你的Manifest檔的package的名稱一樣
*藍色部份是官方的一個的檔案(待會再程式再說明)
*橘色部份是待會接收訊息


官方資料:https://developers.google.com/android/c2dm/#manifest



接下來開始寫程式的部份
在這裡我們使用Google的Lib也就是剛剛提到的藍字部份可以點我下載

檔案放至成這樣



接下來程式目錄下新增一個C2DMReceiver.java 也是剛提到的橘色部份


在裡面打上下面的Code
package your.package;

import java.io.IOException;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

import com.google.android.c2dm.C2DMBaseReceiver;

public class C2DMReceiver extends C2DMBaseReceiver{
    
    private static final String TAG="C2DMReceiver";
    public C2DMReceiver()
    {
        super(C2DMActivity.SENDER_ID);
    }
    public C2DMReceiver(String senderId) {
        super(senderId);
        // TODO Auto-generated constructor stub
    }
    @Override
    protected void onMessage(Context context, Intent intent) {
        // TODO Auto-generated method stub
        Log.v(TAG, "C2DMReceiver message");
            
        }
    }
    @Override
    public void onError(Context context, String errorId) {
        // TODO Auto-generated method stub
        Log.v(TAG, "C2DMReceiver error");
    }
    
    @Override
    public void onRegistered(Context context, String registrationId)
            throws IOException {
        // TODO Auto-generated method stub
        super.onRegistered(context, registrationId);
        Log.v(TAG, "C2DMReceiver Register:"+registrationId);
    }
    @Override
    public void onUnregistered(Context context) {
        // TODO Auto-generated method stub
        super.onUnregistered(context);
        Log.v(TAG, "C2DMReceiver UnRegister");
    }    
}

大概說明一下
onMessage主要是接收到訊息的會進入的function
onRegistered註冊的時候,這裡要注意一下registrationId,因為在這溝通需要這一組registrationId才能將訊息傳送到App所以在這裡用Log標示出來registrationId

在這裡用一個比較的簡單的方式去寫接收到訊息

@Override
protected void onMessage(Context context, Intent intent) {
    // TODO Auto-generated method stub
    Log.v(TAG, "C2DMReceiver message");
    Bundle extras = intent.getExtras();
    if(extras!=null){
        String msg = (String)extras.get(C2DMActivity.MESSAGE_KEY_ONE);
        Log.v(TAG, "The received msg = "+msg);

        NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        Notification notification = new Notification(R.drawable.ic_launcher, msg, System.currentTimeMillis());
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, C2DMActivity.class), 0);
        notification.setLatestEventInfo(this, getString(R.string.app_name), msg, contentIntent);
        notificationManager.notify(0, notification);
        
    }
}

接到訊息後會跳出一個訊息顯示

基本上在Android 的C2DM的建置已經完成了,接下來回到主要的Activity.java去註冊C2DM

public class C2DMActivity extends Activity {
    /** Called when the activity is first created. */
    //Debugging
    private static final String TAG = "C2DM";
    private static final boolean D = true;
    
    public static final String SENDER_ID = "your email";     //使用C2DM服務的用戶帳號
    public static final String MESSAGE_KEY_ONE = "message";           //與Server接收消息的key值
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Log.v(TAG, "Start");
        C2DMessaging.register(this, SENDER_ID);        //register

    }
}

其中的SENDER_ID只是的你的email也就是等一下會介紹的與C2DM官網註冊的Email
這裡建議不用要個人的Email可以去另外申請一個C2DM專用的
MESSAGE_KEY_ONE這邊是所接收的KEY值必需要相同的名子,也是等會Server那邊會介紹到


到這邊Android的部份就完成了


Android Code:C2DMDemo



有興趣可以到以下的參考連結:
http://blog.kenyang.net/2011/12/android-c2dm.html                 :)
http://blog.kenyang.net/2011/12/android-c2dm_22.html           :P
http://blog.kenyang.net/2012/03/android-c2dm-sever.html        :D
http://blog.kenyang.net/2012/03/android-c2dm-android.html     XD








2012年4月23日 星期一

透過App連線AP(密碼) (2)

經過上次的練習發現,Google了一下,發現對於不同的AP的設定有不同的寫法

就好比你的AP所設定的加密方式是WPA、WEP或是沒設密碼

在Android的寫法都有些不同


//初始設定
WifiConfiguration config = new WifiConfiguration();  
config.allowedAuthAlgorithms.clear();
config.allowedGroupCiphers.clear();
config.allowedKeyManagement.clear();
config.allowedPairwiseCiphers.clear();
config.allowedProtocols.clear();
config.SSID = "\"" + SSID + "\"";


//沒設定密碼(開放式網路)
config.wepKeys[0] = "";
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.wepTxKeyIndex = 0;

//WEP
config.preSharedKey = "\""+Password+"\"";   
config.hiddenSSID = true;    
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);  
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);  
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);  
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);  
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);  
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);  
config.wepTxKeyIndex = 0;

//WPA
config.preSharedKey = "\""+Password+"\"";
config.hiddenSSID = true;  
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);  
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);              
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);              
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);        
config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);                     
config.status = WifiConfiguration.Status.ENABLED;

以下連結的作者他針對不同型式寫成了一個函式(93~136行)
參考連結:http://blog.csdn.net/cscmaker/article/details/7032277








2012年4月19日 星期四

透過App連線AP(密碼) (1)

程式碼如下

mWifiManager = (WifiManager)getSystemService(WIFI_SERVICE); 
try {
    WifiConfiguration wc = new WifiConfiguration();
    wc.SSID = "\"ICCL\"";                            //AP SSID NAME
    wc.preSharedKey  = "\"passwd\"";                    //AP passwd
    wc.hiddenSSID = true;
    wc.status = WifiConfiguration.Status.ENABLED; 

    wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
    wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
    wc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
    wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
    wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
    wc.allowedProtocols.set(WifiConfiguration.Protocol.RSN);

    
    int netId = mWifiManager.addNetwork(wc);
    boolean success = mWifiManager.enableNetwork(netId, false);        //Connect AP
    if(success){
        //只能說明你的密碼沒有輸錯,並且網路可用,但不一定連接上了!
        Toast.makeText(getApplicationContext(), "Connect ICCL AP.", Toast.LENGTH_SHORT).show();
    }else{
        Toast.makeText(getApplicationContext(), "Connect ICCL AP.", Toast.LENGTH_SHORT).show();
    }
    

} catch (Exception e) {
    Toast.makeText(getApplicationContext(), "Err", Toast.LENGTH_SHORT).show();
    e.printStackTrace();
}


透過App連線AP(密碼) (2)   有更詳細的說明