解决三件事。
这个很简单。
,保存编译运行即可。在微信调试工具里打开app.js,可以看到有个方法叫wx.login,已经有写好的基本逻辑。用户信息可以console.log查看一下res这个变量。
wx.login({
success: res => {
if (res.code) {
console.log(res)
}// 发送 res.code 到后台换取 openId, sessionKey, unionId
}
})
可以看到,res里包含的只是一些基本用户信息,并不包含一个唯一的ID让我们确定这个用户。所以需要利用获取openid的机制,利用ajax与自建服务器交互。其逻辑图在小程序开发文档–登录机制里写的很清楚。
在这里我直接贴出来我的代码(C#,ashx一般处理程序),里面包含了服务器端获取openid的方式(将信息传到后台的时候,我用的是明文,实际上为了安全,可以自己加密一下再传到后台。)
小程序端:
wx.login({
success: res => {
if (res.code) {
//console.log(res)
//发起网络请求
wx.request({
url: 'https://我的URL路径/处理文件.ashx',
header: {
"Content-Type": "applciation/json"
},
method: 'POST',
data: {
code: res.code
},
success: function (res) {
wx.setStorageSync('openid', res.data);
// console.log(res.data)这里是成功后回调函数,已经拿到了服务器端获取到的openid
//利用小程序的缓存能力,将获取到的openid存进缓存里,在小程序的生命周期里,都可以随意全局调用。
}
})
}// 发送 res.code 到后台换取 openId, sessionKey, unionId
}
})
服务器端:
<%@ WebHandler Language="C#" Class="wx" %>
using System.Web;
using System.Net;
using System.Text;
using System.IO;
using System.Collections.Generic;
public class wx : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "text/plain";
HttpRequest request = context.Request;
Stream stream = request.InputStream;
string json = string.Empty;
string responseJson = string.Empty;
if (stream.Length != 0)
{
StreamReader streamReader = new StreamReader(stream);
json = streamReader.ReadToEnd();
}
Dictionary<string, object> ob =JSONSerializer.Deserialize<Dictionary<string, object>>(json);
string js_code=ob["code"].ToString();
//这里就是与微信服务器交互,获取openid
string data = HttpGet("https://api.weixin.qq.com/sns/jscode2session?appid=你的appid&secret=你的secret&js_code="+js_code+"&grant_type=authorization_code");
Dictionary<string, object> suggestions =JSONSerializer.Deserialize<Dictionary<string, object>>(data);
string openid = suggestions["openid"].ToString();
//将openid返回
context.Response.Write(openid);
}
public static string HttpGet(string Url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
request.Method = "GET";
request.ContentType = "text/html;charset=UTF-8";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream myResponseStream = response.GetResponseStream();
StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
string retString = myStreamReader.ReadToEnd();
myStreamReader.Close();
myResponseStream.Close();
return retString;
}
public bool IsReusable {
get {
return false;
}
}
}
到此为止,就获取到了有效用户信息。
首先我们发现,小程序里不可以像html那样随意append组件,web-view目前也仅有一个src可以和小程序环境有交互,所以,就想到可以用get方式传值,比如url配置url?openid=1234
就可以把信息传进入。
以免出现没有用户信息的情况,我没有在index页面直接写web-view,我用它当前置页面,页面加载时,会判定有没有用户信息,如果有的话,会自动跳到web页面,web页面就是我方web-view的地方。如果没有用户信息的话,会强制获取用户信息,然后再跳转,其代码大概是这样的:
onLoad: function () {
if (app.globalData.userInfo) {
this.setData({
userInfo: app.globalData.userInfo,
hasUserInfo: true
})
wx.setStorageSync('url', encodeURI("你的url?nickname=" + app.globalData.userInfo.nickName + "&city=" + app.globalData.userInfo.city + "&country=" + app.globalData.userInfo.country + "&gender=" + app.globalData.userInfo.gender + "&province=" + app.globalData.userInfo.province + "&avatarUrl=" + app.globalData.userInfo.avatarUrl + "&openid=" + wx.getStorageSync('openid')))
//这里的globalData变量是存的用户基本信息,我为了方便把它们都传进去了,其实就传一个openid就够了
wx.navigateTo({
url: '../web/web'
})
} else if (this.data.canIUse){
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
app.userInfoReadyCallback = res => {
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
wx.setStorageSync('url', encodeURI("你的URL?nickname=" + app.globalData.userInfo.nickName + "&city=" + app.globalData.userInfo.city + "&country=" + app.globalData.userInfo.country + "&gender=" + app.globalData.userInfo.gender + "&province=" + app.globalData.userInfo.province + "&avatarUrl=" + app.globalData.userInfo.avatarUrl + "&openid=" + wx.getStorageSync('openid')))
wx.navigateTo({
url: '../web/web'
})
}
} else {
// 在没有 open-type=getUserInfo 版本的兼容处理
wx.getUserInfo({
success: res => {
//console.log(res)
app.globalData.userInfo = res.userInfo
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
wx.setStorageSync('url', encodeURI("你的URL?nickname=" + app.globalData.userInfo.nickName + "&city=" + app.globalData.userInfo.city + "&country=" + app.globalData.userInfo.country + "&gender=" + app.globalData.userInfo.gender + "&province=" + app.globalData.userInfo.province + "&avatarUrl=" + app.globalData.userInfo.avatarUrl + "&openid=" + wx.getStorageSync('openid')))
wx.navigateTo({
url: '../web/web'
})
}
})
}
},
然后是web页面。
web.wxml:
<web-view src="{{url}}">web-view>
web.js:
onLoad: function (options) {
var dataurl = wx.getStorageSync('url');//获取缓存里的url信息
console.log(dataurl.length)
this.setData({
url: dataurl
});
},
上面有个重要的坑需要特别说明一下,这种传值方式在微信调试工具和安卓手机上完全没问题,但是在IOS上,你会发现传值传不进去,其原因就是在ios下,web-view的src不能出现中文或者一些特殊字符,当用户名比较特殊时,就传不进去值,所以,我在index.js里写了urlencode。当然,在这里也可以把内容加密一下再传至后台。
比如最简单的无需秘钥的base64,我写一下用法:
onLoad: function (options) {
function base64_encode(str) { // 编码,配合encodeURIComponent使用
var c1, c2, c3;
var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var i = 0, len = str.length, strin = '';
while (i < len) {
c1 = str.charCodeAt(i++) & 0xff;
if (i == len) {
strin += base64EncodeChars.charAt(c1 >> 2);
strin += base64EncodeChars.charAt((c1 & 0x3) << 4);
strin += "==";
break;
}
c2 = str.charCodeAt(i++);
if (i == len) {
strin += base64EncodeChars.charAt(c1 >> 2);
strin += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
strin += base64EncodeChars.charAt((c2 & 0xF) << 2);
strin += "=";
break;
}
c3 = str.charCodeAt(i++);
strin += base64EncodeChars.charAt(c1 >> 2);
strin += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
strin += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
strin += base64EncodeChars.charAt(c3 & 0x3F)
}
return strin
}
var dataurl = wx.getStorageSync('测试base64');
var base64Url = base64_encode(dataurl)
},
到此为止,用户信息就传到后台了,那么后台就可以做用户对应了,然后将openid在页面的生命周期里保持,就可以记录用户行为了。
首先,我们要知道,所有的内容都是在web-view里的,所以当用户分享小程序时,无论用户正在看哪个页面,分享出去之后,其他用户打开,web-view都会重新加载,直接跳到主页,那么,用户分享页面的时候,怎么样才能让其他人打开的时候直接跳到分享者正在看的页面呢?
在这里我们注意到:
那么我们可以这样设计:
onShareAppMessage: function (options) {
function base64_encode(str) { // 编码,配合encodeURIComponent使用
var c1, c2, c3;
var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var i = 0, len = str.length, strin = '';
while (i < len) {
c1 = str.charCodeAt(i++) & 0xff;
if (i == len) {
strin += base64EncodeChars.charAt(c1 >> 2);
strin += base64EncodeChars.charAt((c1 & 0x3) << 4);
strin += "==";
break;
}
c2 = str.charCodeAt(i++);
if (i == len) {
strin += base64EncodeChars.charAt(c1 >> 2);
strin += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
strin += base64EncodeChars.charAt((c2 & 0xF) << 2);
strin += "=";
break;
}
c3 = str.charCodeAt(i++);
strin += base64EncodeChars.charAt(c1 >> 2);
strin += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
strin += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
strin += base64EncodeChars.charAt(c3 & 0x3F)
}
return strin
}
console.log(options.webViewUrl)
var webViewUrl = base64_encode(options.webViewUrl)
console.log(webViewUrl)
return {
path: 'pages/content/content?url=' + encodeURI(webViewUrl) // 路径,传递参数到指定页面。
}
}
当然,content里怎么写也显而易见了。
content.wxml:
<web-view src="{{url}}">web-view>
content.js
onLoad: function (options) {
var openid = wx.getStorageSync('openid');
if (openid.length<=10)
{
wx.navigateTo({
url: '../index/index'
})
}
function base64_decode(input) { // 解码,配合decodeURIComponent使用
var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = base64EncodeChars.indexOf(input.charAt(i++));
enc2 = base64EncodeChars.indexOf(input.charAt(i++));
enc3 = base64EncodeChars.indexOf(input.charAt(i++));
enc4 = base64EncodeChars.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
return utf8_decode(output);
}
function utf8_decode(utftext) { // utf-8解码
var string = '';
let i = 0;
let c = 0;
let c1 = 0;
let c2 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if ((c > 191) && (c < 224)) {
c1 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
i += 2;
} else {
c1 = utftext.charCodeAt(i + 1);
c2 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
i += 3;
}
}
return string;
}
var weburl = base64_decode(options.url)//这里就是将分享时的web-view的页面路径值还原出来
var data=""
if (weburl.indexOf("?")!=-1)
{
data ="&openid="+openid
}
else
{
data = "?openid=" + openid
}//这里是将openid加在每个页面上,可以用来开发记录用户行为的模块
this.setData({
url: weburl + data
})
},
如果小程序里的页面有其他链接的话,会提示“不支持打开非业务域名xxxxx,请重新配置”。因为web-view不是浏览器,不是所有的网址都可以跳的,只有你自己网址,在后台配置过业务域名的,才可以跳。所以,这里要自己在自己的网站里把跳转屏蔽一下,当用户点击一些非业务链接地址跳转的时候,弹出“此链接是外部链接,已复制到粘贴板”,然后用clipboardjs把链接内容复制到粘贴板即可,这样用户体验更好点。这里就不讲怎么用了,点击链接可以去它的GitHub主页看一下,有各种demo,很简单。