企业微信如果想要使用企业微信的JS_SDK来实现拍照、定位等等功能,就需要预先在使用到的页面进行配置,当然你可以做全局配置。对于JS_SDK的配置设计前端和后端的统一配置。下面我来说明下具体的步骤。
特别说明:1、企业微信有的接口需要配置wx.config,有的接口需要配置wx.agentConfig,下面我将分别举例说明。
2、只要按照我的步骤进行配置,有一定代码基础的同学,就能完成。
一、wx.config配置
此配置配置完成后,一些基础功能就可以调用了,如:拍照、定位等等,还有其它的功能,需要参考企业微信开发文档。那么如何配置,直接通过代码来讲解:前端使用的时vue脚手架,后端使用的
.net web api。
首先在vue脚手架项目的index.html全局引用引入js文件:
js 代码:
//首先,在created中初始化配
created() {
this.initQyWxConfig();
}
methods: {
initQyWxConfig() {
let that = this;
var postData = {
url: window.location.href,
};
xapi.ajax({
url: "/api/***/****/AccessQyWxConfigBaseMessage",
type: "POST",
contentType: "application/json",
data: postData,
success: function (data, status, xhr) {
that.configQyWx(data.Data, function () {});
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(
"错误:" +
textStatus +
":" +
errorThrown +
":" +
XMLHttpRequest.status
);
},
complete: function (xhr, status) {
$.hideLoading();
},
});
},
configQyWx(data, callback) {
wx.config({
beta: false,
debug: false,
appId: data.appId, // 必填,企业微信的corpid,必须与当前登录的企业一致
timestamp: data.timestamp, // 必填,生成签名的时间戳
nonceStr: data.nonceStr, // 必填,生成签名的随机串
signature: data.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法
jsApiList: ["chooseImage", "uploadImage"], //必填,传入需要使用的接口名称
success: function (res) {
callback();
},
fail: function (res) {
if (res.errMsg.indexOf("function not exist") > -1) {
alert("版本过低请升级");
}
},
});
},
//上述配置调用成功后,就可以写一个点击事件uploadImage(),在其中就可以调用wx.chooseImage,"chooseImage"需要在上面的wx.config中进行配置。
uploadImage() {
var that = this;
wx.chooseImage({
count: 1, // 默认9
sizeType: ["original", "compressed"], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ["album"], // 可以指定来源是相册还是相机,默认二者都有
defaultCameraMode: "batch", //表示进入拍照界面的默认模式,目前有normal与batch两种选择,normal表示普通单拍模式,batch表示连拍模式,不传该参数则为normal模式。从3.0.26版本开始支持front和batch_front两种值,其中front表示默认为前置摄像头单拍模式,batch_front表示默认为前置摄像头连拍模式。(注:用户进入拍照界面仍然可自由切换两种模式)
isSaveToAlbum: 1, //整型值,0表示拍照时不保存到系统相册,1表示自动保存,默认值是1
success: function (res) {
var localIds = res.localIds; // 返回选定照片的本地ID列表,
console.log("localIds:" + localIds);
wx.uploadImage({
localId: localIds.toString(), // 需要上传的图片的本地ID,由chooseImage接口获得
isShowProgressTips: 1, // 默认为1,显示进度提示
success: function (res) {
var serverId = res.serverId; // 返回图片的服务器端ID
xapi.ajax({ //自己写个ajax方法,此处时框架封装的xapi方法。
url: "/api/***/Common/AccessMediaImage",
type: "POST",
contentType: "application/json",
data: { mediaId: serverId },
success: function (data, status, xhr) {
if (data.Result) {
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(
"错误:" +
textStatus +
":" +
errorThrown +
":" +
XMLHttpRequest.status
);
},
complete: function (xhr, status) {
$.hideLoading();
},
});
},
});
// }
},
});
},
}
c#后端代码:下面的代码有的不在同一个.cs文件中,大家有c#开发经验的应该能看懂怎么调用,自己封装到项目中就行。
[HttpPost]
public CommonResult AccessQyWxConfigBaseMessage([FromBody] dynamic req)
{
///此处的url可以从前台传过来,主要就是把当前的页面进行配置,然后前端对应的页面就可以使用jsSDK
var url = "https://www.xxx.com/TestApi/dist/index.html#/indexPage";// ((string)req.url).HasValue("页面url").Trim();
var data = bll.AccessQyWxConfigDto(QyMpId, url);
return new CommonResult
{
Result = true,
Data = data
};
}
/// 然后调用业务逻辑处理代码
public QywxConfigDto AccessQyWxConfigDto(string mpId, string url)
{
var targetIndex = url.IndexOf("#");
if (targetIndex != -1)
{
url = url.Split('#')[0];
}
string qyWxTicket = GetQyWxJsapi_Ticket(mpId);
string nonceStr = CreatenNonce_str();
long timestamp = CreatenTimestamp();
GetSignature(qyWxTicket, nonceStr, timestamp, url, out string signature);
QywxConfigDto anentConfigDto = new QywxConfigDto()
{
appId = "ww67c7*****806a", //企业微信的appID
timestamp = timestamp,
nonceStr = nonceStr,
signature = signature
};
return anentConfigDto;
}
///此处是获取token的,主要是调用次数受限,记得存缓存, MPTools.GetMPCachedAccessToken是个缓存类,可以自己写一个。
public static void GetQyWxToken(string corpid, string corpsecret, string mpId, out string token)
{
try
{
MPTools.GetMPCachedAccessToken(mpId, out token, out DateTime expTime);
if (string.IsNullOrEmpty(token))
{
lock (tokenLock)
{
string url = string.Format("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={0}&corpsecret={1}", corpid, corpsecret);
HttpHelper helper = new HttpHelper();
string back = helper.SendGetMessage(url, mpId);
var tokenDto = JsonConvert.DeserializeObject(back);
token = tokenDto.access_token;
GlobalTools.WriteLog("GetQyWxToken", 0, $"token:{token}");
MPTools.SaveMPCachedAccessToken(mpId, token, DateTime.Now, DateTime.Now.AddMinutes(90));
}
}
}
catch (Exception ex)
{
GlobalTools.WriteErrLog("GetQyWxToken", ex);
token = "";
}
}
///根据mpID和MP_APP_SECRET获得token,这边我把相关数据做成了配置,根据mpId来获取,大家可以直接写死,后面再改成配置。应该比较简单!
public string GetAccessToken(string mpId)
{
string contackMpId = mpId;
var mp = _mp.Get(p => p.MP_ID == contackMpId);
if (mp == null)
{
throw new ValidateException("未找到MpId信息");
}
CommonBll.GetQyWxToken(mp.MP_APP_ID, mp.MP_APP_SECRET, contackMpId, out string accessToken);
return accessToken;
}
public string GetQyWxJsapi_Ticket(string mpId)
{
string accessToken = GetAccessToken(mpId);
string reqUrl = string.Format("https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token={0}", accessToken);
CommonBll.GetQyJsApiTicket(mpId, accessToken, "qyTicket", reqUrl, out string ticketValue);
return ticketValue;
}
public static void GetQyJsApiTicket(string mpId, string accessToken, string key, string reqUrl, out string ticketValue)
{
try
{
MPTools.GetMPCachedAccessToken(key, out ticketValue, out DateTime expTime);
if (string.IsNullOrEmpty(ticketValue))
{
lock (ticketLock)
{
string ticketUrl = reqUrl;
HttpHelper helper = new HttpHelper();
string back = helper.SendGetMessage(ticketUrl, mpId);
GlobalTools.WriteLog("GetQyWxToken", 0, $"back:{back}");
TicketDto ticketDto = JsonConvert.DeserializeObject(back);
MPTools.SaveMPCachedAccessToken(key, ticketDto.ticket, DateTime.Now, DateTime.Now.AddMinutes(90));
}
}
}
catch (Exception ex)
{
ticketValue = "";
MPTools.RemoveMPCachedAccessToken(key);
}
}
public static string[] strs = new string[]
{
"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"
};
public string CreatenNonce_str()
{
Random r = new Random();
var sb = new StringBuilder();
var length = strs.Length;
for (int i = 0; i < 15; i++)
{
sb.Append(strs[r.Next(length - 1)]);
}
return sb.ToString();
}
private long CreatenTimestamp()
{
return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
}
public static string Sha1Encrypt(string source, Encoding encoding = null)
{
if (encoding == null) encoding = Encoding.UTF8;
// 第一种方式
byte[] byteArray = encoding.GetBytes(source);
using (HashAlgorithm hashAlgorithm = new SHA1CryptoServiceProvider())
{
byteArray = hashAlgorithm.ComputeHash(byteArray);
StringBuilder stringBuilder = new StringBuilder(256);
foreach (byte item in byteArray)
{
stringBuilder.AppendFormat("{0:x2}", item);
}
hashAlgorithm.Clear();
return stringBuilder.ToString();
}
}
public void GetSignature(string jsapi_ticket, string noncestr, long timestamp, string url, out string signature)
{
var string1Builder = new StringBuilder();
string1Builder.Append("jsapi_ticket=").Append(jsapi_ticket).Append("&")
.Append("noncestr=").Append(noncestr).Append("&")
.Append("timestamp=").Append(timestamp).Append("&")
.Append("url=").Append(url.IndexOf("#") >= 0 ? url.Substring(0, url.IndexOf("#")) : url);
string string1 = string1Builder.ToString();
signature = Sha1Encrypt(string1, Encoding.UTF8);
GlobalTools.WriteLog("GetSignature", 0, $"signature:{signature}");
}
现在,你的wx.config配置就完成了。
注意点:1、这些功能很多时候只能在手机真机中进行调试
2、需要耐心对着上述步骤配置,因为本身配置就比较复杂,源码写在了项目中,有时间给大家单独整理个demo。如果有不懂的地方,可以加我微信:1057359832。
写在最后,下一篇我将介绍下wx.agentConfig的配置,与wx.config类似,但是也有区别。