- 有这样一个需求,一键发圈
- 将页面的图片视频下载保存到相册
- 将页面的文字复制到粘贴板
我们的项目是小程序嵌套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,// 必填,签名,见附录1jsApiList: ['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,调用下载图片的方法```javascriptwx.downloadImage({serverId: res.media_id, // 需要下载的图片的服务器端ID,由uploadImage接口获得isShowProgressTips: 1, // 默认为1,显示进度提示success: function (result) {var localId = result.localId; // 返回图片下载后的本地IDif (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 = "";// 获取 TOKENif(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.typewx.showLoading({title: '下载中',mask: true})let srcData = that.data.srcDatalet srcDataLen = srcData.lengthlet successNum = 0for (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})}})}
- 功能完成,可以正常使用,并且可以下载视频
