手机Web APP如何实现分享多平台功能


Posted in Javascript onAugust 19, 2016

话说App一般都带有分享到社交平台的入口,web网页的分享也有很不错的框架,但是随着HTML5的不断发展,手机web页面越来越多的进入到我们的生活中,那如何在我们的手机上完成分享呢?话说各大分享平台都有针对Android、Ios的SDK,作为开发者,我们只需要将SDK集成的我们的项目中即可,通过提供的外部接口,我们可以很容易的完成分享的功能;web网页呢,网上也存在很多优秀的分享框架,例如:bShare分享 、JiaThis分享;我们可以很方便的集成到我们的项目中;但是手机web页面实现分享就需要我们下点功夫了,以为这个时候,我们就可以通过调用用户安装的客户端进行分享,这里需要特别提到的就是微信分享了,网页端我们分享时,一般都是弹出一个分享的二维码,我们使用微信App扫描然后进行分享,手机端我们就不能这样操作了,我们需要当用户选中微信分享时,直接打开App进行分享,这里就要吐槽一下微信的分享JS SDK了,初次接触到这个东东时,还以为只要完成操作就可以实现自定义分享了,随着各种坑不断,最后发现,微信JS SDK仅仅只是将我们的自定义内容临时缓存,当我们需要分享时,还是需要通过微信右上角的按钮来完成操作的。好嘞,不多讲废话了,进入今天的主题,接下来我将按照通过超链接完成新浪、QQ、QQ空间、腾讯微博分享,然后为大家奉上基于C#平台的微信JS SDK分享组件的签名逻辑,最后带领大家完成手机web端分享。

进入第一点:通过超链接完成分享

对于常用的社交平台我们基本可以通过超链接的方式进行内容分享,当然微信除外,微信不支持这种分享方式,这种分享方式可以便于我们自定义分享,并且使用起来非常的方便。

function shareSina() {
//分享到新浪微博
var sharesinastring = 'http://service.weibo.com/share/share.php?title=' + $("#title").val() + '&url=' + $("#url").val();
window.location.href = sharesinastring;
}
function shareQQzone(){
var p = {
url:location.href,
showcount:'0',/*是否显示分享总数,显示:'1',不显示:'0' */
desc:'',/*默认分享理由(可选)*/
summary:'',/*分享摘要(可选)*/
title:'',/*分享标题(可选)*/
site:'满艺网',/*分享来源 如:腾讯网(可选)*/
pics:'', /*分享图片的路径(可选)*/
style:'203',
width:98,
height:22
};
//分享到QQ空间
var sharesinastring = 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?title=' + $("#title").val() + '&url=' + $("#url").val() + '&site="满艺网"';
window.location.href = sharesinastring;
}
function shareQQ() {
var p = {
url: location.href, /*获取URL,可加上来自分享到QQ标识,方便统计*/
desc: '', /*分享理由(风格应模拟用户对话),支持多分享语随机展现(使用|分隔)*/
title: '', /*分享标题(可选)*/
summary: '', /*分享摘要(可选)*/
pics: '', /*分享图片(可选)*/
flash: '', /*视频地址(可选)*/
site: '满艺网', /*分享来源(可选) 如:QQ分享*/
style: '201',
width: 32,
height: 32
};
//分享到QQ
var sharesinastring = 'http://connect.qq.com/widget/shareqq/index.html?title=' + $("#title").val() + '&summary=' + $("#url").val() + '&url=' + $("#url").val() + '&site="满艺网"';
window.location.href = sharesinastring;
}
function shareQQweibo() {
var p = {
url: location.href, /*获取URL,可加上来自分享到QQ标识,方便统计*/
title: '', /*分享标题(可选)*/
pic: '', /*分享图片(可选)*/
site: '满艺网' /*分享来源(可选) 如:QQ分享*/
};
//分享到腾讯微博
var sharesinastring = 'http://v.t.qq.com/share/share.php?title=' + $("#title").val() + '&url=' + $("#url").val() + '&site="满艺网"';
window.location.href = sharesinastring;
}

以上便是分享都新浪微博、QQ、QQ空间、腾讯微博的JS代码,我们只需要在页面需要分享的位置进行一下调用即可。当然还有很多平台,一样支持这种形式的分享内容,各位小伙伴自己去摸索吧,这里我们不再一一赘述。

下面介绍一些微信分享:

一开始我们便说道微信内置的浏览器右上角带有分享功能,这也导致我们在自己的网页上无法直接分享到微信的朋友圈,而微信为我们提供了一个用于微信自定义分享的JS SDK,小伙伴是不是已经按耐不住自己的激情了,下面我们来先简单看一这个JS SDK为何物?微信官方提供的文档到时挺详细,但是想要开发JS SDK我们首先需要一个微信公众号,然后我们点击“接口权限”可以查看到我们所拥有的权限,如下:

手机Web APP如何实现分享多平台功能

对于上面这些基本的东西就不在多说,下面我们重点看一下如何获取jsapi_ticket,如何进行签名。官方文档提示的步骤是,先获取access_token,然后通过access_token来获取jsapi_ticket,最后通过jsapi_ticket进行签名。下面我们就一步一步完成上面的工作。注:官方提供了php、java、python、nodejs的实例程序,这里我将以C#为例为大家结束如何完成上面的操作。

第一步、获取access_token

官方文档是这样说的:access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。

手机Web APP如何实现分享多平台功能

第二步获取jsapi_ticket

官方文档是这样说的:jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。

1.参考以下文档获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token):../15/54ce45d8d30b6bf6758f68d2e95bc627.html

手机Web APP如何实现分享多平台功能

2.用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi

获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了。

  第三步生成JS-SDK权限验证的签名

签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。

手机Web APP如何实现分享多平台功能

注意事项

1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同;

2.签名用的url必须是调用JS接口页面的完整URL;

3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。

以上便是微信JS SDK的签名逻辑部分,下面奉上具体的代码实现:

using System;
using System.Net;
using System.Web.Mvc;
using System.IO;
using System.Text;
using System.Web.Script.Serialization;
using ManYiAbyWAP.Models;
/// <summary>
/// 微信获取jsapi_ticket
/// </summary>
namespace ManYiAbyWAP.Controllers
{
public class WXMessageController : Controller
{
private static string APPID = "微信提供的appid";
private static string SECRECT = "微信提供的secrect";
public static WXInfo accessToken = null;//全局对象,每7200秒更新一次,微信对每日获取Token有请求次数与时效限制
public static DateTime overTime = DateTime.Now;//用于Token的过期验证
public ActionResult GetToken(string url) {
if (accessToken != null)
{
TimeSpan span = Convert.ToDateTime(overTime).Subtract(Convert.ToDateTime(DateTime.Now));
if (span.TotalHours > 2)
{
accessToken = GETWinXinToken();
overTime = DateTime.Now;
}
}
else
{
accessToken = GETWinXinToken();
overTime = DateTime.Now;
}
//生成签名的时间戳
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
accessToken.timestamp = Convert.ToInt64(ts.TotalSeconds).ToString();
//获取随机串
accessToken.noncestr = createNonceStr(16);
string str = "jsapi_ticket="+ accessToken .ticket+ "&noncestr="+ accessToken.noncestr + "×tamp="+ accessToken.timestamp + "&url="+ url;
accessToken.signature = SHA1(str).ToLower();
accessToken.APPID = APPID;
return Json(accessToken, JsonRequestBehavior.AllowGet);
}
//生成随机串
private string createNonceStr(int length = 16)
{
string str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random r = new Random();
string result = string.Empty;
//生成一个8位长的随机字符,具体长度可以自己更改
for (int i = 0; i < length; i++)
{
int m = r.Next(0, 62);//这里下界是0,随机数可以取到,上界应该是62,因为随机数取不到上界,也就是最大62,符合我们的题意
string s = str.Substring(m, 1);
result += s;
}
return result;
}
//散列算法
private static string SHA1(string text)
{
byte[] cleanBytes = Encoding.Default.GetBytes(text);
byte[] hashedBytes = System.Security.Cryptography.SHA1.Create().ComputeHash(cleanBytes);
return BitConverter.ToString(hashedBytes).Replace("-", "");
}
//通过GET请求获取Token
private static WXInfo GETWinXinToken() {
//获取access_token
HttpWebResponse response = CreateGetHttpResponse("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + APPID + "&secret=" + SECRECT, 5000);
StreamReader reader = new StreamReader(response.GetResponseStream());
String line;
StringBuilder sb = new StringBuilder();
while ((line = reader.ReadLine()) != null)
{
sb.Append(line.ToString());
}
JavaScriptSerializer js = new JavaScriptSerializer();
WXInfo accessToken = js.Deserialize<WXInfo>(sb.ToString());
//获取jsapi_ticket
response = CreateGetHttpResponse("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken.access_token + "&type=jsapi", 5000);
reader = new StreamReader(response.GetResponseStream());
sb = new StringBuilder();
while ((line = reader.ReadLine()) != null)
{
sb.Append(line.ToString());
}
accessToken = js.Deserialize<WXInfo>(sb.ToString());
return accessToken;
}
/// <summary> 
/// 创建GET方式的HTTP请求 
/// </summary> 
/// <param name="url">请求的URL</param> 
/// <param name="timeout">请求的超时时间</param> 
/// <param name="userAgent">请求的客户端浏览器信息,可以为空</param> 
/// <param name="cookies">随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空</param> 
/// <returns></returns> 
public static HttpWebResponse CreateGetHttpResponse(string url, int? timeout, string userAgent=null, CookieCollection cookies=null)
{
if (string.IsNullOrEmpty(url))
{
throw new ArgumentNullException("url");
}
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "GET";
if (!string.IsNullOrEmpty(userAgent))
{
request.UserAgent = userAgent;
}
if (timeout.HasValue)
{
request.Timeout = timeout.Value;
}
if (cookies != null)
{
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add(cookies);
}
return request.GetResponse() as HttpWebResponse;
}
}
}

用于存放Token信息的全局对象WXInfo.cs

namespace ManYiAbyWAP.Models
{
/// <summary>
/// 微信获取Token返回参数类
/// </summary>
public class WXInfo
{
public string APPID { get; set; }
public string access_token { get; set; }//access_token
public string expires_in { get; set; }//Token过期时间,7200秒内有效
public string ticket { get; set; }//jsapi_ticket
public string errmsg { get; set; }
public int errcode { get; set; }
public string noncestr { get; set; }//生成签名的随机串
public string timestamp { get; set; }//生成签名的时间戳
public string signature { get; set; }//签名返回值
}
}

网页端进行初始化的JS代码:

//微信JS SDK请求状态
var requestStatus = 0;
function shareWX() {
if (requestStatus != 1) {
requestStatus = 1;//正在请求
var ajaxPara = "url=" + encodeURIComponent(window.location.href.split('#')[0]);
$.ajax({
url: '/WXMessage/GetToken',
dataType: 'json',
data: ajaxPara,
success: function (json) {
if (undefined != json && json !== "") {
var jsonObjs = eval(json);
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: jsonObjs.APPID, // 必填,公众号的唯一标识
timestamp: jsonObjs.timestamp, // 必填,生成签名的时间戳
nonceStr: jsonObjs.noncestr, // 必填,生成签名的随机串
signature: jsonObjs.signature,// 必填,签名,见附录1
jsApiList: [
'checkJsApi',
'onMenuShareTimeline',
'onMenuShareAppMessage',
'onMenuShareQQ',
'onMenuShareWeibo',
'onMenuShareQZone'
] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
wx.ready(function () {
//alert("微信验证成功");
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
wx.checkJsApi({
jsApiList: [
'checkJsApi',
'onMenuShareTimeline',
'onMenuShareAppMessage',
'onMenuShareQQ',
'onMenuShareWeibo',
'onMenuShareQZone'
], // 需要检测的JS接口列表,所有JS接口列表见附录2,
success: function (res) {
// 以键值对的形式返回,可用的api值true,不可用为false
// 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
}
});
wx.onMenuShareWeibo({
title: '满艺网分享测试', // 分享标题
desc: '满艺网分享描述测试', // 分享描述
link: 'http://www.manyiaby.com', // 分享链接
imgUrl: 'http://www.manyiaby.com/img/logo_2.jpg', // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
alert("分享成功");
},
cancel: function () {
// 用户取消分享后执行的回调函数
alert("分享取消");
}
});
});
wx.error(function (res) {
//alert("微信验证失败 res:"+res);
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});
requestStatus = 2;//请求完成
}
},
complete: function () {
window.setTimeout(function () {
requestStatus = 2;//请求完成
}, 300);
}
});
}

到这里关于微信分享JS SDK的使用就为大家介绍完毕,大家可以结合自己的需求进行参考。一开始已经为大家介绍了,微信提供的分享JS SDK仅仅只是一个对于微信内部浏览器的缓存处理,真正的分享还是需要我们点击右上角的分享按钮。 

 上面这些都不是太完美的手机web分享解决方法,最后给大家介绍一些Sosh社会化分享组件,当我看到这个组件时,我就知道这是我需要的,简洁的界面,整好可以让我们的网站看起来典雅舒服。好了,废话不多说,进入主题:

手机Web APP如何实现分享多平台功能

以上所述是小编给大家介绍的手机Web APP如何实现分享多平台功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
javascript获取当前ip的代码
May 10 Javascript
js二级地域选择的实现方法
Jun 17 Javascript
javascript判断css3动画结束 css3动画结束的回调函数
Mar 10 Javascript
JavaScript使用pop方法移除数组最后一个元素用法实例
Apr 06 Javascript
基于JavaScript实现表单密码的隐藏和显示出来
Mar 02 Javascript
全面了解构造函数继承关键apply call
Jul 26 Javascript
Ionic项目中Native Camera的使用方法
Jun 07 Javascript
微信小程序实现聊天对话(文本、图片)功能
Jul 06 Javascript
详解vue引入子组件方法
Feb 12 Javascript
VUE 项目在IE11白屏报错 SCRIPT1002: 语法错误的解决
Sep 27 Javascript
为什么JavaScript中0.1 + 0.2 != 0.3
Dec 03 Javascript
如何在JavaScript中使用localStorage详情
Feb 04 Javascript
浅谈Javascript中的12种DOM节点类型
Aug 19 #Javascript
js实现select选择框效果及美化
Aug 19 #Javascript
JavaScript面向对象编写购物车功能
Aug 19 #Javascript
javascript设计模式之module(模块)模式
Aug 19 #Javascript
JS实现六位字符密码输入器功能
Aug 19 #Javascript
javascript简单实现跟随滚动条漂浮的返回顶部按钮效果
Aug 19 #Javascript
巧用jQuery选择器提高写表单效率的方法
Aug 19 #Javascript
You might like
人大复印资料处理程序_补充篇
2006/10/09 PHP
echo(),print(),print_r()之间的区别?
2006/11/19 PHP
实现php加速的eAccelerator dll支持文件打包下载
2007/09/30 PHP
discuz7 phpMysql操作类
2009/06/21 PHP
Mac系统下使用brew搭建PHP(LNMP/LAMP)开发环境
2015/03/03 PHP
PHP使用array_fill定义多维数组的方法
2015/03/18 PHP
如何离线执行php任务
2017/02/21 PHP
html超链接打开窗口大小的方法
2013/03/05 Javascript
公共js在页面底部加载的注意事项介绍
2013/07/18 Javascript
get(0).tagName获得作用标签示例代码
2014/10/08 Javascript
Canvas 制作动态进度加载水球详解及实例代码
2016/12/09 Javascript
js继承实现方法详解
2016/12/16 Javascript
JS实现浏览器打印、打印预览示例
2017/02/28 Javascript
Angular 2父子组件之间共享服务通信的实现
2017/07/04 Javascript
浅析Visual Studio Code断点调试Vue
2018/02/27 Javascript
react中fetch之cors跨域请求的实现方法
2018/03/14 Javascript
Angular 利用路由跳转到指定页面的指定位置方法
2018/08/31 Javascript
node实现mock-plugin中间件的方法
2019/12/25 Javascript
[33:17]OG vs VGJ.T 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
Python 使用SMTP发送邮件的代码小结
2016/09/21 Python
在Django中URL正则表达式匹配的方法
2018/12/20 Python
Python3标准库之functools管理函数的工具详解
2020/02/27 Python
如何基于python3和Vue实现AES数据加密
2020/03/27 Python
keras中的backend.clip用法
2020/05/22 Python
使用tensorflow实现VGG网络,训练mnist数据集方式
2020/05/26 Python
pandas 数据类型转换的实现
2020/12/29 Python
ebookers英国:隶属全球最大的在线旅游公司Expedia
2017/12/28 全球购物
家庭睡衣和家庭用品:Little Blue House
2018/03/18 全球购物
生产内勤岗位职责
2013/12/07 职场文书
酒店管理专业毕业生求职自荐信
2014/04/28 职场文书
入职担保书怎么写
2014/05/12 职场文书
安全例会汇报材料
2014/08/23 职场文书
2014年行政助理工作总结
2014/11/19 职场文书
撤诉书怎么写
2015/05/19 职场文书
舞出我人生观后感
2015/06/16 职场文书
详解Nginx启动失败的几种错误处理
2021/04/01 Servers