文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

安卓端微信H5下载文件处理:让微信自动弹起跳转外部浏览器窗口

2023-09-07 06:20

关注

配套视频:https://www.bilibili.com/video/BV1oA411B7gv/


背景

今天鼓捣了一下手机投屏到笔记本,就想录个视频展示一下学习成果,正好就想起了很早之前实现的这个功能。
H5文件下载是一个很简单的功能,但是把这个H5放在安卓版微信打开,功能就不能用了,因为安卓端的微信内置浏览器拦截了所有下载文件的请求。
即使微信的sdk也没有提供直接保存文件的接口,所以出路只有一条,就是跳到第三方应用进行下载,比如跳到手机浏览器、跳到微信小程序。如果是上架了应用宝的app,可以跳转应用宝下载。
之所以屏蔽,应该是H5无法监管的原因,但是不能理解的是,ios端的微信是可以下载的,难道苹果手机高人一等?

解决方案收集

最终选择的解决方案

java实现

import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import org.springframework.web.context.WebApplicationContext;import org.springframework.web.method.HandlerMethod;import org.springframework.web.servlet.mvc.method.RequestMappingInfo;import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.OutputStream;import java.net.URLEncoder;import java.text.MessageFormat;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;@RestControllerpublic class ApiController {    // 获取日志对象 Spring Boot 中内置了日志框架 Slf4j    private static Logger log = LoggerFactory.getLogger(ApiController.class);        @GetMapping("downloadFileWx")    public void downloadFileWx(@RequestParam String path, HttpServletRequest request, HttpServletResponse response) throws Exception {        responseOutputFileWx(path, null, request, response);    }        public void responseOutputFileWx(String path, String outputFileName,       HttpServletRequest request, HttpServletResponse response)            throws Exception {        File file = new File(path);        if (file == null || !file.exists() || !file.isFile()) {            log.error("文件不存在");            // 重定向到当前页面,相当于刷新页面            String contextPath = request.getContextPath();            response.sendRedirect(contextPath + "/downFile");            return;        }        if (outputFileName == null || outputFileName.trim().length() == 0) {            // 假如下载文件名参数为空,则设置为原始文件名            outputFileName = file.getName();        }        ServletContext context = request.getServletContext();        // 文件绝对路径        String absolutePath = file.getAbsolutePath();        // 获取文件的MIME type        String mimeType = context.getMimeType(absolutePath);        if (mimeType == null) {            // 没有发现则设为二进制流            mimeType = "application/octet-stream";        }        response.setContentType(mimeType);        // 设置文件下载响应头        String headerKey = "Content-Disposition";        String headerValue = null;        if (isWx(request)) {            // 微信浏览器,打开手机默认浏览器下载文件            // 注意排除企业微信            try {                if (isAndroidWx(request)) {                    // 安卓端,xlsx文件类型会触发微信弹出跳转外部浏览器窗口,欺骗一下                    response.setContentType("application/octet-stream");                    outputFileName = "123456.xlsx";                } else {                    // ios 微信对contentType要求比较严格                    // https://juejin.cn/post/6844904086463053837                    if (absolutePath.endsWith("xlsx")) {                        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");                    } else if (absolutePath.endsWith("xls")) {                        response.setContentType("application/vnd.ms-excel");                    } else if (absolutePath.endsWith("doc")) {                        response.setContentType("application/msword");                    } else if (absolutePath.endsWith("docx")) {                        response.setContentType("application/application/vnd.openxmlformats-officedocument.wordprocessingml.document");                    }                }                headerValue = String.format("attachment; filename=\"%s\"", URLEncoder.encode(outputFileName, "UTF-8"));            } catch (Exception e) {                headerValue = String.format("attachment; filename=\"%s\"", outputFileName);                log.error(e.getMessage(), e);            }        } else {            try {                // 解决Firefox浏览器中文件名中文乱码                // https://blog.csdn.net/Jon_Smoke/article/details/53699400                headerValue = String.format("attachment; filename* = UTF-8''%s",                        URLEncoder.encode(outputFileName, "UTF-8")                );            } catch (Exception e) {                headerValue = String.format("attachment; filename=\"%s\"", outputFileName);                log.error(e.getMessage(), e);            }        }        response.setHeader(headerKey, headerValue);        String fileName = file.getName();        try (OutputStream outputStream = response.getOutputStream()) {            response.setCharacterEncoding("utf-8");            // 将下面2行放开,可以测试微信最原始反应            // 设置返回类型            // response.setContentType("multipart/form-data");            // // 文件名转码一下,不然会出现中文乱码            // response.setHeader("Content-Disposition", "attachment;fileName=" + encodeStr(fileName));            byte[] bytes = readBytes(file);            if (bytes == null) {                log.error("文件不存在");            }            outputStream.write(bytes);            log.info("文件下载成功!" + fileName);        } catch (Exception e) {            e.printStackTrace();        }    }        private String encodeStr(String str) throws Exception {        return URLEncoder.encode(str, "UTF-8");    }        public byte[] readBytes(File file) throws Exception {        long len = file.length();        // 无论数组的类型如何,数组中的最大元素数为Integer.MAX_VALUE,大约20亿        if (len >= 2147483647L) {            return null;        } else {            byte[] bytes = new byte[(int) len];            try (FileInputStream in = new FileInputStream(file)) {                int readLength = in.read(bytes);                if ((long) readLength < len) {                    log.error("文件未读取完全");                    return null;                }            } catch (Exception var10) {                return null;            }            return bytes;        }    }        private static boolean isAndroidWx(HttpServletRequest request) {        String userAgent = request.getHeader("user-agent");        return userAgent != null && userAgent.toLowerCase().indexOf("micromessenger") > -1                && userAgent.toLowerCase().indexOf("wxwork") < 0                && userAgent.toLowerCase().indexOf("android") > -1;    }        private static boolean isWx(HttpServletRequest request) {        String userAgent = request.getHeader("user-agent");        return userAgent != null && userAgent.toLowerCase().indexOf("micromessenger") > -1                && userAgent.toLowerCase().indexOf("wxwork") < 0;    }}

题外话:手机如何投屏笔记本

方式1:win10自带投屏

方式2:幕享 软件

来源地址:https://blog.csdn.net/weixin_44174211/article/details/128985936

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯