zoukankan      html  css  js  c++  java
  • 用c#开发微信 (13) 微统计

     

    微信平台自带的统计功能太简单,有时我们需要统计有哪些微信个人用户阅读、分享了微信公众号的手机网页,以及微信个人用户访问手机网页的来源:朋友圈分享访问、好友分享消息访问等。本系统实现了手机网页阅读、分享与来源统计及手机网页在朋友圈的传播路径分析。

    本系统使用最传统的三层架构。本文是微统计的第三篇,主要介绍如下内容:

     

    1. 为页面HighCharts画图控件提供数据

    2. 接收分享记录信息并保存到数据库

    3. 访问记录统计图

    4. 阅读统计界面

    5. 处理文字请求

    前端开发框架使用Bootstrap,没有注明前台的页面表示前台不用显示任何内容

    1. 为页面HighCharts画图控件提供数据 Data.aspx

    public partial class Data : System.Web.UI.Page
            {
                protected void Page_Load(object sender, EventArgs e)
                {
                    string result = "";
                    string typeStr = System.Web.HttpContext.Current.Request.QueryString["type"];
                    if (!string.IsNullOrEmpty(typeStr))
                    {
                        switch (typeStr)
                        {
                            case "navChart": //页面访问图
                                result = JsonConvert.SerializeObject(GetPageNavStatistics());
                                break;
                            case "shareChart": //页面分享图
                                result = JsonConvert.SerializeObject(GetPageShareStatistics());
                                break;
                        }
                    }
                    //将HighCharts绘图所需的数据返回给页面
                    HttpResponse response = System.Web.HttpContext.Current.Response;
                    response.ContentType = "application/json";
                    response.Write(result);
                    response.End();
                }
     
                /// <summary>
                /// 获取页面访问统计信息
                /// </summary>
                /// <returns></returns>
                private ChartData GetPageNavStatistics()
                {
                    //取过去两天的数据进行统计
                    DateTime startTime = DateTime.Now.AddDays(-3);
                    DateTime endTime = DateTime.Now.AddDays(1);
                    List<PageNavEntity> temp = new PageNavBll().GetPageNavList();
                    List<decimal> statistics = new List<decimal>();
                    //HighCharts时间轴的起始时间
                    ChartData chartData = new ChartData
                    {
                        StartYear = startTime.Year,
                        StartDay = startTime.Day,
                        StartMonth = startTime.Month
                    };
                    //生成按小时统计的数据
                    while (startTime < endTime)
                    {
                        statistics.Add(temp.FindAll(e => e.VisitTime >= startTime && e.VisitTime < startTime.AddHours(1)).Count());
                        startTime = startTime.AddHours(1);
                    }
                    chartData.Statistics = statistics.ToArray();
                    return chartData;
                }
     
                /// <summary>
                /// 获取页面分享统计信息
                /// </summary>
                /// <returns></returns>
                private ChartData GetPageShareStatistics()
                {
                    //取过去两天的数据进行统计
                    DateTime startTime = DateTime.Now.AddDays(-3);
                    DateTime endTime = DateTime.Now.AddDays(1);
                    List<PageShareEntity> temp = new PageShareBll().GetPageShareList();
                    List<decimal> statistics = new List<decimal>();
                    //HighCharts时间轴的起始时间
                    ChartData chartData = new ChartData
                    {
                        StartYear = startTime.Year,
                        StartDay = startTime.Day,
                        StartMonth = startTime.Month
                    };
                    //生成按小时统计的数据
                    while (startTime < endTime)
                    {
                        statistics.Add(temp.FindAll(e => e.ShareTime >= startTime && e.ShareTime < startTime.AddHours(1)).Count());
                        startTime = startTime.AddHours(1);
                    }
                    chartData.Statistics = statistics.ToArray();
                    return chartData;
                }
            }

    2. 接收分享记录信息并保存到数据库 Share.aspx

    public partial class Share : System.Web.UI.Page
        {
            ILog m_Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
     
            protected void Page_Load(object sender, EventArgs e)
            {
                string typeStr = Request.QueryString["type"];
     
                m_Log.Info("share type: " + typeStr);
                m_Log.Info("share url: " + Request["url"]);
     
                if (!string.IsNullOrEmpty(typeStr))
                {
                    //识别分享类型
                    ShareType type = ShareType.Unknown;
                    switch (typeStr)
                    {
                        case "timeline":
                            type = ShareType.Timeline;
                            break;
                        case "friend":
                            type = ShareType.Friend;
                            break;
                    }
                    //构造分享记录
                    var pageShare = new PageShareEntity()
                    {
                        Id = Guid.NewGuid(),
                        Url = GetOrigenalUrl(Request["url"]),
                        ParentShareOpenId = Request["s"],
                        ShareOpenId = Request["u"],
                        From = type,
                        ShareTime = DateTime.Now
                    };
                    //保存分享记录
                   bool insertShare = new PageShareBll().InsertPageShare(pageShare);
     
                   m_Log.Info("insert share: " + insertShare.ToString());
                }
            }
     
            /// <summary>
            /// 获取不含统计相关参数的页面地址
            /// </summary>
            /// <param name="url">网址</param>
            /// <returns>不含统计相关参数的页面地址</returns>
            private string GetOrigenalUrl(string url)
            {
                url = System.Web.HttpUtility.UrlDecode(url);
                Uri uri = new Uri(url);
                StringBuilder urlBuilder = new StringBuilder();
                //获取不含QueryString的URL
                urlBuilder.Append("http://")
                    .Append(uri.Host)
                    .Append(uri.AbsolutePath)
                    .Append("?");
                //构造移除统计相关参数的Query
                Dictionary<string, string> queryString = uri.Query.Replace("?", "").Split('&').Where(p => !string.IsNullOrEmpty(p)).ToDictionary(p => p.Split('=')[0], p => p.Split('=')[1].Split('#')[0]);
                foreach (var key in queryString.Keys)
                {
                    if (key != "s" && key != "u" && key != "from" && key != "code" && key != "state")
                    {
                        urlBuilder.Append(key).Append("=").Append(queryString[key]).Append("&");
                    }
                }
                return urlBuilder.ToString();
            }
        }

    当发送朋友或朋友圈时保存分享数据。

     

    3. 访问记录统计图 StatisticsPage.aspx

    前台:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="StatisticsPage.aspx.cs" Inherits="Statistics.StatisticsPage" %>
     
    <!DOCTYPE html>
     
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>统计</title>
        <%-- Bootstrap --%>
        <link href="Css/bootstrap.min.css" rel="stylesheet" type="text/css" />
        <script src="Scripts/bootstrap.min.js" type="text/javascript"></script>
        <script src="Scripts/jquery-1.9.1.min.js" type="text/javascript"></script>
        <%-- HighCharts用于图表显示 --%>
        <link href="Css/highcharts/charts.css" rel="stylesheet" type="text/css" />
        <script src="Scripts/HighCharts/highcharts.js" type="text/javascript"></script>
        <script src="Scripts/HighCharts/highcharts-more.js" type="text/javascript"></script>
        <script src="Scripts/HighCharts/publiclinecharts.js" type="text/javascript"></script>
    </head>
    <body>
        <div class="container">
            <div class="row-fluid">
                <div class="span12">
                    <h3>访问记录</h3>
                    <%-- 访问记录统计图 --%>
                    <div class="box">
                        <div class="box-content">
                            <div class="row" style="margin-top: 30px; ">
                                <div class="area">
                                    <div id="page-nav-chart">
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <%-- 访问记录列表 --%>
                    <div class="maincontentinner1" >
                        <div id="Div12" class="dataTables_wrapper">
                            <table id="page-nav-table" class="table table-bordered responsive dataTable">
                                <%-- 访问记录列表列名 --%>
                                <thead>
                                    <tr>
                                        <th>页面地址
                                        </th>
                                        <th>访问来源
                                        </th>
                                        <th>访问者openid
                                        </th>
                                        <th>分享自openid
                                        </th>
                                        <th>访问时间
                                        </th>
                                    </tr>
                                </thead>
                                <tbody id="page-nav-table-body">
                                    <%-- 一行一行生成访问记录列表 --%>
                                    <% foreach (Statistics.ViewEntity.PageNavEntity entity in (ViewState["NavList"] as List<Statistics.ViewEntity.PageNavEntity>))
                                       { %>
                                    <tr class="gradeX odd">
                                        <td>
                                            <%= entity.Url%>
                                            </td>
                                        <td class=" ">
                                            <%= entity.From.ToString()%>
                                            </td>
                                        <td class=" ">
                                            <%= entity.NavOpenId%>
                                            </td>
                                        <td class=" ">
                                            <%= entity.ShareOpenId%>
                                            </td>
                                        <td class=" ">
                                            <%= entity.VisitTime.ToString()%>
                                            </td>
                                    </tr>
                                    <% } %>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <script>
            //图表参数
            var pageNavChartOpts = {
                getStatisticsUrl: 'Data.aspx?type=navChart', //读取数据的访问地址
                titletext: "",
                ytext: "",
                startyear: 0,
                startmonth: 0,
                startday: 0,
                lineinterval: 3600 * 1000, //竖线以1小时为间隔显示
                pointInterval: 3600 * 1000,//点以1小时为间隔显示
                countArray: [],
                formid: "page-nav-chart", //图表容器ID
                seriesname: "访问次数",
                unit: "次"
            };
            jQuery(function () {
                //使用HighCharts绘制图表
                highcharts.extFunction.PreDrawMethod = function (repJson) {
                    pageNavChartOpts.startyear = repJson.StartYear;
                    pageNavChartOpts.startmonth = repJson.StartMonth;
                    pageNavChartOpts.startday = repJson.StartDay;
                    highcharts.displayMode = repJson.DisplayMode;
                    pageNavChartOpts.lineinterval = repJson.LineInterval;
                    pageNavChartOpts.pointInterval = repJson.PointInterval;
                };
                highcharts.init(pageNavChartOpts);
            });
        </script>
    </body>
    </html>

    用HighCharts来图表显示数据。

     

    后台:

    protected void Page_Load(object sender, EventArgs e)
    {
        //传递给页面显示的记录列表
        ViewState["NavList"] = new PageNavBll().GetPageNavList();
        ViewState["ShareList"] = new PageShareBll().GetPageShareList();
    }

    通过业务逻辑层获取数据。

     

    4. 阅读统计界面 WeixinPageIndex.aspx

    前台:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WeixinPageIndex.aspx.cs" Inherits="Statistics.WeixinPageIndex" %>
     
    <!DOCTYPE html>
     
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <script src="Scripts/jquery-1.9.1.min.js"></script>
        <script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
    </head>
    <body>
        <form id="form1" type="post" runat="server">
            <div>
                <%-- 所有的跳转页面,加上访问者与分享者的OpenId --%>
                <a href="WeixinPageSubPage.aspx?u=<%= ViewState["navOpenId"] as string %>&s=<%= ViewState["shareOpenId"] as string %>">WeixinPageSubPage</a>
     
            </div>
        </form>
    </body>
    </html>
    <script>
        var url = location.href;
        alert(url);
        wx.config({
            debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
            appId: '<%= appID %>', // 必填,公众号的唯一标识
            timestamp: '<%= timestamp %>', // 必填,生成签名的时间戳
            nonceStr: '<%= nonceStr %>', // 必填,生成签名的随机串
            signature: '<%= signature %>',// 必填,签名,见附录1
            // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
            jsApiList: [
            'onMenuShareAppMessage'
            ]
        });
     
        friendcallback = function (res) {
            var shareUrl = "Share.aspx?type=friend&url=" + encodeURIComponent(url) + "&u=" + "<%= ViewState["navOpenId"] as string %>" + "&s=" + "<%= ViewState["shareOpenId"] as string %>";
     
            //AJAX请求
            $.ajax({
                type: "get",
                url: shareUrl,
                beforeSend: function () {
                },
                success: function () {
                },
                complete: function () {
                },
                error: function () {
                }
            });
        };
     
        wx.ready(function () {
            wx.onMenuShareAppMessage({
                title: '用c#开发微信 系列汇总',
                desc: '网上开发微信开发的教程很多,但c#相对较少。这里列出了我所有c#开发微信的文章,方便自己随时查阅。如果可能,我尽量附上源码,这样就可以直接发布运行看效果,更好地理解原理。',
                link: url,
                imgUrl: 'http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg',
                trigger: function (res) {
                },
                success: function (res) {
                    friendcallback(res);
                },
                cancel: function (res) {
                },
                fail: function (res) {
                    alert(JSON.stringify(res));
                }
            });
            wx.onMenuShareTimeline({
                title: '用c#开发微信 系列汇总',
                desc: '网上开发微信开发的教程很多,但c#相对较少。这里列出了我所有c#开发微信的文章,方便自己随时查阅。如果可能,我尽量附上源码,这样就可以直接发布运行看效果,更好地理解原理。',
                link: url,
                imgUrl: 'http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg',
                trigger: function (res) {
                },
                success: function (res) {
                    friendcallback(res);
                },
                cancel: function (res) {
                },
                fail: function (res) {
                    alert(JSON.stringify(res));
                }
            });
        });
     
    </script>

    利用JS-SDK来获取分享者,并通过Share页面来保存分享数据。

     

     

    后台:

    public partial class WeixinPageIndex : System.Web.UI.Page
        {
            static ILog m_Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
     
            public string timestamp = string.Empty;
            public string nonceStr = string.Empty;
            public string signature = string.Empty;
     
            /// <summary>
            /// 从微信公众平台获取的开发者凭据
            /// </summary>
            public readonly string appID = ConfigurationManager.AppSettings["appID"];
            /// <summary>
            /// 从微信公众平台获取的开发者凭据
            /// </summary>
            readonly string appSecret = ConfigurationManager.AppSettings["appSecret"];
     
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!Page.IsPostBack)
                {
                    #region 1. Get wx.config
     
                    string ticket = string.Empty;
                    timestamp = JSSDKHelper.GetTimestamp();
                    nonceStr = JSSDKHelper.GetNoncestr();
                    JSSDKHelper jssdkhelper = new JSSDKHelper();
     
                    try
                    {
                        ticket = JsApiTicketContainer.TryGetTicket(appID, appSecret);
                        signature = jssdkhelper.GetSignature(ticket, nonceStr, timestamp, Request.Url.AbsoluteUri.ToString());
                    }
                    catch (ErrorJsonResultException ex)
                    {
                        m_Log.Error("errorcode:" + ex.JsonResult.errcode.ToString() + "  errmsg: " + ex.JsonResult.errmsg, ex);
                    }
     
                    #endregion
     
                    NameValueCollection parameters = System.Web.HttpContext.Current.Request.Params;
     
                    m_Log.Info("URL: " + Request.Url.ToString());
     
                    //取得链接中的分享者OpenId
                    string shareOpenId = parameters["s"];
                    //获取访问者的OpenId
                    string navOpenId = GetNavOpenId();
     
                    if (navOpenId != null)
                    {
                        NavStatistics(navOpenId, shareOpenId);
                        //传递给页面的访问者OpenId
                        ViewState["navOpenId"] = navOpenId;
                        //传递给页面的分享者OpenId
                        ViewState["shareOpenId"] = shareOpenId;
                    }
     
                    m_Log.Info("timestamp: " + timestamp + " nocestr: " + nonceStr + " singnature: " + signature);
                    m_Log.Info("nav open id: " + navOpenId + " share open id: " + shareOpenId);
                }
            }
     
            /// <summary>
            /// 记录页面访问
            /// </summary>
            /// <param name="navOpenId">访问者微信openid</param>
            /// <param name="shareOpenId">当访问来源为朋友圈时的分享者微信openid</param>
            private void NavStatistics(string navOpenId, string shareOpenId)
            {
                //获取访问来源
                NavFrom fromType = GetNavFromType();
                //构造访问记录
                var pageNav = new PageNavEntity()
                {
                    Id = Guid.NewGuid(),
                    Url = GetOrigenalUrl(),
                    NavOpenId = navOpenId,
                    ShareOpenId = navOpenId == shareOpenId ? "" : shareOpenId,
                    From = fromType,
                    VisitTime = DateTime.Now
                };
                //访问记录写入数据库
                new PageNavBll().InsertPageNav(pageNav);
            }
     
            /// <summary>
            /// 判断页面访问来源类型
            /// </summary>
            /// <returns></returns>
            private static NavFrom GetNavFromType()
            {
                //网址中的参数集合
                NameValueCollection parameters = System.Web.HttpContext.Current.Request.Params;
                string fromStr = parameters["from"]; //发送给朋友、分享到朋友圈的链接会含有from参数
     
                m_Log.Info("from: " + fromStr);
     
                NavFrom fromType;
                if (!Enum.TryParse<NavFrom>(fromStr, true, out fromType)) //通过判断from参数,识别页面访问是来自于发送给朋友的链接还是分享到朋友圈的链接
                {
                    //获取HTTP访问头中的User-Agent参数的值
                    string agent = System.Web.HttpContext.Current.Request.Headers["User-Agent"];
                    if (agent.Contains(NavFrom.MicroMessenger.ToString())) //判断页面是否是在微信内置浏览器中打开
                        fromType = NavFrom.MicroMessenger;
                    else
                        fromType = NavFrom.Other;
                }
                return fromType;
            }
     
            /// <summary>
            /// 获取不含统计相关参数的页面地址
            /// </summary>
            /// <returns>不含统计相关参数的页面地址</returns>
            private string GetOrigenalUrl()
            {
                StringBuilder urlBuilder = new StringBuilder();
                //获取不含QueryString的URL
                urlBuilder.Append("http://")
                    .Append(System.Web.HttpContext.Current.Request.Url.Host)
                    .Append(System.Web.HttpContext.Current.Request.Url.AbsolutePath)
                    .Append("?");
                //构造移除统计相关参数的Query
                foreach (var key in System.Web.HttpContext.Current.Request.QueryString.AllKeys)
                {
                    if (key != "s" && key != "u" && key != "from" && key != "code" && key != "state")
                    {
                        urlBuilder.Append(key).Append("=").Append(System.Web.HttpContext.Current.Request.QueryString[key]).Append("&");
                    }
                }
                return urlBuilder.ToString();
            }
     
            /// <summary>
            /// 获取访问者openId
            /// </summary>
            private string GetNavOpenId()
            {
                NameValueCollection parameters = System.Web.HttpContext.Current.Request.Params;
                //获取链接中的openId
                string navOpenId = parameters["u"];
                #region 如果是从微信浏览器浏览,获取真实的微信OpenId
                if (!string.IsNullOrEmpty(appID) && !string.IsNullOrEmpty(appSecret))
                {
                    string accessSource = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_USER_AGENT"];
     
                    if (accessSource.Contains("MicroMessenger")) //如果是从微信打开页面
                    {
                        string[] cookieKeys = new[] { CookieHelper.COOKIE_NAME };
                        Dictionary<string, string> realIdCookie = CookieHelper.GetLoginCookies(cookieKeys); //获取保存在Cookie中的OpenId
                        //如果Cookie中不存在OpenId,或者链接中的openId与Cookie中的OpenId不一致,链接中的openId为分享者的OpenId,需要获取当前用户的真实OpenId
                        if (NeedGetReadOpenId(parameters, realIdCookie))
                        {
                            if (parameters["code"] == null)
                            {
                                // 先去获取code,并记录分享者
                                string snsapi_baseUrl = GoCodeUrl(navOpenId);
                                if (!string.IsNullOrEmpty(snsapi_baseUrl))
                                {
                                    CookieHelper.CleanLoginCookie(cookieKeys);
                                    //跳转到微信网页授权页面
                                    System.Web.HttpContext.Current.Response.Redirect(snsapi_baseUrl, true);
                                    System.Web.HttpContext.Current.Response.End();
                                    return null;
                                }
                            }
                            else
                            {
                                m_Log.Info("code: " + parameters["code"].ToString());
     
                                OAuthAccessTokenResult tokenResult = GetRealOpenId(parameters["code"].ToString());
                                if (null != tokenResult && !string.IsNullOrEmpty(tokenResult.openid))
                                {
                                    m_Log.Info("tokenResult.openid: " + tokenResult.openid);
     
                                    navOpenId = tokenResult.openid;
                                    // 获取到的当前访问者的OpenId保存到cookie里
                                    CookieHelper.CleanLoginCookie(cookieKeys);
                                    realIdCookie[CookieHelper.COOKIE_NAME] = tokenResult.openid;
                                    CookieHelper.WriteLoginCookies(realIdCookie, DateTime.MinValue);
                                }
                            }
                        }
                    }
                }
                #endregion
                return navOpenId;
            }
     
            /// <summary>
            /// 如果Cookie中存在OpenId且链接中的openId与Cookie中的OpenId一致
            /// 则不需要调用网页授权接口,链接中的openId即为当前访问者的真实OpenId
            /// </summary>
            /// <param name="parameters"></param>
            /// <param name="realIdCookie"></param>
            /// <returns></returns>
            private bool NeedGetReadOpenId(NameValueCollection parameters, Dictionary<string, string> realIdCookie)
            {
                string referer = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_REFERER"];
                string openId = null;
                if (realIdCookie != null)
                {
                    if (realIdCookie.ContainsKey(CookieHelper.COOKIE_NAME))
                    {
                        openId = realIdCookie[CookieHelper.COOKIE_NAME];
                    }
                }
     
                m_Log.Info("NeedGetReadOpenId openid: " + openId + " referer: " + referer + " u: " + parameters["u"].ToString());
     
                if (!string.IsNullOrEmpty(referer) && openId == parameters["u"].ToString())
                    return false;
                else
                    return true;
            }
     
            /// <summary>
            /// 网页授权接口第一步
            /// 跳转到获取code的url
            /// </summary>
            /// <param name="shareOpenId">当访问来源为朋友圈时的分享者微信openid</param>
            private string GoCodeUrl(string shareOpenId)
            {
                string url = System.Web.HttpContext.Current.Request.Url.AbsoluteUri + "&s=" + shareOpenId; //添加分享者OpenId
                return OAuthApi.GetAuthorizeUrl(appID, url, "STATE", OAuthScope.snsapi_base);
            }
     
            /// <summary>
            /// 网页授权接口第二步
            /// 解析code并获取当前访问者真正的openId
            /// </summary>
            /// <param name="parameters">url参数</param>
            /// <returns>真正的openId</returns>
            private OAuthAccessTokenResult GetRealOpenId(string code)
            {
                OAuthAccessTokenResult result = new OAuthAccessTokenResult();
                try
                {
                    result = OAuthApi.GetAccessToken(appID, appSecret, code);
                }
                catch (Exception ex)
                {
                    m_Log.Error(ex.Message, ex);
                }
                return result;
            }
        }

    保存访问者记录,识别访问者和分享者。

     

    5. 处理文字请求

    在CustomMessageHandler里处理文字请求,详细的使用方法可参考《用c#开发微信(2)扫描二维码,用户授权后获取用户基本信息 (源码下载)》:

    public override IResponseMessageBase OnTextRequest(RequestMessageText requestMessage)
            {
                var responseMessage = CreateResponseMessage<ResponseMessageNews>();
                responseMessage.Articles.Add(new Article()
                {
                    Title = "首页",
                    Description = "点击进入首页",
                    PicUrl = "",
                    Url = System.Configuration.ConfigurationManager.AppSettings["site"] + "/WeixinPageIndex.aspx?u=" + requestMessage.FromUserName
                });
                return responseMessage;
            }

    这里把访问者的OpenId带上,为了方便识别访问者和分享者。

     

     

    所有界面如下:

    image

    未完待续!!!

     

     

    用c#开发微信 系列汇总
  • 相关阅读:
    【转+补充】在OpenCV for Android 2.4.5中使用SURF(nonfree module)
    Delphi StarOffice Framework Beta 1.0 发布
    Angular ngIf相关问题
    angularjs文档下载
    公众号微信支付开发
    公众号第三方平台开发 教程六 代公众号使用JS SDK说明
    公众号第三方平台开发 教程五 代公众号处理消息和事件
    公众号第三方平台开发 教程四 代公众号发起网页授权说明
    公众号第三方平台开发 教程三 微信公众号授权第三方平台
    公众号第三方平台开发 教程二 component_verify_ticket和accessToken的获取
  • 原文地址:https://www.cnblogs.com/fengwenit/p/4553728.html
Copyright © 2011-2022 走看看