這次公司要我們做一個功能,就是當用戶成功注冊以后,他登錄以后要收到消息,當然這個消息是安裝了我們的手機APP應用的手機咯。
極光推送的網站的網址是:https://www.jpush.cn/
極光推送的官方API以及幫助文檔都在這里:http://docs.jpush.cn/display/dev/Index
其中服務端的接口以及示例代碼都在這里:http://docs.jpush.cn/display/dev/Server-SDKs
大家有興趣的可以看看,因為這次我做的不是客戶端APP,所以一筆帶過啦,就跟大家介紹一下C#端的吧。
首先我們下載一下極光推送的C#例子吧,如下圖。

然后例子里面有詳細的介紹,注釋什么的。
極光推送的NET.FRAMEWORK的版本號是4.0的,所以如果我們的網站如果是2.0的,那么就要把極光推送的代碼集成到WebService里面,然后從要用的時候直接調用這個WebService就行了。
下面是例子的源碼:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Collections; using cn.jpush.api; using cn.jpush.api.push; using cn.jpush.api.report; using cn.jpush.api.common; using cn.jpush.api.util; namespace JpushApiClientExample { class JPushApiExample { public class ExtralClass { public String sound = "ssss"; public String menu="button"; } static void Main(string[] args) { Console.WriteLine("************"); Console.WriteLine("*****開始發送******"); //String result; String app_key = "_"; String master_secret = "_"; //int sendno = 9; HashSet<DeviceEnum> set = new HashSet<DeviceEnum>(); set.Add(DeviceEnum.Android); set.Add(DeviceEnum.IOS); JPushClient client = new JPushClient(app_key, master_secret, 0, set, true); MessageResult result = null; NotificationParams notifyParams = new NotificationParams(); CustomMessageParams customParams = new CustomMessageParams(); //notifyParams. //傳入json字符串 String extras = null; extras = "{\"ios\":{\"badge\":88, \"sound\":\"happy\"}}"; //extras中有中文請用HttpUtility.UrlEncode編碼 //System.Web.HttpUtility.UrlEncode(notificationContent, Encoding.UTF8); Console.WriteLine("*****發送帶tag通知******"); /** *發送類型 *APP_KEY 通知 *TAG TAG *ALIAS ALIAS *REGISTRATION_ID REGISTRATION_ID */ notifyParams.ReceiverType = ReceiverTypeEnum.APP_KEY; notifyParams.SendNo = 256; //notifyParams.OverrideMsgId = "1"; result = client.sendNotification("酷派tag111111", notifyParams, extras); Console.WriteLine("sendNotification by tag:**返回狀態:" + result.getErrorCode().ToString() + " **返回信息:" + result.getErrorMessage() + " **Send No.:" + result.getSendNo() + " msg_id:" + result.getMessageId() + " 頻率次數:" + result.getRateLimitQuota() + " 可用頻率:" + result.getRateLimitRemaining() + " 重置時間:" + result.getRateLimitReset()); Console.WriteLine("*****發送帶tag消息******"); //customParams.addPlatform(DeviceEnum.Android); customParams.ReceiverType = ReceiverTypeEnum.TAG; customParams.ReceiverValue = "tag_api"; customParams.SendNo = 256; result = client.sendCustomMessage("send custom mess by tag", "tag notify content", customParams, extras); Console.WriteLine("sendCustomMessage:**返回狀態:" + result.getErrorCode().ToString() + " **返回信息:" + result.getErrorMessage() + " **Send No.:" + result.getSendNo() + " msg_id:" + result.getMessageId() + " 頻率次數:" + result.getRateLimitQuota() + " 可用頻率:" + result.getRateLimitRemaining() + " 重置時間:" + result.getRateLimitReset()); Console.WriteLine(); String msg_ids = "1613113584,1229760629,1174658841,1174658641"; ReceivedResult receivedResult = client.getReceivedApi(msg_ids); Console.WriteLine("Report Result:"); foreach(ReceivedResult.Received re in receivedResult.ReceivedList) { Console.WriteLine("getReceivedApi************msgid=" + re.msg_id+ " ***andriod received="+re.android_received+" ***ios received="+re.ios_apns_sent); } Console.WriteLine(); } public class IOSExtras { public int badge = 888; public String sound = "happy"; } } }
然后我們還是來結合例子一步一步走吧。
首先是發送通知:
Console.WriteLine("************");
Console.WriteLine("*****開始發送******");
//String result;
String app_key = "_";
String master_secret = "_";
//int sendno = 9;
HashSet<DeviceEnum> set = new HashSet<DeviceEnum>();
set.Add(DeviceEnum.Android);
set.Add(DeviceEnum.IOS);
JPushClient client = new JPushClient(app_key, master_secret, 0, set, true);
MessageResult result = null;
NotificationParams notifyParams = new NotificationParams();
CustomMessageParams customParams = new CustomMessageParams();
//notifyParams.
//傳入json字符串
String extras = null;
extras = "{\"ios\":{\"badge\":88, \"sound\":\"happy\"}}";
//extras中有中文請用HttpUtility.UrlEncode編碼
//System.Web.HttpUtility.UrlEncode(notificationContent, Encoding.UTF8);
Console.WriteLine("*****發送帶tag通知******");
/**
*發送類型
*APP_KEY 通知
*TAG TAG
*ALIAS ALIAS
*REGISTRATION_ID REGISTRATION_ID
*/
notifyParams.ReceiverType = ReceiverTypeEnum.APP_KEY;
notifyParams.SendNo = 256;
//notifyParams.OverrideMsgId = "1";
result = client.sendNotification("酷派tag111111", notifyParams, extras);
Console.WriteLine("sendNotification by tag:**返回狀態:" + result.getErrorCode().ToString() +
" **返回信息:" + result.getErrorMessage() +
" **Send No.:" + result.getSendNo() +
" msg_id:" + result.getMessageId() +
" 頻率次數:" + result.getRateLimitQuota() +
" 可用頻率:" + result.getRateLimitRemaining() +
" 重置時間:" + result.getRateLimitReset());
這里我們需要先了解幾個概念。
- APP_KEY:客戶端在極光推送里的唯一標識符,相當於ID
- Master_Secret:客戶端在極光推送的唯一標識符的密碼。
這個是我自己總結的,無非就是我們在極光推送ISP里的一個相當於對於APP應用的一個唯一進入憑證。
極光推送C#版本的SDK目前支持Android和IOS系統,因為上面的代碼是發送通知,而通知應該是對所有安裝了APP的人開放,所以應該選擇APP_KEY。
大家是不是對JpushClient這個類有些疑惑呢,下面就帶大家來解析這個類。
public class JPushClient
{
private PushClient _pushClient;
/// <summary>
/// 帶兩個參數的構造函數,該狀態下,ApnsProduction默認為true
/// </summary>
/// <param name="app_key">Portal上產生的app_key</param>
/// <param name="masterSecret">你的API MasterSecret</param>
public JPushClient(String app_key, String masterSecret)
{
HashSet<DeviceEnum> devices = new HashSet<DeviceEnum>();
devices.Add(DeviceEnum.IOS);
devices.Add(DeviceEnum.Android);
_pushClient = new PushClient(masterSecret, app_key, MessageParams.NO_TIME_TO_LIVE, null, true);
_reportClient = new ReportClient(app_key, masterSecret);
}
/// <summary>
/// 發送通知
/// </summary>
/// <param name="notificationContent">通知內容</param>
/// <param name="notifyParams"></param>
/// <param name="extras"></param>
/// <returns></returns>
public MessageResult sendNotification(String notificationContent, NotificationParams notifyParams, String extras)
{
return _pushClient.sendNotification(notificationContent, notifyParams, extras);
}
}
看來上面其實就是帶入了幾個參數,其核心是PushClient,磨刀不誤砍柴工,我們來看看PushClient這個類。
internal class PushClient:BaseHttpClient
{
private const String HOST_NAME_SSL = "https://api.jpush.cn";
private const String HOST_NAME = "http://api.jpush.cn:8800";
private const String PUSH_PATH = "/v2/push";
private String appKey;
private String masterSecret;
private bool enableSSL = false;
private long timeToLive;
private bool apnsProduction = false;
private HashSet<DeviceEnum> devices = new HashSet<DeviceEnum>();
public MessageResult sendNotification(String notificationContent, NotificationParams notParams, String extras)
{
if ( !string.IsNullOrEmpty(extras) )
{
notParams.NotyfyMsgContent.n_extras = extras;
}
notParams.NotyfyMsgContent.n_content = System.Web.HttpUtility.UrlEncode(notificationContent, Encoding.UTF8);
//notParams.NotyfyMsgContent.n_content = notificationContent;
return sendMessage(notParams, MsgTypeEnum.NOTIFICATIFY);
}
private MessageResult sendPush(MessageParams msgParams, MsgTypeEnum msgType)
{
String url = enableSSL ? HOST_NAME_SSL : HOST_NAME;
url += PUSH_PATH;
String pamrams = prase(msgParams, msgType);
//Console.WriteLine("begin post");
ResponseResult result = sendPost(url, null, pamrams);
//Console.WriteLine("end post");
MessageResult messResult = new MessageResult();
if (result.responseCode == System.Net.HttpStatusCode.OK)
{
//Console.WriteLine("responseContent===" + result.responseContent);
messResult = (MessageResult)JsonTool.JsonToObject(result.responseContent, messResult);
String content = result.responseContent;
}
messResult.ResponseResult = result;
return messResult;
}
}
從上面看來,這個地方有2個重點,一個是極光推送給我們的接口地址,這個非常重要,
另一個就是SendPush方法,下面的Parse方法轉換成極光推送認識的字符串也是相當的重要的。
private String prase(MessageParams message, MsgTypeEnum msgType)
{
StringBuilder sb = new StringBuilder();
sb.Append(message.SendNo).Append((int)message.ReceiverType).Append(message.ReceiverValue).Append(message.MasterSecret);
String verificationCode = sb.ToString();
//Console.WriteLine(verificationCode);
verificationCode = Md5.getMD5Hash(verificationCode);
sb.Clear();
message.setMsgContent();
String receiverVallue = System.Web.HttpUtility.UrlEncode(message.ReceiverValue, Encoding.UTF8);
sb.Append("sendno=").Append(message.SendNo).Append("&app_key=").Append(message.AppKey).Append("&receiver_type=").Append((int)message.ReceiverType)
.Append("&receiver_value=").Append(receiverVallue).Append("&verification_code=").Append(verificationCode)
.Append("&msg_type=").Append((int)msgType).Append("&msg_content=").Append(message.MsgContent).Append("&platform=").Append(message.getPlatform())
.Append("&apns_production=").Append(message.ApnsProduction);
if(message.TimeToLive >= 0)
{
sb.Append("&time_to_live=").Append(message.TimeToLive);
}
if(message.OverrideMsgId != null)
{
sb.Append("&override_msg_id=").Append(message.OverrideMsgId);
}
Console.WriteLine(sb.ToString());
//Debug.Print(sb.ToString());
return sb.ToString();
}
}
上面的調用方法其實極光推送里面也寫到了:http://docs.jpush.cn/display/dev/Push+API+v2
其實很明白了,上面的就是我們一開始帶進來的參數了,至於msgid,我猜想應該是極光推送給我們自動生成的一個自增長的ID,當然這個肯定是服務端生成的。
總結一下上面的一切的一切,其實無非就是方法之間的嵌套調用,真正的重點是調用到的最終的極光推送的URL的那個接口。相當於我們只是傳參數吧。
不過我猜想應該是極光推送的保密性,不然哪里會這么調用呢,直接傳個URL不就得了。偷笑~~
下面我們再來討論一下給單個用戶推消息,比如:有一個注冊用戶,他的文章需要審核才能發布,然后管理員審核了他的文章,當管理員審核通過的那么一瞬間,就應該給這個安裝了APP的用戶發送一條消息,提示這個用戶應該取發布文章了。這個就是向單個人去推的思路。
因為公司這次的項目只用到了ALIAS(別名),就想當於每個在手機上登錄的用戶,都邦定了一個別名,這個別名是唯一的,但是卻是區別於用戶名的,只要這個用戶邦定了這個別名,即使他的APP保持了登錄狀態(沒有注銷),那么他在任何時刻都可以接受到服務端SDK給這個用戶推送到的消息。如下圖。

這個別名是怎么產生的呢,因為我在webservice里面給了手機端一個登錄接口,這個登錄接口的形參里有別名,當然了,我是通過用戶名去尋找別名了,下面是代碼 ,最后返回的是一個JSON的字符串
//用戶登錄
[WebMethod(Description = "用戶登錄,帶入參數,用戶名,密碼以及數據庫的類型", EnableSession = true)]
public string LoginUser(string username, string password,string alias)
{
JavaScriptSerializer ser = new JavaScriptSerializer();
SysBaseTag sys = new SysBaseTag();
sys.data = new List<object>();
try
{
//輸入查詢用戶的SQL,查詢2張表,一張用戶表,一張用戶詳細信息表。
string sql = "select a.*,b.* from t_sys_user a,t_sys_userinfo b where a.id='" + username + "' and a.password='" + password + "' and a.id=b.userid";
//查詢出結果
DataSet dbSet = DBHelperSQL.Query(sql, DBHelperSQL.GetDBString(), 2);
if (dbSet != null && dbSet.Tables[0].Rows.Count > 0)
{
sys.message = "成功";
sys.result = true;
Users userInfo = new Users();
foreach (DataRow Row in dbSet.Tables[0].Rows)
{
userInfo.ID = Row["ID"].ToString();
userInfo.Phone = Row["Phone"].ToString();
userInfo.Name = Row["name"].ToString();
userInfo.Email = Row["email"].ToString();
userInfo.QQ = Row["qq"].ToString();
userInfo.CompanyName = Row["companyname"].ToString();
userInfo.ComapnyType = Row["companytype"].ToString();
userInfo.CompanyAddress = Row["companyaddress"].ToString();
userInfo.Website = Row["website"].ToString();
userInfo.Introduce = Row["introduce"].ToString();
userInfo.Products = Row["products"].ToString();
userInfo.Reward = Row["reward"].ToString();
}
sys.data.Add(userInfo);
sys.count = 1;
//臨時:插入別名
string sql_ins = "update t_sys_user set alias='" + alias + "' where id='" + username + "'";
int a=DBHelperSQL.ExecuteSQL(sql_ins,DBHelperSQL.GetDBString(),2);
}
else
{
sys.message = "失敗";
sys.result = false;
sys.count = 0;
}
}
catch (System.Exception e)
{
sys.message = e.Message;
sys.result = false;
sys.count = 0;
}
return ser.Serialize(sys);
}
因為客戶需要,我還做了一個表,專門存放手機消息的發送記錄,如果成功推送消息,那么就往這張表里插入一條記錄。
下面是JSON的示例,大家看看就好。

總之大家要明白,ALIAS是唯一的,不同於用戶名的,我們判斷的是這個人對應的手機APP的ALIAS(唯一性),而不是關心她的用戶名。
基本上原理就這樣,然后的話我們需要建立一個WEBSERVICE,ASMX文件,然后把這個ASMX文件部署到網上去。
比如我們調用這個WebService的地址是http://xxx.com/test.asmx,基本上就這個原理了。通過后台傳參數給WEBSERVICE。
//發布文章的時候同時發送短信。 public void PublishToMobile(string []ids) { cs.Common.Web.BasePage bp = new cs.Common.Web.BasePage(); string ids_=""; //最終得到的字符串 for (int i = 0; i < ids.Length; i++) { ids_ += ",'" + ids[i]+"'"; } ids_ = ids_.Substring(1); DataSet set = bp.DataManager.Fill("select * from cms_core_content where id in(" + ids_ + ")"); string title = ""; //標題 string content = ""; //內容 string publishDate = ""; //發布時間 foreach (DataRow Row in set.Tables[0].Rows) { title = Row["title"].ToString(); content = Row["Text"].ToString(); publishDate = Row["publishdate"].ToString(); string wsUrl = BL.AppContext.AppSettings["MobileWs"]; string rs = (string)BL.WebHelper.InvokeWebService(wsUrl, "GetMsg_ArticlePublish", new object[] { publishDate, title, content }); }
上面的是一段示例代碼,其中的InvokeWebService方法就是調用Webservie的方法了,第一參數是調用的URL,第二個是方法名,第三個是參數。
基本上好像沒什么說的了吧,反正一個是群發,一個是向某一個用戶發,而用戶因為邦定了別名,所以可以通過這個別名向指定的用戶進行發送消息,
下一次有空的話把微信那一塊的說一下,就是微信C#入門啦。
有什么問題還請大家多多切磋。
