隨着微信開逐步開放更多JSSDK的接口,咱們能夠利用自定義網頁的方式來調用更多微信的接口,實現咱們更加豐富的界面功能和效果,例如咱們能夠在頁面中調用各類手機的硬件來獲取信息,如攝像頭拍照,GPS信息、掃描二維碼等等,本篇介紹如何利用這些JSSDK接口實現簽到的功能,其中籤到須要報送地理座標和地址,調用攝像頭實時拍照,以及獲取當前用戶的相關信息等等。javascript
微信JS-SDK是微信公衆平臺面向網頁開發者提供的基於微信內的網頁開發工具包。經過使用微信JS-SDK,網頁開發者可藉助微信高效地使用拍照、選圖、語音、位置等手機系統的能力,同時能夠直接使用微信分享、掃一掃、卡券、支付等微信特有的能力,爲微信用戶提供更優質的網頁體驗。html
目前JSSDK支持的接口分類包括下面幾類:基礎接口、分享接口、圖像接口、音頻接口、智能接口、設備信息、地理位置、搖一搖周邊、界面操做、微信掃一掃、微信小店、微信卡券、微信支付,隨着微信功能的所有整合,估計更多的接口會陸續開放出來。java
在微信的後臺進入【開發者文檔】模塊,咱們能夠看到對應的JSSDK的功能分類和介紹,以下所示。jquery
從右側咱們能夠詳細看到各個接口的使用說明,基本上JSSDK的使用方法都相似,所以調試經過並掌握其中一兩個,其餘的也就依葫蘆畫瓢,照着作就能夠了。git
1)JSSDK使用步驟web
步驟一:綁定域名ajax
先登陸微信公衆平臺進入「公衆號設置」的「功能設置」裏填寫「JS接口安全域名」。以下所示,在公衆平臺進行設置。算法
備註:登陸後可在「開發者中心」查看對應的接口權限。json
步驟二:引入JS文件api
在須要調用JS接口的頁面引入以下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js
如需使用搖一搖周邊功能,請引入 http://res.wx.qq.com/open/js/jweixin-1.1.0.js
備註:支持使用 AMD/CMD 標準模塊加載方法加載
固然,咱們通常編輯頁面,爲了方便實現更多的效果,可能還會引入其餘JS,如JQuery的類庫等等。還有,咱們還能夠基於WeUI的jquery-weui類庫,實現更加豐富的功能,以下是咱們案例代碼裏面的JS引用。
<script src="~/Content/wechat/jquery-weui/lib/jquery-2.1.4.js"></script> <script src="~/Content/wechat/jquery-weui/js/jquery-weui.js"></script> <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.1.0.js"></script>
步驟三:經過config接口注入權限驗證配置
全部須要使用JS-SDK的頁面必須先注入配置信息,不然將沒法調用(同一個url僅需調用一次,對於變化url的SPA的web app可在每次url變化時進行調用,目前Android微信客戶端不支持pushState的H5新特性,因此使用pushState來實現web app的頁面會致使簽名失敗,此問題會在Android6.2中修復)。
wx.config({ debug: true, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。 appId: '', // 必填,公衆號的惟一標識 timestamp: , // 必填,生成簽名的時間戳 nonceStr: '', // 必填,生成簽名的隨機串 signature: '',// 必填,簽名,見附錄1 jsApiList: [] // 必填,須要使用的JS接口列表,全部JS接口列表見附錄2 });
以上的配置就是JSSDK的核心所在,裏面須要配置好對應的appid,還有timestamp,nonceStr這些都沒有特別之處,最值得注意的是signature的實現機制,這樣咱們在後臺生成好對應的值,賦給JS頁面就能夠了,這樣也是最爲安全的作法。
以下代碼是咱們實際項目裏面,在Asp.net的視圖頁面裏面的HTML代碼,以下所示。
<script language="javascript"> var appid = '@ViewBag.appid'; var noncestr = '@ViewBag.noncestr'; var signature = '@ViewBag.signature'; var timestamp = '@ViewBag.timestamp'; wx.config({ debug: false, appId: appid, // 必填,公衆號的惟一標識 timestamp: timestamp, // 必填,生成簽名的時間戳 nonceStr: noncestr, // 必填,生成簽名的隨機串 signature: signature, // 必填,簽名,見附錄1 jsApiList: [ 'checkJsApi', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone', 'hideMenuItems', 'showMenuItems', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem', 'translateVoice', 'startRecord', 'stopRecord', 'onVoiceRecordEnd', 'playVoice', 'onVoicePlayEnd', 'pauseVoice', 'stopVoice', 'uploadVoice', 'downloadVoice', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'getNetworkType', 'openLocation', 'getLocation', 'hideOptionMenu', 'showOptionMenu', 'closeWindow', 'scanQRCode', 'chooseWXPay', 'openProductSpecificView', 'addCard', 'chooseCard', 'openCard' ] });
步驟四:經過ready接口處理成功驗證
wx.ready(function(){ // config信息驗證後會執行ready方法,全部接口調用都必須在config接口得到結果以後,config是一個客戶端的異步操做,因此若是須要在頁面加載時就調用相關接口,
//則須把相關接口放在ready函數中調用來確保正確執行。對於用戶觸發時才調用的接口,則能夠直接調用,不須要放在ready函數中。 });
這個ready的接口,也就是在頁面順利加載完畢後的處理內容了,通常咱們須要作不少操做,都是須要在頁面加載完畢後才能調用相關的對象進行賦值、處理等操做。
例如咱們在頁面ready後,獲取對應的GPS座標等操做,能夠用下面的JS代碼實現。
wx.ready(function () { wx.getLocation({ type: 'wgs84', // 默認爲wgs84的gps座標,若是要返回直接給openLocation用的火星座標,可傳入'gcj02' success: function (res) { var latitude = res.latitude; // 緯度,浮點數,範圍爲90 ~ -90 var longitude = res.longitude; // 經度,浮點數,範圍爲180 ~ -180。 var speed = res.speed; // 速度,以米/每秒計 var accuracy = res.accuracy; // 位置精度 $("#lblLoacation").text(latitude + "," + longitude); } }); });
步驟五:經過error接口處理失敗驗證
wx.error(function(res){ // config信息驗證失敗會執行error函數,如簽名過時致使驗證失敗,具體錯誤信息能夠打開config的debug模式查看, // 也能夠在返回的res參數中查看,對於SPA能夠在這裏更新簽名。 });
這個error接口也就是用來處理異常信息的,通常狀況下能夠在這裏提示用戶出現的錯誤。
2)、簽名算法
簽名生成規則以下:參與簽名的字段包括noncestr(隨機字符串), 有效的jsapi_ticket, timestamp(時間戳), url(當前網頁的URL,不包含#及其後面部分) 。對全部待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)後,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1。這裏須要注意的是全部參數名均爲小寫字符。對string1做sha1加密,字段名和字段值都採用原始值,不進行URL 轉義。
即signature=sha1(string1)。 示例:
noncestr=Wm3WZYTPz0wzccnW jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg timestamp=1414587457 url=http://mp.weixin.qq.com?params=value
步驟1. 對全部待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)後,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1:
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value
步驟2. 對string1進行sha1簽名,獲得signature:
0f9de62fce790f9a083d5c99e95740ceb90c27ed
注意事項
1.簽名用的noncestr和timestamp必須與wx.config中的nonceStr和timestamp相同。
2.簽名用的url必須是調用JS接口頁面的完整URL。
3.出於安全考慮,開發者必須在服務器端實現簽名的邏輯。
如出現invalid signature 等錯誤詳見附錄5常見錯誤及解決辦法。
以上就是JSSDK整體的使用流程,雖然看起來比較抽象,可是基本上也就是這些步驟了。
上面的過程是具體的參數處理邏輯,咱們要對應到C#代碼的簽名實現,須要對幾個變量進行處理,下面是對應的生成noncestr、timestamp、以及簽名等操做的代碼。
/// <summary> /// 生成時間戳,標準北京時間,時區爲東八區,自1970年1月1日 0點0分0秒以來的秒數 /// </summary> /// <returns>時間戳</returns> private static string GetTimeStamp() { TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalSeconds).ToString(); } /// <summary> /// 生成隨機串,隨機串包含字母或數字 /// </summary> /// <returns>隨機串</returns> private static string GetNonceStr() { return Guid.NewGuid().ToString().Replace("-", ""); }
還有咱們要實現JSSDK簽名的處理,必須先根據幾個變量,構建好URL字符串,具體的處理過程,咱們能夠把它們逐一放在一個Hashtable裏面,以下代碼所示。
/// <summary> /// 獲取JSSDK所須要的參數信息,返回Hashtable結合 /// </summary> /// <param name="appId">微信AppID</param> /// <param name="jsTicket">根據Token獲取到的JSSDK ticket</param> /// <param name="url">頁面URL</param> /// <returns></returns> public static Hashtable GetParameters(string appId, string jsTicket, string url) { string timestamp = GetTimeStamp(); string nonceStr = GetNonceStr(); // 這裏參數的順序要按照 key 值 ASCII 碼升序排序 string rawstring = "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "×tamp=" + timestamp + "&url=" + url + ""; string signature = GetSignature(rawstring); Hashtable signPackage = new Hashtable(); signPackage.Add("appid", appId); signPackage.Add("noncestr", nonceStr); signPackage.Add("timestamp", timestamp); signPackage.Add("url", url); signPackage.Add("signature", signature); signPackage.Add("jsapi_ticket", jsTicket); signPackage.Add("rawstring", rawstring); return signPackage; }
咱們注意到URL參數的字符串組合:
string rawstring = "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "×tamp=" + timestamp + "&url=" + url + "";
這裏咱們拼接好URL參數後,就須要使用簽名的規則來實現簽名的處理了,簽名的代碼以下所示,註釋代碼和上面代碼等同。
/// <summary> /// 使用SHA1哈希加密算法生成簽名 /// </summary> /// <param name="rawstring">待處理的字符串</param> /// <returns></returns> private static string GetSignature(string rawstring) { return FormsAuthentication.HashPasswordForStoringInConfigFile(rawstring, "SHA1").ToLower(); ////下面和上面代碼等價 //SHA1 sha1 = new SHA1CryptoServiceProvider(); //byte[] bytes_sha1_in = System.Text.UTF8Encoding.Default.GetBytes(rawstring); //byte[] bytes_sha1_out = sha1.ComputeHash(bytes_sha1_in); //string signature = BitConverter.ToString(bytes_sha1_out); //signature = signature.Replace("-", "").ToLower(); //return signature; }
這樣咱們有了對應的值後,咱們就能夠把它們的參數所有放在集合裏面了供使用。
/// <summary> /// 獲取用於JS-SDK的相關參數列表(該方法對accessToken和JSTicket都進行了指定時間的緩存處理,屢次調用不會重複生成) /// 集合裏面包括jsapi_ticket、noncestr、timestamp、url、signature、appid、rawstring /// </summary> /// <param name="appid">應用ID</param> /// <param name="appSecret">開發者憑據</param> /// <param name="url">頁面URL</param> /// <returns></returns> public Hashtable GetJSAPI_Parameters(string appid, string appSecret, string url) { string accessToken = GetAccessToken(appid, appSecret); string jsTicket = GetJSAPI_Ticket(accessToken); return JSSDKHelper.GetParameters(appid, jsTicket, url); }
下面咱們經過具體的代碼案例來介紹使用的過程。
其實簽到,均可以在微信公衆號和企業號實現,微信的企業號可能實現更佳一些,不過他們使用JSSDK的接口操做是同樣的,咱們能夠拓展過去就能夠了。這裏介紹微信公衆號JSSDK實現簽到的功能處理。
簽到的功能,咱們但願記錄用戶的GPS位置信息,還有就是利用拍照功能,拍一個照片同時上傳到服務器,這樣咱們就能夠實現整個業務效果了。
首先咱們來設計簽到的界面,代碼及效果以下所示。
界面預覽效果以下所示:
咱們來看看微信JSSDK裏面對於【獲取地理位置接口】的說明:
wx.getLocation({ type: 'wgs84', // 默認爲wgs84的gps座標,若是要返回直接給openLocation用的火星座標,可傳入'gcj02' success: function (res) { var latitude = res.latitude; // 緯度,浮點數,範圍爲90 ~ -90 var longitude = res.longitude; // 經度,浮點數,範圍爲180 ~ -180。 var speed = res.speed; // 速度,以米/每秒計 var accuracy = res.accuracy; // 位置精度 } });
以及圖形接口裏面【拍照或從手機相冊中選圖接口】的說明:
wx.chooseImage({ count: 1, // 默認9 sizeType: ['original', 'compressed'], // 能夠指定是原圖仍是壓縮圖,默認兩者都有 sourceType: ['album', 'camera'], // 能夠指定來源是相冊仍是相機,默認兩者都有 success: function (res) { var localIds = res.localIds; // 返回選定照片的本地ID列表,localId能夠做爲img標籤的src屬性顯示圖片 } });
上傳圖片到微信服務器接口以下所示。
wx.uploadImage({ localId: '', // 須要上傳的圖片的本地ID,由chooseImage接口得到 isShowProgressTips: 1, // 默認爲1,顯示進度提示 success: function (res) { var serverId = res.serverId; // 返回圖片的服務器端ID } });
備註:上傳圖片有效期3天,可用微信多媒體接口下載圖片到本身的服務器,此處得到的 serverId 即 media_id。
根據這幾個接口,咱們來對它們進行包裝,以實現咱們的業務需求。根據咱們的須要,咱們對JSSDK接口進行了調用,以下所示。
<script language="javascript"> var appid = '@ViewBag.appid'; var noncestr = '@ViewBag.noncestr'; var signature = '@ViewBag.signature'; var timestamp = '@ViewBag.timestamp'; wx.config({ debug: false, appId: appid, // 必填,公衆號的惟一標識 timestamp: timestamp, // 必填,生成簽名的時間戳 nonceStr: noncestr, // 必填,生成簽名的隨機串 signature: signature, // 必填,簽名,見附錄1 jsApiList: [ 'checkJsApi', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'getNetworkType', 'openLocation', 'getLocation' ] }); wx.ready(function () { wx.getLocation({ type: 'wgs84', // 默認爲wgs84的gps座標,若是要返回直接給openLocation用的火星座標,可傳入'gcj02' success: function (res) { var latitude = res.latitude; // 緯度,浮點數,範圍爲90 ~ -90 var longitude = res.longitude; // 經度,浮點數,範圍爲180 ~ -180。 var speed = res.speed; // 速度,以米/每秒計 var accuracy = res.accuracy; // 位置精度 $("#lblLoacation").text(latitude + "," + longitude); //解析座標地址 var location = latitude + "," + longitude; $.ajax({ type: 'GET', url: '/JSSDKTest/GetAddress?location=' + location, //async: false, //同步 //dataType: 'json', success: function (json) { $("#lblAddress").text(json); }, error: function (xhr, status, error) { $.messager.alert("提示", "操做失敗" + xhr.responseText); //xhr.responseText } }); } }); wx.getNetworkType({ success: function (res) { var networkType = res.networkType; // 返回網絡類型2g,3g,4g,wifi $("#lblNetwork").text(networkType); } }); chooseImage(); }); </script>
其中的chooseImage()是咱們在頁面開始的時候,讓用戶拍照的操做,具體JS代碼以下所示。
//拍照顯示 var localIds; function chooseImage() { wx.chooseImage({ count: 1, // 默認9 sizeType: ['original', 'compressed'], // 能夠指定是原圖仍是壓縮圖,默認兩者都有 sourceType: ['camera'], // 能夠指定來源是相冊仍是相機,默認兩者都有 success: function (res) { localIds = res.localIds; // 返回選定照片的本地ID列表,localId能夠做爲img標籤的src屬性顯示圖片 $("#imgUpload").attr("src", localIds); } }); }
但用戶使用攝像頭拍照後,就會返回一個res.localIds集合,由於咱們拍照一個,那麼能夠把它直接賦值給圖片對象,讓它顯示當前拍照的圖片。
拍照完成,咱們單擊【簽到】應該把圖片和相關的座標等信息上傳到服務器的,圖片首先是保存在微信服務器的,上傳圖片有效期3天,可用微信多媒體接口下載圖片到本身的服務器,此處得到的 serverId 即 media_id。
爲了實現咱們本身的業務數據,咱們須要把圖片集相關信息存儲在本身的服務器,這樣才能夠實現信息的保存,最後提示【簽到操做成功】,具體過程以下所示。
//上傳圖片 var serverId; function upload() { wx.uploadImage({ localId: localIds[0], success: function (res) { serverId = res.serverId; //提交數據到服務器 //提示信息 $.toast("簽到操做成功"); }, fail: function (res) { alert(JSON.stringify(res)); } }); }
另外,咱們爲了實現單擊圖片控件,實現從新拍照的操做,以及簽到的事件處理,咱們對控件的單擊處理進行了綁定,以下代碼所示。
document.querySelector('#imgUpload').onclick = function () { chooseImage(); }; $(document).on("click", "#btnSignIn", function () { if (localIds == undefined || localIds== null) { $.toast('請先拍照', "forbidden"); return; } //調用上傳圖片得到媒體ID upload(); });
若是對這個《C#開發微信門戶及應用》系列感興趣,能夠關注個人其餘文章,系列隨筆以下所示:
C#開發微信門戶及應用(39)--使用微信JSSDK實現簽到的功能
C#開發微信門戶及應用(35)--微信支付之企業付款封裝操做
C#開發微信門戶及應用(32)--微信支付接入和API封裝使用
C#開發微信門戶及應用(31)--微信語義理解接口的實現和處理
C#開發微信門戶及應用(28)--微信「搖一搖·周邊」功能的使用和接口的實現
C#開發微信門戶及應用(23)-微信小店商品管理接口的封裝和測試
C#開發微信門戶及應用(21)-微信企業號的消息和事件的接收處理及解密
C#開發微信門戶及應用(19)-微信企業號的消息發送(文本、圖片、文件、語音、視頻、圖文消息等)
C#開發微信門戶及應用(18)-微信企業號的通信錄管理開發之成員管理
C#開發微信門戶及應用(17)-微信企業號的通信錄管理開發之部門管理
C#開發微信門戶及應用(15)-微信菜單增長掃一掃、發圖片、發地理位置功能
C#開發微信門戶及應用(14)-在微信菜單中採用重定向獲取用戶數據
C#開發微信門戶及應用(11)--微信菜單的多種表現方式介紹
C#開發微信門戶及應用(10)--在管理系統中同步微信用戶分組信息