├── .babelrc ├── .gitignore ├── NativeShare.js ├── README.md ├── demo ├── demo.png └── index.html ├── package.json ├── src ├── BAIDUAndroidBrowser.js ├── BaiduIosBrowser.js ├── Others.js ├── QQAndroid.js ├── QQIos.js ├── QQMobileBrowser.js ├── QZone.js ├── Share.js ├── SogouIosBrowser.js ├── UCAndroidBrowser.js ├── UCIosBrowser.js ├── Wechat.js ├── command.js ├── index.js ├── shareData.js ├── specifyShare.js └── utils.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "es2015", 5 | { 6 | "modules": false 7 | } 8 | ], 9 | "stage-0" 10 | ], 11 | "plugins": ["transform-decorators"] 12 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-error.log 6 | .idea/ 7 | *.map 8 | *.zip 9 | .vscode/ 10 | yarn* 11 | .history -------------------------------------------------------------------------------- /NativeShare.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports["NativeShare.js"]=t():e["NativeShare.js"]=t()}("undefined"!=typeof self?self:this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=0)}([function(e,t,n){"use strict";function r(){}function o(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:r,n=document.getElementsByTagName("script")[0],o=document.createElement("script");o.src=e,o.async=!0,n.parentNode.insertBefore(o,n),o.onload=t}function i(e,t){if(null==e)throw new TypeError("Cannot convert undefined or null to object");for(var n=Object(e),r=1;r1&&void 0!==arguments[1]&&arguments[1],n=[];for(var r in e)t?n.push(r+"="+encodeURIComponent(e[r])):n.push(r+"="+e[r]);return n.join("&")}function u(e){var t=document.createElement("a");return t.href=e,t.hostname}function s(e){ye?ye.content=e:document.head.insertAdjacentHTML("beforeend",'')}function f(e){de?de.href=e:document.head.insertAdjacentHTML("beforeend",'')}function l(e){document.title=e}function p(e){return c({share_id:924053302,url:be.encode(e.link),title:be.encode(e.title),description:be.encode(e.desc),previewimageUrl:be.encode(e.icon),image_url:be.encode(e.icon)})}function h(){a((ie?"mqqapi://share/to_fri?src_type=web&version=1&file_type=news":"mqqapi://share/to_fri?src_type=isqqBrowser&version=1&file_type=news")+"&"+p(ge))}function b(){a((ie?"mqqapi://share/to_fri?file_type=news&src_type=web&version=1&generalpastboard=1&shareType=1&cflag=1&objectlocation=pasteboard&callback_type=scheme&callback_name=QQ41AF4B2A":"mqqapi://share/to_qzone?src_type=isqqBrowser&version=1&file_type=news&req_type=1")+"&"+p(ge))}function y(){var e={url:ge.link,title:ge.title,pic:ge.icon,desc:ge.desc};location.href="http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?"+c(e,!0)}function d(){var e={url:ge.link,title:ge.title,pic:ge.icon};location.href="http://service.weibo.com/share/share.php?"+c(e,!0)}function g(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function v(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function m(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function w(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function O(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function j(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function S(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function k(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function P(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function q(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function T(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function C(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function E(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function D(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function x(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function Q(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function M(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function A(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function B(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function N(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function W(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function R(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function U(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function z(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function I(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function L(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function Z(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function F(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function H(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function J(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function X(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function G(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function K(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function V(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function Y(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function $(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var ee,te=navigator.userAgent,ne=/(iPad).*OS\s([\d_]+)/.test(te),re=/(iPod)(.*OS\s([\d_]+))?/.test(te),oe=!ne&&/(iPhone\sOS)\s([\d_]+)/.test(te),ie=ne||re||oe,ae=/(Android);?[\s\/]+([\d.]+)?/.test(te),ce=/micromessenger/i.test(te),ue=/QQ\/([\d\.]+)/.test(te),se=/Qzone\//.test(te),fe=/MQQBrowser/i.test(te)&&!ce&&!ue,le=/UCBrowser/i.test(te),pe=/mobile.*baidubrowser/i.test(te),he=/SogouMobileBrowser/i.test(te),be=(/baiduboxapp/i.test(te),{_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t,n,r,o,i,a,c,u="",s=0;for(e=be._utf8_encode(e);s>2,i=(3&t)<<4|n>>4,a=(15&n)<<2|r>>6,c=63&r,isNaN(n)?a=c=64:isNaN(r)&&(c=64),u=u+this._keyStr.charAt(o)+this._keyStr.charAt(i)+this._keyStr.charAt(a)+this._keyStr.charAt(c);return u},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");for(var t="",n=0;n127&&r<2048?(t+=String.fromCharCode(r>>6|192),t+=String.fromCharCode(63&r|128)):(t+=String.fromCharCode(r>>12|224),t+=String.fromCharCode(r>>6&63|128),t+=String.fromCharCode(63&r|128))}return t}}),ye=document.querySelector("meta[name=description]"),de=document.querySelector("link[rel*=icon]"),ge={link:location.href,title:function(){return document.title}(),desc:function(){return Object(ye).content||""}(),icon:function(){return Object(de).href||location.protocol+"//"+location.hostname+"/favicon.ico"}(),from:"",success:r,fail:r,trigger:r},ve=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};i(this._shareData,e),this._config.syncDescToTag&&s(this._shareData.desc),this._config.syncIconToTag&&f(this._shareData.icon),this._config.syncTitleToTag&&l(this._shareData.title)}},{key:"setConfig",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};i(this._config,e)}},{key:"getConfig",value:function(){return i({},this._config)}}]),e}(),we=me,_e=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:"default",t=arguments[1];this.setShareData(t);var n=this.getShareData(),r=this.constructor.commamdMap[String(e).toLowerCase()];browser.app.share({title:n.title,description:n.desc,url:n.link,img_url:n.icon,from:n.from,to_app:r})}}]),t}(we);Oe.commamdMap=(ee={},v(ee,"wechattimeline",8),v(ee,"wechatfriend",1),v(ee,"qqfriend",4),v(ee,"qzone",3),v(ee,"weibo",11),v(ee,"copyurl",10),v(ee,"more",5),v(ee,"generateqrcode",7),v(ee,"default",void 0),ee);var je,Se=Oe,ke=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:"default",t=arguments[1];this.setShareData(t);var n=this.getShareData(),r=this.constructor.commamdMap[String(e).toLowerCase()];ucbrowser.web_shareEX?ucbrowser.web_shareEX(JSON.stringify({title:n.title,content:n.desc,sourceUrl:n.link,imageUrl:n.icon,source:n.from,target:r})):ucbrowser.web_share(title,desc,link,r,"",from,"")}}]),t}(we);Pe.commamdMap=(je={},O(je,"wechattimeline","kWeixinFriend"),O(je,"wechatfriend","kWeixin"),O(je,"qqfriend","kQQ"),O(je,"qzone","kQZone"),O(je,"weibo","kSinaWeibo"),O(je,"default",void 0),je);var qe,Te=Pe,Ce=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:"default",t=arguments[1];this.setShareData(t);var n=this.getShareData(),r=this.constructor.commamdMap[String(e).toLowerCase()];ucweb.startRequest("shell.page_share",[n.title,n.desc,n.link,r,"",n.from,n.icon])}}]),t}(we);Ee.commamdMap=(qe={},P(qe,"wechattimeline","WechatTimeline"),P(qe,"wechatfriend","WechatFriends"),P(qe,"qqfriend","QQ"),P(qe,"qzone","Qzone"),P(qe,"weibo","SinaWeibo"),P(qe,"default",""),qe);var De=Ee,xe=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:"default",t=arguments[1];if(this.setShareData(t),!navigator.share){if("weibo"!==(e=String(e).toLowerCase()))throw"qqfriend"===e?h():"qzone"===e&&b(),new Error("the browser may not support command "+e+"!");return void d()}var n=this.getShareData(),r={url:n.link,title:n.title,text:n.desc};navigator.share(r).then(n.success).catch(n.fail)}}]),t}(we),Je=He,Xe=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]&&arguments[0],arguments[1]);this.setShareData(e),mqq.ui.showShareMenu()}},{key:"init",value:function(){var e=this;o("https://open.mobile.qq.com/sdk/qqapi.js",function(){var t=e._shareData;mqq.ui.setOnShareHandler(function(e){mqq.ui.shareMessage({back:!0,share_type:e,title:t.title,desc:t.desc,share_url:t.link,image_url:t.icon,sourceName:t.from},function(e){0===e.retCode?t.success(e):t.fail(e)})})})}}]),t}(we),Ke=Ge,Ve=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]&&arguments[0],arguments[1]);this.setShareData(e),mqq.ui.showShareMenu()}},{key:"init",value:function(){var e=this;o("https://open.mobile.qq.com/sdk/qqapi.js",function(){e.setShareData()})}}]),t}(we),et=$e,tt=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]&&arguments[0],arguments[1]);this.setShareData(t);for(var n=this.getShareData(),r=[],o=[],i=[],a=[],c=0;c<5;c++)r.push(n.icon),a.push(n.link),o.push(n.title),i.push(n.desc);QZAppExternal.setShare(function(t){0!=t.code&&(e.hasSomethingWrong=!0)},{type:"share",image:r,title:o,summary:i,shareURL:a})}},{key:"setShareData",value:function(e){try{this.call("default",e)}catch(e){}}},{key:"init",value:function(){var e=this;o("https://qzonestyle.gtimg.cn/qzone/phone/m/v4/widget/mobile/jsbridge.js",function(){e.call("default")})}}]),t}(we),rt=nt;n.d(t,"Share",function(){return we}),n.d(t,"QQMobileBrowser",function(){return Se}),n.d(t,"UCIosBrowser",function(){return Te}),n.d(t,"UCAndroidBrowser",function(){return De}),n.d(t,"BaiduAndroidBrowser",function(){return Me}),n.d(t,"BaiduIosBrowser",function(){return Ne}),n.d(t,"SogouIosBrowser",function(){return Ue}),n.d(t,"Wechat",function(){return Ze}),n.d(t,"Others",function(){return Je}),n.d(t,"QQIos",function(){return Ke}),n.d(t,"QQAndroid",function(){return et}),n.d(t,"QZone",function(){return rt}),n.d(t,"shareToQQ",function(){return h}),n.d(t,"shareToQZone",function(){return b}),n.d(t,"shareToWeibo4Web",function(){return d}),n.d(t,"shareToQZone4Web",function(){return y});var ot=void 0;ot=ce?Ze:ue&&ie?Ke:ue&&ae?et:se?rt:fe?Se:le&&ie?Te:le&&ae?De:pe&&ae?Me:pe&&ie?Ne:he&&ie?Ue:Je,window.NativeShare=ot;t.default=ot}])}); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 原文地址 [https://github.com/fa-ge/NativeShare/blob/master/README.md](https://github.com/fa-ge/NativeShare/blob/master/README.md) 2 | 3 | ### 起因 4 | 5 | 最近有一个活动页需要在移动端浏览器分享网页到微信,QQ。虽然每一个浏览器都有分享到微信的能力,但不是每个都提供接口供网页来调用。即使有提供,浏览器暴露出的api也各不相同,而我写[NativeShare](https://github.com/fa-ge/NativeShare)的目的只是为前端开发者提供一致的api来调用浏览器的原生分享组件。大小uglify + gzip = 4k。 6 | 7 | 8 | 9 | ### 兼容性(毫无疑问是兼容浏览器最多的插件了) 10 | 11 | - **移动端几乎所有浏览器都支持分享到QQ和QQ空间** 12 | - QQ浏览器 13 | - UC浏览器 14 | - 微信自带浏览器 15 | - QQ自带浏览器 16 | - QQ空间APP 17 | - 百度浏览器 18 | - ios 搜狗浏览器 19 | - 支持分享到web微博 20 | - 支持safari,chome浏览器(页面地址必须是https) 21 | 22 | 存在的问题 23 | 24 | * 安卓的QQ自带浏览器不支持.com以外的域名后缀。可能会支持.cn,.com.cn,但明确不支持.me,.io这个具体可以自己测试。 25 | * 安卓的QQ自带浏览器分享url必须跟页面url同一个域名,否则所有设置不生效。 26 | * 安卓的QQ自带浏览器无法直接分享 27 | * 虽然几乎所有的浏览器都支持分享到QQ和QQ空间,但是webview中基本都会不支持。我也很难判断当前浏览器是否支持,浏览器是否唤起QQ APP我也很难判断,所有除了上述支持的浏览器,APP外其他情况调用分享到QQ我也会抛出异常。 28 | * UC浏览器安卓端不能设置icon 29 | * 百度浏览器,百度APP不能直接分享 30 | * QQ空间APP,微信自带浏览器只能设置文案,分享需要用户手动点击右上角 31 | 32 | 33 | 34 | ### 示例 35 | [demo](https://fa-ge.github.io/NativeShare/demo/index.html) 36 | 37 | ![demo](https://fa-ge.github.io/NativeShare/demo/demo.png) 38 | 39 | ### npm包安装 40 | npm install --save nativeshare 41 | 42 | ### 使用 43 | 支持ES6模块,AMD,CMD引入 44 | 如果你的项目没有模块化。你也可以直接用script标签引入NativeShare.js。可以参考[demo](https://fa-ge.github.io/NativeShare/demo/index.html) 45 | ```javascript 46 | import NativeShare from 'nativeshare' 47 | 48 | // 先创建一个实例 49 | var nativeShare = new NativeShare() 50 | // 如果你需要在微信浏览器中分享,那么你需要设置额外的微信配置 51 | // 特别提示一下微信分享有一个坑,不要分享安全域名以外的链接(具体见jssdk文档),否则会导致你配置的文案无效 52 | // 创建实例应该带参数 53 | var nativeShare = new NativeShare({ 54 | wechatConfig: { 55 | appId: '', 56 | timestamp: '', 57 | nonceStr: '', 58 | signature: '', 59 | }, 60 | // 让你修改的分享的文案同步到标签里,比如title文案会同步到标签中 61 | // 这样可以让一些不支持分享的浏览器也能修改部分文案,默认都不会同步 62 | syncDescToTag: false, 63 | syncIconToTag: false, 64 | syncTitleToTag: false, 65 | }) 66 | 67 | // 你也可以在setConfig方法中设置配置参数 68 | nativeShare.setConfig({ 69 | wechatConfig: { 70 | appId: '', 71 | timestamp: '', 72 | nonceStr: '', 73 | signature: '', 74 | } 75 | }) 76 | 77 | 78 | // 设置分享文案 79 | nativeShare.setShareData({ 80 | icon: 'https://pic3.zhimg.com/v2-080267af84aa0e97c66d5f12e311c3d6_xl.jpg', 81 | link: 'https://github.com/fa-ge/NativeShare', 82 | title: 'NativeShare', 83 | desc: 'NativeShare是一个整合了各大移动端浏览器调用原生分享的插件', 84 | from: '@fa-ge', 85 | }) 86 | 87 | // 唤起浏览器原生分享组件(如果在微信中不会唤起,此时call方法只会设置文案。类似setShareData) 88 | try { 89 | nativeShare.call() 90 | // 如果是分享到微信则需要 nativeShare.call('wechatFriend') 91 | // 类似的命令下面有介绍 92 | } catch(err) { 93 | // 如果不支持,你可以在这里做降级处理 94 | } 95 | ``` 96 | 97 | ### API 98 | 99 | NativeShare一共只有五个实例方法 100 | 101 | * getShareData() 获得分享的文案 102 | * setShareData() 设置分享的文案 103 | * call(command = 'default', [options]) 调用浏览器原生的分享组件 104 | * setConfig() 设置配置参数和new NativeShare()中设置的一样 105 | * getConfig() 获得配置参数 106 | 107 | ```javascript 108 | { 109 | icon: '', 110 | link: '', 111 | title: '', 112 | desc: '', 113 | from: '', 114 | 115 | // 以下两个个回调目前只有在微信和百度APP中很好的支持 116 | success: noop, 117 | fail: noop, 118 | 119 | // 只有微信支持 120 | trigger: noop, 121 | } 122 | ``` 123 | 124 | 调用call方法时第一个参数是指定用什么命令调用分享组件。目前支持6个命令。分别是 125 | 126 | * default 默认,调用起底部的分享组件,当其他命令不支持的时候也会调用该命令 127 | * wechatTimeline 分享到朋友圈 128 | * wechatFriend 分享给微信好友 129 | * qqFriend 分享给QQ好友 130 | * qZone 分享到QQ空间 131 | * weibo 分享到微博 132 | 133 | 134 | ### 交流 135 | 如果你是浏览器开发者或者你知道其他浏览器调用分享的方式,请务必一定要告诉我。 136 | -------------------------------------------------------------------------------- /demo/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fa-ge/NativeShare/98715cb7336b91e7b2b9cf59f11175cdc7b10c98/demo/demo.png -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html> 3 | 4 | <head> 5 | <meta charset="utf-8"> 6 | <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" /> 7 | <meta name="description" content="NativeShare 是一个整合了各大移动端浏览器调用原生分享的插件!!!"> 8 | <title>NativeShare demo 9 | 25 | 34 | 35 | 36 | 37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 | 47 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nativeshare", 3 | "version": "2.1.5", 4 | "description": "NativeShare是一个整合了各大移动端浏览器调用原生分享的插件", 5 | "main": "NativeShare.js", 6 | "scripts": { 7 | "lib": "webpack --env=lib" 8 | }, 9 | "keywords": [ 10 | "share", 11 | "NativeShare", 12 | "browser" 13 | ], 14 | "author": "fa-ge", 15 | "license": "ISC", 16 | "devDependencies": { 17 | "babel-core": "^6.21.0", 18 | "babel-loader": "^6.2.10", 19 | "babel-plugin-transform-decorators": "^6.24.1", 20 | "babel-preset-es2015": "^6.18.0", 21 | "babel-preset-stage-0": "^6.16.0", 22 | "webpack": "^3.0.0" 23 | }, 24 | "repository": { 25 | "type": "git", 26 | "url": "git+https://github.com/fa-ge/NativeShare.git" 27 | }, 28 | "bugs": { 29 | "url": "https://github.com/fa-ge/NativeShare/issues" 30 | }, 31 | "homepage": "https://github.com/fa-ge/NativeShare#readme", 32 | "dependencies": {} 33 | } 34 | -------------------------------------------------------------------------------- /src/BAIDUAndroidBrowser.js: -------------------------------------------------------------------------------- 1 | import Share from './Share' 2 | 3 | export default class BaiduAndroidBrowser extends Share { 4 | constructor(config) { 5 | super(config) 6 | } 7 | 8 | call(command, options) { 9 | this.setShareData(options) 10 | const shareData = this.getShareData() 11 | _flyflowNative.exec( 12 | 'bd_utils', 13 | 'shareWebPage', 14 | JSON.stringify({ 15 | title: shareData.title, 16 | content: shareData.desc, 17 | landurl: shareData.link, 18 | imageurl: shareData.icon, 19 | shareSource: shareData.from, 20 | }), 21 | '' 22 | ) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/BaiduIosBrowser.js: -------------------------------------------------------------------------------- 1 | import Share from './Share' 2 | 3 | export default class BaiduIosBrowser extends Share { 4 | constructor(config) { 5 | super(config) 6 | } 7 | 8 | call(command, options) { 9 | this.setShareData(options) 10 | const shareData = this.getShareData() 11 | location.href = 12 | 'baidubrowserapp://bd_utils?action=shareWebPage¶ms=' + 13 | encodeURIComponent( 14 | JSON.stringify({ 15 | title: shareData.title, 16 | content: shareData.desc, 17 | imageurl: shareData.icon, 18 | landurl: shareData.link, 19 | mediaType: 0, 20 | share_type: 'webpage', 21 | }) 22 | ) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Others.js: -------------------------------------------------------------------------------- 1 | import { shareToQQ, shareToQZone, shareToWeibo4Web } from './specifyShare' 2 | import { qqFriend, qZone, weibo } from './command' 3 | import Share from './Share' 4 | 5 | export default class Others extends Share { 6 | constructor(config) { 7 | super(config) 8 | } 9 | 10 | call(command = 'default', options) { 11 | this.setShareData(options) 12 | 13 | if (!navigator.share) { 14 | command = String(command).toLowerCase() 15 | if (command === weibo) { 16 | shareToWeibo4Web() 17 | } else { 18 | if (command === qqFriend) { 19 | shareToQQ() 20 | } else if (command === qZone) { 21 | shareToQZone() 22 | } 23 | 24 | throw new Error(`the browser may not support command ${command}!`) 25 | } 26 | return 27 | } 28 | 29 | const shareData = this.getShareData() 30 | const queryObj = { 31 | url: shareData.link, 32 | title: shareData.title, 33 | text: shareData.desc, 34 | } 35 | navigator 36 | .share(queryObj) 37 | .then(shareData.success) 38 | .catch(shareData.fail) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/QQAndroid.js: -------------------------------------------------------------------------------- 1 | import { loadJs, getHostnameFromUrl } from './utils' 2 | import Share from './Share' 3 | 4 | export default class QQAndroid extends Share { 5 | constructor(config) { 6 | super(config) 7 | this.init() 8 | } 9 | 10 | setShareData(options) { 11 | super.setShareData(options) 12 | const shareData = this.getShareData() 13 | if (getHostnameFromUrl(shareData.link) !== location.hostname) { 14 | shareData.link = location.href 15 | console.warn('安卓的QQ自带浏览器分享url必须跟页面url同一个域名,已自动为你设置为当前页面的url') 16 | } 17 | try { 18 | mqq.data.setShareInfo( 19 | { 20 | share_url: shareData.link, 21 | title: shareData.title, 22 | desc: shareData.desc, 23 | image_url: shareData.icon, 24 | }, 25 | data => { 26 | if (data !== true) { 27 | console.warn(data) 28 | } 29 | } 30 | ) 31 | } catch (err) {} 32 | } 33 | 34 | call(command = 'default', options) { 35 | this.setShareData(options) 36 | mqq.ui.showShareMenu() 37 | } 38 | 39 | init() { 40 | loadJs('https://open.mobile.qq.com/sdk/qqapi.js', () => { 41 | this.setShareData() 42 | }) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/QQIos.js: -------------------------------------------------------------------------------- 1 | import { loadJs } from './utils' 2 | import Share from './Share' 3 | 4 | export default class QQIos extends Share { 5 | constructor(config) { 6 | super(config) 7 | this.init() 8 | } 9 | 10 | call(command = 'default', options) { 11 | this.setShareData(options) 12 | mqq.ui.showShareMenu() 13 | } 14 | 15 | init() { 16 | loadJs('https://open.mobile.qq.com/sdk/qqapi.js', () => { 17 | const shareData = this._shareData 18 | mqq.ui.setOnShareHandler(type => { 19 | mqq.ui.shareMessage( 20 | { 21 | back: true, 22 | share_type: type, 23 | title: shareData.title, 24 | desc: shareData.desc, 25 | share_url: shareData.link, 26 | image_url: shareData.icon, 27 | sourceName: shareData.from, 28 | }, 29 | data => { 30 | if (data.retCode === 0) { 31 | shareData.success(data) 32 | } else { 33 | shareData.fail(data) 34 | } 35 | } 36 | ) 37 | }) 38 | }) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/QQMobileBrowser.js: -------------------------------------------------------------------------------- 1 | import { loadJs, openAppByScheme, generateQueryString, Base64, isIos } from './utils' 2 | import { wechatTimeline, wechatFriend, qqFriend, qZone, weibo, copyUrl, more, generateQRCode, defaultCommand } from './command' 3 | import Share from './Share' 4 | 5 | export default class QQMobileBrowser extends Share { 6 | static commamdMap = { 7 | [wechatTimeline]: 8, 8 | [wechatFriend]: 1, 9 | [qqFriend]: 4, 10 | [qZone]: 3, 11 | [weibo]: 11, 12 | [copyUrl]: 10, 13 | [more]: 5, 14 | [generateQRCode]: 7, 15 | [defaultCommand]: undefined, 16 | } 17 | 18 | constructor(config) { 19 | super(config) 20 | loadJs('https://jsapi.qq.com/get?api=app.share') 21 | } 22 | 23 | call(command = 'default', options) { 24 | this.setShareData(options) 25 | const shareData = this.getShareData() 26 | const toApp = this.constructor.commamdMap[String(command).toLowerCase()] 27 | browser.app.share({ 28 | title: shareData.title, 29 | description: shareData.desc, 30 | url: shareData.link, 31 | img_url: shareData.icon, 32 | from: shareData.from, 33 | to_app: toApp, 34 | }) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/QZone.js: -------------------------------------------------------------------------------- 1 | import { loadJs, assign } from './utils' 2 | import Share from './Share' 3 | 4 | export default class QQ extends Share { 5 | constructor(config) { 6 | super(config) 7 | this.init() 8 | } 9 | 10 | call(command = 'default', options) { 11 | this.setShareData(options) 12 | 13 | const shareData = this.getShareData() 14 | const imageArr = [], 15 | titleArr = [], 16 | summaryArr = [], 17 | shareURLArr = [] 18 | for (let i = 0; i < 5; i++) { 19 | imageArr.push(shareData.icon) 20 | shareURLArr.push(shareData.link) 21 | titleArr.push(shareData.title) 22 | summaryArr.push(shareData.desc) 23 | } 24 | QZAppExternal.setShare( 25 | ({ code }) => { 26 | if (code != 0) { 27 | this.hasSomethingWrong = true 28 | } 29 | }, 30 | { 31 | type: 'share', 32 | image: imageArr, 33 | title: titleArr, 34 | summary: summaryArr, 35 | shareURL: shareURLArr, 36 | } 37 | ) 38 | } 39 | 40 | setShareData(options) { 41 | try { 42 | this.call('default', options) 43 | } catch (err) {} 44 | } 45 | 46 | init() { 47 | loadJs('https://qzonestyle.gtimg.cn/qzone/phone/m/v4/widget/mobile/jsbridge.js', () => { 48 | this.call('default') 49 | }) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Share.js: -------------------------------------------------------------------------------- 1 | import { 2 | noop, 3 | assign, 4 | openAppByScheme, 5 | generateQueryString, 6 | Base64, 7 | isIos, 8 | setDescTagContent, 9 | setIconTagHref, 10 | setTitleTagTitle, 11 | } from './utils' 12 | import shareData from './shareData' 13 | 14 | export default class Share { 15 | _shareData = shareData 16 | _config = { 17 | syncDescToTag: false, 18 | syncIconToTag: false, 19 | syncTitleToTag: false, 20 | } 21 | 22 | constructor(config) { 23 | this.setConfig(config) 24 | } 25 | 26 | getShareData() { 27 | return assign({}, this._shareData) 28 | } 29 | 30 | setShareData(options = {}) { 31 | assign(this._shareData, options) 32 | if (this._config.syncDescToTag) { 33 | setDescTagContent(this._shareData.desc) 34 | } 35 | if (this._config.syncIconToTag) { 36 | setIconTagHref(this._shareData.icon) 37 | } 38 | if (this._config.syncTitleToTag) { 39 | setTitleTagTitle(this._shareData.title) 40 | } 41 | } 42 | 43 | setConfig(config = {}) { 44 | assign(this._config, config) 45 | } 46 | 47 | getConfig() { 48 | return assign({}, this._config) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/SogouIosBrowser.js: -------------------------------------------------------------------------------- 1 | import Share from './Share' 2 | 3 | export default class SogouIosBrowser extends Share { 4 | constructor(config) { 5 | super(config) 6 | } 7 | 8 | call(command, options) { 9 | this.setShareData(options) 10 | const shareData = this.getShareData() 11 | SogouMse.Utility.shareWithInfo({ 12 | shareTitle: shareData.title, 13 | shareContent: shareData.desc, 14 | shareImageUrl: shareData.icon, 15 | shareUrl: shareData.link, 16 | }) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/UCAndroidBrowser.js: -------------------------------------------------------------------------------- 1 | import { wechatTimeline, wechatFriend, qqFriend, qZone, weibo, defaultCommand } from './command' 2 | import Share from './Share' 3 | 4 | export default class UCAndroidBrowser extends Share { 5 | static commamdMap = { 6 | [wechatTimeline]: 'WechatTimeline', 7 | [wechatFriend]: 'WechatFriends', 8 | [qqFriend]: 'QQ', 9 | [qZone]: 'Qzone', 10 | [weibo]: 'SinaWeibo', 11 | [defaultCommand]: '', 12 | } 13 | 14 | constructor(config) { 15 | super(config) 16 | } 17 | 18 | call(command = 'default', options) { 19 | this.setShareData(options) 20 | const shareData = this.getShareData() 21 | const toApp = this.constructor.commamdMap[String(command).toLowerCase()] 22 | ucweb.startRequest('shell.page_share', [ 23 | shareData.title, 24 | shareData.desc, 25 | shareData.link, 26 | toApp, 27 | '', 28 | shareData.from, 29 | shareData.icon, 30 | ]) 31 | } 32 | } -------------------------------------------------------------------------------- /src/UCIosBrowser.js: -------------------------------------------------------------------------------- 1 | import { wechatTimeline, wechatFriend, qqFriend, qZone, weibo, defaultCommand } from './command' 2 | import Share from './Share' 3 | 4 | export default class UCIosBrowser extends Share { 5 | static commamdMap = { 6 | [wechatTimeline]: 'kWeixinFriend', 7 | [wechatFriend]: 'kWeixin', 8 | [qqFriend]: 'kQQ', 9 | [qZone]: 'kQZone', 10 | [weibo]: 'kSinaWeibo', 11 | [defaultCommand]: undefined, 12 | } 13 | 14 | constructor(config) { 15 | super(config) 16 | } 17 | 18 | call(command = 'default', options) { 19 | this.setShareData(options) 20 | const shareData = this.getShareData() 21 | const toApp = this.constructor.commamdMap[String(command).toLowerCase()] 22 | if (ucbrowser.web_shareEX) { 23 | ucbrowser.web_shareEX( 24 | JSON.stringify({ 25 | title: shareData.title, 26 | content: shareData.desc, 27 | sourceUrl: shareData.link, 28 | imageUrl: shareData.icon, 29 | source: shareData.from, 30 | target: toApp, 31 | }) 32 | ) 33 | } else { 34 | ucbrowser.web_share(title, desc, link, toApp, '', from, '') 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Wechat.js: -------------------------------------------------------------------------------- 1 | import { assign, loadJs } from './utils' 2 | import Share from './Share' 3 | 4 | export default class Wechat extends Share { 5 | constructor(config) { 6 | super(config) 7 | this.setConfig(config) 8 | } 9 | 10 | call(command, options) { 11 | this.setShareData(options) 12 | } 13 | 14 | setConfig(config) { 15 | super.setConfig(config) 16 | this.init(this.getConfig().wechatConfig) 17 | } 18 | 19 | init(config) { 20 | if (!config) { 21 | return 22 | } 23 | loadJs('https://res.wx.qq.com/open/js/jweixin-1.4.0.js', () => { 24 | wx.config( 25 | assign( 26 | { 27 | debug: false, 28 | jsApiList: [ 29 | 'onMenuShareTimeline', 30 | 'onMenuShareAppMessage', 31 | 'onMenuShareQQ', 32 | 'onMenuShareWeibo', 33 | 'onMenuShareQZone', 34 | 'updateAppMessageShareData', 35 | 'updateTimelineShareData', 36 | ], 37 | }, 38 | config 39 | ) 40 | ) 41 | 42 | const shareData = this._shareData 43 | const wxShareData = {} 44 | 45 | Object.defineProperty(wxShareData, 'trigger', { 46 | get() { 47 | return (...args) => { 48 | assign(wxShareData, { 49 | title: shareData.title, 50 | desc: shareData.desc, 51 | link: shareData.link, 52 | imgUrl: shareData.icon, 53 | success: shareData.success, 54 | fail: shareData.fail, 55 | cancel: shareData.fail, 56 | }) 57 | shareData.trigger(...args) 58 | } 59 | }, 60 | set(newValue) { 61 | shareData.trigger = newValue 62 | }, 63 | enumerable: true, 64 | }) 65 | 66 | wx.ready(() => { 67 | wx.onMenuShareAppMessage(wxShareData) 68 | wx.onMenuShareQQ(wxShareData) 69 | wx.onMenuShareQZone(wxShareData) 70 | wx.onMenuShareWeibo(wxShareData) 71 | wx.onMenuShareTimeline(wxShareData) 72 | wx.updateAppMessageShareData(wxShareData) 73 | wx.updateTimelineShareData(wxShareData) 74 | }) 75 | }) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/command.js: -------------------------------------------------------------------------------- 1 | export const wechatFriend = 'wechatfriend' 2 | export const wechatTimeline = 'wechattimeline' 3 | export const qqFriend = 'qqfriend' 4 | export const qZone = 'qzone' 5 | export const weibo = 'weibo' 6 | export const copyUrl = 'copyurl' 7 | export const more = 'more' 8 | export const generateQRCode = 'generateqrcode' 9 | export const defaultCommand = 'default' 10 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { shareToQQ, shareToQZone, shareToWeibo4Web, shareToQZone4Web } from './specifyShare' 2 | import { 3 | isQQMBrowser, 4 | isUCMBrowser, 5 | isWechat, 6 | isBaiduMBrowser, 7 | isAndroid, 8 | isIos, 9 | isQQ, 10 | isQZone, 11 | isSogouMBrowser, 12 | } from './utils' 13 | import Share from './Share' 14 | import QQMobileBrowser from './QQMobileBrowser' 15 | import UCIosBrowser from './UCIosBrowser' 16 | import UCAndroidBrowser from './UCAndroidBrowser' 17 | import BaiduAndroidBrowser from './BaiduAndroidBrowser' 18 | import BaiduIosBrowser from './BaiduIosBrowser' 19 | import SogouIosBrowser from './SogouIosBrowser' 20 | import Wechat from './Wechat' 21 | import Others from './Others' 22 | import QQIos from './QQIos' 23 | import QQAndroid from './QQAndroid' 24 | import QZone from './QZone' 25 | 26 | let NativeShare 27 | 28 | if (isWechat) { 29 | NativeShare = Wechat 30 | } else if (isQQ && isIos) { 31 | NativeShare = QQIos 32 | } else if (isQQ && isAndroid) { 33 | NativeShare = QQAndroid 34 | } else if (isQZone) { 35 | NativeShare = QZone 36 | } else if (isQQMBrowser) { 37 | NativeShare = QQMobileBrowser 38 | } else if (isUCMBrowser && isIos) { 39 | NativeShare = UCIosBrowser 40 | } else if (isUCMBrowser && isAndroid) { 41 | NativeShare = UCAndroidBrowser 42 | } else if (isBaiduMBrowser && isAndroid) { 43 | NativeShare = BaiduAndroidBrowser 44 | } else if (isBaiduMBrowser && isIos) { 45 | NativeShare = BaiduIosBrowser 46 | } else if (isSogouMBrowser && isIos) { 47 | NativeShare = SogouIosBrowser 48 | } else { 49 | NativeShare = Others 50 | } 51 | 52 | export { 53 | Share, 54 | QQMobileBrowser, 55 | UCIosBrowser, 56 | UCAndroidBrowser, 57 | BaiduAndroidBrowser, 58 | BaiduIosBrowser, 59 | SogouIosBrowser, 60 | Wechat, 61 | Others, 62 | QQIos, 63 | QQAndroid, 64 | QZone, 65 | shareToQQ, 66 | shareToQZone, 67 | shareToWeibo4Web, 68 | shareToQZone4Web, 69 | } 70 | 71 | window.NativeShare = NativeShare 72 | export default NativeShare 73 | -------------------------------------------------------------------------------- /src/shareData.js: -------------------------------------------------------------------------------- 1 | import { noop, getContentFromDescTag, getHrefFromIconTag, getTitleFromTitleTag } from './utils' 2 | 3 | export default { 4 | link: location.href, 5 | title: getTitleFromTitleTag(), 6 | desc: getContentFromDescTag(), 7 | icon: getHrefFromIconTag(), 8 | from: '', 9 | success: noop, 10 | fail: noop, 11 | trigger: noop, 12 | } 13 | -------------------------------------------------------------------------------- /src/specifyShare.js: -------------------------------------------------------------------------------- 1 | import { openAppByScheme, generateQueryString, Base64, isIos } from './utils' 2 | import shareData from './shareData' 3 | 4 | function generateQQQueryString(shareData) { 5 | return generateQueryString({ 6 | share_id: 924053302, 7 | url: Base64.encode(shareData.link), 8 | title: Base64.encode(shareData.title), 9 | description: Base64.encode(shareData.desc), 10 | previewimageUrl: Base64.encode(shareData.icon), // ios 11 | image_url: Base64.encode(shareData.icon), // android 12 | }) 13 | } 14 | 15 | function shareToQQ() { 16 | const shareScheme = isIos 17 | ? 'mqqapi://share/to_fri?src_type=web&version=1&file_type=news' 18 | : 'mqqapi://share/to_fri?src_type=isqqBrowser&version=1&file_type=news' 19 | openAppByScheme(`${shareScheme}&${generateQQQueryString(shareData)}`) 20 | } 21 | 22 | function shareToQZone() { 23 | const shareScheme = isIos 24 | ? 'mqqapi://share/to_fri?file_type=news&src_type=web&version=1&generalpastboard=1&shareType=1&cflag=1&objectlocation=pasteboard&callback_type=scheme&callback_name=QQ41AF4B2A' 25 | : 'mqqapi://share/to_qzone?src_type=isqqBrowser&version=1&file_type=news&req_type=1' 26 | openAppByScheme(`${shareScheme}&${generateQQQueryString(shareData)}`) 27 | } 28 | 29 | function shareToQZone4Web() { 30 | const queryObj = { 31 | url: shareData.link, 32 | title: shareData.title, 33 | pic: shareData.icon, 34 | desc: shareData.desc, 35 | } 36 | location.href = `http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?${generateQueryString(queryObj, true)}` 37 | } 38 | 39 | function shareToWeibo4Web() { 40 | const queryObj = { 41 | url: shareData.link, 42 | title: shareData.title, 43 | pic: shareData.icon, 44 | } 45 | location.href = `http://service.weibo.com/share/share.php?${generateQueryString(queryObj, true)}` 46 | } 47 | 48 | export { shareToQQ, shareToQZone, shareToWeibo4Web, shareToQZone4Web } 49 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | const UA = navigator.userAgent 2 | 3 | const isIpad = /(iPad).*OS\s([\d_]+)/.test(UA) 4 | const isIpod = /(iPod)(.*OS\s([\d_]+))?/.test(UA) 5 | const isIphone = !isIpad && /(iPhone\sOS)\s([\d_]+)/.test(UA) 6 | const isIos = isIpad || isIpod || isIphone 7 | const isAndroid = /(Android);?[\s\/]+([\d.]+)?/.test(UA) 8 | const isWechat = /micromessenger/i.test(UA) 9 | const isQQ = /QQ\/([\d\.]+)/.test(UA) 10 | const isQZone = /Qzone\//.test(UA) 11 | const isQQMBrowser = /MQQBrowser/i.test(UA) && !isWechat && !isQQ 12 | const isUCMBrowser = /UCBrowser/i.test(UA) 13 | const isBaiduMBrowser = /mobile.*baidubrowser/i.test(UA) 14 | const isSogouMBrowser = /SogouMobileBrowser/i.test(UA) 15 | const isBaiduApp = /baiduboxapp/i.test(UA) 16 | 17 | function noop() {} 18 | 19 | function loadJs(src, callback = noop) { 20 | const ref = document.getElementsByTagName('script')[0] 21 | const script = document.createElement('script') 22 | script.src = src 23 | script.async = true 24 | ref.parentNode.insertBefore(script, ref) 25 | script.onload = callback 26 | } 27 | 28 | function assign(target, varArgs) { 29 | if (target == null) { 30 | throw new TypeError('Cannot convert undefined or null to object') 31 | } 32 | 33 | var to = Object(target) 34 | 35 | for (var index = 1; index < arguments.length; index++) { 36 | var nextSource = arguments[index] 37 | 38 | if (nextSource != null) { 39 | for (var nextKey in nextSource) { 40 | if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { 41 | to[nextKey] = nextSource[nextKey] 42 | } 43 | } 44 | } 45 | } 46 | return to 47 | } 48 | 49 | function openAppByScheme(scheme) { 50 | if (isIos) { 51 | location.href = scheme 52 | } else { 53 | var iframe = document.createElement('iframe') 54 | iframe.style.display = 'none' 55 | iframe.src = scheme 56 | document.body.appendChild(iframe) 57 | setTimeout(function() { 58 | iframe && iframe.parentNode && iframe.parentNode.removeChild(iframe) 59 | }, 2000) 60 | } 61 | } 62 | 63 | function generateQueryString(queryObj, needEncode = false) { 64 | const arr = [] 65 | for (let key in queryObj) { 66 | if (needEncode) { 67 | arr.push(`${key}=${encodeURIComponent(queryObj[key])}`) 68 | } else { 69 | arr.push(`${key}=${queryObj[key]}`) 70 | } 71 | } 72 | return arr.join('&') 73 | } 74 | 75 | const Base64 = { 76 | _keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', 77 | encode: function(a) { 78 | var b, 79 | c, 80 | d, 81 | e, 82 | f, 83 | g, 84 | h, 85 | i = '', 86 | j = 0 87 | for (a = Base64._utf8_encode(a); j < a.length; ) 88 | (b = a.charCodeAt(j++)), (c = a.charCodeAt(j++)), (d = a.charCodeAt(j++)), (e = b >> 2), (f = 89 | ((3 & b) << 4) | (c >> 4)), (g = ((15 & c) << 2) | (d >> 6)), (h = 63 & d), isNaN(c) 90 | ? (g = h = 64) 91 | : isNaN(d) && (h = 64), (i = 92 | i + this._keyStr.charAt(e) + this._keyStr.charAt(f) + this._keyStr.charAt(g) + this._keyStr.charAt(h)) 93 | return i 94 | }, 95 | _utf8_encode: function(a) { 96 | a = a.replace(/\r\n/g, '\n') 97 | for (var b = '', c = 0; c < a.length; c++) { 98 | var d = a.charCodeAt(c) 99 | d < 128 100 | ? (b += String.fromCharCode(d)) 101 | : d > 127 && d < 2048 102 | ? ((b += String.fromCharCode((d >> 6) | 192)), (b += String.fromCharCode((63 & d) | 128))) 103 | : ( 104 | (b += String.fromCharCode((d >> 12) | 224)), 105 | (b += String.fromCharCode(((d >> 6) & 63) | 128)), 106 | (b += String.fromCharCode((63 & d) | 128)) 107 | ) 108 | } 109 | return b 110 | }, 111 | } 112 | 113 | function getHostnameFromUrl(url) { 114 | const a = document.createElement('a') 115 | a.href = url 116 | return a.hostname 117 | } 118 | 119 | const descTag = document.querySelector('meta[name=description]') 120 | const iconTag = document.querySelector('link[rel*=icon]') 121 | 122 | function getContentFromDescTag() { 123 | return Object(descTag).content || '' 124 | } 125 | 126 | function getHrefFromIconTag() { 127 | return Object(iconTag).href || `${location.protocol}//${location.hostname}/favicon.ico` 128 | } 129 | 130 | function getTitleFromTitleTag() { 131 | return document.title 132 | } 133 | 134 | function setDescTagContent(content) { 135 | if (descTag) { 136 | descTag.content = content 137 | } else { 138 | document.head.insertAdjacentHTML('beforeend', ``) 139 | } 140 | } 141 | 142 | function setIconTagHref(href) { 143 | if (iconTag) { 144 | iconTag.href = href 145 | } else { 146 | document.head.insertAdjacentHTML('beforeend', ``) 147 | } 148 | } 149 | 150 | function setTitleTagTitle(title) { 151 | document.title = title 152 | } 153 | 154 | export { 155 | isWechat, 156 | isQQ, 157 | isQZone, 158 | isIos, 159 | isAndroid, 160 | isQQMBrowser, 161 | isUCMBrowser, 162 | isBaiduMBrowser, 163 | isSogouMBrowser, 164 | isBaiduApp, 165 | loadJs, 166 | noop, 167 | assign, 168 | openAppByScheme, 169 | generateQueryString, 170 | Base64, 171 | getHostnameFromUrl, 172 | getContentFromDescTag, 173 | getHrefFromIconTag, 174 | getTitleFromTitleTag, 175 | setDescTagContent, 176 | setIconTagHref, 177 | setTitleTagTitle, 178 | } 179 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | const path = require('path') 3 | 4 | module.exports = { 5 | entry: { 6 | NativeShare: './src/index.js', 7 | }, 8 | output: { 9 | path: path.resolve(__dirname, './'), 10 | filename: '[name].js', 11 | library: '[name].js', 12 | libraryTarget: 'umd', 13 | }, 14 | module: { 15 | rules: [ 16 | { 17 | test: /\.js$/, 18 | use: [ 19 | { 20 | loader: 'babel-loader', 21 | }, 22 | ], 23 | }, 24 | ], 25 | }, 26 | plugins: [new webpack.optimize.UglifyJsPlugin(), new webpack.optimize.ModuleConcatenationPlugin()], 27 | } 28 | --------------------------------------------------------------------------------