写点什么

CEF | CEF 浏览器客户端功能扩展:实现下载列表功能

作者:YOLO.
  • 2022-10-19
    河北
  • 本文字数:2977 字

    阅读完需:约 1 分钟

背景

之前的文章已经实现了浏览器的一些扩展功能,如网页的前进、后退、浏览器的刷新、通过组合快捷键调出控制台窗口、设置 cookie 等。


这里实现了拓展浏览器的下载功能,实现一个可视化的下载列表,可以控制下载、暂停、删除、打开文件位置、打开文件等功能。

效果图

功能

  1. 暂停下载: 点击暂停按钮,下载暂停。

  2. 继续下载: 点击继续按钮,下载继续。

  3. 删除下载: 点击删除按钮,删除下载的本地文件。

  4. 更新下载进度: 通过进图条展示下载进度。

  5. 打开文件: 打开下载的本地文件。

  6. 打开文件夹: 打开下载的本地文件所在的文件夹,并选中文件。

具体实现

首先要修改 SimpleHandler 类,让 SimpleHandler 继承 CefDownloadHandler 类,并重新实现 OnBeforeDownload 方法和 OnDownloadUpdated 方法。


//simple_handler.h class SimpleHandler : public QObject,                       public CefClient,                       public CefDisplayHandler,                       public CefLifeSpanHandler,                       public CefLoadHandler,                       public CefDownloadHandler //继承CefDownloadHandler类 {     ……    virtual CefRefPtr<CefDownloadHandler> GetDownloadHandler() OVERRIDE{return this;} //一定要有    ……     // CefDownloadHandler methods:     // 重载OnBeforeDownload和OnDownloadUpdated    virtual void OnBeforeDownload(CefRefPtr<CefBrowser> browser,                                  CefRefPtr<CefDownloadItem> download_item,                                  const CefString &suggested_name,                                  CefRefPtr<CefBeforeDownloadCallback> callback) override;                                      virtual void OnDownloadUpdated(CefRefPtr<CefBrowser> browser,                                   CefRefPtr<CefDownloadItem> download_item,                                   CefRefPtr<CefDownloadItemCallback> callback) override;    …… }
复制代码


实现 OnBeforeDownload 方法:


在正式开始下载前会执行 OnBeforeDownload 方法,在方法中调用 callback 的 Continue,才算执行了下载命令。参数一是下载时文件的建议名称,参数二是下载时是否弹出路径选择窗口,true 表示弹出,false 表示不弹出。


void ClientHandler::OnBeforeDownload(CefRefPtr<CefBrowser> browser,                                      CefRefPtr<CefDownloadItem> download_item,                                      const CefString &suggested_name,                                      CefRefPtr<CefBeforeDownloadCallback> callback){    callback->Continue(suggested_name, true);}
复制代码


实现 OnDownloadUpdated 方法:


OnDownloadUpdated 方法中,我们可以通过 download_item 参数获取是否完成、是否取消、当前速度、完成度百分比、总大小、已完成大小、开始时间、结束时间、路径、建议名称等信息。通过 callback 参数实现下载的暂停、取消和继续功能。


void ClientHandler::OnDownloadUpdated(CefRefPtr<CefBrowser> browser,                                       CefRefPtr<CefDownloadItem> download_item,                                       CefRefPtr<CefDownloadItemCallback> callback){    int64 bytes = download_item->GetCurrentSpeed(); // 下载速度    int64 totalBytes = download_item->GetTotalBytes();  // 总大小    int64 reciveBytes = download_item->GetReceivedBytes();  // 完成大小    int32 id = download_item->GetId();  // id    QString fileName = QString::fromStdWString(download_item->GetSuggestedFileName());//建议名称    QString url = QString::fromStdString(download_item->GetURL()); //url    QString fullPath = download_item->GetFullPath(); // 本地路径        // 插入一条下载        ...            // 更新下载进度        ...        // 判断是否下载完成        ...        // 取消一条下载        ...}
复制代码


踩过的坑:


  • 在正式开始下载前也会执行 OnDownloadUpdated 方法,甚至 OnDownloadUpdated 方法是在 OnBeforeDownload 方法之前执行的。在下载过程中会不断执行 OnDownloadUpdated 方法。

  • 其中有一个 IsInProgress()用来获取是否正在下载。但是我试过,弹出保存框还没有点击保存时,它就返回 true。所以不能用它判断是否正在下载过程中。

  • 通过 download_item 获取建议名称时,有些情况会返回空。


最有意思的是:


  • 当我们点击下载后,会先执行 OnDownloadUpdated,然后执行 OnBeforeDownload,此时会弹出弹窗 Save file。

  • 当我们不管是点击保存还是取消,都会执行若干次 OnDownloadUpdated 方法,并且每次都可以获取到下载速度、总大小和已完成大小,即使点击了取消,下载速度等值也是有数据的。

  • 在若干次 OnDownloadUpdated 执行完之后,如果我们之前点击的是取消,download_item->IsCanceled()会返回 true。如果我们之前点击的是保存,download_item->IsComplete()会返回 true。所以我们没有办法在开始下载前判断是否点击了取消按钮。


解决办法:


  • 当下载速度大于 0 时,认定它是一次下载,保存它的 id 和 callback。id 作为一条下载的唯一标识。(我当初想用 download_item 作为一条下载的唯一标识,发现同一条下载的 download_item 值是会变的。)

  • 获取建议名称为空时,通过 GetURL()方法获取它的 url 值,截取 url 的最后一个反斜杠‘/’后面的字符串作为文件名称。

  • 创建一条下载时:将它的 id、callback、文件名、总大小通过信号的方式发送给页面。

  • 更新下载进度时:通过 id 作为唯一标识,将下载的当前速度、已下载大小或者百分比通过信号的方式发送给页面。

  • 判断是否下载完成:下载完成后才会返回文件下载到本地的路径,通过 download_item->GetFullPath()获取。将文件的本地路径通过信号的方式发送给页面。

  • 判断是否取消下载:发送取消下载信号给页面。在页面中添加一个标志位,判断接收到的取消信号是我们点击保存框的取消按钮发送的,还是我们在下载过程中点击删除按钮发送的。如果是我们点击保存框的取消按钮时发送的,我们就要将创建的这条下载删除掉。如果是我们在下载过程中点击删除按钮时执行了 callback->Cancel()触发的,就不需要删除这一条下载(因为效果图上没有删除)。

  • 因为我们在创建一条下载时将 callback 传递给页面了,所以点击页面上的按钮时,直接调用对应的 callback 的方法就可以实现暂停、继续、取消了。

  • 删除下载就是手动调用 callback 的取消,如果是删除已经下载完成的,需要将文件从本地删除掉。


删除文件:


QFileInfo fileInfo(filePath);if(fileInfo.exists()){    QFile file(m_filePath);    file.remove();}
复制代码


打开文件:


QFileInfo fileInfo(filePath);if(fileInfo.exists()){    QUrl url = QUrl::fromLocalFile("file:///" + filePath);    QDesktopServices::openUrl(url);}
复制代码


打开文件夹并选中文件:


QProcess *m_processFolder;                  // 打开文件夹进程m_processFolder = new QProcess(this);
filePath.replace("/", "\"); // 只能识别 "\"QString cmd = QString("explorer.exe /select,%1").arg(filePath);m_processFolder->start(cmd);
复制代码


发布于: 刚刚阅读数: 3
用户头像

YOLO.

关注

还未添加个人签名 2022-05-06 加入

还未添加个人简介

评论

发布
暂无评论
CEF | CEF浏览器客户端功能扩展:实现下载列表功能_qt_YOLO._InfoQ写作社区