這篇是舊版的,已經被deprecated,新版為GCM,新版的實作請看新版的Android篇這篇主要在說明Android端的實作第一篇在講參數說明第二篇在講流程說明第三篇在講server端的實作這篇主要會完成下列項目:
- 基本的manifest設定(加入receiver,permission)。
- 向C2DM 註冊。
- 接收自C2DM Sever回傳的registration id 並傳送 Registration Id 到我們的Server,以及接收Message
【1. 設定Manifest資料 】
這步驟,分了兩個部分!
第一個就是要先加入一個receiver,
記得下面的category android:name,
裡面的value要改成自己的package name
如下:
<!-- 用來接收C2DM Server的receiver,且要有send的permssion -->
<receiver android:name=".C2DMReceiver" 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="net.kenyang.android" />
</intent-filter>
<!-- Receive the registration id -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="net.kenyang.android" />
</intent-filter>
</receiver>
第二部分就是加入應有的permission,
<!-- 下面的net.kenyang記得要改成自己的package name -->
<permission android:name="net.kenyang.android.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="net.kenyang.android.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.INTERNET"/>
【2. 向C2DM註冊 】 這一步驟就是啟動C2DM,並告訴C2DM要註冊,
Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
registrationIntent.putExtra("app", PendingIntent.getBroadcast(SelectLoginMode.this, 0, new Intent(), 0)); // boilerplate
registrationIntent.putExtra("sender", "xxxxx@gmail.com"); // 記得這邊要填入當初你在第三篇註冊的MAIL
startService(registrationIntent);
【3. 接收與傳送資料 】 這一步驟就是寫一個receiver,
這個receiver會
- 接收C2DM傳來的registration id,
- 也會接收C2DM傳來的message(這個message就是我們Server傳給C2DM的message)
- 並且將registration id傳送到我們第三篇實作的server上面去
我們先在receiver中寫一個函數將registration id傳送至我們第三篇實作的server上面去,
server只要收到,就會傳送資料到C2DM上!
private void fnRegistrationDone(final String strRegistrationId){
try{
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection conn = (HttpURLConnection) new URL("http://c2dm.kenyang.net/registration").openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("GET"); // 因為在GAE上面的servlet,我是用get method
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", strRegistrationId.getBytes().length); // 告訴c2dm要傳送的資料長度
// 送出資料
OutputStream out = conn.getOutputStream();
out.write(strRegistrationId.getBytes());
out.close();
conn.fnClose();
// 到這,一個註冊就完成,接著就是等著收資料
}
});
thread.start();
}catch (Exception e) {
}
}
接著開始寫接收資料(registration_id, message)的code,如下:
@Override
public void onReceive(Context context, Intent intent) {
// 接收到C2DM的訊息
if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {
String strRegistrationId = intent.getStringExtra("registration_id");
// 如果註冊失敗
if (intent.getStringExtra("error") != null) {
Log.d("Ken.yang", "c2dm registration fail");
// Registration 成功
} else if (strRegistrationId != null) {
// 把registration_id傳到我們server(呼叫我們上面寫的函數)
fnRegistrationDone(strRegistrationId);
}
} else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
// 接收來自C2DM的MESSAGE,這message就是我們server傳給C2DM的 (可以看第三篇)
if (intent.getExtras().containsKey("keyHello")){
strValue = intent.getExtras().getString("keyHello");
Log.d("Ken.yang", "C2DM=== receive" + strValue);
}
}
}
完成上面步驟,就完成c2dm了!
也可以收到訊息了!!!!
因為我們
第三篇server上傳送的訊息是fromKen,
所以這裡收到的也是fromKen!!
這篇是舊版的,已經被deprecated,新版為GCM,新版的實作請看新版的Server篇最後一篇進入到了Android C2DM的coding了!!
哈! 這篇存在草稿也三個月了..........
今天終於有一點點時間來修改!
第一篇在講參數說明第二篇在講流程說明這篇專注於server端的實作下一篇才會專注於android端的實作OK,
在coding之前,請先去
Google官網註冊你的app,
比較要注意的是下面兩項
- Package name of your Android app *
- Role (sender) account email *
第1項,是指你的Android app的package name,這裡一定要填對,不然C2DM Server不知道送到哪個app去。
第2項,是指用來傳遞訊息的帳號,也就是開發者的帳號,這裡的建議是不要用個人帳號,建議新申請另一個帳號來使用。
完成上面註冊動作以後,就可以開始coding了!
網路上的code教學都是拿
Google官網上面放的範例(JumpNote),
我覺得這樣不太native,畢竟這是別人寫的app!
所以我直接講最基本的流程!
接下來的code大概會分成下面幾種:
- 實作Server端:使用Google Client Login API取得Auth token,並且存起來。
- 實作Server端:Sending Message to C2DM Server。
- Android端:基本的設定。
- Android端:向C2DM 註冊,並且取得registration id。
- Android端:傳送 Registration Id 到我們的Server
因為其實有點多,所以就分成兩篇來打,
一篇為Sever篇,就是此篇!
另一篇為Android篇,就是下篇!
【1. 使用Google Client Login API取得Auth token 】因為得把token傳至C2DM Server,
C2DM Sever才知道你有登入,且是合格的。
至於Google Client Login API的流程在這就不贅述,
就直接實做! 但大家可以去
Google Client Login API官網看!!!
這裡我是架在
Google App Engine上,把
GAE當作我們的Sever。
由於auth token可以重複使用,
所以我們可能可以每段時間去執行ClientLogin,
並取得auth token!
這時候就可以用GAE的cron,可能設定每天去登入一次以取得token。
而Client Login的code如下:
String strClientLoginUrl = "https://www.google.com/accounts/ClientLogin"; // client login的url
String strAccountType = "accountType=HOSTED_OR_GOOGLE&";// 你要登入的帳號型態,這裡就輸入HOSTED_OR_GOOGLE
String strEmail = "Email=test@gmail.com&"; // 你的email!!
String strPasswd= "Passwd=123456&"; // 你的密碼
String strService= "service=ac2dm&"; // 你登入以後,要拿這token存取Google哪個Service,這裡是ac2dm
String strSource= "source=KenYang-AndroidC2DM-1.0";// 這個只是用來identify你的application,格式要companyName-applicationName-versionID
HttpURLConnection conn = (HttpURLConnection) new URL(strClientLoginUrl).openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST"); // 設定request Method為POST
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
// 送出資料
OutputStream out = conn.getOutputStream();
String strPostData = strAccountType+strEmail+strPasswd+strService+strSource;
out.write(strPostData.getBytes());
out.close();
// 取得response code,成功的話就是200
resp.getWriter().println(conn.getResponseCode()+ "</br>");
// 把資料讀進來並且印出來
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));
String strLine = "";
while((strLine=reader.readLine())!=null){
resp.getWriter().println(strLine+"</br>");
}
正常來說,如果你帳號沒有問題,
或者密碼沒有輸入錯誤,
或者的確有這帳號存在!
那麼response code會是200!
就代表登入成功!
此時就要取得auth token。
印出來的資料如下:
SID=DQAAAGgA...7Zg8CTN
LSID=DQAAAGsA...lk8BBbG
Auth=DQAAAGgA...dk3fA5N
這時候,只要取得最後那一行資料即可!
就是Auth那一行!!!
然後把Auth存起來!
這裡我是先存在GAE的datastore!
以利待會使用!
【2. 傳送資料至C2DM Server 】至於傳送甚麼資料,可以來這
官網看詳細參數說明!
這邊就簡單地說明幾種"必需"的參數!
- registration_id :android 裝置的id,一定要傳這資料給C2DM Server,C2DM才知道訊息要傳給誰,至於這個值,是來自android device的!
- collapse_key :這個value可以是隨意的值,這個參數的用意是怕android device的狀態是離線狀態,一旦狀態恢復為連線,避免使用者突然收到大量訊息!(這個參數可以每次都不一樣,也可以每次都一樣)
- data.<key> :這個參數就是你要傳給android device的訊息了! 型態為key-value。如data.keyName=value
- GoogleLogin auth :這個不是要post的參數,而是要送出的header值! 而值就是上面存在datastore裡面的Auth!
實際的code如下:
String strSendUrl = "https://android.apis.google.com/c2dm/send"; // c2dm的url
String strRegistrationId = "registration_id="+req.getParameter("device_token")+"&"; // 接收來自android傳來的參數
String strCollapse= "collapse_key=1&"; // 這個參數上面說明了
String strAuth = "xxxxxx"; // 從datastore撈出來的值,這裡就不寫有關datastore的操作了
String strData = "data.keyHello=fromKen"; // 你要送的訊息
String strPostData = strRegistrationId+strCollapse+strData;
HttpURLConnection conn = (HttpURLConnection) new URL(strSendUrl).openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Authorization", "GoogleLogin auth=" + strAuth); // 設定header
conn.setRequestProperty("Content-Length", Integer.toString(strPostData.getBytes().length)); // 告訴c2dm要傳送的資料長度
// 送出資料
OutputStream out = conn.getOutputStream();
out.write(strPostData.getBytes());
out.close();
// 看response code, 200為OK
resp.getWriter().println(conn.getResponseCode()+ "</br></br>");
完成上面的步驟,server端就完成了!
但還要完成android端,才能真正收到訊息!
下一篇會專注於android端的實作
這篇似乎是我歷年來第一篇有關M$的筆記.........
真是寫得有點心不甘情不願XD
畢竟本人真的是沒有很喜歡M$的東西,
當然不是因為M$不好,M$也有它好的一面,
只能說或許是習慣問題....
OK,進入正題,
這篇主要是去說明如何利用C#去控制你的網路攝影機,
且是使用Emgu這套dll,
甚麼是Emgu呢?
他和OpenCV有點關聯,
OpenCV相信不管是Java, C, C++等language的開發者,都了解OpenCV是甚麼!?
簡單說,OpenCV是一套強大的影像處理library,由INTEL開發,
非常強大,甚至你可以利用OpenCV去做到OCR,很方便。
也由於OpenCV沒有支援C#,那C#要怎麼使用OpenCV呢?
就是靠
Emgu,
Emgu是一套允許OpenCV的function在C#等語言中被使用。
但我們這邊並不會使用到OpenCV的功能,
就是簡單的介紹Emgu很基本的功能,
就是存取攝影機,
首先先去
下載Emgu,並且安裝,
安裝完成以後就可以開始寫程式....
看你是要開啟一個WPF專案,還是一個Window Form專案,
建議你開啟Window Form,因為到時Webcam回傳回來的image型態,
可以直接在 Window Form中的pictureBox裡面使用。
開啟以後,就在你的專案中加入reference,
加入以下四個dll,dll的位置就是在你安裝Emgu位置的bin底下:
- Emgu.CV.dll
- Emgu.CV.ML.dll
- Emgu.CV.UI.dll
- Emgu.Util.dll
加入以後,請先儲存你的專案,
儲存以後請在你安裝Emgu位置的bin底下找到兩個dll,
- opencv_core231.dll
- opencv_highgui231.dll
把這兩個dll放置到你的專案的/bin/Debug/底下。
因為Emgu.CV.dll會使用到上述兩個dll。
完成上述動作以後就開始寫code,
先import會使用到的lib,如下:
using Emgu.CV;
using Emgu.CV.Structure;
先宣告一個Capture物件,如下:
private Capture cap = null; // Webcam物件
這個物件就是用來連結到你的webcam。
接著在Form1_Load event中,
連結到攝影機以及建立一個event用來抓取畫面,如下:
private void Form1_Load(object sender, EventArgs e)
{
cap = new Capture(0); // 連結到攝影機0,如果你有兩台攝影機,第二台就是1
Application.Idle += new EventHandler(Application_Idle); // 在Idle的event下,把畫面設定到pictureBox上(當然你也可以用timer事件)
}
接下來要寫抓取畫面event的code,
void Application_Idle(object sender, EventArgs e)
{
Image<Bgr, Byte> frame = cap.QueryFrame(); // 去query該畫面
pictureBox1.Image = frame.ToBitmap(); // 把畫面轉換成bitmap型態,在餵給pictureBox元件
}
完成以後按下F5執行,應該就可以順利取得攝影機畫面瞜!