Files
g.hnyhua.cn/Jiguang.JPush/JPushV3.cs
2026-02-07 15:48:27 +08:00

709 lines
18 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Configuration;
using System.IO;
using System.Collections;
using Jiguang.JPush.Model;
/*
* 参考文档http://docs.jpush.cn/display/dev/Index 选择里面的:服务器端 APIPush-API-V3
*
* 极光推送的网站的网址是https://www.jpush.cn/
* 旧版本V2 http://docs.jpush.cn/display/dev/Push+API+v2
* 最新版本V3 http://docs.jpush.cn/display/dev/Push-API-v3
*
* 其中服务端的接口以及示例代码都在这里http://docs.jpush.cn/display/dev/Server-SDKs
*/
/// <summary>
/// 极光推送的最新版PUSH-API-V3
/// 参考地址 http://docs.jpush.cn/display/dev/Push-API-v3
/// POST https://api.jpush.cn/v3/push
/// </summary>
namespace Jiguang.JPush
{
public class JPushV3
{
/// <summary>
/// 应用标识:极光推送的用户名
/// </summary>
private readonly string AppKey = ConfigurationManager.AppSettings["JGAppKey"];
/// <summary>
/// 极光推送的密码
/// </summary>
private readonly string MasterSecret = ConfigurationManager.AppSettings["JGAppSecret"];
/// <summary>
/// 极光推送请求的url地址
/// </summary>
private readonly string RequestUrl = "https://api.jpush.cn/v3/push";
/// <summary>
/// 查询推送结果请求的Url地址
/// </summary>
private readonly string ReceivedUrl = "https://report.jpush.cn/v3/received";
/// <summary>
/// 推送消息并保存到已发送表
/// </summary>
/// <param name="RegistrationIDList">推送TokenID集合</param>
/// <param name="title">标题</param>
/// <param name="senduser">作者</param>
/// <param name="toid">推送对象ID</param>
/// <param name="contype">推送对象</param>
/// <param name="dataid"></param>
/// <param name="strMsg">推送内容</param>
/// <param name="is_production"></param>
/// <param name="strLog">返回日志</param>
/// <returns></returns>
public bool SendPushV2(List<string> RegistrationIDList, string title, string dataid, string strMsg, bool is_production, out string strLog)
{
try
{
var parmARR = new Dictionary<string, object>();
parmARR.Add("dataid", dataid);
var mm = new M_PushRegistration();
mm.registration_id = RegistrationIDList;
//生成JSON格式参数
PushPayload pushPayload = new PushPayload()
{
Platform = new List<string> { "android", "ios" },//推送平台
Audience = mm,//推送对象
Notification = new Notification
{
Alert = strMsg,
Android = new Android
{
Alert = strMsg,
Title = title,
Extras = parmARR
},
IOS = new IOS
{
Alert = strMsg,
Badge = "+1",
Extras = parmARR
}
},
Options = new Options
{
IsApnsProduction = is_production // 设置 iOS 推送生产环境。不设置默认为开发环境。
}
};
var strParms = pushPayload.ToString();
var result = SendPostRequest(strParms);
strLog = result.ToString();
return true;
/*var retM = result.Exp_JsonToModel<M_PushReturn>(1);
if (retM.error == null)
{
strLog = "向设备推送消息成功\r\n请求参数=" + strParms + "\r\n";
return true;
}
else
{
strLog = "推送失败,错误码:" + retM.error.code + ",错误信息:" + retM.error.message;
return false;
}*/
}
catch (Exception ex)
{
strLog = "推送异常:" + ex.Message;
return false;
}
}
/// <summary>
/// 发送推送请求到JPush使用HttpWebRequest
/// </summary>
/// <param name="method">传入POST或GET</param>
/// <param name="url">固定地址</param>
/// <param name="auth">用户名AppKey和密码MasterSecret形成的Base64字符串</param>
/// <param name="reqParams">请求的json参数一般由Platform(平台)、Audience(设备对象标识)、Notification(通知)、Message(自定义消息)、Options(推送可选项)组成</param>
/// <returns></returns>
public string SendRequest(String method, String url, String auth, String reqParams)
{
string resultJson = "";
HttpWebRequest myReq = null;
HttpWebResponse response = null;
try
{
myReq = (HttpWebRequest)WebRequest.Create(url);
myReq.Method = method;
myReq.ContentType = "application/json";
if (!String.IsNullOrEmpty(auth))
{
myReq.Headers.Add("Authorization", "Basic " + auth);
}
if (method == "POST")
{
byte[] bs = UTF8Encoding.UTF8.GetBytes(reqParams);
myReq.ContentLength = bs.Length;
using (Stream reqStream = myReq.GetRequestStream())
{
reqStream.Write(bs, 0, bs.Length);
reqStream.Close();
}
}
response = (HttpWebResponse)myReq.GetResponse();
HttpStatusCode statusCode = response.StatusCode;
if (Equals(response.StatusCode, HttpStatusCode.OK))
{
using (StreamReader reader = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8))
{
resultJson = reader.ReadToEnd();
try
{
object json = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson);
}
catch
{
resultJson = string.Format("{{\"error\": {{\"message\": \"{0}\", \"code\": 10086}}}}", "响应的结果不是正确的json格式");
}
}
}
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
HttpStatusCode errorCode = ((HttpWebResponse)ex.Response).StatusCode;
string statusDescription = ((HttpWebResponse)ex.Response).StatusDescription;
using (StreamReader sr = new StreamReader(((HttpWebResponse)ex.Response).GetResponseStream(), System.Text.Encoding.UTF8))
{
resultJson = sr.ReadToEnd();
//{"errcode":404,"errmsg":"request api doesn't exist"}
Dictionary<string, object> dict = JsonToDictionary(resultJson);
string errCode = "10086";
string errMsg = "发送推送的请求地址不存在或无法连接";
if (dict.ContainsKey("errcode"))
{
errCode = dict["errcode"].ToString();
}
if (dict.ContainsKey("errmsg"))
{
errMsg = dict["errmsg"].ToString();
}
resultJson = string.Format("{{\"error\": {{\"message\": \"{0}\", \"code\": {1}}}}}", errMsg, errCode);
}
}
else
{
//这里一定是error作为键名自定义错误号10086和极光推送失败时的json格式保持一致 如 {"error": {"message": "Missing parameter", "code": 1002}}
resultJson = string.Format("{{\"error\": {{\"message\": \"{0}\", \"code\": 10086}}}}", ex.Message.Replace("\"", " ").Replace("'", " "));
}
}
catch (System.Exception ex)
{
resultJson = string.Format("{{\"error\": {{\"message\": \"{0}\", \"code\": 10086}}}}", ex.Message.Replace("\"", " ").Replace("'", " "));
}
finally
{
if (response != null)
{
response.Close();
}
if (myReq != null)
{
myReq.Abort();
}
}
return resultJson;
}
/// <summary>
/// 通过用户名AppKey和密码获取验证码
/// </summary>
/// <returns></returns>
private string GetBase64Auth()
{
string str = this.AppKey + ":" + this.MasterSecret;
byte[] bytes = Encoding.Default.GetBytes(str);
return Convert.ToBase64String(bytes);
}
/// <summary>
/// 发送推送请求到JPush
/// </summary>
/// <param name="method">POST或GET</param>
/// <param name="reqParams">请求的json参数一般由Platform(平台)、Audience(设备对象标识)、Notification(通知)、Message(自定义消息)、Options(推送可选项)组成</param>
/// <returns></returns>
public string SendRequest(String method, String reqParams)
{
string auth = GetBase64Auth();
return SendRequest(method, this.RequestUrl, auth, reqParams);
}
/// <summary>
/// 发送Post请求
/// </summary>
/// <param name="reqParams">请求的json参数一般由Platform(平台)、Audience(设备对象标识)、Notification(通知)、Message(自定义消息)、Options(推送可选项)组成</param>
/// <returns></returns>
public string SendPostRequest(String reqParams)
{
string auth = GetBase64Auth();
return SendRequest("POST", this.RequestUrl, auth, reqParams);
}
/// <summary>
/// 发送Get请求
/// </summary>
/// <param name="reqParams">请求的json参数一般由Platform(平台)、Audience(设备对象标识)、Notification(通知)、Message(自定义消息)、Options(推送可选项)组成</param>
/// <returns></returns>
public string SendGetRequest(String reqParams)
{
string auth = GetBase64Auth();
return SendRequest("GET", this.RequestUrl, auth, reqParams);
}
/*
* 生成唯一的sendNo的方法 取序列号
* 查看返回结果的方法
*/
/// <summary>
/// 查询推送的结果
/// </summary>
/// <param name="msg_ids">生成的json信息唯一id</param>
/// <returns></returns>
public string GetReceivedResult(String msg_ids)
{
string url = this.ReceivedUrl + "?msg_ids=" + msg_ids;
String auth = GetBase64Auth();
return SendRequest("GET", url, auth, null); ;
}
/*
* 1.正确时返回结果{"sendno":"123456","msg_id":"1799597405"}
* 或者 {"sendno":"0","msg_id":"351403900"}
* 2.入参json完全正确但找不到要到达的设备。错误时返回
* {"msg_id": 3125719446, "error": {"message": "cannot find user by this audience", "code": 1011}}
* 3.传入空字符串 或者 非json格式或者没有必须的选项{"error": {"message": "Missing parameter", "code": 1002}}
* 传入的键(键区分大小写)、值不符合要求 {"error": {"message": "Audience value must be JSON Array format!", "code": 1003}}
*/
/// <summary>
/// 将返回的json转换为Hashtable对象
/// </summary>
/// <param name="jsonString"></param>
/// <returns></returns>
public Hashtable JsonToHashtable(string jsonString)
{
/*
* 正确时返回结果{"sendno":"123456","msg_id":"1799597405"}
* {"sendno":"0","msg_id":"351403900"}
* 入参json完全正确但找不到要到达的设备。错误时返回 {"msg_id": 3125719446, "error": {"message": "cannot find user by this audience", "code": 1011}}
* 传入空字符串 或者 非json格式或者没有必须的选项{"error": {"message": "Missing parameter", "code": 1002}}
* 传入的键值不符合要求 {"error": {"message": "Audience value must be JSON Array format!", "code": 1003}} 键区分大小写
*/
Hashtable ht = new Hashtable();
object json = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString);
//返回的结果一定是一个json对象
Newtonsoft.Json.Linq.JObject jsonObject = json as Newtonsoft.Json.Linq.JObject;
if (jsonObject == null)
{
return ht;
}
foreach (Newtonsoft.Json.Linq.JProperty jProperty in jsonObject.Properties())
{
Newtonsoft.Json.Linq.JToken jToken = jProperty.Value;
string value = "";
if (jToken != null)
{
value = jToken.ToString();
}
ht.Add(jProperty.Name, value);
}
return ht;
}
/// <summary>
/// 根据json返回的结果判断是否推送成功
/// </summary>
/// <param name="jsonString">响应的json</param>
/// <param name="errorMessage">错误信息</param>
/// <param name="errorCode">错误号</param>
/// <returns></returns>
public bool IsSuccess(string jsonString, out string errorMessage, out string errorCode)
{
Hashtable ht = JsonToHashtable(jsonString);
errorMessage = "";
errorCode = "";
foreach (string key in ht.Keys)
{
//如果存在error键,说明推送出错
if (key == "error")
{
string errJson = ht[key].ToString();
Hashtable htError = JsonToHashtable(errJson);
errorMessage = htError["message"].ToString();
errorCode = htError["code"].ToString();
return false;
}
}
return true;
}
/// <summary>
/// 根据返回的响应json来判断推送是否成功成功时记录sendno与msg_id。
/// 失败时记录错误信息errorMessage、错误号errCode等
/// </summary>
/// <param name="jsonString">响应的json</param>
/// <param name="errorMessage">错误信息</param>
/// <param name="errorCode">错误号</param>
/// <param name="sendno">用户自定义的推送编号从序列号中获取不设置则为0成功后返回该编号</param>
/// <param name="msg_id">极光服务器处理后返回的信息编号</param>
/// <returns></returns>
public bool IsSuccess(string jsonString, out string errorMessage, out string errorCode, out string sendno, out string msg_id)
{
bool result = IsSuccess(jsonString, out errorMessage, out errorCode);
Hashtable ht = JsonToHashtable(jsonString);
sendno = "";
msg_id = "";
if (result) //推送成功时只有键sendno、msg_id
{
sendno = ht["sendno"].ToString();
msg_id = ht["msg_id"].ToString();
}
else //如果失败时存在msg_id键则记录msg_id的值
{
if (ht.ContainsKey("msg_id"))
{
msg_id = ht["msg_id"].ToString();
}
}
return result;
}
/// <summary>
/// 将返回的json转换为字典Dictionary对象
/// </summary>
/// <param name="jsonString"></param>
/// <returns></returns>
public Dictionary<string, object> JsonToDictionary(string jsonString)
{
Dictionary<string, object> ht = new Dictionary<string, object>();
object json = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString);
//返回的结果一定是一个json对象
Newtonsoft.Json.Linq.JObject jsonObject = json as Newtonsoft.Json.Linq.JObject;
if (jsonObject == null)
{
return ht;
}
foreach (Newtonsoft.Json.Linq.JProperty jProperty in jsonObject.Properties())
{
Newtonsoft.Json.Linq.JToken jToken = jProperty.Value;
string value = "";
if (jToken != null)
{
value = jToken.ToString();
}
ht.Add(jProperty.Name, value);
}
return ht;
}
public class M_PushRegistration
{
public List<string> registration_id { get; set; }
}
public class M_PushReturn
{
public string sendno { get; set; }
public string msg_id { get; set; }
public M_PushError error { get; set; }
}
public class M_PushError
{
public string message { get; set; }
public string code { get; set; }
}
}
}