在小程序的web-view里使用微信的JS-SDK,步骤整理,以及遇到的坑

官方文档在这里:https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html

如果只是使用wx.miniProgram.navigateTo这种导航的接口,jssdk可以不用做配置,引用js后直接使用就行,如果chooseImage这种,就需要获取配置了,步骤如下:

  1. 先在后端通过AppID和AppSecret取到access_token,并缓存access_token
  2. 再通过access_token获取到jsapi_ticket,jsapi_ticket的值也要缓存
  3. 使用jsapi_ticket、当前URL、随机字符串、1970年1月1日00:00:00至今的秒数生成签名及及配置,返回给前端,签名记得使用https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign校验是否正确
  4. 前端拿到config后放到wx.config里执行
  5. 在wx.ready中注册事件

步骤比较多但是并不复杂,主要是这其中几个坑需要避开别踩到:

  1. AppID和AppSecret不能用小程序的,要用公众号的,否则会报invalid url domain的错误,官方文档上并没有说明这一点,所以这个坑非常深非常隐蔽,另外这个公众号要不要与小程序关联还不清楚,我用的是关联的。
  2. 签名用到的当前URl不要解码,拿到的是什么就用什么,否则即使签名校验通过也会报签名错误
  3. 如果你用了chooseImage这个api,需要获取到选择的图片的话,官方文档上说是在success的tempFilePaths参数里,实际上并不是,是在localIds里面

以下是部分代码:

.Net后台:

        #region JS-SDK配置
        /// 
        /// 获取access_token(AppID和AppSecret不能使用小程序的,要使用公众号的)
        /// 
        /// access_token
        public static string GetAccessToken()
        {
            object obj = NetCacheHelper.GetCache("access_token");
            string access_token = "";
            if (obj == null)
            {
                string AppID = SystemHelper.GetSystemStrValue("AppID");
                string AppSecret = SystemHelper.GetSystemStrValue("AppSecret");
                string url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + AppID + "&secret=" + AppSecret;
                string value = HttpHelper.Get(url);
                WxAccessTokenModel model = JsonConvert.DeserializeObject(value);
                NetCacheHelper.SetCache("access_token", model.access_token, TimeSpan.FromSeconds(model.expires_in - 60));
                access_token = model.access_token;
            }
            else
            {
                access_token = obj.ToString();
            }
            return access_token;
        }

        /// 
        /// 获取jsapi_ticket
        /// 
        /// jsapi_ticket
        public static string GetTicket()
        {
            string access_token = GetAccessToken();
            object obj = NetCacheHelper.GetCache("jsapi_ticket");
            string jsapi_ticket = "";
            if (obj == null)
            {
                string url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+ access_token + "&type=jsapi";
                string value = HttpHelper.Get(url);
                WxTicketModel model = JsonConvert.DeserializeObject(value);
                NetCacheHelper.SetCache("jsapi_ticket", model.ticket, TimeSpan.FromSeconds(model.expires_in - 60));
                jsapi_ticket = model.ticket;
            }
            else
            {
                jsapi_ticket = obj.ToString();
            }
            return jsapi_ticket;
        }

        /// 
        /// 获取JSSDK的配置
        /// 
        /// 需要使用的JS接口列表
        /// 是否是调试模式
        /// JSSDK的配置
        public static string GetJSSDKConfig(List jsApiList, bool isDebug)
        {
            string url = HttpHelper.GetCurrentFullURL(true, false, "weixin");
            return GetJSSDKConfig(jsApiList, isDebug, url);
        }

        /// 
        /// 获取JSSDK的配置
        /// 
        /// 需要使用的JS接口列表
        /// 是否是调试模式
        /// 页面URL
        /// JSSDK的配置
        public static string GetJSSDKConfig(List jsApiList, bool isDebug, string url)
        {
            #region 准备签名必须要的参数
            string noncestr = DataHelper.GetRandomString(16, true, true, true, false, "");
            string jsapi_ticket = GetTicket();
            string timestamp = DateHelper.Get19700101seconds(false).ToString();
            #endregion

            #region 进行签名
            Dictionary dic = new Dictionary();
            dic.Add("noncestr", noncestr);
            dic.Add("jsapi_ticket", jsapi_ticket);
            dic.Add("timestamp", timestamp);
            dic.Add("url", url);
            dic = dic.OrderBy(t => t.Key).ToDictionary(m => m.Key, m => m.Value);
            string sign = dic.Aggregate("", (current, d) => current + (d.Key + "=" + d.Value + "&")).Trim('&');
            string signature = EncryptionHelper.GetSHA1(sign).ToLower();
            #endregion

            #region 获得配置
            WxJSSDKConfig config = new WxJSSDKConfig();
            config.appId = SystemHelper.GetSystemStrValue("AppID");
            config.debug = isDebug;
            config.jsApiList = jsApiList;
            config.nonceStr = noncestr;
            config.signature = signature;
            config.timestamp = timestamp;
            #endregion

            string json = JsonConvert.SerializeObject(config);
            return json;
        }

        #endregion

.Net后台的部分帮助类和模型类:

    /// 
    /// 获取微信access_token返回的数据格式
    /// 
    public class WxAccessTokenModel
    {
        /// 
        /// access_token
        /// 
        public string access_token { get; set; }
        /// 
        /// expires_in
        /// 
        public int expires_in { get; set; }
    }
    /// 
    /// 访问微信ticket返回的数据格式
    /// 
    public class WxTicketModel
    {
        /// 
        /// expires_in
        /// 
        public int expires_in { get; set; }

        /// 
        /// ticket
        /// 
        public string ticket { get; set; }

        /// 
        /// 错误代码
        /// 
        public string errcode { get; set; }

        /// 
        /// 错误消息
        /// 
        public string errmsg { get; set; }
    }
    /// 
    /// 微信JS-SDK的配置
    /// 
    public class WxJSSDKConfig
    {
        /// 
        /// 开启调试模式
        /// 
        public bool debug { get; set; }
        /// 
        /// 公众号的唯一标识
        /// 
        public string appId { get; set; }
        /// 
        /// 生成签名的时间戳
        /// 
        public string timestamp { get; set; }
        /// 
        /// 生成签名的随机串
        /// 
        public string nonceStr { get; set; }
        /// 
        /// 签名
        /// 
        public string signature { get; set; }
        /// 
        /// 需要使用的JS接口列表
        /// 
        public List jsApiList { get; set; }
    }
        ///
        ///生成随机字符串 
        ///
        ///目标字符串的长度
        ///是否包含数字,1=包含,默认为包含
        ///是否包含小写字母,1=包含,默认为包含
        ///是否包含大写字母,1=包含,默认为包含
        ///是否包含特殊字符,1=包含,默认为不包含
        ///要包含的自定义字符,直接输入要包含的字符列表
        ///指定长度的随机字符串
        public static string GetRandomString(int length, bool useNum, bool useLow, bool useUpp, bool useSpe, string custom)
        {
            byte[] b = new byte[4];
            new System.Security.Cryptography.RNGCryptoServiceProvider().GetBytes(b);
            Random r = new Random(BitConverter.ToInt32(b, 0));
            string s = null, str = custom;
            if (useNum == true) { str += "0123456789"; }
            if (useLow == true) { str += "abcdefghijklmnopqrstuvwxyz"; }
            if (useUpp == true) { str += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; }
            if (useSpe == true) { str += "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; }
            for (int i = 0; i < length; i++)
            {
                s += str.Substring(r.Next(0, str.Length - 1), 1);
            }
            return s;
        }
        /// 
        /// 获取1970年1月1日00:00:00至今的秒数
        /// 
        /// 是否保留小数点
        /// 1970年1月1日00:00:00至今的秒数
        public static double Get19700101seconds(bool keepDecimal)
        {
            DateTime time = DateTime.Parse("1970-01-01 00:00:00");
            DateTime now = DateTime.Now;
            TimeSpan ts = now - time;
            if (keepDecimal)
            {
                return ts.TotalSeconds;
            }
            else
            {
                return Math.Floor(ts.TotalSeconds);
            }
        }
        /// 
        /// SHA1加密
        /// 
        /// 原字符串
        /// 加密后的字符串
        public static string GetSHA1(string source)
        {
            try
            {
                SHA1 sha1 = new SHA1CryptoServiceProvider();
                byte[] bytes_in = Encoding.UTF8.GetBytes(source);
                byte[] bytes_out = sha1.ComputeHash(bytes_in);
                sha1.Dispose();
                string result = BitConverter.ToString(bytes_out);
                result = result.Replace("-", "");
                return result;
            }
            catch (Exception)
            {
                return "";
            }
        }

.Net调用:

string config = WxHelper.GetJSSDKConfig(new List() { "chooseImage", "previewImage", "uploadImage" }, false);

前端JS:

    var config = $("#Config").val();
    config = JSON.parse(config);
    wx.config(config);
    wx.ready(function () {
        document.querySelector('#addFile').onclick = function () {
            wx.chooseImage({
                success: function (res) {
                    wx.previewImage({
                        current: res.localIds[0], // 当前显示图片的http链接
                        urls: res.localIds// 需要预览的图片http链接列表
                    })
                }
            });
        };
    });

    wx.error(function (res) {
        
    });

 

你可能感兴趣的:(js,微信小程序,微信开发,.Net)