C#—ASP.NET:集成极光推送(Push API v3)

原文地址: https://blog.csdn.net/CXLLLK/article/details/86489994
 

1、极光推送官网(https://www.jpush.cn/)申请一个账号。

2、服务中心,开发者服务中,创建一个新的应用,输入正确的Android的包名

3、获取到了一个AppKey 和一个 Master Secret,这两个参数比较重要,验证权限使用。

4、去官网找到下载C# SDK的包https://docs.jiguang.cn/jpush/resources/

Github 源码:https://github.com/jpush/jpush-api-csharp-client

5、源码生成DLL

6、项目引用DLL,新建类 using Jiguang.JPush.Model;

7、代码封装HTTP 调用官方API,转载地址为pohreb博客:https://www.cnblogs.com/yangwujun/p/5973120.html

 

/// 极光推送的最新版:PUSH-API-V3

/// 参考地址 http://docs.jpush.cn/display/dev/Push-API-v3
  1. #region 基础方法
  2. /// <summary>
  3. /// 应用标识:极光推送的用户名
  4. /// </summary>
  5. private const string AppKey = "填写你应用的AppKey";
  6. /// <summary>
  7. /// 极光推送的密码
  8. /// </summary>
  9. private const string MasterSecret = "填写你的MasterSecret";
  10. ///// <summary>
  11. ///// 极光推送请求的url地址
  12. ///// </summary>
  13. private const string RequestUrl = "https://api.jpush.cn/v3/push";
  14. //private const string RequestUrl = "https://bjapi.push.jiguang.cn/v3/push";
  15. /// <summary>
  16. /// 查询推送结果请求的Url地址
  17. /// </summary>
  18. private const string ReceivedUrl = "https://report.jpush.cn/v3/received";
  19. /// <summary>
  20. /// 发送推送请求到JPush,使用HttpWebRequest
  21. /// </summary>
  22. /// <param name="method">传入POST或GET</param>
  23. /// <param name="url">固定地址</param>
  24. /// <param name="auth">用户名AppKey和密码MasterSecret形成的Base64字符串</param>
  25. /// <param name="reqParams">请求的json参数,一般由Platform(平台)、Audience(设备对象标识)、Notification(通知)、Message(自定义消息)、Options(推送可选项)组成</param>
  26. /// <returns></returns>
  27. private static string SendRequest(String method, String url, String auth, String reqParams)
  28. {
  29. string resultJson = "";
  30. HttpWebRequest myReq = null;
  31. HttpWebResponse response = null;
  32. try
  33. {
  34. myReq = (HttpWebRequest)WebRequest.Create(url);
  35. myReq.Method = method;
  36. myReq.ContentType = "application/json";
  37. if (!String.IsNullOrEmpty(auth))
  38. {
  39. myReq.Headers.Add("Authorization", "Basic " + auth);
  40. }
  41. if (method == "POST")
  42. {
  43. byte[] bs = UTF8Encoding.UTF8.GetBytes(reqParams);
  44. myReq.ContentLength = bs.Length;
  45. using (Stream reqStream = myReq.GetRequestStream())
  46. {
  47. reqStream.Write(bs, 0, bs.Length);
  48. reqStream.Close();
  49. }
  50. }
  51. response = (HttpWebResponse)myReq.GetResponse();
  52. HttpStatusCode statusCode = response.StatusCode;
  53. if (Equals(response.StatusCode, HttpStatusCode.OK))
  54. {
  55. using (StreamReader reader = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8))
  56. {
  57. resultJson = reader.ReadToEnd();
  58. try
  59. {
  60. object json = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson);
  61. }
  62. catch
  63. {
  64. resultJson = string.Format("{{\"error\": {{\"message\": \"{0}\", \"code\": 10086}}}}", "响应的结果不是正确的json格式");
  65. }
  66. }
  67. }
  68. }
  69. catch (WebException ex)
  70. {
  71. if (ex.Status == WebExceptionStatus.ProtocolError)
  72. {
  73. HttpStatusCode errorCode = ((HttpWebResponse)ex.Response).StatusCode;
  74. string statusDescription = ((HttpWebResponse)ex.Response).StatusDescription;
  75. using (StreamReader sr = new StreamReader(((HttpWebResponse)ex.Response).GetResponseStream(), System.Text.Encoding.UTF8))
  76. {
  77. resultJson = sr.ReadToEnd();
  78. //{"errcode":404,"errmsg":"request api doesn't exist"}
  79. Dictionary<string, object> dict = JsonToDictionary(resultJson);
  80. string errCode = "10086";
  81. string errMsg = "发送推送的请求地址不存在或无法连接";
  82. if (dict.ContainsKey("errcode"))
  83. {
  84. errCode = dict["errcode"].ToString();
  85. }
  86. if (dict.ContainsKey("errmsg"))
  87. {
  88. errMsg = dict["errmsg"].ToString();
  89. }
  90. resultJson = string.Format("{{\"error\": {{\"message\": \"{0}\", \"code\": {1}}}}}", errMsg, errCode);
  91. }
  92. }
  93. else
  94. {
  95. //这里一定是error作为键名(自定义错误号10086),和极光推送失败时的json格式保持一致 如 {"error": {"message": "Missing parameter", "code": 1002}}
  96. resultJson = string.Format("{{\"error\": {{\"message\": \"{0}\", \"code\": 10086}}}}", ex.Message.Replace("\"", " ").Replace("'", " "));
  97. }
  98. }
  99. catch (System.Exception ex)
  100. {
  101. resultJson = string.Format("{{\"error\": {{\"message\": \"{0}\", \"code\": 10086}}}}", ex.Message.Replace("\"", " ").Replace("'", " "));
  102. }
  103. finally
  104. {
  105. if (response != null)
  106. {
  107. response.Close();
  108. }
  109. if (myReq != null)
  110. {
  111. myReq.Abort();
  112. }
  113. }
  114. return resultJson;
  115. }
  116. /// <summary>
  117. /// 通过用户名AppKey和密码获取验证码
  118. /// </summary>
  119. /// <returns></returns>
  120. private static string GetBase64Auth()
  121. {
  122. string str = AppKey + ":" + MasterSecret;
  123. byte[] bytes = Encoding.Default.GetBytes(str);
  124. return Convert.ToBase64String(bytes);
  125. }
  126. /// <summary>
  127. /// 发送推送请求到JPush
  128. /// </summary>
  129. /// <param name="method">POST或GET</param>
  130. /// <param name="reqParams">请求的json参数,一般由Platform(平台)、Audience(设备对象标识)、Notification(通知)、Message(自定义消息)、Options(推送可选项)组成</param>
  131. /// <returns></returns>
  132. public static string SendRequest(String method, String reqParams)
  133. {
  134. string auth = GetBase64Auth();
  135. return SendRequest(method, RequestUrl, auth, reqParams);
  136. }
  137. /// <summary>
  138. /// 发送Post请求
  139. /// </summary>
  140. /// <param name="reqParams">请求的json参数,一般由Platform(平台)、Audience(设备对象标识)、Notification(通知)、Message(自定义消息)、Options(推送可选项)组成</param>
  141. /// <returns></returns>
  142. public static string SendPostRequest(String reqParams)
  143. {
  144. string auth = GetBase64Auth();
  145. return SendRequest("POST", RequestUrl, auth, reqParams);
  146. }
  147. /// <summary>
  148. /// 发送Get请求
  149. /// </summary>
  150. /// <param name="reqParams">请求的json参数,一般由Platform(平台)、Audience(设备对象标识)、Notification(通知)、Message(自定义消息)、Options(推送可选项)组成</param>
  151. /// <returns></returns>
  152. public static string SendGetRequest(String reqParams)
  153. {
  154. string auth = GetBase64Auth();
  155. return SendRequest("GET", RequestUrl, auth, reqParams);
  156. }
  157. /*
  158. * 生成唯一的sendNo的方法: 取序列号
  159. * 查看返回结果的方法
  160. */
  161. /// <summary>
  162. /// 查询推送的结果
  163. /// </summary>
  164. /// <param name="msg_ids">生成的json信息唯一id</param>
  165. /// <returns></returns>
  166. public static string GetReceivedResult(String msg_ids)
  167. {
  168. string url = ReceivedUrl + "?msg_ids=" + msg_ids;
  169. String auth = GetBase64Auth();
  170. return SendRequest("GET", url, auth, null);
  171. }
  172. /*
  173. * 1.正确时返回结果{"sendno":"123456","msg_id":"1799597405"}
  174. * 或者 {"sendno":"0","msg_id":"351403900"}
  175. * 2.入参json完全正确,但找不到要到达的设备。错误时:返回
  176. * {"msg_id": 3125719446, "error": {"message": "cannot find user by this audience", "code": 1011}}
  177. * 3.传入空字符串 或者 非json格式,或者没有必须的选项:{"error": {"message": "Missing parameter", "code": 1002}}
  178. * 传入的键(键区分大小写)、值不符合要求 {"error": {"message": "Audience value must be JSON Array format!", "code": 1003}}
  179. */
  180. /// <summary>
  181. /// 将返回的json转换为Hashtable对象
  182. /// </summary>
  183. /// <param name="jsonString"></param>
  184. /// <returns></returns>
  185. public static Hashtable JsonToHashtable(string jsonString)
  186. {
  187. /*
  188. * 正确时返回结果{"sendno":"123456","msg_id":"1799597405"}
  189. * {"sendno":"0","msg_id":"351403900"}
  190. * 入参json完全正确,但找不到要到达的设备。错误时:返回 {"msg_id": 3125719446, "error": {"message": "cannot find user by this audience", "code": 1011}}
  191. * 传入空字符串 或者 非json格式,或者没有必须的选项:{"error": {"message": "Missing parameter", "code": 1002}}
  192. * 传入的键值不符合要求 {"error": {"message": "Audience value must be JSON Array format!", "code": 1003}} 键区分大小写
  193. */
  194. Hashtable ht = new Hashtable();
  195. object json = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString);
  196. //返回的结果一定是一个json对象
  197. Newtonsoft.Json.Linq.JObject jsonObject = json as Newtonsoft.Json.Linq.JObject;
  198. if (jsonObject == null)
  199. {
  200. return ht;
  201. }
  202. foreach (Newtonsoft.Json.Linq.JProperty jProperty in jsonObject.Properties())
  203. {
  204. Newtonsoft.Json.Linq.JToken jToken = jProperty.Value;
  205. string value = "";
  206. if (jToken != null)
  207. {
  208. value = jToken.ToString();
  209. }
  210. ht.Add(jProperty.Name, value);
  211. }
  212. return ht;
  213. }
  214. /// <summary>
  215. /// 根据json返回的结果判断是否推送成功
  216. /// </summary>
  217. /// <param name="jsonString">响应的json</param>
  218. /// <param name="errorMessage">错误信息</param>
  219. /// <param name="errorCode">错误号</param>
  220. /// <returns></returns>
  221. public static bool IsSuccess(string jsonString, out string errorMessage, out string errorCode)
  222. {
  223. Hashtable ht = JsonToHashtable(jsonString);
  224. errorMessage = "";
  225. errorCode = "";
  226. foreach (string key in ht.Keys)
  227. {
  228. //如果存在error键,说明推送出错
  229. if (key == "error")
  230. {
  231. string errJson = ht[key].ToString();
  232. Hashtable htError = JsonToHashtable(errJson);
  233. errorMessage = htError["message"].ToString();
  234. errorCode = htError["code"].ToString();
  235. return false;
  236. }
  237. }
  238. return true;
  239. }
  240. /// <summary>
  241. /// 根据返回的响应json来判断推送是否成功,成功时记录sendno与msg_id。
  242. /// 失败时记录错误信息errorMessage、错误号errCode等
  243. /// </summary>
  244. /// <param name="jsonString">响应的json</param>
  245. /// <param name="errorMessage">错误信息</param>
  246. /// <param name="errorCode">错误号</param>
  247. /// <param name="sendno">用户自定义的推送编号(从序列号中获取),不设置则为0,成功后返回该编号</param>
  248. /// <param name="msg_id">极光服务器处理后返回的信息编号</param>
  249. /// <returns></returns>
  250. public static bool IsSuccess(string jsonString, out string errorMessage, out string errorCode, out string sendno, out string msg_id)
  251. {
  252. bool result = IsSuccess(jsonString, out errorMessage, out errorCode);
  253. Hashtable ht = JsonToHashtable(jsonString);
  254. sendno = "";
  255. msg_id = "";
  256. if (result) //推送成功时,只有键sendno、msg_id
  257. {
  258. sendno = ht["sendno"].ToString();
  259. msg_id = ht["msg_id"].ToString();
  260. }
  261. else //如果失败时存在msg_id键,则记录msg_id的值
  262. {
  263. if (ht.ContainsKey("msg_id"))
  264. {
  265. msg_id = ht["msg_id"].ToString();
  266. }
  267. }
  268. return result;
  269. }
  270. /// <summary>
  271. /// 将返回的json转换为字典Dictionary对象
  272. /// </summary>
  273. /// <param name="jsonString"></param>
  274. /// <returns></returns>
  275. public static Dictionary<string, object> JsonToDictionary(string jsonString)
  276. {
  277. Dictionary<string, object> ht = new Dictionary<string, object>();
  278. object json = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString);
  279. //返回的结果一定是一个json对象
  280. Newtonsoft.Json.Linq.JObject jsonObject = json as Newtonsoft.Json.Linq.JObject;
  281. if (jsonObject == null)
  282. {
  283. return ht;
  284. }
  285. foreach (Newtonsoft.Json.Linq.JProperty jProperty in jsonObject.Properties())
  286. {
  287. Newtonsoft.Json.Linq.JToken jToken = jProperty.Value;
  288. string value = "";
  289. if (jToken != null)
  290. {
  291. value = jToken.ToString();
  292. }
  293. ht.Add(jProperty.Name, value);
  294. }
  295. return ht;
  296. }
  297. #endregion

8、其中我们主要使用registration_id的方式推送,也就是通过APP上的用户Token推送。

新增两个实体类一个存储APP用户Token,以及设备平台(安卓,苹果),一个存储推送记录,其实极光官网也有推送记录。

因为需要推送多个用户情况,新添List存储registration_id

新建返回对象存储返回信息

扩展方法使用,根据文档实现JSON格式并调用基本方法实现推送https://docs.jiguang.cn/jpush/server/push/rest_api_v3_push/

 

/// <summary>

/// 推送消息并保存到已发送表
  1. /// </summary>
  2. /// <param name="RegistrationIDList">推送TokenID集合</param>
  3. /// <param name="title">标题</param>
  4. /// <param name="senduser">作者</param>
  5. /// <param name="toid">推送对象ID</param>
  6. /// <param name="contype">推送对象</param>
  7. /// <param name="dataid"></param>
  8. /// <param name="strMsg">推送内容</param>
  9. /// <param name="is_production"></param>
  10. /// <param name="strLog">返回日志</param>
  11. /// <returns></returns>
  12. public static bool SendPushV2(List<string> RegistrationIDList, string title, string senduser, string toid,int contype,string dataid, string strMsg, bool is_production, out string strLog)
  13. {
  14. try
  15. {
  16. var parmARR = new Dictionary<string, object>();
  17. parmARR.Add("dataid", dataid);
  18. var mm = new M_PushRegistration();
  19. mm.registration_id = RegistrationIDList;
  20. //生成JSON格式参数
  21. PushPayload pushPayload = new PushPayload()
  22. {
  23. Platform = new List<string> { "android", "ios" },//推送平台
  24. Audience = mm,//推送对象
  25. Notification = new Notification
  26. {
  27. Alert = strMsg,
  28. Android = new Android
  29. {
  30. Alert = strMsg,
  31. Title = "你的标题",
  32. Extras = parmARR
  33. },
  34. IOS = new IOS
  35. {
  36. Alert = strMsg,
  37. Badge = "+1",
  38. Extras = parmARR
  39. }
  40. },
  41. Options = new Options
  42. {
  43. IsApnsProduction = true // 设置 iOS 推送生产环境。不设置默认为开发环境。
  44. }
  45. };
  46. var strParms = pushPayload.Exp_ModelToJson();
  47. strParms.WriteFile("log/push");
  48. var result = JPushHelperV3.SendPostRequest(strParms);
  49. var retM = result.Exp_JsonToModel<M_PushReturn>(1);
  50. strLog = "";
  51. strLog += "result=" + result + "&&retModel=" + retM.Exp_ModelToJson();
  52. strLog.WriteFile("log/push");
  53. if (retM.error == null)
  54. {
  55. //保存推送信息
  56. string[] teacherArr = toid.Split(',');
  57. for (int i = 0; i < teacherArr.Length; i++)
  58. {
  59. D_T_PushMsg_Exp pushmsgDal = new D_T_PushMsg_Exp();
  60. M_T_PushMsg pushmsgModel = new M_T_PushMsg();
  61. pushmsgModel.Title = title;
  62. pushmsgModel.MsgAuthor = senduser;
  63. pushmsgModel.MsgContent = strMsg;
  64. pushmsgModel.Flag = true;
  65. pushmsgModel.IsRead = false;
  66. pushmsgModel.IsSend = true;
  67. pushmsgModel.Contype = contype;
  68. pushmsgModel.Remark1 = teacherArr[i].Exp_IntTryParse(); //发送给谁
  69. pushmsgModel.AddTime = DateTime.Now;
  70. pushmsgModel.SendTime = DateTime.Now;
  71. pushmsgModel.Remark2 = "";
  72. pushmsgModel.Remark3 = false;
  73. pushmsgDal.Admin_Add(pushmsgModel);
  74. }
  75. strLog = "向设备推送消息成功\r\n请求参数=" + strParms + "\r\n";
  76. return true;
  77. }
  78. else
  79. {
  80. strLog = "推送失败,错误码:" + retM.error.code + ",错误信息:" + retM.error.message;
  81. return false;
  82. }
  83. }
  84. catch (Exception ex)
  85. {
  86. strLog = "推送异常:" + ex.Message;
  87. ex.Exp_WriteErrorLog();
  88. return false;
  89. }
  90. }

调用该方法即可实现推送。

9、调试,注意事项。

需改进:该基本方法,返回的错误信息不知什么原因并不是官方给出的错误信息,他判断的是HTTP Status Code 返回的异常,容易迷惑以为授权失败。具体错误信息可以去官网查看。或者使用https://api.jpush.cn/v3/push/validate校验API

扩展方法中的Exp_、Admin_方法为自己封装DLL功能,可根据要求自行编写,只是记录思路。

开发者服务中-应用设置-推送设置,IOS需要你填写授权方式,Android下可以快速集成扫描下载安装包。

https://docs.jiguang.cn/jpush/client/Android/android_3m/

安装应用并运行,点击 即可看见分配给本机的RegId

测试接口中可以填写该RegId,进行测试。需要手机能联网,部分机型可能收不到推送(努比亚部分机型?)
调用测试后可以在极光开发者服务-推送-推送历史中查看API类型的推送。

该RegId需要为极光分配给该应用下的该用户设备RegId,所以APP端也需要集成极光推送注册用户为极光推送对象,如果不是原生的开发,看你的需要选择:https://docs.jiguang.cn/jpush/client/client_plugins/

以上为接口端集成。


扩展记录——APICloud客户端集成极光推送(并点击推送消息跳转相应页面)

1、APICloud开发APP应用中端开发需要添加极光推送模块

2、APP应用中config.xml,加入配置app_key对应的APPKEY

3、 在应用打开时Index.html页面中加入注册RegId。

 

setToken=function() {

var token = $api.getStorage('user.token');//获取用户信息
  1. //console.log('jpush:start==>token=' + token);
  2. var jpush = api.require('ajpush');//加载jpush模块
  3. if ('ios' == api.systemType) {
  4. jpush.getRegistrationId(function(ret) {
  5. //console.log('ios jpush getRegistrationId:' + JSON.stringify(ret));
  6. var registrationId = ret.id;
  7. $api.setStorage('user.token', ret.id);
  8. });
  9. } else {
  10. jpush.init(function(ret0, err0) {//安卓需要初始化jpush
  11. // console.log('android jpush.init:' + JSON.stringify(ret0)+"|||||"+JSON.stringify(err0));
  12. if (ret0.status == 1) {
  13. jpush.getRegistrationId(function(ret) {//获取极光该应用该设备下的Regid
  14. // console.log('android jpush getRegistrationId:' + JSON.stringify(ret));
  15. var registrationId = ret.id;//保存Regid
  16. $api.setStorage('user.token', ret.id);//保存Regid到用户信息,保存推送对象
  17. });
  18. }
  19. });
  20. }
  21. }

4、登陆时需要将该用户的(Regid)Token,更新到服务器端用户对应的推送下,也就是上面集成C#中的M_T_PushToken数据表中,方便推送时在里面寻找对象。


扩展更新——APICloud客户端推送,传递自定义参数,用来点击通知跳转页面。

1、主要是更改发送的参数配置即可,更新c#集成的SendPushV2方法中的部分代码,极光推送文档https://docs.jiguang.cn/jpush/server/push/rest_api_v3_push/#notification

 

PushPayload pushPayload = new PushPayload()

{
Platform = new List<string> { "android", "ios" },

Audience = mm,

Notification = new Notification

{

Alert = strMsg,

Android = new Android

{

Alert = strMsg,//内容

Title = title,//标题

Style = 1,//样式

BigText = strMsg,//大文本

Extras = parmARR

},

IOS = new IOS

{

Alert = strMsg,

Badge = "+1",

Extras = parmARR

}

},

Options = new Options

{

IsApnsProduction = true // 设置 iOS 推送生产环境。不设置默认为开发环境。

}

};

2、中的Extras数据应为JSON格式数据,c#中  var parmARR = new Dictionary<string, object>();方法实现

3、检查接口端推送数据格式是否正确后,可以登陆极光官网,(极光开发者服务-相应应用推送-发送通知)中模拟推送,选择需要的通知样式。选择大段文本样式,可以解决推送内容过多显示不全情况。

4、接口端配置完成后,需要在客户端监听通知点击事件。注意点击后的跳转地址即可。

 

var jpush = api.require('ajpush');

//安卓端监听

api.addEventListener({name:'appintent'}, function(ret,err) {

// alert('通知被点击,收到数据:\n' + JSON.stringify(ret));//监听通知被点击后收到的数据

var data=ret.appParam.ajpush.extra;

openWinExp(data.DWin,data.Win,{"TypeID":data.TypeID});

})

//IOS端监听

api.addEventListener({name:'noticeclicked'}, function(ret,err) {

// alert('通知被点击,收到数据:\n' + JSON.stringify(ret));//监听通知被点击后收到的数据

var data=ret.appParam.ajpush.extra;

openWinExp(data.DWin,data.Win,{"TypeID":data.TypeID});

})

//因为在Index下,所以注意跳转地址。

openWinExp=function(dir,name, parms) {

//console.log("openWin===>dir=" + dir + "&name=" + name + "&parms=" + JSON.stringify(parms));

api.openWin({

name: name,

url: strurl='html/'+ dir + '/' + name + '.html',//注意跳转地址

bounces: false,

rect: {

x: 0,

y: 0,

w: 'auto',

h: 'auto'

},

delay: 0,

reload: true,

slidBackEnabled: false,

animation: {

type: stnet.setting.animation.type,

duration: 300,

subType: (parms && parms.type) ? 'from_' + parms.type : stnet.setting.animation.subType

},

pageParam: parms

});

}

C#—ASP.NET:集成极光推送(Push API v3)的更多相关文章

  1. 李洪强iOS之集成极光推送三iOS集成指南

    李洪强iOS之集成极光推送三iOS集成指南 SDK说明 适用版本 本文匹配的 SDK版本:r2.1.5 以后.查看最近更新了解最新的SDK更新情况.使用Xcode 6及以上版本可以使用新版Push S ...

  2. 李洪强iOS之集成极光推送二iOS 证书 设置指南

    李洪强iOS之集成极光推送二iOS 证书 设置指南 创建应用程序ID 登陆 iOS Dev Center 选择进入iOS Provisioning Portal. 在 iOS Provisioning ...

  3. 李洪强iOS之集成极光推送一iOS SDK概述

    李洪强iOS之集成极光推送一iOS SDK概述 JPush iOS 从上图可以看出,JPush iOS Push 包括 2 个部分,APNs 推送(代理),与 JPush 应用内消息. 红色部分是 A ...

  4. Android集成极光推送

    要说学习极光推送,个人感觉官方文档就非常好啦,但是没法,人太懒啦,为了下次能够快速的将极光推送集成到项目中,故结合之前开发的项目和官方文档记录下简单的Android集成极光推送,在这之前,先上一张简单 ...

  5. 1、Android Studio集成极光推送(Jpush) 报错 java.lang.UnsatisfiedLinkError: cn.jpush.android.service.PushProtoco

    Android studio 集成极光推送(Jpush) (华为手机)报错, E/JPush: [JPushGlobal] Get sdk version fail![获取sdk版本失败!] W/Sy ...

  6. Swift3集成极光推送

      现在很多程序都开始使用Swift开发了,但是第三方库大多数都是用OC写的,所以我们要使用Swift和OC混编.今天的内容主要讲Swift3.0集成极光推送. 1.准备工作   集成指南,极光上说的 ...

  7. iOS 集成极光推送

    最近极光推送更新到V3版本之后,推送又不成功!配合服务器联调了半天,发现是服务器环境配置有问题. 想着就把极光推送的步骤给记录下来. 一.配置push证书 这个可以到极光文档里写,很详细 二.导入必要 ...

  8. ThinkPHP 3.2.x 集成极光推送指北

    3.2版本已经过了维护生命周期,官方已经不再维护,请及时更新至5.0版本 -- ThinkPHP 官方仓库 以上,如果有条件,请关闭这个页面,然后升级至 ThinkPHP 5,如果由于各种各样的原因无 ...

  9. ionic2集成极光推送

    ionic2集成极光推送: ionic2api:https://ionicframework.com/docs/ 极光推送官网:https://www.jiguang.cn android-怎么注册极 ...

随机推荐

  1. mybatis笔记01

    目录 1. Mybatis的介绍 2. 使用JDBC编码的分析 2.1 准备 2.3 程序代码 2.4 JDBC问题 3. Mybatis架构 4. Mybatis入门程序 4.1 mybatis下载 ...

  2. java——初识

    java是现在最火的高级编程语言之一,功能强,应用广. java可以做什么? 1. 开发桌面应用程序 2. 开发面向Internet的应用程序 开发java程序的基本步骤: 1. 编写源程序:mypr ...

  3. mysql基础整理02

    比较运算符 > < = >= <= !=和<> !=和<>都是一个意思,都是不等于的意思 and和or and 并且&& 需要同时满足多 ...

  4. 设计模式—装饰模式的C++实现

    这是Bwar在2009年写的设计模式C++实现,代码均可编译可运行,一直存在自己的电脑里,曾经在团队技术分享中分享过,现搬到线上来. 1. 装饰模式简述 1.1 目的 动态地给一个对象添加一些额外的职 ...

  5. hive SQL查询结果添加行号

    用窗口函数可以解决这个问题: 例:select row_number() over(order by user_id desc) ,tab.* from dws_user_visit_month1 a ...

  6. react-conponent-todo

    <!DOCTYPE html> <html> <head> <script src="../../build/react.js">& ...

  7. window.requestAnimationFrame与Tween.js配合使用实现动画缓动效果

    window.requestAnimationFrame 概述 window.requestAnimationFrame()这个方法是用来在页面重绘之前,通知浏览器调用一个指定的函数,以满足开发者操作 ...

  8. 2019-01-13 [日常]mov文件转换为gif

    因为需要将之前mac下用QuickTime录屏生成的文件(mov格式)转换成gif文件, 便于传到某些博客平台, 于是找到了这个转换工具, 已将原代码的命名中文化并简化. Ruby和视频转换都是新手, ...

  9. 2018-10-19 Chrome插件实现GitHub代码离线翻译v0.0.4

    续前文Chrome插件实现GitHub代码翻译v0.0.3. 添加了对驼峰命名的支持. 由于调用浏览器插件-离线英汉词典进行词汇翻译, 因此也不依赖于任何在线翻译服务. Chrome插件: 官网链接 ...

  10. HashMap的resize方法中尾部遍历出现死循环问题 Tail Traversing (多线程)

    一.背景介绍: 在看HashMap源码是看到了resize()的源代码,当时发现在将old链表中引用数据复制到新的链表中时,发现复制过程中时,源码是进行了反序,此时是允许反序存储的,同时这样设计的效率 ...