1. <?php
2. class JSSDK {
3. private $appId;
4. private $appSecret;
5.
6. public function __construct($appId, $appSecret) {
7. $this->appId = $appId;
8. $this->appSecret = $appSecret;
9. }
10.
11. public function getSignPackage() {
12. $jsapiTicket = $this->getJsApiTicket();
13.
14. // 注意 URL 一定要动态获取,不能 hardcode.
15. $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
16. $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
17.
18. $timestamp = time();
19. $nonceStr = $this->createNonceStr();
20.
21. // 这里参数的顺序要按照 key 值 ASCII 码升序排序
22. $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url";
23.
24. $signature = sha1($string);
25.
26. $signPackage = array(
27. "appId" => $this->appId,
28. "nonceStr" => $nonceStr,
29. "timestamp" => $timestamp,
30. "url" => $url,
31. "signature" => $signature,
32. "rawString" => $string
33. );
34. return $signPackage;
35. }
36.
37. private function createNonceStr($length = 16) {
38. $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
39. $str = "";
40. for ($i = 0; $i < $length; $i++) {
41. $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
42. }
43. return $str;
44. }
45.
46. private function getJsApiTicket() {
47. // jsapi_ticket 应该全局存储与更新,以下代码以写入到文件中做示例
48. $data = json_decode(file_get_contents("jsapi_ticket.json"));
49. if ($data->expire_time < time()) {
50. $accessToken = $this->getAccessToken();
51. // 如果是企业号用以下 URL 获取 ticket
52. // $url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=$accessToken";
53. $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$accessToken";
54. $res = json_decode($this->httpGet($url));
55. $ticket = $res->ticket;
56. if ($ticket) {
57. $data->expire_time = time() + 7000;
58. $data->jsapi_ticket = $ticket;
59. $fp = fopen("jsapi_ticket.json", "w");
60. fwrite($fp, json_encode($data));
61. fclose($fp);
62. }
63. } else {
64. $ticket = $data->jsapi_ticket;
65. }
66.
67. return $ticket;
68. }
69.
70. private function getAccessToken() {
71. // access_token 应该全局存储与更新,以下代码以写入到文件中做示例
72. $data = json_decode(file_get_contents("access_token.json"));
73. if ($data->expire_time < time()) {
74. // 如果是企业号用以下URL获取access_token
75. // $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=$this->appId&corpsecret=$this->appSecret";
76. $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$this->appId&secret=$this->appSecret";
77. $res = json_decode($this->httpGet($url));
78. $access_token = $res->access_token;
79. if ($access_token) {
80. $data->expire_time = time() + 7000;
81. $data->access_token = $access_token;
82. $fp = fopen("access_token.json", "w");
83. fwrite($fp, json_encode($data));
84. fclose($fp);
85. }
86. } else {
87. $access_token = $data->access_token;
88. }
89. return $access_token;
90. }
91.
92. private function httpGet($url) {
93. $curl = curl_init();
94. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
95. curl_setopt($curl, CURLOPT_TIMEOUT, 500);
96. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
97. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
98. curl_setopt($curl, CURLOPT_URL, $url);
99.
100. $res = curl_exec($curl);
101. curl_close($curl);
102.
103. return $res;
104. }
105. }
sample.php这个是微信的前台展示页面,需要注意:其中的微信id和秘钥需要换成自己的微信公众账号的,代码
[php] view plain copy
1. <?php
2. require_once "jssdk.php";
3. $jssdk = new JSSDK("自己的微信id", "自己的秘钥");
4. $signPackage = $jssdk->GetSignPackage();
5. ?>
6. <!DOCTYPE html>
7. <html>
8. <head>
9. <meta charset="utf-8">
10. <title>微信JS-SDK Demo</title>
11. <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
12. <link rel="stylesheet" href="style.css">
13. </head>
14. <body ontouchstart="">
15. <div class="wxapi_container">
16. <div class="wxapi_index_container">
17. <ul class="label_box lbox_close wxapi_index_list">
18. <li class="label_item wxapi_index_item"><a class="label_inner" href="#menu-basic">基础接口</a></li>
19. <li class="label_item wxapi_index_item"><a class="label_inner" href="#menu-share">分享接口</a></li>
20. <li class="label_item wxapi_index_item"><a class="label_inner" href="#menu-image">图像接口</a></li>
21. <li class="label_item wxapi_index_item"><a class="label_inner" href="#menu-voice">音频接口</a></li>
22. <li class="label_item wxapi_index_item"><a class="label_inner" href="#menu-smart">智能接口</a></li>
23. <li class="label_item wxapi_index_item"><a class="label_inner" href="#menu-device">设备信息接口</a></li>
24. <li class="label_item wxapi_index_item"><a class="label_inner" href="#menu-location">地理位置接口</a></li>
25. <li class="label_item wxapi_index_item"><a class="label_inner" href="#menu-webview">界面操作接口</a></li>
26. <li class="label_item wxapi_index_item"><a class="label_inner" href="#menu-scan">微信扫一扫接口</a></li>
27. <li class="label_item wxapi_index_item"><a class="label_inner" href="#menu-shopping">微信小店接口</a></li>
28. <li class="label_item wxapi_index_item"><a class="label_inner" href="#menu-card">微信卡券接口</a></li>
29. <li class="label_item wxapi_index_item"><a class="label_inner" href="#menu-pay">微信支付接口</a></li>
30. </ul>
31. </div>
32. <div class="lbox_close wxapi_form">
33. <h3 id="menu-basic">基础接口</h3>
34. <span class="desc">判断当前客户端是否支持指定JS接口</span>
35. <button class="btn btn_primary" id="checkJsApi">checkJsApi</button>
36.
37. <h3 id="menu-share">分享接口</h3>
38. <span class="desc">获取“分享到朋友圈”按钮点击状态及自定义分享内容接口</span>
39. <button class="btn btn_primary" id="onMenuShareTimeline">onMenuShareTimeline</button>
40. <span class="desc">获取“分享给朋友”按钮点击状态及自定义分享内容接口</span>
41. <button class="btn btn_primary" id="onMenuShareAppMessage">onMenuShareAppMessage</button>
42. <span class="desc">获取“分享到QQ”按钮点击状态及自定义分享内容接口</span>
43. <button class="btn btn_primary" id="onMenuShareQQ">onMenuShareQQ</button>
44. <span class="desc">获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口</span>
45. <button class="btn btn_primary" id="onMenuShareWeibo">onMenuShareWeibo</button>
46.
47. <h3 id="menu-image">图像接口</h3>
48. <span class="desc">拍照或从手机相册中选图接口</span>
49. <button class="btn btn_primary" id="chooseImage">chooseImage</button>
50. <span class="desc">预览图片接口</span>
51. <button class="btn btn_primary" id="previewImage">previewImage</button>
52. <span class="desc">上传图片接口</span>
53. <button class="btn btn_primary" id="uploadImage">uploadImage</button>
54. <span class="desc">下载图片接口</span>
55. <button class="btn btn_primary" id="downloadImage">downloadImage</button>
56.
57. <h3 id="menu-voice">音频接口</h3>
58. <span class="desc">开始录音接口</span>
59. <button class="btn btn_primary" id="startRecord">startRecord</button>
60. <span class="desc">停止录音接口</span>
61. <button class="btn btn_primary" id="stopRecord">stopRecord</button>
62. <span class="desc">播放语音接口</span>
63. <button class="btn btn_primary" id="playVoice">playVoice</button>
64. <span class="desc">暂停播放接口</span>
65. <button class="btn btn_primary" id="pauseVoice">pauseVoice</button>
66. <span class="desc">停止播放接口</span>
67. <button class="btn btn_primary" id="stopVoice">stopVoice</button>
68. <span class="desc">上传语音接口</span>
69. <button class="btn btn_primary" id="uploadVoice">uploadVoice</button>
70. <span class="desc">下载语音接口</span>
71. <button class="btn btn_primary" id="downloadVoice">downloadVoice</button>
72.
73. <h3 id="menu-smart">智能接口</h3>
74. <span class="desc">识别音频并返回识别结果接口</span>
75. <button class="btn btn_primary" id="translateVoice">translateVoice</button>
76.
77. <h3 id="menu-device">设备信息接口</h3>
78. <span class="desc">获取网络状态接口</span>
79. <button class="btn btn_primary" id="getNetworkType">getNetworkType</button>
80.
81. <h3 id="menu-location">地理位置接口</h3>
82. <span class="desc">使用微信内置地图查看位置接口</span>
83. <button class="btn btn_primary" id="openLocation">openLocation</button>
84. <span class="desc">获取地理位置接口</span>
85. <button class="btn btn_primary" id="getLocation">getLocation</button>
86.
87. <h3 id="menu-webview">界面操作接口</h3>
88. <span class="desc">隐藏右上角菜单接口</span>
89. <button class="btn btn_primary" id="hideOptionMenu">hideOptionMenu</button>
90. <span class="desc">显示右上角菜单接口</span>
91. <button class="btn btn_primary" id="showOptionMenu">showOptionMenu</button>
92. <span class="desc">关闭当前网页窗口接口</span>
93. <button class="btn btn_primary" id="closeWindow">closeWindow</button>
94. <span class="desc">批量隐藏功能按钮接口</span>
95. <button class="btn btn_primary" id="hideMenuItems">hideMenuItems</button>
96. <span class="desc">批量显示功能按钮接口</span>
97. <button class="btn btn_primary" id="showMenuItems">showMenuItems</button>
98. <span class="desc">隐藏所有非基础按钮接口</span>
99. <button class="btn btn_primary" id="hideAllNonBaseMenuItem">hideAllNonBaseMenuItem</button>
100. <span class="desc">显示所有功能按钮接口</span>
101. <button class="btn btn_primary" id="showAllNonBaseMenuItem">showAllNonBaseMenuItem</button>
102.
103. <h3 id="menu-scan">微信扫一扫</h3>
104. <span class="desc">调起微信扫一扫接口</span>
105. <button class="btn btn_primary" id="scanQRCode0">scanQRCode(微信处理结果)</button>
106. <button class="btn btn_primary" id="scanQRCode1">scanQRCode(直接返回结果)</button>
107.
108. <h3 id="menu-shopping">微信小店接口</h3>
109. <span class="desc">跳转微信商品页接口</span>
110. <button class="btn btn_primary" id="openProductSpecificView">openProductSpecificView</button>
111.
112. <h3 id="menu-card">微信卡券接口</h3>
113. <span class="desc">批量添加卡券接口</span>
114. <button class="btn btn_primary" id="addCard">addCard</button>
115. <span class="desc">调起适用于门店的卡券列表并获取用户选择列表</span>
116. <button class="btn btn_primary" id="chooseCard">chooseCard</button>
117. <span class="desc">查看微信卡包中的卡券接口</span>
118. <button class="btn btn_primary" id="openCard">openCard</button>
119.
120. <h3 id="menu-pay">微信支付接口</h3>
121. <span class="desc">发起一个微信支付请求</span>
122. <button class="btn btn_primary" id="chooseWXPay">chooseWXPay</button>
123. </div>
124. </div>
125. </body>
126. <script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
127. <script>
128. /*
129. * 注意:
130. * 1. 所有的JS接口只能在公众号绑定的域名下调用,公众号开发者需要先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。
131. * 2. 如果发现在 Android 不能分享自定义内容,请到官网下载最新的包覆盖安装,Android 自定义分享接口需升级至 6.0.2.58 版本及以上。
132. * 3. 常见问题及完整 JS-SDK 文档地址:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html
133. *
134. * 开发中遇到问题详见文档“附录5-常见错误及解决办法”解决,如仍未能解决可通过以下渠道反馈:
135. * 邮箱地址:weixin-open@qq.com
136. * 邮件主题:【微信JS-SDK反馈】具体问题
137. * 邮件内容说明:用简明的语言描述问题所在,并交代清楚遇到该问题的场景,可附上截屏图片,微信团队会尽快处理你的反馈。
138. */
139. wx.config({
140. debug: true,
141. appId: '<?php echo $signPackage["appId"];?>',
142. timestamp: <?php echo $signPackage["timestamp"];?>,
143. nonceStr: '<?php echo $signPackage["nonceStr"];?>',
144. signature: '<?php echo $signPackage["signature"];?>',
145. jsApiList: [
146. 'checkJsApi',
147. 'onMenuShareTimeline',
148. 'onMenuShareAppMessage',
149. 'onMenuShareQQ',
150. 'onMenuShareWeibo',
151. 'hideMenuItems',
152. 'showMenuItems',
153. 'hideAllNonBaseMenuItem',
154. 'showAllNonBaseMenuItem',
155. 'translateVoice',
156. 'startRecord',
157. 'stopRecord',
158. 'onRecordEnd',
159. 'playVoice',
160. 'pauseVoice',
161. 'stopVoice',
162. 'uploadVoice',
163. 'downloadVoice',
164. 'chooseImage',
165. 'previewImage',
166. 'uploadImage',
167. 'downloadImage',
168. 'getNetworkType',
169. 'openLocation',
170. 'getLocation',
171. 'hideOptionMenu',
172. 'showOptionMenu',
173. 'closeWindow',
174. 'scanQRCode',
175. 'chooseWXPay',
176. 'openProductSpecificView',
177. 'addCard',
178. 'chooseCard',
179. 'openCard'
180. ]
181. });
182. </script>
183. <script src="demo.js"> </script>
184. </html>
demo.js这个是微信的js事件,代码
[javascript] view plain copy
1. /*
2. * 注意:
3. * 1. 所有的JS接口只能在公众号绑定的域名下调用,公众号开发者需要先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。
4. * 2. 如果发现在 Android 不能分享自定义内容,请到官网下载最新的包覆盖安装,Android 自定义分享接口需升级至 6.0.2.58 版本及以上。
5. * 3. 完整 JS-SDK 文档地址:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html
6. *
7. * 如有问题请通过以下渠道反馈:
8. * 邮箱地址:weixin-open@qq.com
9. * 邮件主题:【微信JS-SDK反馈】具体问题
10. * 邮件内容说明:用简明的语言描述问题所在,并交代清楚遇到该问题的场景,可附上截屏图片,微信团队会尽快处理你的反馈。
11. */
12. wx.ready(function () {
13. // 1 判断当前版本是否支持指定 JS 接口,支持批量判断
14. document.querySelector('#checkJsApi').onclick = function () {
15. wx.checkJsApi({
16. jsApiList: [
17. 'getNetworkType',
18. 'previewImage'
19. ],
20. success: function (res) {
21. alert(JSON.stringify(res));
22. }
23. });
24. };
25.
26. // 2. 分享接口
27. // 2.1 监听“分享给朋友”,按钮点击、自定义分享内容及分享结果接口
28. document.querySelector('#onMenuShareAppMessage').onclick = function () {
29. wx.onMenuShareAppMessage({
30. title: '互联网之子',
31. desc: '在长大的过程中,我才慢慢发现,我身边的所有事,别人跟我说的所有事,那些所谓本来如此,注定如此的事,它们其实没有非得如此,事情是可以改变的。更重要的是,有些事既然错了,那就该做出改变。',
32. link: 'http://movie.douban.com/subject/25785114/',
33. imgUrl: 'http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg',
34. trigger: function (res) {
35. // 不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回
36. alert('用户点击发送给朋友');
37. },
38. success: function (res) {
39. alert('已分享');
40. },
41. cancel: function (res) {
42. alert('已取消');
43. },
44. fail: function (res) {
45. alert(JSON.stringify(res));
46. }
47. });
48. alert('已注册获取“发送给朋友”状态事件');
49. };
50.
51. // 2.2 监听“分享到朋友圈”按钮点击、自定义分享内容及分享结果接口
52. document.querySelector('#onMenuShareTimeline').onclick = function () {
53. wx.onMenuShareTimeline({
54. title: '互联网之子',
55. link: 'http://movie.douban.com/subject/25785114/',
56. imgUrl: 'http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg',
57. trigger: function (res) {
58. // 不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回
59. alert('用户点击分享到朋友圈');
60. },
61. success: function (res) {
62. alert('已分享');
63. },
64. cancel: function (res) {
65. alert('已取消');
66. },
67. fail: function (res) {
68. alert(JSON.stringify(res));
69. }
70. });
71. alert('已注册获取“分享到朋友圈”状态事件');
72. };
73.
74. // 2.3 监听“分享到QQ”按钮点击、自定义分享内容及分享结果接口
75. document.querySelector('#onMenuShareQQ').onclick = function () {
76. wx.onMenuShareQQ({
77. title: '互联网之子',
78. desc: '在长大的过程中,我才慢慢发现,我身边的所有事,别人跟我说的所有事,那些所谓本来如此,注定如此的事,它们其实没有非得如此,事情是可以改变的。更重要的是,有些事既然错了,那就该做出改变。',
79. link: 'http://movie.douban.com/subject/25785114/',
80. imgUrl: 'http://img3.douban.com/view/movie_poster_cover/spst/public/p2166127561.jpg',
81. trigger: function (res) {
82. alert('用户点击分享到QQ');
83. },
84. complete: function (res) {
85. alert(JSON.stringify(res));
86. },
87. success: function (res) {
88. alert('已分享');
89. },
90. cancel: function (res) {
91. alert('已取消');
92. },
93. fail: function (res) {
94. alert(JSON.stringify(res));
95. }
96. });
97. alert('已注册获取“分享到 QQ”状态事件');
98. };
99.
100. // 2.4 监听“分享到微博”按钮点击、自定义分享内容及分享结果接口
101. document.querySelector('#onMenuShareWeibo').onclick = function () {
102. wx.onMenuShareWeibo({
103. title: '互联网之子',
104. desc: '在长大的过程中,我才慢慢发现,我身边的所有事,别人跟我说的所有事,那些所谓本来如此,注定如此的事,它们其实没有非得如此,事情是可以改变的。更重要的是,有些事既然错了,那就该做出改变。',
105. link: 'http://movie.douban.com/subject/25785114/',
106. imgUrl: 'http://img3.douban.com/view/movie_poster_cover/spst/public/p2166127561.jpg',
107. trigger: function (res) {
108. alert('用户点击分享到微博');
109. },
110. complete: function (res) {
111. alert(JSON.stringify(res));
112. },
113. success: function (res) {
114. alert('已分享');
115. },
116. cancel: function (res) {
117. alert('已取消');
118. },
119. fail: function (res) {
120. alert(JSON.stringify(res));
121. }
122. });
123. alert('已注册获取“分享到微博”状态事件');
124. };
125.
126.
127. // 3 智能接口
128. var voice = {
129. localId: '',
130. serverId: ''
131. };
132. // 3.1 识别音频并返回识别结果
133. document.querySelector('#translateVoice').onclick = function () {
134. if (voice.localId == '') {
135. alert('请先使用 startRecord 接口录制一段声音');
136. return;
137. }
138. wx.translateVoice({
139. localId: voice.localId,
140. complete: function (res) {
141. if (res.hasOwnProperty('translateResult')) {
142. alert('识别结果:' + res.translateResult);
143. } else {
144. alert('无法识别');
145. }
146. }
147. });
148. };
149.
150. // 4 音频接口
151. // 4.2 开始录音
152. document.querySelector('#startRecord').onclick = function () {
153. wx.startRecord({
154. cancel: function () {
155. alert('用户拒绝授权录音');
156. }
157. });
158. };
159.
160. // 4.3 停止录音
161. document.querySelector('#stopRecord').onclick = function () {
162. wx.stopRecord({
163. success: function (res) {
164. voice.localId = res.localId;
165. },
166. fail: function (res) {
167. alert(JSON.stringify(res));
168. }
169. });
170. };
171.
172. // 4.4 监听录音自动停止
173. wx.onVoiceRecordEnd({
174. complete: function (res) {
175. voice.localId = res.localId;
176. alert('录音时间已超过一分钟');
177. }
178. });
179.
180. // 4.5 播放音频
181. document.querySelector('#playVoice').onclick = function () {
182. if (voice.localId == '') {
183. alert('请先使用 startRecord 接口录制一段声音');
184. return;
185. }
186. wx.playVoice({
187. localId: voice.localId
188. });
189. };
190.
191. // 4.6 暂停播放音频
192. document.querySelector('#pauseVoice').onclick = function () {
193. wx.pauseVoice({
194. localId: voice.localId
195. });
196. };
197.
198. // 4.7 停止播放音频
199. document.querySelector('#stopVoice').onclick = function () {
200. wx.stopVoice({
201. localId: voice.localId
202. });
203. };
204.
205. // 4.8 监听录音播放停止
206. wx.onVoicePlayEnd({
207. complete: function (res) {
208. alert('录音(' + res.localId + ')播放结束');
209. }
210. });
211.
212. // 4.8 上传语音
213. document.querySelector('#uploadVoice').onclick = function () {
214. if (voice.localId == '') {
215. alert('请先使用 startRecord 接口录制一段声音');
216. return;
217. }
218. wx.uploadVoice({
219. localId: voice.localId,
220. success: function (res) {
221. alert('上传语音成功,serverId 为' + res.serverId);
222. voice.serverId = res.serverId;
223. }
224. });
225. };
226.
227. // 4.9 下载语音
228. document.querySelector('#downloadVoice').onclick = function () {
229. if (voice.serverId == '') {
230. alert('请先使用 uploadVoice 上传声音');
231. return;
232. }
233. wx.downloadVoice({
234. serverId: voice.serverId,
235. success: function (res) {
236. alert('下载语音成功,localId 为' + res.localId);
237. voice.localId = res.localId;
238. }
239. });
240. };
241.
242. // 5 图片接口
243. // 5.1 拍照、本地选图
244. var images = {
245. localId: [],
246. serverId: []
247. };
248. document.querySelector('#chooseImage').onclick = function () {
249. wx.chooseImage({
250. success: function (res) {
251. images.localId = res.localIds;
252. alert('已选择 ' + res.localIds.length + ' 张图片');
253. }
254. });
255. };
256.
257. // 5.2 图片预览
258. document.querySelector('#previewImage').onclick = function () {
259. wx.previewImage({
260. current: 'http://img5.douban.com/view/photo/photo/public/p1353993776.jpg',
261. urls: [
262. 'http://img3.douban.com/view/photo/photo/public/p2152117150.jpg',
263. 'http://img5.douban.com/view/photo/photo/public/p1353993776.jpg',
264. 'http://img3.douban.com/view/photo/photo/public/p2152134700.jpg'
265. ]
266. });
267. };
268.
269. // 5.3 上传图片
270. document.querySelector('#uploadImage').onclick = function () {
271. if (images.localId.length == 0) {
272. alert('请先使用 chooseImage 接口选择图片');
273. return;
274. }
275. var i = 0, length = images.localId.length;
276. images.serverId = [];
277. function upload() {
278. wx.uploadImage({
279. localId: images.localId[i],
280. success: function (res) {
281. i++;
282. alert('已上传:' + i + '/' + length);
283. images.serverId.push(res.serverId);
284. if (i < length) {
285. upload();
286. }
287. },
288. fail: function (res) {
289. alert(JSON.stringify(res));
290. }
291. });
292. }
293. upload();
294. };
295.
296. // 5.4 下载图片
297. document.querySelector('#downloadImage').onclick = function () {
298. if (images.serverId.length === 0) {
299. alert('请先使用 uploadImage 上传图片');
300. return;
301. }
302. var i = 0, length = images.serverId.length;
303. images.localId = [];
304. function download() {
305. wx.downloadImage({
306. serverId: images.serverId[i],
307. success: function (res) {
308. i++;
309. alert('已下载:' + i + '/' + length);
310. images.localId.push(res.localId);
311. if (i < length) {
312. download();
313. }
314. }
315. });
316. }
317. download();
318. };
319.
320. // 6 设备信息接口
321. // 6.1 获取当前网络状态
322. document.querySelector('#getNetworkType').onclick = function () {
323. wx.getNetworkType({
324. success: function (res) {
325. alert(res.networkType);
326. },
327. fail: function (res) {
328. alert(JSON.stringify(res));
329. }
330. });
331. };
332.
333. // 7 地理位置接口
334. // 7.1 查看地理位置
335. document.querySelector('#openLocation').onclick = function () {
336. wx.openLocation({
337. latitude: 23.099994,
338. longitude: 113.324520,
339. name: 'TIT 创意园',
340. address: '广州市海珠区新港中路 397 号',
341. scale: 14,
342. infoUrl: 'http://weixin.qq.com'
343. });
344. };
345.
346. // 7.2 获取当前地理位置
347. document.querySelector('#getLocation').onclick = function () {
348. wx.getLocation({
349. success: function (res) {
350. alert(JSON.stringify(res));
351. },
352. cancel: function (res) {
353. alert('用户拒绝授权获取地理位置');
354. }
355. });
356. };
357.
358. // 8 界面操作接口
359. // 8.1 隐藏右上角菜单
360. document.querySelector('#hideOptionMenu').onclick = function () {
361. wx.hideOptionMenu();
362. };
363.
364. // 8.2 显示右上角菜单
365. document.querySelector('#showOptionMenu').onclick = function () {
366. wx.showOptionMenu();
367. };
368.
369. // 8.3 批量隐藏菜单项
370. document.querySelector('#hideMenuItems').onclick = function () {
371. wx.hideMenuItems({
372. menuList: [
373. 'menuItem:readMode', // 阅读模式
374. 'menuItem:share:timeline', // 分享到朋友圈
375. 'menuItem:copyUrl' // 复制链接
376. ],
377. success: function (res) {
378. alert('已隐藏“阅读模式”,“分享到朋友圈”,“复制链接”等按钮');
379. },
380. fail: function (res) {
381. alert(JSON.stringify(res));
382. }
383. });
384. };
385.
386. // 8.4 批量显示菜单项
387. document.querySelector('#showMenuItems').onclick = function () {
388. wx.showMenuItems({
389. menuList: [
390. 'menuItem:readMode', // 阅读模式
391. 'menuItem:share:timeline', // 分享到朋友圈
392. 'menuItem:copyUrl' // 复制链接
393. ],
394. success: function (res) {
395. alert('已显示“阅读模式”,“分享到朋友圈”,“复制链接”等按钮');
396. },
397. fail: function (res) {
398. alert(JSON.stringify(res));
399. }
400. });
401. };
402.
403. // 8.5 隐藏所有非基本菜单项
404. document.querySelector('#hideAllNonBaseMenuItem').onclick = function () {
405. wx.hideAllNonBaseMenuItem({
406. success: function () {
407. alert('已隐藏所有非基本菜单项');
408. }
409. });
410. };
411.
412. // 8.6 显示所有被隐藏的非基本菜单项
413. document.querySelector('#showAllNonBaseMenuItem').onclick = function () {
414. wx.showAllNonBaseMenuItem({
415. success: function () {
416. alert('已显示所有非基本菜单项');
417. }
418. });
419. };
420.
421. // 8.7 关闭当前窗口
422. document.querySelector('#closeWindow').onclick = function () {
423. wx.closeWindow();
424. };
425.
426. // 9 微信原生接口
427. // 9.1.1 扫描二维码并返回结果
428. document.querySelector('#scanQRCode0').onclick = function () {
429. wx.scanQRCode();
430. };
431. // 9.1.2 扫描二维码并返回结果
432. document.querySelector('#scanQRCode1').onclick = function () {
433. wx.scanQRCode({
434. needResult: 1,
435. desc: 'scanQRCode desc',
436. success: function (res) {
437. alert(JSON.stringify(res));
438. }
439. });
440. };
441.
442. // 10 微信支付接口
443. // 10.1 发起一个支付请求
444. document.querySelector('#chooseWXPay').onclick = function () {
445. // 注意:此 Demo 使用 2.7 版本支付接口实现,建议使用此接口时参考微信支付相关最新文档。
446. wx.chooseWXPay({
447. timestamp: 1414723227,
448. nonceStr: 'noncestr',
449. package: 'addition=action_id%3dgaby1234%26limit_pay%3d&bank_type=WX&body=innertest&fee_type=1&input_charset=GBK¬ify_url=http%3A%2F%2F120.204.206.246%2Fcgi-bin%2Fmmsupport-bin%2Fnotifypay&out_trade_no=1414723227818375338&partner=1900000109&spbill_create_ip=127.0.0.1&total_fee=1&sign=432B647FE95C7BF73BCD177CEECBEF8D',
450. signType: 'SHA1', // 注意:新版支付接口使用 MD5 加密
451. paySign: 'bd5b1933cda6e9548862944836a9b52e8c9a2b69'
452. });
453. };
454.
455. // 11.3 跳转微信商品页
456. document.querySelector('#openProductSpecificView').onclick = function () {
457. wx.openProductSpecificView({
458. productId: 'pDF3iY_m2M7EQ5EKKKWd95kAxfNw'
459. });
460. };
461.
462. // 12 微信卡券接口
463. // 12.1 添加卡券
464. document.querySelector('#addCard').onclick = function () {
465. wx.addCard({
466. cardList: [
467. {
468. cardId: 'pDF3iY9tv9zCGCj4jTXFOo1DxHdo',
469. cardExt: '{"code": "", "openid": "", "timestamp": "1418301401", "signature":"64e6a7cc85c6e84b726f2d1cbef1b36e9b0f9750"}'
470. },
471. {
472. cardId: 'pDF3iY9tv9zCGCj4jTXFOo1DxHdo',
473. cardExt: '{"code": "", "openid": "", "timestamp": "1418301401", "signature":"64e6a7cc85c6e84b726f2d1cbef1b36e9b0f9750"}'
474. }
475. ],
476. success: function (res) {
477. alert('已添加卡券:' + JSON.stringify(res.cardList));
478. }
479. });
480. };
481.
482. // 12.2 选择卡券
483. document.querySelector('#chooseCard').onclick = function () {
484. wx.chooseCard({
485. cardSign: '97e9c5e58aab3bdf6fd6150e599d7e5806e5cb91',
486. timestamp: 1417504553,
487. nonceStr: 'k0hGdSXKZEj3Min5',
488. success: function (res) {
489. alert('已选择卡券:' + JSON.stringify(res.cardList));
490. }
491. });
492. };
493.
494. // 12.3 查看卡券
495. document.querySelector('#openCard').onclick = function () {
496. alert('您没有该公众号的卡券无法打开卡券。');
497. wx.openCard({
498. cardList: [
499. ]
500. });
501. };
502.
503. var shareData = {
504. title: '微信JS-SDK Demo',
505. desc: '微信JS-SDK,帮助第三方为用户提供更优质的移动web服务',
506. link: 'http://demo.open.weixin.qq.com/jssdk/',
507. imgUrl: 'http://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRt8Qia4lv7k3M9J1SKqKCImxJCt7j9rHYicKDI45jRPBxdzdyREWnk0ia0N5TMnMfth7SdxtzMvVgXg/0'
508. };
509. wx.onMenuShareAppMessage(shareData);
510. wx.onMenuShareTimeline(shareData);
511. });
512.
513. wx.error(function (res) {
514. alert(res.errMsg);
515. });
style.css这个是微信的页面样式,主要是为了美观,代码
[css] view plain copy
1. html {
2. -ms-text-size-adjust: 100%;
3. -webkit-text-size-adjust: 100%;
4. -webkit-user-select: none;
5. user-select: none;
6. }
7. body {
8. line-height: 1.6;
9. font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
10. background-color: #f1f0f6;
11. }
12. * {
13. margin: 0;
14. padding: 0;
15. }
16. button {
17. font-family: inherit;
18. font-size: 100%;
19. margin: 0;
20. *font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
21. }
22. ul,
23. ol {
24. padding-left: 0;
25. list-style-type: none;
26. }
27. a {
28. text-decoration: none;
29. }
30. .label_box {
31. background-color: #ffffff;
32. }
33. .label_item {
34. padding-left: 15px;
35. }
36. .label_inner {
37. padding-top: 10px;
38. padding-bottom: 10px;
39. min-height: 24px;
40. position: relative;
41. }
42. .label_inner:before {
43. content: " ";
44. position: absolute;
45. left: 0;
46. top: 0;
47. width: 200%;
48. height: 1px;
49. border-top: 1px solid #ededed;
50. -webkit-transform-origin: 0 0;
51. transform-origin: 0 0;
52. -webkit-transform: scale(0.5);
53. transform: scale(0.5);
54. top: auto;
55. bottom: -2px;
56. }
57. .lbox_close {
58. position: relative;
59. }
60. .lbox_close:before {
61. content: " ";
62. position: absolute;
63. left: 0;
64. top: 0;
65. width: 200%;
66. height: 1px;
67. border-top: 1px solid #ededed;
68. -webkit-transform-origin: 0 0;
69. transform-origin: 0 0;
70. -webkit-transform: scale(0.5);
71. transform: scale(0.5);
72. }
73. .lbox_close:after {
74. content: " ";
75. position: absolute;
76. left: 0;
77. top: 0;
78. width: 200%;
79. height: 1px;
80. border-top: 1px solid #ededed;
81. -webkit-transform-origin: 0 0;
82. transform-origin: 0 0;
83. -webkit-transform: scale(0.5);
84. transform: scale(0.5);
85. top: auto;
86. bottom: -2px;
87. }
88. .lbox_close .label_item:last-child .label_inner:before {
89. display: none;
90. }
91. .btn {
92. display: block;
93. margin-left: auto;
94. margin-right: auto;
95. padding-left: 14px;
96. padding-right: 14px;
97. font-size: 18px;
98. text-align: center;
99. text-decoration: none;
100. overflow: visible;
101. /*.btn_h(@btnHeight);*/
102. height: 42px;
103. border-radius: 5px;
104. -moz-border-radius: 5px;
105. -webkit-border-radius: 5px;
106. box-sizing: border-box;
107. -moz-box-sizing: border-box;
108. -webkit-box-sizing: border-box;
109. color: #ffffff;
110. line-height: 42px;
111. -webkit-tap-highlight-color: rgba(255, 255, 255, 0);
112. }
113. .btn.btn_inline {
114. display: inline-block;
115. }
116. .btn_primary {
117. background-color: #04be02;
118. }
119. .btn_primary:not(.btn_disabled):visited {
120. color: #ffffff;
121. }
122. .btn_primary:not(.btn_disabled):active {
123. color: rgba(255, 255, 255, 0.9);
124. background-color: #039702;
125. }
126. button.btn {
127. width: 100%;
128. border: 0;
129. outline: 0;
130. -webkit-appearance: none;
131. }
132. button.btn:focus {
133. outline: 0;
134. }
135. .wxapi_container {
136. font-size: 16px;
137. }
138. h1 {
139. font-size: 14px;
140. font-weight: 400;
141. line-height: 2em;
142. padding-left: 15px;
143. color: #8d8c92;
144. }
145. .desc {
146. font-size: 14px;
147. font-weight: 400;
148. line-height: 2em;
149. color: #8d8c92;
150. }
151. .wxapi_index_item a {
152. display: block;
153. color: #3e3e3e;
154. -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
155. }
156. .wxapi_form {
157. background-color: #ffffff;
158. padding: 0 15px;
159. margin-top: 30px;
160. padding-bottom: 15px;
161. }
162. h3 {
163. padding-top: 16px;
164. margin-top: 25px;
165. font-size: 16px;
166. font-weight: 400;
167. color: #3e3e3e;
168. position: relative;
169. }
170. h3:first-child {
171. padding-top: 15px;
172. }
173. h3:before {
174. content: " ";
175. position: absolute;
176. left: 0;
177. top: 0;
178. width: 200%;
179. height: 1px;
180. border-top: 1px solid #ededed;
181. -webkit-transform-origin: 0 0;
182. transform-origin: 0 0;
183. -webkit-transform: scale(0.5);
184. transform: scale(0.5);
185. }
186. .btn {
187. margin-bottom: 15px;
188. }
以上就是我做的微信dome例子,亲测,可以使用,如果大家使用中遇到问题可以留言给我,这些代码在微信的文档中都可以下载,我这里只是进行了一下总结。
注意:1.这个dome会生成两个文件access_token.json、jsapi_ticket.json,进行缓存,请确保有读写文件的权限。
2.确保你获取用来签名的url是动态获取的,动态页面可参见实例代码中php的实现方式。如果是html的静态页面在前端通过ajax将url传到后台签名,前端需要用js获取当前页面除去'#'hash部分的链接(可用location.href.split('#')[0]获取,而且需要encodeURIComponent),因为页面一旦分享,微信客户端会在你的链接末尾加入其它参数,如果不是动态获取当前链接,将导致分享后的页面签名失败