c#微信扫码支付,完整版。包括回调
2016-01-27 15:41
507 查看
1、我们需要用到的类,下载一个微信sdk。sdk中有相关的工具类链接地址为:
https://pay.weixin.qq.com/wiki/doc/api/download/WxPayAPI_CS_v3.zip
2、如果觉得不想下载没有关系,我贴代码
* 生成随机串,随机串包含字母或数字 * @return 随机串 */ public static string GenerateNonceStr() { return Guid.NewGuid().ToString().Replace("-", ""); } }}
3、所有的工具类完成了,下面就开始调用
4、页面操作,因为之前的调用微信给我们有用的东西就是一个二维码链接,我们还得把这个连接转换为二维码。
5、ok你可以完整的使用微信扫码支付了,回调操作后续在写(回调链接地址)。
https://pay.weixin.qq.com/wiki/doc/api/download/WxPayAPI_CS_v3.zip
2、如果觉得不想下载没有关系,我贴代码
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Web; namespace WxPayTest.WxHelper { public class HttpService { public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) { //直接确认,否则打不开 return true; } public static string Post(string xml, string url, bool isUseCert, int timeout) { System.GC.Collect();//垃圾回收,回收没有正常关闭的http连接 string result = "";//返回结果 HttpWebRequest request = null; HttpWebResponse response = null; Stream reqStream = null; try { //设置最大连接数 ServicePointManager.DefaultConnectionLimit = 200; //设置https验证方式 if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase)) { ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult); } /*************************************************************** * 下面设置HttpWebRequest的相关属性 * ************************************************************/ request = (HttpWebRequest)WebRequest.Create(url); request.Method = "POST"; request.Timeout = timeout * 1000; //设置代理服务器 WebProxy proxy = new WebProxy(); //定义一个网关对象 proxy.Address = new Uri(WxPayConfig.PROXY_URL); //网关服务器端口:端口 request.Proxy = proxy; //设置POST的数据类型和长度 request.ContentType = "text/xml"; byte[] data = System.Text.Encoding.UTF8.GetBytes(xml); request.ContentLength = data.Length; //是否使用证书 if (isUseCert) { string path = HttpContext.Current.Request.PhysicalApplicationPath; X509Certificate2 cert = new X509Certificate2(path + WxPayConfig.SSLCERT_PATH, WxPayConfig.SSLCERT_PASSWORD); request.ClientCertificates.Add(cert); } //往服务器写入数据 reqStream = request.GetRequestStream(); reqStream.Write(data, 0, data.Length); reqStream.Close(); //获取服务端返回 response = (HttpWebResponse)request.GetResponse(); //获取服务端返回数据 StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8); result = sr.ReadToEnd().Trim(); sr.Close(); } catch (System.Threading.ThreadAbortException e) { System.Threading.Thread.ResetAbort(); } catch (WebException e) { if (e.Status == WebExceptionStatus.ProtocolError) { } throw new WxPayException(e.ToString()); } catch (Exception e) { throw new WxPayException(e.ToString()); } finally { //关闭连接和流 if (response != null) { response.Close(); } if (request != null) { request.Abort(); } } return result; } /// <summary> /// 请求Url,发送数据 /// </summary> public static string PostUrl(string url, string postData) { byte[] data = Encoding.UTF8.GetBytes(postData); // 设置参数 HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; CookieContainer cookieContainer = new CookieContainer(); request.CookieContainer = cookieContainer; request.AllowAutoRedirect = true; request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = data.Length; Stream outstream = request.GetRequestStream(); outstream.Write(data, 0, data.Length); outstream.Close(); //发送请求并获取相应回应数据 HttpWebResponse response = request.GetResponse() as HttpWebResponse; //直到request.GetResponse()程序才开始向目标网页发送Post请求 Stream instream = response.GetResponseStream(); StreamReader sr = new StreamReader(instream, Encoding.UTF8); //返回结果网页(html)代码 string content = sr.ReadToEnd(); return content; } /// <summary> /// 处理http GET请求,返回数据 /// </summary> /// <param name="url">请求的url地址</param> /// <returns>http GET成功后返回的数据,失败抛WebException异常</returns> public static string Get(string url) { System.GC.Collect(); string result = ""; HttpWebRequest request = null; HttpWebResponse response = null; //请求url以获取数据 try { //设置最大连接数 ServicePointManager.DefaultConnectionLimit = 200; //设置https验证方式 if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase)) { ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult); } /*************************************************************** * 下面设置HttpWebRequest的相关属性 * ************************************************************/ request = (HttpWebRequest)WebRequest.Create(url); request.Method = "GET"; //设置代理 WebProxy proxy = new WebProxy(); proxy.Address = new Uri(WxPayConfig.PROXY_URL); request.Proxy = proxy; //获取服务器返回 response = (HttpWebResponse)request.GetResponse(); //获取HTTP返回数据 StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8); result = sr.ReadToEnd().Trim(); sr.Close(); } catch (System.Threading.ThreadAbortException e) { System.Threading.Thread.ResetAbort(); } catch (WebException e) { if (e.Status == WebExceptionStatus.ProtocolError) { } throw new WxPayException(e.ToString()); } catch (Exception e) { throw new WxPayException(e.ToString()); } finally { //关闭连接和流 if (response != null) { response.Close(); } if (request != null) { request.Abort(); } } return result; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace WxPayTest.WxHelper { public class NativePay { /** * 生成直接支付url,支付url有效期为2小时,模式二 * @param productId 商品ID * @return 模式二URL */ public string GetPayUrl(string productId) { WxPayData data = new WxPayData(); data.SetValue("body", "test");//商品描述 data.SetValue("attach", "test");//附加数据 data.SetValue("out_trade_no", WxPayApi.GenerateOutTradeNo());//随机字符串 data.SetValue("total_fee", 1);//总金额 data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));//交易起始时间 data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));//交易结束时间 data.SetValue("goods_tag", "jjj");//商品标记 data.SetValue("trade_type", "NATIVE");//交易类型 data.SetValue("product_id", productId);//商品ID WxPayData result = WxPayApi.UnifiedOrder(data);//调用统一下单接口 string url = result.GetValue("code_url").ToString();//获得统一下单接口返回的二维码链接 return url; } /** * 参数数组转换为url格式 * @param map 参数名与参数值的映射表 * @return URL字符串 */ private string ToUrlParams(SortedDictionary<string, object> map) { string buff = ""; foreach (KeyValuePair<string, object> pair in map) { buff += pair.Key + "=" + pair.Value + "&"; } buff = buff.Trim('&'); return buff; } } }
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Web; namespace WxPayTest.WxHelper { public class WeiXinHelper { /** * 生成直接支付url,支付url有效期为2小时,模式二 * @param productId 商品ID * @return 模式二URL */ public string GetPayUrl(string productId) { WxPayData data = new WxPayData(); data.SetValue("body", "test");//商品描述 data.SetValue("attach", "test");//附加数据 data.SetValue("out_trade_no", WxPayApi.GenerateOutTradeNo());//随机字符串 data.SetValue("total_fee", 1);//总金额 data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));//交易起始时间 data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));//交易结束时间 data.SetValue("goods_tag", "jjj");//商品标记 data.SetValue("trade_type", "NATIVE");//交易类型 data.SetValue("product_id", productId);//商品ID WxPayData result = WxPayApi.UnifiedOrder(data);//调用统一下单接口 string url = result.GetValue("code_url").ToString();//获得统一下单接口返回的二维码链接 return url; } /** * 参数数组转换为url格式 * @param map 参数名与参数值的映射表 * @return URL字符串 */ private string ToUrlParams(SortedDictionary<string, object> map) { string buff = ""; foreach (KeyValuePair<string, object> pair in map) { buff += pair.Key + "=" + pair.Value + "&"; } buff = buff.Trim('&'); return buff; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace WxPayTest.WxHelper { public class WxPayApi { /** * * 统一下单 * @param WxPaydata inputObj 提交给统一下单API的参数 * @param int timeOut 超时时间 * @throws WxPayException * @return 成功时返回,其他抛异常 */ public static WxPayData UnifiedOrder(WxPayData inputObj, int timeOut = 600) { string url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //检测必填参数 if (!inputObj.IsSet("out_trade_no")) { throw new WxPayException("缺少统一支付接口必填参数out_trade_no!"); } else if (!inputObj.IsSet("body")) { throw new WxPayException("缺少统一支付接口必填参数body!"); } else if (!inputObj.IsSet("total_fee")) { throw new WxPayException("缺少统一支付接口必填参数total_fee!"); } else if (!inputObj.IsSet("trade_type")) { throw new WxPayException("缺少统一支付接口必填参数trade_type!"); } //关联参数 if (inputObj.GetValue("trade_type").ToString() == "JSAPI" && !inputObj.IsSet("openid")) { throw new WxPayException("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!"); } if (inputObj.GetValue("trade_type").ToString() == "NATIVE" && !inputObj.IsSet("product_id")) { throw new WxPayException("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!"); } //异步通知url未设置,则使用配置文件中的url if (!inputObj.IsSet("notify_url")) { inputObj.SetValue("notify_url", WxPayConfig.NOTIFY_URL);//异步通知url } inputObj.SetValue("appid", WxPayConfig.APPID);//公众账号ID inputObj.SetValue("mch_id", WxPayConfig.MCHID);//商户号 inputObj.SetValue("spbill_create_ip", WxPayConfig.IP);//终端ip inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串 //签名 inputObj.SetValue("sign", inputObj.MakeSign()); string xml = inputObj.ToXml(); var start = DateTime.Now; //string response = HttpService.Post(xml, url, false, timeOut); string response = HttpService.PostUrl(url, xml); var end = DateTime.Now; int timeCost = (int)((end - start).TotalMilliseconds); WxPayData result = new WxPayData(); result.FromXml(response); ReportCostTime(url, timeCost, result);//测速上报 return result; } /** * * 测速上报 * @param string interface_url 接口URL * @param int timeCost 接口耗时 * @param WxPayData inputObj参数数组 */ private static void ReportCostTime(string interface_url, int timeCost, WxPayData inputObj) { //如果不需要进行上报 if (WxPayConfig.REPORT_LEVENL == 0) { return; } //如果仅失败上报 if (WxPayConfig.REPORT_LEVENL == 1 && inputObj.IsSet("return_code") && inputObj.GetValue("return_code").ToString() == "SUCCESS" && inputObj.IsSet("result_code") && inputObj.GetValue("result_code").ToString() == "SUCCESS") { return; } //上报逻辑 WxPayData data = new WxPayData(); data.SetValue("interface_url", interface_url); data.SetValue("execute_time_", timeCost); //返回状态码 if (inputObj.IsSet("return_code")) { data.SetValue("return_code", inputObj.GetValue("return_code")); } //返回信息 if (inputObj.IsSet("return_msg")) { data.SetValue("return_msg", inputObj.GetValue("return_msg")); } //业务结果 if (inputObj.IsSet("result_code")) { data.SetValue("result_code", inputObj.GetValue("result_code")); } //错误代码 if (inputObj.IsSet("err_code")) { data.SetValue("err_code", inputObj.GetValue("err_code")); } //错误代码描述 if (inputObj.IsSet("err_code_des")) { data.SetValue("err_code_des", inputObj.GetValue("err_code_des")); } //商户订单号 if (inputObj.IsSet("out_trade_no")) { data.SetValue("out_trade_no", inputObj.GetValue("out_trade_no")); } //设备号 if (inputObj.IsSet("device_info")) { data.SetValue("device_info", inputObj.GetValue("device_info")); } try { Report(data); } catch (WxPayException ex) { //不做任何处理 } } /** * * 测速上报接口实现 * @param WxPayData inputObj 提交给测速上报接口的参数 * @param int timeOut 测速上报接口超时时间 * @throws WxPayException * @return 成功时返回测速上报接口返回的结果,其他抛异常 */ public static WxPayData Report(WxPayData inputObj, int timeOut = 1) { string url = "https://api.mch.weixin.qq.com/payitil/report"; //检测必填参数 if (!inputObj.IsSet("interface_url")) { throw new WxPayException("接口URL,缺少必填参数interface_url!"); } if (!inputObj.IsSet("return_code")) { throw new WxPayException("返回状态码,缺少必填参数return_code!"); } if (!inputObj.IsSet("result_code")) { throw new WxPayException("业务结果,缺少必填参数result_code!"); } if (!inputObj.IsSet("user_ip")) { throw new WxPayException("访问接口IP,缺少必填参数user_ip!"); } if (!inputObj.IsSet("execute_time_")) { throw new WxPayException("接口耗时,缺少必填参数execute_time_!"); } inputObj.SetValue("appid", WxPayConfig.APPID);//公众账号ID inputObj.SetValue("mch_id", WxPayConfig.MCHID);//商户号 inputObj.SetValue("user_ip", WxPayConfig.IP);//终端ip inputObj.SetValue("time", DateTime.Now.ToString("yyyyMMddHHmmss"));//商户上报时间 inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串 inputObj.SetValue("sign", inputObj.MakeSign());//签名 string xml = inputObj.ToXml(); string response = HttpService.Post(xml, url, false, timeOut); WxPayData result = new WxPayData(); result.FromXml(response); return result; } /** * 根据当前系统时间加随机序列来生成订单号 * @return 订单号 */ public static string GenerateOutTradeNo() { var ran = new Random(); return string.Format("{0}{1}{2}", WxPayConfig.MCHID, DateTime.Now.ToString("yyyyMMddHHmmss"), ran.Next(999)); } /** * 生成时间戳,标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数 * @return 时间戳 */ public static string GenerateTimeStamp() { TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalSeconds).ToString(); } /**<pre name="code" class="csharp">using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace WxPayTest.WxHelper { /** * 配置账号信息 */ public class WxPayConfig { //=======【基本信息设置】===================================== /* 微信公众号信息配置 * APPID:绑定支付的APPID(必须配置) * MCHID:商户号(必须配置) * KEY:商户支付密钥,参考开户邮件设置(必须配置) * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置) */ public const string APPID = "11111111111111"; //需要自己提供我就不提供 public const string MCHID = "11111111111111";//需要自己提供我就不提供 public const string KEY = "11111111111111";//需要自己提供我就不提供 public const string APPSECRET = "11111111111111";//需要自己提供我就不提供 //=======【证书路径设置】===================================== /* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要) */ public const string SSLCERT_PATH = "cert/apiclient_cert.p12"; public const string SSLCERT_PASSWORD = "1233410002"; //=======【支付结果通知url】===================================== /* 支付结果通知回调url,用于商户接收支付结果 */ public const string NOTIFY_URL = "http://paysdk.weixin.qq.com/example/ResultNotifyPage.aspx"; //需要写自己的回调地址,方便处理 //=======【商户系统后台机器IP】===================================== /* 此参数可手动配置也可在程序中自动获取 */ public const string IP = "8.8.8.8"; //=======【代理服务器设置】=================================== /* 默认IP和端口号分别为0.0.0.0和0,此时不开启代理(如有需要才设置) */ public const string PROXY_URL = "http://10.152.18.220:8080"; //=======【上报信息配置】=================================== /* 测速上报等级,0.关闭上报; 1.仅错误时上报; 2.全量上报 */ public const int REPORT_LEVENL = 1; //=======【日志级别】=================================== /* 日志等级,0.不输出日志;1.只输出错误信息; 2.输出错误和正常信息; 3.输出错误信息、正常信息和调试信息 */ public const int LOG_LEVENL = 0; } }
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Web; using System.Xml; namespace WxPayTest.WxHelper { /// <summary> /// 微信支付协议接口数据类,所有的API接口通信都依赖这个数据结构, /// 在调用接口之前先填充各个字段的值,然后进行接口通信, /// 这样设计的好处是可扩展性强,用户可随意对协议进行更改而不用重新设计数据结构, /// 还可以随意组合出不同的协议数据包,不用为每个协议设计一个数据包结构 /// </summary> public class WxPayData { public WxPayData() { } //采用排序的Dictionary的好处是方便对数据包进行签名,不用再签名之前再做一次排序 private SortedDictionary<string, object> m_values = new SortedDictionary<string, object>(); /** * 设置某个字段的值 * @param key 字段名 * @param value 字段值 */ public void SetValue(string key, object value) { m_values[key] = value; } /** * 根据字段名获取某个字段的值 * @param key 字段名 * @return key对应的字段值 */ public object GetValue(string key) { object o = null; m_values.TryGetValue(key, out o); return o; } /** * 判断某个字段是否已设置 * @param key 字段名 * @return 若字段key已被设置,则返回true,否则返回false */ public bool IsSet(string key) { object o = null; m_values.TryGetValue(key, out o); if (null != o) return true; else return false; } /** * @将Dictionary转成xml * @return 经转换得到的xml串 * @throws WxPayException **/ public string ToXml() { //数据为空时不能转化为xml格式 if (0 == m_values.Count) { throw new WxPayException("WxPayData数据为空!"); } string xml = "<xml>"; foreach (KeyValuePair<string, object> pair in m_values) { //字段值不能为null,会影响后续流程 if (pair.Value == null) { throw new WxPayException("WxPayData内部含有值为null的字段!"); } if (pair.Value.GetType() == typeof(int)) { xml += "<" + pair.Key + ">" + pair.Value + "</" + pair.Key + ">"; } else if (pair.Value.GetType() == typeof(string)) { xml += "<" + pair.Key + ">" + "<![CDATA[" + pair.Value + "]]></" + pair.Key + ">"; } else//除了string和int类型不能含有其他数据类型 { throw new WxPayException("WxPayData字段数据类型错误!"); } } xml += "</xml>"; return xml; } /** * @将xml转为WxPayData对象并返回对象内部的数据 * @param string 待转换的xml串 * @return 经转换得到的Dictionary * @throws WxPayException */ public SortedDictionary<string, object> FromXml(string xml) { if (string.IsNullOrEmpty(xml)) { throw new WxPayException("将空的xml串转换为WxPayData不合法!"); } XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(xml); XmlNode xmlNode = xmlDoc.FirstChild;//获取到根节点<xml> XmlNodeList nodes = xmlNode.ChildNodes; foreach (XmlNode xn in nodes) { XmlElement xe = (XmlElement)xn; m_values[xe.Name] = xe.InnerText;//获取xml的键值对到WxPayData内部的数据中 } try { //2015-06-29 错误是没有签名 if (m_values["return_code"] != "SUCCESS") { return m_values; } CheckSign();//验证签名,不通过会抛异常 } catch (WxPayException ex) { throw new WxPayException(ex.Message); } return m_values; } /** * @Dictionary格式转化成url参数格式 * @ return url格式串, 该串不包含sign字段值 */ public string ToUrl() { string buff = ""; foreach (KeyValuePair<string, object> pair in m_values) { if (pair.Value == null) { throw new WxPayException("WxPayData内部含有值为null的字段!"); } if (pair.Key != "sign" && pair.Value.ToString() != "") { buff += pair.Key + "=" + pair.Value + "&"; } } buff = buff.Trim('&'); return buff; } /** * @Dictionary格式化成Json * @return json串数据 */ public string ToJson() { string jsonStr =JsonConvert.SerializeObject(m_values); return jsonStr; } /** * @values格式化成能在Web页面上显示的结果(因为web页面上不能直接输出xml格式的字符串) */ public string ToPrintStr() { string str = ""; foreach (KeyValuePair<string, object> pair in m_values) { if (pair.Value == null) { throw new WxPayException("WxPayData内部含有值为null的字段!"); } str += string.Format("{0}={1}<br>", pair.Key, pair.Value.ToString()); } return str; } /** * @生成签名,详见签名生成算法 * @return 签名, sign字段不参加签名 */ public string MakeSign() { //转url格式 string str = ToUrl(); //在string后加入API KEY str += "&key=" + WxPayConfig.KEY; //MD5加密 var md5 = MD5.Create(); var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(str)); var sb = new StringBuilder(); foreach (byte b in bs) { sb.Append(b.ToString("x2")); } //所有字符转为大写 return sb.ToString().ToUpper(); } /** * * 检测签名是否正确 * 正确返回true,错误抛异常 */ public bool CheckSign() { //如果没有设置签名,则跳过检测 if (!IsSet("sign")) { //"WxPayData签名存在但不合法!" return false; } //如果设置了签名但是签名为空,则抛异常 else if (GetValue("sign") == null || GetValue("sign").ToString() == "") { //"WxPayData签名存在但不合法!" return false; } //获取接收到的签名 string return_sign = GetValue("sign").ToString(); //在本地计算新的签名 string cal_sign = MakeSign(); if (cal_sign == return_sign) { return true; } else { return false; } } /** * @获取Dictionary */ public SortedDictionary<string, object> GetValues() { return m_values; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace WxPayTest.WxHelper { public class WxPayException : Exception { public WxPayException(string msg) : base(msg) { } } }
* 生成随机串,随机串包含字母或数字 * @return 随机串 */ public static string GenerateNonceStr() { return Guid.NewGuid().ToString().Replace("-", ""); } }}
3、所有的工具类完成了,下面就开始调用
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using WxPayTest.WxHelper; namespace WxPayTest.Controllers { public class TestController : Controller { // // GET: /Test/ public ActionResult Index() { NativePay nativePay = new NativePay(); //生成扫码支付url string url2 = nativePay.GetPayUrl("123456789"); ViewBag.url = url2; return View(); } } }
4、页面操作,因为之前的调用微信给我们有用的东西就是一个二维码链接,我们还得把这个连接转换为二维码。
jquery.qrcode.min.js 可以百度下载,我这里提供一个连接:http://download.csdn.net/detail/zuozhiyoulaisam/8117785
@{ ViewBag.Title = "Index"; } <script src="~/Scripts/jquery-1.10.2.min.js"></script> <script src="~/Scripts/jquery.qrcode.min.js"></script> <h2>Index</h2> <div id="code"></div> <script> var urlText = '@ViewBag.url'; jQuery('#code').qrcode("" + urlText + ""); </script>
5、ok你可以完整的使用微信扫码支付了,回调操作后续在写(回调链接地址)。
相关文章推荐
- 微信公众平台--5.其他
- 微信公众号支付和移动支付
- 微信公众平台--4.接收事件推送消息
- 支付宝和微信
- 微信付款
- 微信公众平台--3.普通消息交互(发送与接收)
- 微信公众平台--2.获取接口调用凭据
- 微信公众平台--1.开发者接入
- 微信分享
- 手把手教你免费看IOS微信红包照片
- iOS集成微信支付问题, 友盟SDK有干扰或者说是冲突的解决
- 图像的模糊处理原理
- iOS开发:微信支付
- 最新版微信qq抢红包辅助解析
- 微信抢红包辅助工具 AccessibilityService
- 微信公众号多客服开发介绍
- 微信公众号内redirect_uri参数错误
- 仿微信界面的只能点击,不能滑动,和随机显示不同的布局
- JAVA应用小程序(Applet)
- 如何免费看微信红包照片