• uniapp 在线升级(热更新)及java后台


            如果你们也是厌倦了每次升级都要重新下载一整个包,重新安装。那么可以试试这个热更新方案,其实热更新这个技术在移动端并不少见,好几年前做原生APP开发的应该都接触过这个技术,这次我也是用到了uniapp的热更新,所以记录一下,方便后期直接使用。

            技术不难,请往下看 ~ 

            首先我是创建了一个uniapp项目,啥代码都没有写。咱们就把这个当做是实际项目中已经开发好的项目,毕竟只是演示嘛。所以这个版本就当做是1.0.0版本吧

            

             好,那么接下来,我们就在这个1.0.0版本中加入热更新的代码吧。

    一、编写热更新代码到旧版本

            首先打开项目里的App.vue代码,在onLaunch中编写,因为我们希望App一启动的时候就会去检测是否有新版本需要去更新。具体代码如下:

    1. <script>
    2. export default {
    3. onLaunch: function() {
    4. console.log('App Launch');
    5. // #ifdef APP-PLUS
    6. plus.runtime.getProperty(plus.runtime.appid,(widgetInfo)=>{
    7. console.log(widgetInfo);
    8. uni.request({
    9. url:'http://192.168.3.20:8080/UpdateProject/update/check',
    10. data:{
    11. versionCode:widgetInfo.versionCode
    12. },
    13. success:function(res){
    14. console.log(res);
    15. if(res.data.code==0){
    16. if(res.data.data.down){
    17. //下载地址根据实际来修改,我这个是拼接前缀的下载地址
    18. let downUrl="http://192.168.3.20:8080"+res.data.data.down;
    19. console.log("url:"+downUrl);
    20. uni.downloadFile({
    21. url:downUrl,
    22. success:function(downloadResult){
    23. if(downloadResult.statusCode==200){
    24. plus.runtime.install(downloadResult.tempFilePath,{
    25. force:false
    26. },function(){
    27. console.log("安装成功");
    28. plus.runtime.restart();
    29. },function(e){
    30. console.log(e);
    31. console.log("安装失败...")
    32. });
    33. }
    34. }
    35. })
    36. }
    37. }else{
    38. console.log("已经是最新版本,无需更新")
    39. }
    40. }
    41. })
    42. })
    43. // #endif
    44. },
    45. onShow: function() {
    46. console.log('App Show')
    47. },
    48. onHide: function() {
    49. console.log('App Hide')
    50. }
    51. }
    52. </script>
    53. <style>
    54. /*每个页面公共css */
    55. </style>

    代码已经给你了,但是听我解说一下哈, 首先,// #ifdef APP-PLUS 这个玩意不是个注释,这叫条件编译

    条件编译(在组件,css,js , .json配置中都可以使用):

    在某种条件下才会编译执行或者不执行的代码块

    语法: // #条件  平台

       条件:

               ifdef :  if  defined 正向条件,意思就是在xxx平台下才会编译生效

               ifndef : if not defined 反向条件,意思就是在xxx平台下不会生效,其他平台都生效

               endif : 结束标记,意味着条件结束

       平台:

               APP-PLUS        只会在app端环境下生效

               APP-PLUS-NVUE        只会在app nvue环境下生效

               H5        只会在H5环境下生效

               MP        微信小程序/支付宝小程序/百度小程序/头条小程序/QQ小程序

               MP-WEIXIN        只会在微信小程序环境下生效

               MP-ALIPAY        只会在支付宝小程序环境下生效

               MP-BAIDU         只会在百度小程序环境下生效

               MP-TOUTIAO        只会在字节跳动小程序环境下生效

               MP-360        只会在360小程序环境下生效

               MP-QQ          只会在QQ小程序环境下生效

    plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) 就是获取程序自身配置,通过自身的appid获取程序包信息

    widgetInfo 里面就包含了各种包信息,其中就有版本号,版本名称

    就是这个配置,比如我们是1.0.0版本,版本号就是100,等我们修改了bug或者新增了功能,版本我们就可以改成1.0.1,版本号就改成101。这样实际运营时,我们就可以知道目前安装的版本是多少,以及进行版本比较了

     再往下uni.request就是个正常的请求,把自己当前的版本号,记得是数字的那个,不是那个带点的。发给后台,后台去查询最新的版本的版本号进行比较,如果发送的版本小于后台查询的版本,那么说明你需要更新版本了,会返回下载地址等,如果发送的版本不小于后台查询的版本,那么就无需返回下载地址,我是这样写的逻辑。

    所以我判断返回code是否是0,0的话,代表需要更新,然后当下载地址不为空时就去下载了。下载成功后,就使用plus.runtime.install去安装即可

    二、编写新版本

            接下来我们先编写一点代码,也就是实际项目中,我们修复了bug或者新增了功能之后,变成了新的版本。我这里就是简单加行代码表示新增了功能

            

             然后要去manifest.json中修改版本信息

            

    三、生成wgt包

            我们基于新版本生成wgt包,也就是升级包。点击发行选择 原生App-制作应用wgt包

             

     

     加不加混淆看你自己,加了更安全,一定程度上防止反编译

    我们可以看到wgt包已经生成了。

     四、java后台编写(只做参考,实际项目自己修改)

     我的后台是个springboot+layui+mybatis

    而且我只做了查询列表,上传wgt包,跟检查是否需要更新功能

    表结构:

     

    Controller

    1. @RestController
    2. @RequestMapping("/update")
    3. public class UpdateController {
    4. //tomcat虚拟路径,上传的wgt存放在这里,实际项目中存放在ftp服务器,或者oss上
    5. @Value("${upload.filePath}")
    6. private String filePath;
    7. @Autowired
    8. private UpdateService updateService;
    9. /**
    10. * 分页查询App版本列表
    11. * @param page 页码
    12. * @param limit 每页大小
    13. * @return 分页后的版本列表数据
    14. */
    15. @RequestMapping("/list")
    16. public ResultTableBean getListByPage(int page,int limit){
    17. ResultTableBean rtb=new ResultTableBean();
    18. List<UpdateBean> list = updateService.findUpdateBeanList(page, limit);
    19. int updateCount = updateService.getUpdateCount();
    20. rtb.setCode(0);
    21. rtb.setData(list);
    22. rtb.setCount(updateCount);
    23. return rtb;
    24. }
    25. /**
    26. * 检查是否需要更新
    27. * @param versionCode 版本号
    28. * @return 结果
    29. */
    30. @RequestMapping("/check")
    31. public ResultBean checkAppNeedUpdate(int versionCode){
    32. ResultBean rb=new ResultBean();
    33. UpdateBean updateBean = updateService.checkUpdate(versionCode);
    34. if (updateBean!=null){
    35. rb.setCode(0);
    36. rb.setData(updateBean);
    37. }else {
    38. rb.setCode(1);
    39. }
    40. return rb;
    41. }
    42. @RequestMapping("/add")
    43. public ResultBean uploadAppVersion(@RequestParam("app") MultipartFile file, UpdateBean bean){
    44. ResultBean rb=new ResultBean();
    45. //获取文件名
    46. String originalFilename = file.getOriginalFilename();
    47. //获取文件的后缀名
    48. String suffixName = originalFilename.substring(originalFilename.lastIndexOf("."));
    49. //为了避免同一个文件夹下文件名重复问题,所以随机生成uuid作为文件名
    50. String fileName= UUID.randomUUID()+suffixName;
    51. File file1=new File(filePath+fileName);
    52. try {
    53. //文件存放到虚拟路径下
    54. file.transferTo(file1);
    55. //保存虚拟路径到数据库
    56. bean.setDown("/appVersion/"+fileName);
    57. boolean result = updateService.addUpdateBean(bean);
    58. if (result) {
    59. rb.setCode(0);
    60. }else {
    61. rb.setCode(1);
    62. }
    63. } catch (IOException e) {
    64. e.printStackTrace();
    65. rb.setCode(2);
    66. }
    67. return rb;
    68. }
    69. }

    Service

    1. @Service
    2. public class UpdateServiceImpl implements UpdateService {
    3. @Autowired
    4. private UpdateMapper updateMapper;
    5. @Override
    6. public List<UpdateBean> findUpdateBeanList(int page, int limit) {
    7. return updateMapper.findUpdateBeanList((page-1)*limit,limit);
    8. }
    9. @Override
    10. public int getUpdateCount() {
    11. return updateMapper.getUpdateCount();
    12. }
    13. @Override
    14. public boolean addUpdateBean(UpdateBean bean) {
    15. int row = updateMapper.addUpdateBean(bean);
    16. if(row>0){
    17. return true;
    18. }
    19. return false;
    20. }
    21. @Override
    22. public UpdateBean checkUpdate(int versionCode) {
    23. UpdateBean updateBeanLast = updateMapper.findUpdateBeanLast();
    24. if (updateBeanLast!=null){
    25. if (updateBeanLast.getCode()>versionCode){
    26. return updateBeanLast;
    27. }
    28. }
    29. return null;
    30. }
    31. }

     Mapper

    1. @Repository
    2. @Mapper
    3. public interface UpdateMapper {
    4. /**
    5. * 分页查询版本列表
    6. * @param start 起始位置
    7. * @param end 结束位置
    8. * @return 版本列表
    9. */
    10. public List<UpdateBean> findUpdateBeanList(int start,int end);
    11. /**
    12. * 获取版本列表总个数
    13. * @return 总个数
    14. */
    15. public int getUpdateCount();
    16. /**
    17. * 查询最新的版本
    18. * @return 最新的版本
    19. */
    20. public UpdateBean findUpdateBeanLast();
    21. /**
    22. * 新增APP版本
    23. * @param bean 版本信息
    24. * @return 受影响的行数
    25. */
    26. public int addUpdateBean(UpdateBean bean);
    27. }

    Mapper.xml

    1. <select id="findUpdateBeanList" resultType="com.xxx.update.bean.UpdateBean">
    2. select *from tb_update order by upload_time desc limit #{param1},#{param2}
    3. </select>
    4. <select id="getUpdateCount" resultType="int">
    5. select count(*) from tb_update
    6. </select>
    7. <select id="findUpdateBeanLast" resultType="com.xxx.update.bean.UpdateBean">
    8. select *from tb_update order by upload_time desc limit 1
    9. </select>
    10. <insert id="addUpdateBean" parameterType="com.xxx.update.bean.UpdateBean">
    11. insert into tb_update values(null,#{name},#{code},#{desc},#{down},now())
    12. </insert>

     前端页面代码就不放了,意义不大

    前端效果图如下:

     这样就OK了,上传了这个新版本包

    升级后效果:

     好了,到此就告一段落吧!

    本人个人原创,如有雷同,纯属巧合,或者与本人联系,做改动。请转载或者CV组合标明出处,谢谢!(如有疑问或错误欢迎指出,本人QQ:752231513)

  • 相关阅读:
    小匠物联获评2023年度浙江省省工业设计企业
    数学建模之时间序列分析模型
    大模型在百度智能问答、搜索中的应用
    从零开始手写mmo游戏从框架到爆炸(二十四)— 装备系统二
    基础数学知识
    面向对象-05-06-构造方法,标准的 javabean 类
    含电热联合系统的微电网运行优化(Matlab代码实现)
    Node详解
    echart宽度100px原因(解决el-tabs里的echarts图表宽度不自适应,只有100px问题)
    SpringMVC面试中常问到的23道题以及答案
  • 原文地址:https://blog.csdn.net/qq_30548105/article/details/125551858