- 有这样一个需求,一键发圈
- 将页面的图片视频下载保存到相册
- 将页面的文字复制到粘贴板
我们的项目是小程序嵌套H5的老项目(虽然有点恶心,但是还得做)
方法一:JS-SDK(不要用,不好用这个)
这是最开始的方式,h5调用微信api就是JSSDK了,里面有一个
wx.downloadImage
可以下载图片- 通过请求后台获注入JS-SDK配置信息
```javascript
var initWeixin = function(mpid){
var xtD = new Date();
var wxTtimestamp = xtD.getTime();
var wxNonceStr = “WXLMD”+wxTtimestamp;
var url = location.href.split(‘#’)[0];
var wxSignature = null;
$.ajax({
}); }method: "GET",
url: "/wx/jsign",
data: {"timestamp":wxTtimestamp,"noncestr":wxNonceStr,"url":url},
dataType:'json',
success:function(data){
if(data.code!=0){
layer.msg(data.message);
return;
}
wxSignature = data.data.sign;
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: data.data.app, // 必填,公众号的唯一标识
timestamp: wxTtimestamp, // 必填,生成签名的时间戳
nonceStr: wxNonceStr, // 必填,生成签名的随机串
signature: wxSignature,// 必填,签名,见附录1
jsApiList: ['downloadImage'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
},
error:function () {
layer.msg("网络繁忙");
}
wx.error(function(res){ // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。 console.log(res) });
initWeixin();
- 配置成功就可以使用JS-SDK的api,调用下载图片的方法
```javascript
wx.downloadImage({
serverId: res.media_id, // 需要下载的图片的服务器端ID,由uploadImage接口获得
isShowProgressTips: 1, // 默认为1,显示进度提示
success: function (result) {
var localId = result.localId; // 返回图片下载后的本地ID
if (isEnd) {
layer.msg('下载成功');
}
}
});
- media_id是通过发送图片的url请求后台,
- 后台使用
新增临时素材api
上传图片到微信服务器,获取临时素材media_id
@RequestMapping("/uploadImgToWx")
public HashMap uploadImgToWx(HttpServletRequest req, HttpServletResponse response, String url,String suffix) throws IOException, Exception {
// 验证是图片或视频
String type = "image";
if (suffix.equals("mp4")) {
type = "video";
}
ByteArrayOutputStream outStream =new ByteArrayOutputStream();
BufferedOutputStream stream =null;
InputStream inputStream =null;
File file =null;
try {
URL imageUrl =new URL(url);
HttpURLConnection conn =(HttpURLConnection)imageUrl.openConnection();
conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
inputStream = conn.getInputStream();
byte[] buffer =new byte[1024];
int len =0;
while( (len=inputStream.read(buffer)) != -1 ){
outStream.write(buffer, 0, len);
}
file = File.createTempFile("pattern", "." + suffix);
logger.info("临时文件创建成功={}", file.getCanonicalPath());
FileOutputStream fileOutputStream =new FileOutputStream(file);
stream =new BufferedOutputStream(fileOutputStream);
stream.write(outStream.toByteArray());
} catch (Exception e) {
logger.error("创建服务器图片异常", e);
} finally {
try {
if (inputStream !=null) inputStream.close();
if (stream !=null) stream.close();
outStream.close();
} catch (Exception e) {
logger.error("关闭流异常", e);
}
}
MkWxUser user = RequestUtils.GetLoginUser(req);
MkMpInfo info = mpInfoService.getMpInfo(user.getCeoId());
String accessToken = "";
// 获取 TOKEN
if(info.getAuthorizerToken()!=null&&!"".equals(info.getAuthorizerToken())){
accessToken = JedisUtil.get("authorToken_"+info.getUserId());
if(accessToken==null){
ApiAuthorizerTokenRet tokenRet = RefreshTockenUtil.refreshTocken(info.getAppid(),info.getRefreshToken(),info.getUserId());
accessToken = tokenRet.getAuthorizer_access_token();
info.setAuthorizerToken(tokenRet.getAuthorizer_access_token());
info.setRefreshToken(tokenRet.getAuthorizer_refresh_token());
mpInfoService.saveMpInfo(info,info.getUserId());
}
}else{
accessToken = WxUtils.getAccessToken(info.getAppid(), info.getAppsecret());
}
// 新增临时素材 addTemImgUrl("https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN")
String uploadUrl = WxApiConfig.addTemImgUrl.getValue().replace("ACCESS_TOKEN", accessToken);
String json = HttpTool.uploadMedia(uploadUrl + "&type="+type, file, BaseConfig.encoding, 5000, 3000);
ApiResult matterResult = new ApiResult(json);
HashMap map = new HashMap();
map.put("type", matterResult.getStr("type"));
map.put("media_id", matterResult.getStr("media_id"));
map.put("created_at", matterResult.get("created_at"));
return map;
}
// --------------上传素材文件至微信服务器--------------------
public static String uploadMedia( String url,File file,String charset,int connectTimeout,int responseTimeout ) throws Exception {
HttpsURLConnection conn = null;
InputStream in = null;
OutputStream out = null;
try{
conn = (HttpsURLConnection)new URL( url ).openConnection();
conn.setHostnameVerifier( hostnameVerifier );
conn.setSSLSocketFactory( sslContext.getSocketFactory() );
conn.setRequestMethod( METHOD_POST );
conn.setDoInput( true );
conn.setDoOutput( true );
conn.setConnectTimeout( connectTimeout );
conn.setReadTimeout( responseTimeout );
// 定义数据分隔线
String BOUNDARY = "----WebKitFormBoundaryiDGnV9zdZA1eM1yL";
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
out = conn.getOutputStream();
StringBuilder mediaData = new StringBuilder();
mediaData.append("--").append(BOUNDARY).append("\r\n");
mediaData.append("Content-Disposition: form-data;name=\"media\";filename=\""+ file.getName() + "\"\r\n");
mediaData.append("Content-Type:application/octet-stream\r\n\r\n");
byte[] mediaDatas = mediaData.toString().getBytes();
out.write(mediaDatas);
out.flush();
DataInputStream fs = new DataInputStream(new FileInputStream(file));
int bytes = 0;
byte[] bufferOut = new byte[1024];
while ((bytes = fs.read(bufferOut)) != -1) {
out.write(bufferOut, 0, bytes);
}
fs.close();
out.write("\r\n".getBytes());
byte[] end_data = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
out.write(end_data);
out.flush();
out.close();
// 定义BufferedReader输入流来读取URL的响应
InputStream ins = conn.getInputStream();
BufferedReader read = new BufferedReader(new InputStreamReader(ins, "UTF-8"));
String valueString = null;
StringBuffer bufferRes = null;
bufferRes = new StringBuffer();
while ((valueString = read.readLine()) != null){
bufferRes.append(valueString);
}
ins.close();
return bufferRes.toString();
}finally{
if( conn!=null ){
conn.disconnect();
}
if( out!=null ){
try{
out.close();
}catch( IOException e ){
log.error( e );
}
}
if( in!=null ){
try{
in.close();
}catch( IOException e ){
log.error( e );
}
}
}
}
- 将media_id返回给前台拿到的
出现的问题
这个问题我在小程序社区也有问,但是没有答案,链接地址
-
1. 使用手机测试,下载图片成功,但是在手机相册找不到
找了下微信的目录路径,在
文件夹\Tencent\MicroMsg\WeiXin
里2. 图片是有的,但是是重复的两张图片(一张原图,一张压缩过的)
这是下载一张图片的情况,下载多张也是会重复
方法2:h5跳转小程序,使用小程序的原生下载文件api
- 上面的方法遇到的问题没有得到解决,后来又让我们公司的一位大佬看了下这个功能需求
- 将一键下载图片功能的页面写在小程序里
- 在H5跳转到到详情时,使用
wx.miniProgram.navigateTo
跳转回小程序页面,并指向详情页面
wx.miniProgram.navigateTo({
url: '/pages/user/sourceMaterial/details/index?id=' + id
});
- 传递的id值是详情页面获取详情数据需要的接口
- 调用获取详情接口,渲染详情页面
- 点击一键发圈,调用小程序下载文件api
wx.downloadFile
getDownloadFile: function (e) {
let type = e.currentTarget.dataset.type
wx.showLoading({
title: '下载中',
mask: true
})
let srcData = that.data.srcData
let srcDataLen = srcData.length
let successNum = 0
for (let i = 0; i < srcDataLen; i++) {
let imgUrl = srcData[i].replace('http://st', 'https://st')
wx.downloadFile({
url: imgUrl,
success: function (res) {
if (type == 1) {
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: function (data) {
successNum++
if (data.errMsg === 'saveImageToPhotosAlbum:ok') {
if (successNum == srcDataLen) {
that.clipboardData()
}
}
},
fail: function (err) {
console.log(err)
wx.hideLoading()
if (err.errMsg === 'saveImageToPhotosAlbum:fail auth deny') {
wx.showToast({
title: '未开启相册功能授权',
icon: 'none',
duration: 1500
})
wx.openSetting({
success(settingdata) {
if (settingdata.authSetting['scope.writePhotosAlbum']) {
that.getDownloadFile()
} else {
wx.showToast({
title: '授权失败',
icon: 'none',
duration: 1500,
})
}
}
})
}
if (err.errMsg === 'saveImageToPhotosAlbum:fail cancel') {
wx.showToast({
title: '已取消保存',
icon: 'none',
duration: 1500,
})
}
}
})
} else {
wx.saveVideoToPhotosAlbum({
filePath: res.tempFilePath,
success: function (data) {
successNum++
if (data.errMsg === 'saveVideoToPhotosAlbum:ok') {
if (successNum == srcDataLen) {
that.clipboardData()
}
}
},
fail: function (err) {
wx.hideLoading()
if (err.errMsg === 'saveVideoToPhotosAlbum:fail auth deny') {
wx.showToast({
title: '未开启相册功能授权',
icon: 'none',
duration: 1500
})
wx.openSetting({
success(settingdata) {
if (settingdata.authSetting['scope.writePhotosAlbum']) {
that.getDownloadFile()
} else {
wx.showToast({
title: '授权失败',
icon: 'none',
duration: 1500,
})
}
}
})
}
if (err.errMsg === 'saveVideoToPhotosAlbum:fail cancel') {
wx.showToast({
title: '已取消保存',
icon: 'none',
duration: 1500,
})
}
}
})
}
}
})
}
},
代码写的有点长,但是不影响功能
- 调用
wx.downloadFile
下载文件功能之后,要将图片保存到相册就需要先获取相册权限
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: function (data) {
successNum++
if (data.errMsg === 'saveImageToPhotosAlbum:ok') {
if (successNum == srcDataLen) {
that.clipboardData()
}
}
},
fail: function (err) {
console.log(err)
wx.hideLoading()
if (err.errMsg === 'saveImageToPhotosAlbum:fail auth deny') {
wx.showToast({
title: '未开启相册功能授权',
icon: 'none',
duration: 1500
})
wx.openSetting({
success(settingdata) {
if (settingdata.authSetting['scope.writePhotosAlbum']) {
that.getDownloadFile()
} else {
wx.showToast({
title: '授权失败',
icon: 'none',
duration: 1500,
})
}
}
})
}
- 授权成功,保存图片成功的同时将文本复制到粘贴板
clipboardData: function () {
wx.setClipboardData({
data: that.data.resData.title + '\n' + that.data.resData.body,
success(res) {
wx.hideLoading()
wx.showToast({
title: '已复制文案和保存素材,快去分享给朋友吧。',
icon: 'none',
duration: 2000,
mask: true
})
},
fail: function (err) {
wx.showToast({
title: '内容复制出错',
icon: 'none',
duration: 1500
})
}
})
}
- 功能完成,可以正常使用,并且可以下载视频