原生支持 window.open / window.close 系统 js 函数。
App 默认会在新窗口中打开链接,并拥有原生的页面切换动画效果。
对于部分深度应用 ajax 加载的网站,App 可能无法准确截获用户操作的 URL 链接,也就无法在新窗口打开页面,此时推荐使用 open js方法。
点原生标题栏上的“后退/返回”按钮即可回到上一个页面,如未启用或隐藏了原生标题栏,执行 close js函数即可返回。
请下载 最新版 js SDK 解压并引入 jsbridge-mini.js 到您的网页。全部 js 接口请参考 DEMO 演示页
<script src="jsbridge-mini.js"></script>一般情况下,App 会自动初始化 jsBridge 接口,在引用 jsbridge-mini.js 之后可以直接使用 jsBridge 下的方法。
但为保险起见,我们推荐你在 jsBridge.ready 之后调用接口方法,形如:
<script src="jsbridge-mini.js"></script> <script> jsBridge.ready(function () { //jsBridge.share(); //分享 //jsBridge.wxPay(); //微信APP支付 //jsBridge.aliPay(); //支付宝APP支付 //... }); </script>
目前支持分享到 微信朋友圈、微信好友、QQ好友和QQ空间。
App 默认会在 “App 配置” - “原生标题栏” 显示分享按钮,一般无需在网站集成此 js 接口。
jsBridge.share({ //分享到,0 微信朋友圈,1 微信好友,2 QQ好友,3 QQ空间;未指定则弹出分享菜单 to : 0, //标题,未指定则为当前页面 title 标题 title : "可以指定标题", //链接,未指定则为当前页面链接 link : "http://m.baidu.com", //图标,未指定则为 App 图标 imgUrl: "https://m.baidu.com/static/search/baiduapp_icon.png", //描述,如未指定,App 会尝试抓取页面 meta description content,<meta name="description" content="页面描述..." /> //均无描述内容则显示链接 desc: "摘要:内事问百度,外事找谷歌,你懂的。" }, function(succ) { alert(succ ? "分享成功" : "分享失败或取消了分享"); });
//弹出分享菜单,并处理分享结果 jsBridge.share(null, function(succ) { //do something... });
//弹出分享菜单,并指定分享标题 jsBridge.share({ title: "指定分享出去的标题" });
一键分享多图到微信朋友圈、QQ空间(iOS)等,即大家常说的朋友圈九宫格多图,最多支持9张一键分享。
jsBridge.shareImages({ text : "这是一小段说明文本", images: ["imageUrl1", "imageUrl2"] //以 http 打头的图片链接数组,最多9张 }, function(succ) { //仅苹果版支持回调分享结果 if (succ) { alert("发送成功"); } else { alert("失败或取消了"); } });
一键分享多图到微信朋友圈、QQ空间(iOS)等,即大家常说的朋友圈九宫格多图,最多支持9张一键分享。
jsBridge.showImages({ //屏幕方向 0自适应,1横屏,2竖屏,不提供则用APP设置值 screenOrientation: 0, //显示保存到相册按钮,不提供则用APP设置值 save: true, //显示一键分享多图按钮,不提供则用APP设置值 share: true, //多图分享摘要文字,不提供则为网页标题+链接 share_text: "WebApp快捷打包 多图分享摘要", //图片组, text 是文字说明 items:[ { url :"http://i.cdn.yimenapp.com/sys/1.jpg", text:"美丽的大自然 01" }, { url :"http://i.cdn.yimenapp.com/sys/2.jpg", text:"美丽的大自然 02" }, { url :"http://i.cdn.yimenapp.com/sys/3.jpg" }, { url :"http://i.cdn.yimenapp.com/sys/4.jpg" }, { url :"http://i.cdn.yimenapp.com/sys/5.jpg" }, { url :"http://i.cdn.yimenapp.com/sys/6.jpg", text:"美丽的湖泊" }, { url :"http://i.cdn.yimenapp.com/sys/7.jpg" } ] });
//如果启用双击屏幕自动触发多图浏览,APP会用如下函数获取图片数据,请注意 HTML 页面结构; //minWidth、minHeight参数分别为你设置的图片最小高、宽 (px像素),注意是图显示高宽,不是图片实际尺寸; (function (w, h) { var r = { share_text: document.title + ' ' + location.href, items: [] }; var imgs = document.getElementsByTagName('img'); for (var i = 0; i < imgs.length; i++) { var img = imgs[i]; if ((img.width >= w) && (img.height >= h)) { r.items.push({ url: img.src }); } } return r; })(minWidth, minHeight);
使用相机扫码,兼容二维码与条码。
可以在 “App 配置” - “原生标题栏” - “首页标题栏显示 扫一扫 按钮”,无需在网站集成此 js 接口。
jsBridge.scan({ needResult: true, //默认为false,扫描结果由App处理;true则直接返回扫描结果 }, function(code) { if (code) { alert(code); } else { alert("扫码失败或取消了扫码"); } });
//直接启动扫码,扫码结果由 App 处理(如果是链接则打开链接,否则显示扫码内容) jsBridge.scan();
cacheSize 获取 App 本地缓存大小,clearCache 清除缓存。
可以在 “App 配置” - “缓存管理” - “打开首页前先自动清除缓存”,无需在网站集成此 js 接口。
jsBridge.cacheSize(function(size) { alert(size + "字节"); });
jsBridge.clearCache(function() { alert("本地缓存已清除"); });
判断用户设备是否安装了微信APP
为遵守苹果APP上架审核政策,请最好调用此函数判断设备是否已安装了微信客户端,如果没安装微信,就不要呈现微信登录等功能,以免因此被拒。
jsBridge.wxAppInstalled(function(installed) { alert(installed ? "安装了微信客户端" : "没有安装"); });
呼出微信APP,授权同步登录。参考官方文档
jsBridge.wxLogin(callback); callback 参数可以是一个 url 字符串或者是 function 回调函数。
♦ callback 是个 url 字符串: 登录授权成功后App会将用于换取access_token的code附加到url并跳转到这个地址;
♦ callback 是个 function 函数: function(success, object){} , success - 是否成功授权登录,object - 错误信息或授权登录数据;
如果你在“APP 配置” - “微信分享”表单填写了有效的“AppSecret”,APP会自动帮你用授权code及AppSecret获取access_token和userinfo用户信息返回给你,免去重写代码的麻烦; 如果觉得这种方式不够安全,你可以把 AppSecret 留空,拿到 code 过后自己在服务器上去调用微信接口获取 access_token
注意:要在 微信开放平台 一年交300元钱通过认证之后,你的移动应用才能获得微信的登录接口。
//通过 url 跳转回调 //必有参数 code (用于换取 access_token) //如果配置了有效的 AppSecret ,还会返回 openid, access_token, userinfo(json字符串 JSON.stringify(userinfo)) jsBridge.wxLogin("/doc/u.cshtml");
//通过 function 回调 jsBridge.wxLogin(function(succ, obj) { if (succ) { //obj 是个 json 对象,如 // { // code: "qqqqqqqqqqqqqqq", // openid: "wwwwwwwwwwwwwww", // access_token: "aaaaaaaaaaaaaaa", // userinfo: { // nickname: "sssssss" // //... // } // } // alert(JSON.stringify(obj)); } });
呼出手机QQ,授权同步登录。参考官方文档
jsBridge.qqLogin(callback); callback 与微信登录雷同,可以是个 url 字符串或者 function 函数
注意:QQ登录需要在 http://open.qq.com/ 提交移动应用上架审核通过后才能被普通用户使用, 测试期间要在腾讯开放平台点进你的移动应用 - “基础服务” - “QQ登录” - “应用调试者”填写测试用的QQ号。
//通过 url 跳转回调 //返回的参数有 openid, access_token, userinfo(json字符串 JSON.stringify(userinfo)) jsBridge.qqLogin("/doc/u.cshtml");
//通过 function 回调 jsBridge.qqLogin(function(succ, obj) { if (succ) { //obj 是个 json 对象,如 // { // openid: "wwwwwwwwwwwwwww", // access_token: "aaaaaaaaaaaaaaa", // userinfo: { // nickname: "sssssss" // //... // } // } // alert(JSON.stringify(obj)); } });
微信 App 支付的相关说明 请参考腾讯官方
URL 支付,将支付信息提交到本平台地址 https://g.yimenyun.net/pay/ , POST/GET 方式均可。
参数说明:
channel: 支付渠道, 0 微信, 1 支付宝
orderid: 订单号
title: 订单名称
amount: 支付金额(元)
url_succ: 支付成功后跳转的链接
url_fail: 支付失败跳转的链接
注意,要对各参数进行 UrlEncode UTF-8 编码收到支付通知一定要比对支付金额与订单应付金额是否相符,切记。
//示例:调用微信App完成名称为 购买VIP会员 的订单 201701010001 0.01元支付;
支付成功跳转到https://m.baidu.com/,失败跳转到 https://xw.qq.com/
https://g.yimenyun.net/pay/?channel=0&orderid=201701010001&title=%e8%b4%ad%e4%b9%b0VIP%e4%bc%9a%e5%91%98&amount=0.01&url_succ=https%3A%2F%2Fm.baidu.com%2F&url_fail=https%3A%2F%2Fxw.qq.com%2F
js 便捷支付收到支付通知一定要比对支付金额与订单应付金额是否相符,切记。
jsBridge.pay({ channel: 0, //integer, 支付渠道, 0微信,1支付宝 orderid: "201601010001", //string(64), 订单号 title : "购买VIP会员", //string(128), 订单名称 amount : 12.3 //decimal,支付金额(元) }, function(succ) { if (succ) { alert("支付成功"); } else { alert("支付失败或取消了支付"); } });
在你服务器上请求 微信统一支付接口, 拿到预支付 prepayid 后按官方说明 构造支付参数, 将支付参数传给本接口函数。
//注意:支付参数名称(全部小写)和类型应与官方说明完全相同 jsBridge.wxPay({ appid : "应用ID", partnerid: "商户号", prepayid : "预支付交易会话ID", package : "扩展字段", noncestr : "随机字符串", timestamp: "时间戳(单位是秒,不是毫秒,切记)", sign: "签名" }, function (succ, text) { if (succ) { alert("支付成功"); } else { alert("支付失败或取消了支付"); } });
支付宝 App 支付的相关说明 请参考官网
请参考 微信接入方式一 只需将 channel 参数值改为 1 即可。
请参考 微信接入方式二 只需将 channel 参数值改为 1 即可。
请参考 官方手册 构造订单字符串,作为参数传递给本接口。
jsBridge.aliPay({ orderString: "按照官方手册构造的订单字符串" }, function (succ, text) { if (succ) { alert("支付成功"); } else { alert("支付失败或取消了支付"); } });
银联 App 支付的相关说明 请参考官网
请参考 微信接入方式一 只需将 channel 参数值改为 2 即可。
请参考 微信接入方式二 只需将 channel 参数值改为 2 即可。
请参考 官方手册 获取银联受理订单号 tn,作为参数传递给本接口。
jsBridge.unionPay({ tn: "替换成你的银联受理订单号" //当前手机厂商 pay 类型,可选,仅支持安卓 //用 jsBridge.unionSeInfo 函数获取 //, seType : "" }, function (succ, text) { if (succ) { alert("支付成功"); } else { alert("支付失败或取消了支付"); } });
如果你采用 “方式一” 或 “方式二” 接入支付,本平台会将来自微信/支付宝/银联官方的支付结果确认信息以 POST 方式转发到你在 “App 设置” 里填写的 “支付通知地址”。 请以此通知为准来判定用户是否真实完成了支付,切记。
通知参数说明:
channel: 支付渠道, 0 微信, 1 支付宝, 2 银联云闪付, 3 银联全民付
tradeid: 微信/支付宝平台返回的交易号
orderid: 订单号
amount: 支付金额(元)
attach: 原样返回发起支付时的附加字段(使用V2版通知时)
timestamp: 发送通知时的 Unix 时间戳,可用于处理通知过期策略
nonce: 随机串
sign: MD5签名串,参数名=参数值 按参数名升序排列用 & 符号连接,最后加上 App 设置 处的 AppSecret,计算 md5 值
@using System.Linq; @using System.Text; @using System.Collections.Generic; @using System.Security.Cryptography; @{ //这是签名验证串,请在本平台 App设置 查看或重置 const string APP_SECRET = "sdfsadsfasdfwefafsdv03849034urfwi"; const int CH_WeiXin = 0; //支付渠道:微信 const int CH_Alipay = 1; //支付渠道:支付宝 const int CH_UnionPay = 2; //支付渠道:银联云闪付 const int CH_UnionPay = 3; //支付渠道:银联全民付 Response.Clear(); if (!"POST".Equals(Request.HttpMethod, StringComparison.OrdinalIgnoreCase)) { //不是 POST 方法 return; } //发送通知时的 Unix 时间戳,可用于处理通知过期策略 long timestamp; if (!long.TryParse(Request.Form["timestamp"], out timestamp)) { timestamp = 0; } //假定15分钟内有效 if ((timestamp + 15 * 60) < (DateTime.Now.ToUniversalTime() - DateTime.Parse("1970-01-01")).TotalSeconds) { //通知已过期 return; } string sign = ""; var dict = new SortedDictionary<string, string>(); //遍历 form 表单 foreach (var k in Request.Form.AllKeys) { if (k == "sign") { sign = Request.Form[k]; continue; } dict.Add(k, Request.Form[k]); } if (string.IsNullOrEmpty(sign) || (dict.Count == 0)) { //没有签名信息 return; } //验证签名 var s = string.Join("&", dict.Select(x => x.Key + "=" + x.Value)) + APP_SECRET; var md5 = MD5.Create(); var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(s)); var sn = BitConverter.ToString(bs, 0).Replace("-", ""); if (!sign.Equals(sn, StringComparison.OrdinalIgnoreCase)) { //签名错误 return; } //获取有效的参数值 var tradeid = dict["tradeid"]; //支付平台上的交易号 var orderid = dict["orderid"]; //订单号 var amount = Convert.ToDecimal(dict["amount"]); //支付金额 var channel = Convert.ToInt32(dict["channel"]); //支付渠道 var attach = dict["attach"]; //原样返回发起支付时的附加字段(使用V2版通知时) //切记,一定要比对金额: //比对实付金额与订单应付金额是否相符,不相等直接退出 if (amount != [订单应付金额]) return;
//用上面的参数处理支付成功的后续业务 //请在这里自由发挥,尽量不要修改其他地方 //do something... //处理成功后,http 要返回 OK 字符,否则你的服务器可能会多次收到确认通知 Response.Write("OK"); Response.End(); }
<?php //这是签名验证串,在 App配置 查询或重置 $secretKey = "CDg3yXFcVFDHBjdFu12lVAb3qinHYb1Ib"; //发送通知时的 Unix 时间戳,可用于处理通知过期策略 $timestamp = intval($_POST["timestamp"]); //假定15分钟内有效 if (($timestamp + 15 * 60) < date_timestamp_get(date_create())) { //通知已过期 return; } $kv = array(); //遍历 form 表单 foreach ($_POST as $key => $val) { $kv[$key] = $val; } ksort($kv); reset($kv); $param = ''; foreach ($kv AS $key => $val) { if ($key != 'sign') { $param .= "$key=$val&"; } } $param = substr($param, 0, -1).$secretKey; $verify_result = (md5($param) == strtolower($kv["sign"])); if ($verify_result) { //获取有效的参数值 $tradeid = $kv["tradeid"]; //支付平台上的交易号 $orderid = $kv["orderid"]; //订单号 $amount = $kv["amount"] ; //支付金额 $channel = $kv["channel"]; //支付渠道, 0 微信,1 支付宝, 2 银联云闪付, 3 银联全民付 $attach = $kv["attach"]; //原样返回发起支付时的附加字段(使用V2版通知时) //切记,一定要比对金额: //实付金额与订单应付金额是否相符,不相等直接退出 if ($amount != [订单应付金额]) exit();
//用上面的参数处理支付成功的后续业务 //请在这里自由发挥,尽量不要修改其他地方 //do something... //处理成功后,http 要返回 OK 字符,否则你的服务器可能会多次收到确认通知 exit("OK"); } else { //签名验证失败 } ?>
即将到来...
// 引入md5加密库 const md5 = require('md5') //这是签名验证串,在 App配置 查询或重置 const secretKey = 'xxxx' // 假如 你的 nodejs 后端是通过request.post获取post参数 response.end 是输出 const timestamp = parseInt(request.post.timestamp) // 获取当前时间戳 const nowTimestamp = parseInt(new Date().getTime() / 1000) if (timestamp + 15 * 60 < nowTimestamp) { //通知已过期 response.end('timestamp error') return } // 对象排序 const sort = Object.keys(request.post).sort() // //遍历 post 进行参数拼接 let params = '' sort.forEach((key) => { params += `${key}=${request.post[key]}&` }) params = params.substring(0, params.length - 1) + secretKey const verify_result = md5(param) == request.post.sign if (verify_result) { //获取有效的参数值 const tradeid = request.post.tradeid //支付平台上的交易号 const orderid = request.post.orderid //订单号 const amount = request.post.amount //支付金额 const channel = request.post.channel //支付渠道, 0 微信,1 支付宝, 2 银联云闪付, 3 银联全民付 const attach = request.post.attach //原样返回发起支付时的附加字段(使用V2版通知时) //切记,一定要比对金额: //实付金额与订单应付金额是否相符,不相等直接退出 if (amount != '实际的金额') { // 错误返回 } // 处理成功后,http 要返回 OK 字符,否则你的服务器可能会多次收到确认通知 response.end('OK') return } response.end('error')
发起网络访问,这个函数能有效的解决 ajax 跨域限制问题(jsonp 也总有些限制),原生网络请求,性能也会比较好。
jsBridge.net({ //必须 (string, 网络请求地址) url: "http://.....", //可选 (string, HTTP Request Method,GET/POST/PUT/DELETE 之一,默认 GET) method: "POST", //可选 (json object,请求参数) params: { //... }, //可选 (json object, HTTP Request Header,自定义HTTP请求头) headers: { //... }, //可选 (boolean, 是否需要显示 Loading 指示器,默认 true) indicator: true }, function (succ, text) { if (succ) { console.log("服务器返回的字符串:" + text); } else { var err = JSON.parse(text); alert(err.errorCode + ":" + err.errorMessage); } });
剪贴板操作,setClipboardText 复制文本到剪贴板,getClipboardText 获取剪贴板文本。
集成本js函数就不必让用户操作 长按-选中-复制 了,典型应用是在页面上放置一个按钮,点击按钮调用 setClipboardText 函数,你可以设置任何文本内容到剪贴板,用户可以在任何地方粘贴文本。
//复制文本到剪贴板 jsBridge.setClipboardText("Hello 世界!");
//获取剪贴板文本 jsBridge.getClipboardText(function(text) { alert(text); });
contactOne 弹出系统通讯录列表,供用户选择一个联系人;
contactAll 获取通讯录里所有联系人信息;
//选择一个联系人 //回调参数为 person 对象,没选择或没权限则返回 null jsBridge.contactOne(function(person) { if (person) { alert(JSON.stringify(person)); } else { alert("取消了选择或没有使用通讯录的权限"); } });
//获取通讯录里所有联系人信息 //回调参数为 person 数组,没权限则返回 null jsBridge.contactAll(function(persons) { if (persons) { alert("获取到" + persons.length + "个联系人信息\n第一个是\n" + JSON.stringify(persons[0])); } else { alert("没有使用通讯录的权限"); } });
//person 对象字段说明 { id : "联系人编号", //字符串 name : "姓名", //字符串 familyName: "姓", //字符串 givenName : "名", //字符串 phones : [ "电话号码1", "电话号码2", ...], //字符串数组 emails : [ "电子邮箱1", "电子邮箱2", ...] //字符串数组 }
浏览器端 jsBridge.inApp 属性返回页面是否在 App 中打开。
if (jsBridge.inApp) { alert("在App中"); } else { alert("不在App中"); }
服务器端可以通过检查 Request Header 的 UserAgent 是否包含 LT-APP 字符来判定页面是否在 App 中打开的。
浏览器端 jsBridge.version 属性返回 App 内核版本号,如不在 App 内则返回 0
alert("App内核版本 " + jsBridge.version);
服务器端可以用 LT-APP/(\d+) 正则匹配 Request Header 的 UserAgent 取得 App 内核版本号。
浏览器端 jsBridge.appVersion 属性返回 App 打包版本号,如 102 表示 1.0.2
alert("App打包版本 " + jsBridge.appVersion);