WeixinApi.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. /**!
  2. * 微信内置浏览器的Javascript API,功能包括:
  3. *
  4. * 1、分享到微信朋友圈
  5. * 2、分享给微信好友
  6. * 3、分享到腾讯微博
  7. * 4、新的分享接口,包含朋友圈、好友、微博的分享(for iOS)
  8. * 5、隐藏/显示右上角的菜单入口
  9. * 6、隐藏/显示底部浏览器工具栏
  10. * 7、获取当前的网络状态
  11. * 8、调起微信客户端的图片播放组件
  12. * 9、关闭公众平台Web页面
  13. * 10、判断当前网页是否在微信内置浏览器中打开
  14. * 11、增加打开扫描二维码
  15. * 12、支持WeixinApi的错误监控
  16. * 13、检测应用程序是否已经安装(需要官方开通权限)
  17. * 14、打开微信内置地图(认证过的公众号可用)
  18. * 15、发送电子邮件
  19. *
  20. * @author zhaoxianlie(http://www.baidufe.com)
  21. */
  22. (function (window) {
  23. "use strict";
  24. /**
  25. * 定义WeixinApi
  26. */
  27. var WeixinApi = {
  28. version:2.8
  29. };
  30. // 将WeixinApi暴露到window下:全局可使用,对旧版本向下兼容
  31. window.WeixinApi = WeixinApi;
  32. /////////////////////////// CommonJS /////////////////////////////////
  33. if (typeof define === 'function' && (define.amd || define.cmd)) {
  34. if (define.amd) {
  35. // AMD 规范,for:requirejs
  36. define(function () {
  37. return WeixinApi;
  38. });
  39. } else if (define.cmd) {
  40. // CMD 规范,for:seajs
  41. define(function (require, exports, module) {
  42. module.exports = WeixinApi;
  43. });
  44. }
  45. }
  46. /**
  47. * 内部私有方法,分享用
  48. * @private
  49. */
  50. var _share = function (cmd, data, callbacks) {
  51. callbacks = callbacks || {};
  52. // 分享过程中的一些回调
  53. var progress = function (resp) {
  54. switch (true) {
  55. // 用户取消
  56. case /\:cancel$/i.test(resp.err_msg) :
  57. callbacks.cancel && callbacks.cancel(resp);
  58. break;
  59. // 发送成功
  60. case /\:(confirm|ok)$/i.test(resp.err_msg):
  61. callbacks.confirm && callbacks.confirm(resp);
  62. break;
  63. // fail 发送失败
  64. case /\:fail$/i.test(resp.err_msg) :
  65. default:
  66. callbacks.fail && callbacks.fail(resp);
  67. break;
  68. }
  69. // 无论成功失败都会执行的回调
  70. callbacks.all && callbacks.all(resp);
  71. };
  72. // 执行分享,并处理结果
  73. var handler = function (theData, argv) {
  74. // 新的分享接口,单独处理
  75. if (cmd.menu === 'menu:general:share') {
  76. // 如果是分享到朋友圈,则需要把title和desc交换一下
  77. if (argv.shareTo == 'timeline') {
  78. var title = theData.title;
  79. theData.title = theData.desc || title;
  80. theData.desc = title;
  81. } else if (argv.shareTo == 'favorite') {
  82. // 如果是收藏操作,并且在wxCallbacks中配置了favorite为false,则不执行回调
  83. if (callbacks.favorite === false) {
  84. return argv.generalShare(theData, function () {
  85. });
  86. }
  87. }
  88. argv.generalShare(theData, progress);
  89. } else {
  90. WeixinJSBridge.invoke(cmd.action, theData, progress);
  91. }
  92. };
  93. // 监听分享操作
  94. WeixinJSBridge.on(cmd.menu, function (argv) {
  95. if (callbacks.async && callbacks.ready) {
  96. var _callbackKey = "_wx_loadedCb_";
  97. WeixinApi[_callbackKey] = callbacks.dataLoaded || new Function();
  98. if (WeixinApi[_callbackKey].toString().indexOf(_callbackKey) > 0) {
  99. WeixinApi[_callbackKey] = new Function();
  100. }
  101. callbacks.dataLoaded = function (newData) {
  102. WeixinApi[_callbackKey](newData);
  103. handler(newData, argv);
  104. };
  105. // 然后就绪
  106. if (!(argv && argv.shareTo == 'favorite' && callbacks.favorite === false)) {
  107. callbacks.ready && callbacks.ready(argv);
  108. }
  109. } else {
  110. // 就绪状态
  111. if (!(argv && argv.shareTo == 'favorite' && callbacks.favorite === false)) {
  112. callbacks.ready && callbacks.ready(argv);
  113. }
  114. handler(data, argv);
  115. }
  116. });
  117. };
  118. /**
  119. * 分享到微信朋友圈
  120. * @param {Object} data 待分享的信息
  121. * @p-config {String} appId 公众平台的appId(服务号可用)
  122. * @p-config {String} imgUrl 图片地址
  123. * @p-config {String} link 链接地址
  124. * @p-config {String} desc 描述
  125. * @p-config {String} title 分享的标题
  126. *
  127. * @param {Object} callbacks 相关回调方法
  128. * @p-config {Boolean} async ready方法是否需要异步执行,默认false
  129. * @p-config {Function} ready(argv) 就绪状态
  130. * @p-config {Function} dataLoaded(data) 数据加载完成后调用,async为true时有用,也可以为空
  131. * @p-config {Function} cancel(resp) 取消
  132. * @p-config {Function} fail(resp) 失败
  133. * @p-config {Function} confirm(resp) 成功
  134. * @p-config {Function} all(resp) 无论成功失败都会执行的回调
  135. */
  136. WeixinApi.shareToTimeline = function (data, callbacks) {
  137. _share({
  138. menu:'menu:share:timeline',
  139. action:'shareTimeline'
  140. }, {
  141. "appid":data.appId ? data.appId : '',
  142. "img_url":data.imgUrl,
  143. "link":data.link,
  144. "desc":data.title,
  145. "title":data.desc,
  146. "img_width":"640",
  147. "img_height":"640"
  148. }, callbacks);
  149. };
  150. /**
  151. * 发送给微信上的好友
  152. * @param {Object} data 待分享的信息
  153. * @p-config {String} appId 公众平台的appId(服务号可用)
  154. * @p-config {String} imgUrl 图片地址
  155. * @p-config {String} link 链接地址
  156. * @p-config {String} desc 描述
  157. * @p-config {String} title 分享的标题
  158. *
  159. * @param {Object} callbacks 相关回调方法
  160. * @p-config {Boolean} async ready方法是否需要异步执行,默认false
  161. * @p-config {Function} ready(argv) 就绪状态
  162. * @p-config {Function} dataLoaded(data) 数据加载完成后调用,async为true时有用,也可以为空
  163. * @p-config {Function} cancel(resp) 取消
  164. * @p-config {Function} fail(resp) 失败
  165. * @p-config {Function} confirm(resp) 成功
  166. * @p-config {Function} all(resp) 无论成功失败都会执行的回调
  167. */
  168. WeixinApi.shareToFriend = function (data, callbacks) {
  169. _share({
  170. menu:'menu:share:appmessage',
  171. action:'sendAppMessage'
  172. }, {
  173. "appid":data.appId ? data.appId : '',
  174. "img_url":data.imgUrl,
  175. "link":data.link,
  176. "desc":data.desc,
  177. "title":data.title,
  178. "img_width":"640",
  179. "img_height":"640"
  180. }, callbacks);
  181. };
  182. /**
  183. * 分享到腾讯微博
  184. * @param {Object} data 待分享的信息
  185. * @p-config {String} link 链接地址
  186. * @p-config {String} desc 描述
  187. *
  188. * @param {Object} callbacks 相关回调方法
  189. * @p-config {Boolean} async ready方法是否需要异步执行,默认false
  190. * @p-config {Function} ready(argv) 就绪状态
  191. * @p-config {Function} dataLoaded(data) 数据加载完成后调用,async为true时有用,也可以为空
  192. * @p-config {Function} cancel(resp) 取消
  193. * @p-config {Function} fail(resp) 失败
  194. * @p-config {Function} confirm(resp) 成功
  195. * @p-config {Function} all(resp) 无论成功失败都会执行的回调
  196. */
  197. WeixinApi.shareToWeibo = function (data, callbacks) {
  198. _share({
  199. menu:'menu:share:weibo',
  200. action:'shareWeibo'
  201. }, {
  202. "content":data.desc,
  203. "url":data.link
  204. }, callbacks);
  205. };
  206. /**
  207. * 新的分享接口
  208. * @param {Object} data 待分享的信息
  209. * @p-config {String} appId 公众平台的appId(服务号可用)
  210. * @p-config {String} imgUrl 图片地址
  211. * @p-config {String} link 链接地址
  212. * @p-config {String} desc 描述
  213. * @p-config {String} title 分享的标题
  214. *
  215. * @param {Object} callbacks 相关回调方法
  216. * @p-config {Boolean} async ready方法是否需要异步执行,默认false
  217. * @p-config {Function} ready(argv,shareTo) 就绪状态
  218. * @p-config {Function} dataLoaded(data) 数据加载完成后调用,async为true时有用,也可以为空
  219. * @p-config {Function} cancel(resp,shareTo) 取消
  220. * @p-config {Function} fail(resp,shareTo) 失败
  221. * @p-config {Function} confirm(resp,shareTo) 成功
  222. * @p-config {Function} all(resp,shareTo) 无论成功失败都会执行的回调
  223. */
  224. WeixinApi.generalShare = function (data, callbacks) {
  225. _share({
  226. menu:'menu:general:share'
  227. }, {
  228. "appid":data.appId ? data.appId : '',
  229. "img_url":data.imgUrl,
  230. "link":data.link,
  231. "desc":data.title,
  232. "title":data.desc,
  233. "img_width":"640",
  234. "img_height":"640"
  235. }, callbacks);
  236. };
  237. /**
  238. * 加关注(此功能只是暂时先加上,不过因为权限限制问题,不能用,如果你的站点是部署在*.qq.com下,也许可行)
  239. * @param {String} appWeixinId 微信公众号ID
  240. * @param {Object} callbacks 回调方法
  241. * @p-config {Function} fail(resp) 失败
  242. * @p-config {Function} confirm(resp) 成功
  243. */
  244. WeixinApi.addContact = function (appWeixinId, callbacks) {
  245. callbacks = callbacks || {};
  246. WeixinJSBridge.invoke("addContact", {
  247. webtype:"1",
  248. username:appWeixinId
  249. }, function (resp) {
  250. var success = !resp.err_msg || "add_contact:ok" == resp.err_msg
  251. || "add_contact:added" == resp.err_msg;
  252. if (success) {
  253. callbacks.success && callbacks.success(resp);
  254. } else {
  255. callbacks.fail && callbacks.fail(resp);
  256. }
  257. })
  258. };
  259. /**
  260. * 调起微信Native的图片播放组件。
  261. * 这里必须对参数进行强检测,如果参数不合法,直接会导致微信客户端crash
  262. *
  263. * @param {String} curSrc 当前播放的图片地址
  264. * @param {Array} srcList 图片地址列表
  265. */
  266. WeixinApi.imagePreview = function (curSrc, srcList) {
  267. if (!curSrc || !srcList || srcList.length == 0) {
  268. return;
  269. }
  270. WeixinJSBridge.invoke('imagePreview', {
  271. 'current':curSrc,
  272. 'urls':srcList
  273. });
  274. };
  275. /**
  276. * 显示网页右上角的按钮
  277. */
  278. WeixinApi.showOptionMenu = function () {
  279. WeixinJSBridge.call('showOptionMenu');
  280. };
  281. /**
  282. * 隐藏网页右上角的按钮
  283. */
  284. WeixinApi.hideOptionMenu = function () {
  285. WeixinJSBridge.call('hideOptionMenu');
  286. };
  287. /**
  288. * 显示底部工具栏
  289. */
  290. WeixinApi.showToolbar = function () {
  291. WeixinJSBridge.call('showToolbar');
  292. };
  293. /**
  294. * 隐藏底部工具栏
  295. */
  296. WeixinApi.hideToolbar = function () {
  297. WeixinJSBridge.call('hideToolbar');
  298. };
  299. /**
  300. * 返回如下几种类型:
  301. *
  302. * network_type:wifi wifi网络
  303. * network_type:edge 非wifi,包含3G/2G
  304. * network_type:fail 网络断开连接
  305. * network_type:wwan 2g或者3g
  306. *
  307. * 使用方法:
  308. * WeixinApi.getNetworkType(function(networkType){
  309. *
  310. * });
  311. *
  312. * @param callback
  313. */
  314. WeixinApi.getNetworkType = function (callback) {
  315. if (callback && typeof callback == 'function') {
  316. WeixinJSBridge.invoke('getNetworkType', {}, function (e) {
  317. // 在这里拿到e.err_msg,这里面就包含了所有的网络类型
  318. callback(e.err_msg);
  319. });
  320. }
  321. };
  322. /**
  323. * 关闭当前微信公众平台页面
  324. * @param {Object} callbacks 回调方法
  325. * @p-config {Function} fail(resp) 失败
  326. * @p-config {Function} success(resp) 成功
  327. */
  328. WeixinApi.closeWindow = function (callbacks) {
  329. callbacks = callbacks || {};
  330. WeixinJSBridge.invoke("closeWindow", {}, function (resp) {
  331. switch (resp.err_msg) {
  332. // 关闭成功
  333. case 'close_window:ok':
  334. callbacks.success && callbacks.success(resp);
  335. break;
  336. // 关闭失败
  337. default :
  338. callbacks.fail && callbacks.fail(resp);
  339. break;
  340. }
  341. });
  342. };
  343. /**
  344. * 当页面加载完毕后执行,使用方法:
  345. * WeixinApi.ready(function(Api){
  346. * // 从这里只用Api即是WeixinApi
  347. * });
  348. * @param readyCallback
  349. */
  350. WeixinApi.ready = function (readyCallback) {
  351. if (readyCallback && typeof readyCallback == 'function') {
  352. var Api = this;
  353. var wxReadyFunc = function () {
  354. readyCallback(Api);
  355. };
  356. if (typeof window.WeixinJSBridge == "undefined") {
  357. if (document.addEventListener) {
  358. document.addEventListener('WeixinJSBridgeReady', wxReadyFunc, false);
  359. } else if (document.attachEvent) {
  360. document.attachEvent('WeixinJSBridgeReady', wxReadyFunc);
  361. document.attachEvent('onWeixinJSBridgeReady', wxReadyFunc);
  362. }
  363. } else {
  364. wxReadyFunc();
  365. }
  366. }
  367. };
  368. /**
  369. * 判断当前网页是否在微信内置浏览器中打开
  370. */
  371. WeixinApi.openInWeixin = function () {
  372. return /MicroMessenger/i.test(navigator.userAgent);
  373. };
  374. /*
  375. * 打开扫描二维码
  376. * @param {Object} callbacks 回调方法
  377. * @p-config {Function} fail(resp) 失败
  378. * @p-config {Function} success(resp) 成功
  379. */
  380. WeixinApi.scanQRCode = function (callbacks) {
  381. callbacks = callbacks || {};
  382. WeixinJSBridge.invoke("scanQRCode", {}, function (resp) {
  383. switch (resp.err_msg) {
  384. // 打开扫描器成功
  385. case 'scan_qrcode:ok':
  386. callbacks.success && callbacks.success(resp);
  387. break;
  388. // 打开扫描器失败
  389. default :
  390. callbacks.fail && callbacks.fail(resp);
  391. break;
  392. }
  393. });
  394. };
  395. /**
  396. * 检测应用程序是否已安装
  397. * by mingcheng 2014-10-17
  398. *
  399. * @param {Object} data 应用程序的信息
  400. * @p-config {String} packageUrl 应用注册的自定义前缀,如 xxx:// 就取 xxx
  401. * @p-config {String} packageName 应用的包名
  402. *
  403. * @param {Object} callbacks 相关回调方法
  404. * @p-config {Function} fail(resp) 失败
  405. * @p-config {Function} success(resp) 成功,如果有对应的版本信息,则写入到 resp.version 中
  406. * @p-config {Function} all(resp) 无论成功失败都会执行的回调
  407. */
  408. WeixinApi.getInstallState = function (data, callbacks) {
  409. callbacks = callbacks || {};
  410. WeixinJSBridge.invoke("getInstallState", {
  411. "packageUrl":data.packageUrl || "",
  412. "packageName":data.packageName || ""
  413. }, function (resp) {
  414. var msg = resp.err_msg, match = msg.match(/state:yes_?(.*)$/);
  415. if (match) {
  416. resp.version = match[1] || "";
  417. callbacks.success && callbacks.success(resp);
  418. } else {
  419. callbacks.fail && callbacks.fail(resp);
  420. }
  421. callbacks.all && callbacks.all(resp);
  422. });
  423. };
  424. /**
  425. * 从网页里直接调起微信地图
  426. *
  427. * @param {Object} data 打开地图所需要的数据
  428. * @p-config {String} latitude 纬度
  429. * @p-config {String} longitude 经度
  430. * @p-config {String} name POI名称
  431. * @p-config {String} adress 地址
  432. * @p-config {String} scale 缩放
  433. * @p-config {String} infoUrl 查看位置界面底部的超链接
  434. *
  435. * @param {Object} callbacks 相关回调方法
  436. * @p-config {Function} fail(resp) 失败
  437. * @p-config {Function} success(resp) 成功
  438. * @p-config {Function} all(resp) 无论成功失败都会执行的回调
  439. */
  440. WeixinApi.openLocation = function (data, callbacks) {
  441. callbacks = callbacks || {};
  442. WeixinJSBridge.invoke('openLocation', {
  443. "latitude":data.latitude,
  444. "longitude":data.longitude,
  445. "name":data.name,
  446. "address":data.address,
  447. "scale":data.scale || 14,
  448. "infoUrl":data.infoUrl || ''
  449. }, function (resp) {
  450. if (resp.err_msg === "open_location:ok") {
  451. callbacks.success && callbacks.success(resp);
  452. } else {
  453. callbacks.fail && callbacks.fail(resp);
  454. }
  455. callbacks.all && callbacks.all(resp);
  456. });
  457. };
  458. /**
  459. * 发送邮件
  460. * @param {Object} data 邮件初始内容
  461. * @p-config {String} subject 邮件标题
  462. * @p-config {String} body 邮件正文
  463. *
  464. * @param {Object} callbacks 相关回调方法
  465. * @p-config {Function} fail(resp) 失败
  466. * @p-config {Function} success(resp) 成功
  467. * @p-config {Function} all(resp) 无论成功失败都会执行的回调
  468. */
  469. WeixinApi.sendEmail = function (data, callbacks) {
  470. callbacks = callbacks || {};
  471. WeixinJSBridge.invoke("sendEmail", {
  472. "title":data.subject,
  473. "content":data.body
  474. }, function (resp) {
  475. if (resp.err_msg === 'send_email:sent') {
  476. callbacks.success && callbacks.success(resp);
  477. } else {
  478. callbacks.fail && callbacks.fail(resp);
  479. }
  480. callbacks.all && callbacks.all(resp);
  481. })
  482. };
  483. /**
  484. * 开启Api的debug模式,比如出了个什么错误,能alert告诉你,而不是一直很苦逼的在想哪儿出问题了
  485. * @param {Function} callback(error) 出错后的回调,默认是alert
  486. */
  487. WeixinApi.enableDebugMode = function (callback) {
  488. /**
  489. * @param {String} errorMessage 错误信息
  490. * @param {String} scriptURI 出错的文件
  491. * @param {Long} lineNumber 出错代码的行号
  492. * @param {Long} columnNumber 出错代码的列号
  493. */
  494. window.onerror = function (errorMessage, scriptURI, lineNumber, columnNumber) {
  495. // 有callback的情况下,将错误信息传递到options.callback中
  496. if (typeof callback === 'function') {
  497. callback({
  498. message:errorMessage,
  499. script:scriptURI,
  500. line:lineNumber,
  501. column:columnNumber
  502. });
  503. } else {
  504. // 其他情况,都以alert方式直接提示错误信息
  505. var msgs = [];
  506. msgs.push("额,代码有错。。。");
  507. msgs.push("\n错误信息:", errorMessage);
  508. msgs.push("\n出错文件:", scriptURI);
  509. msgs.push("\n出错位置:", lineNumber + '行,' + columnNumber + '列');
  510. alert(msgs.join(''));
  511. }
  512. }
  513. };
  514. })(window);