WebEngine ウィジェット権限ブラウザの例

Webサイトのパーミッション要求を処理し、既存のパーミッションを管理する方法を示します。

Permission Browser は、QWebEnginePermission クラスを使用して Web サイトのパーミッションを管理する方法を示します。この例には、入ってくるパーミッションのリクエストを処理するコードと、すでに存在するパーミッションを修正するコードが含まれています。また、QWebEngineProfile クラスの中で定義された異なるパーミッションの永続化ポリシーの効果も示します。

例の実行

Qt Creator からサンプルを実行するには、Welcome モードを開き、Examples からサンプルを選択します。詳細については、Building and Running an Example を参照してください。

クラスの定義

メインウィンドウ

MainWindow クラスはQMainWindow を継承している。内部では、個々のパーミッションを操作するために使用されるウィジェットをレイアウトするQVBoxLayout への便利なポインタと、現在保留中のパーミッション要求を表示するウィジェットへの別の便利なポインタを宣言します。また、実際のウェブページ・コンテンツを表示するために使用されるQWebEngineView も宣言します。

class MainWindow : public QMainWindow, public Ui_MainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(const QUrl &url);
    ~MainWindow();

private slots:
    void handlePermissionRequested(QWebEnginePermission permission);
    void handleUrlChanged(const QUrl &url);

    void handlePermissionModified(PermissionWidget *widget);
    void handleDeleteAllClicked();
    void handleNewClicked();
    void handleRefreshClicked();
    void handleBackClicked();
    void handleForwardClicked();
    void handlePolicyComboBoxIndexChanged(int index);

private:
    bool containsPermission(const QWebEnginePermission &permission);
    PermissionWidget *createPermissionWidget(const QWebEnginePermission &permission);
    void loadStoredPermissions();

    QVBoxLayout *m_layout;
    QWebEngineProfile *m_profile;
    QWebEngineView *m_webview;
    PermissionWidget *m_pendingWidget;
};

アプリケーションの残りのレイアウトはmainwindow.uiの中で定義され、Qt Creatorのデザインモードを使って作成されています。MainWindow はUi_MainWindowの子クラスで、mainwindow.uiの中の定義からコンパイル時に生成されるC++クラスです。

PermissionWidgetとPermissionDialog

PermissionWidget クラスは一つのQWebEnginePermission インスタンスに対応するウィジェットを定義します。便宜上、QWebEnginePermission オブジェクトが格納されています。ウィジェット自身はパーミッションを許可、拒否、削除するためのコントロールを持っています; このすべてはPermissionWidget.ui の中で定義されます。

class PermissionWidget : public QWidget, public Ui_PermissionWidget
{
    Q_OBJECT
public:
    PermissionWidget(const QWebEnginePermission &permission, QWidget *parent = nullptr);

    QWebEnginePermission m_permission;

signals:
    void permissionModified(PermissionWidget *widget);

private:
    void updateState();
};

メインウィンドウのUIで "New "ボタンをクリックすると、ポップアップウィンドウが表示され、ユーザーは既知のオリジンに対して事前にパーミッションを付与することができる。このポップアップはPermissionDialog クラスで定義されています:

class PermissionDialog : public QDialog, public Ui_PermissionDialog
{
    Q_OBJECT
public:
    PermissionDialog(const QWebEngineProfile *profile, QWidget *parent = nullptr);
    ~PermissionDialog();
    QWebEnginePermission permission();

private:
    const QWebEngineProfile *m_profile;
    QWebEnginePermission *m_permission;
};

パーミッション要求の処理

ウェブサイトがユーザーのプライバシーを侵害する可能性のあるAPIを使用するときはいつでも、ブラウザは許可を与えるか拒否するかを尋ねるプロンプトを表示することが期待されています。PermissionBrowserの例では、右下に専用のセクションがあり、そのようなことが起こるたびにPermissionWidget

PermissionWidget は、パーミッションのオリジン、リクエストされたQWebEnginePermission::PermissionType 、パーミッションの現在のステータスを表示します。また、パーミッションの許可と拒否のボタンもあります。パーミッションのステータスは(デフォルトで)記憶されるので、削除ボタンは、ユーザーが基礎となるストレージからパーミッションを削除することを可能にする。

これらすべてを実現するために、まずQWebEnginePagepermissionRequested シグナルをMainWindowhandlePermissionRequested スロットに接続する:

    connect(m_webview->page(), &QWebEnginePage::permissionRequested, this, &MainWindow::handlePermissionRequested);

このシグナル・ハンドラは比較的単純である。提供されたQWebEnginePermission オブジェクトに対してPermissionWidget インスタンスの作成を試み、成功すれば、保留中のパーミッション用に指定されたQFrame にそのウィジェットをプラグインする。また、PermissionWidget'のpermissionModified シグナルもサブスクライブして、PermissionWidget を右下から上の既存ウィジェットのリストに移動できるようにしています。

void MainWindow::handlePermissionRequested(QWebEnginePermission permission)
{
    PermissionWidget *widget = createPermissionWidget(permission);
    if (widget) {
        m_pendingFrame->layout()->addWidget(widget);
        connect(widget, &PermissionWidget::permissionModified, this, &MainWindow::handlePermissionModified);

        if (m_pendingWidget)
            m_pendingWidget->deleteLater();

        m_pendingWidget = widget;
    }
}

新しいPermissionWidget を作成するのは、まだ既存のものがない場合だけです:

PermissionWidget *MainWindow::createPermissionWidget(const QWebEnginePermission &permission)
{
    if (containsPermission(permission))
        return nullptr;

    return new PermissionWidget(permission, this);
}

パーミッションの変更とユーザーへの表示

QWebEnginePermission インターフェースはgrant() と {QWebEnginePermission::deny}{deny}() 関数を提供します。これらはパーミッションのステータスを変更するために必要なものです。アプリケーションがパーミッションについて忘れる必要がある場合、{QWebEnginePermission::reset}{reset}()関数を使います。

PermissionWidget コンストラクタの内部で、これらの関数をボタンのclicked シグナルにフックし、QWebEnginePermission オブジェクト上で関連する機能を実行できるようにします。

ボタンが押されるたびに、permissionModified シグナルを発信します。MainWindow は、ウィジェットを右下から既存のパーミッションのリストに移動する必要があるときに、このシグナルを使います。また、ウィジェットの視覚的な更新を処理するupdateState() も必ず呼び出します。削除ボタンが押されたとき、ウィジェットを削除するようにマークすることも確認します。

PermissionWidget::PermissionWidget(const QWebEnginePermission &permission, QWidget *parent)
    : QWidget(parent)
    , m_permission(permission)
{
    setupUi(this);
    connect(m_deleteButton, &QPushButton::clicked, [this]() {
        m_permission.reset();
        emit permissionModified(this);
        deleteLater();
    });

    connect(m_grantButton, &QPushButton::clicked, [this]() {
        m_permission.grant();
        updateState();
        emit permissionModified(this);
    });

    connect(m_denyButton, &QPushButton::clicked, [this]() {
        m_permission.deny();
        updateState();
        emit permissionModified(this);
    });

    updateState();
}

updateState() 関数は、QWebEnginePermission によって提供されたデータをユーザーに表示します。また、パーミッションがQWebEnginePermission::Invalid の状態にあるとき、許可または拒否のボタンが無効になるようにします。

void PermissionWidget::updateState()
{
    switch (m_permission.state()) {
    case QWebEnginePermission::State::Invalid:
        m_stateLabel->setText("<font color='gray'>Invalid</font>");
        m_grantButton->setEnabled(false);
        m_denyButton->setEnabled(false);
        break;
    case QWebEnginePermission::State::Ask:
        m_stateLabel->setText("<font color='yellow'>Waiting for response</font>");
        break;
    case QWebEnginePermission::State::Granted:
        m_stateLabel->setText("<font color='green'>Granted</font>");
        break;
    case QWebEnginePermission::State::Denied:
        m_stateLabel->setText("<font color='red'>Denied</font>");
        break;
    }

    m_typeLabel->setText(QMetaEnum::fromType<QWebEnginePermission::PermissionType>().valueToKey((quint8)m_permission.permissionType()));
    m_originLabel->setText(m_permission.origin().toDisplayString());
}

保留中のパーミッションが許可または拒否されたとき、関連するウィジェットを、現在存在するすべてのパーミッションを含む上のリストに移動したい。これをMainWindow::handlePermissionModifiedスロットで行います。

void MainWindow::handlePermissionModified(PermissionWidget *widget)
{
    if (!m_pendingWidget || m_pendingWidget != widget)
        return;

    m_pendingFrame->layout()->removeWidget(widget);
    m_pendingWidget = nullptr;

    if (!QWebEnginePermission::isPersistent(widget->m_permission.permissionType())
        || widget->m_permission.state() == QWebEnginePermission::State::Ask
        || m_profile->persistentPermissionsPolicy() == QWebEngineProfile::PersistentPermissionsPolicy::AskEveryTime) {

        widget->deleteLater();
        return;
    }

    m_layout->insertWidget(0, widget);
}

PermissionTypes の中には永続的でないものがあります。つまり、使用するたびにユーザーにパーミッションのプロンプトを表示する必要があります。また、QWebEnginePermission::Ask 状態のパーミッションは除外します。これは、パーミッションがreset() であったことを示すものです。QWebEngineProfile::persistentPermissionsPolicyAskEveryTime に設定されている場合、既存のパーミッションのリストに何も追加しません。

注: どのPermissionTypes が永続的であるかはQWebEnginePermission::PermissionType のドキュメントを確認してください。

既存のパーミッションの表示と変更

デフォルトでは、パーミッションはディスクに保存され、アプリケーションの起動時に再度取得されます。既存のすべてのパーミッションのリストを取得するには、QWebEngineProfile::listAllPermissions()を呼び出します:

void MainWindow::loadStoredPermissions()
{
    QList<QWebEnginePermission> permissionsList = m_profile->listAllPermissions();
    for (QWebEnginePermission &permission : permissionsList) {
        PermissionWidget *widget = createPermissionWidget(permission);
        if (widget)
            m_layout->insertWidget(0, widget);
    }
}

リスト内のすべてのパーミッションについて、単純に新しいPermissionWidget を作成し、画面右側のリストに追加します。既存のパーミッションは、保留中のものとまったく同じAPIを使用して変更される。

パーミッションの事前付与

特定のパーミッションは、オリジンとパーミッションのタイプがわかっていれば、事前に付与することができる。右上の "New "ボタンをクリックすると、そのためのダイアログがポップアップ表示されます。このダイアログはPermissionDialog クラスによって実装されています:

PermissionDialog::PermissionDialog(const QWebEngineProfile *profile, QWidget *parent)
    : QDialog(parent)
    , m_profile(profile)
    , m_permission(nullptr)
{
    setupUi(this);

    auto metaEnum = QMetaEnum::fromType<QWebEnginePermission::PermissionType>();
    Q_ASSERT(metaEnum.value((quint8)QWebEnginePermission::PermissionType::Unsupported) == 0);
    for (int i = 1; i < metaEnum.keyCount(); ++i) {
        QWebEnginePermission::PermissionType permissionType = QWebEnginePermission::PermissionType(metaEnum.value(i));
        if (QWebEnginePermission::isPersistent(permissionType))
            m_permissionTypeComboBox->addItem(metaEnum.valueToKey((quint8)permissionType), QVariant::fromValue(permissionType));
    }
}

QWebEnginePermission::PermissionType に関連づけられたQMetaEnum タイプを使用して、QComboBox に入力します。永続的でないパーミッション・タイプは事前に付与することがサポートされていないため、必ずフィルタリングしてください。

ダイアログを表示し、結果のPermissionWidget をUIのMainWindow::handleNewClicked スロットに追加します。新しいパーミッションは、ウェブサイトから要求された場合と同じように扱われます:handlePermissionRequested() を呼び出すことによって。

void MainWindow::handleNewClicked()
{
    PermissionDialog dialog(m_profile);
    if (dialog.exec() == QDialog::Accepted) {
        handlePermissionRequested(dialog.permission());
    }
}

パーミッションの永続化ポリシーの変更

デフォルトでは、パーミッションはすべての名前付きQWebEngineProfile に対してディスクに保存され、すべての名前なし/記録外のものに対してはメモリに保存される。通常、この設定を実行時に変更することはないが、この例では各オプションの効果を調べる。

  • QWebEngineProfile::StoreOnDisk はデフォルトであり、現在のアプリケー ション実行時に付与されたパーミッションが、次回起動時に確実にロードさ れるようにする。パーミッションは一度だけ付与されればよく、アプリケーションが ()を呼び出すまで、リクエストのトリガーとなったAPIのその後の使用は、自動的に付与されます。 li パーミッションはアプリケーションの終了時に破棄され、ディスクにコミットされないことを除けば、上記と同じ動作です。したがって、Web APIがパーミッションを必要とするたびに、新しいプロンプトがユーザーに表示されます。このオプションは後方互換性と、独自のパーミッション保存を実装するアプリケーションを意図しています。QWebEngineProfile::AskEveryTime QWebEnginePermission::reset QWebEngineProfile::StoreInMemory

ユーザーに以前に存在したパーミッションが表示されるようにするには、QWebEngineProfile::listAllPermissions()を呼び出す必要がある:

void MainWindow::loadStoredPermissions()
{
    QList<QWebEnginePermission> permissionsList = m_profile->listAllPermissions();
    for (QWebEnginePermission &permission : permissionsList) {
        PermissionWidget *widget = createPermissionWidget(permission);
        if (widget)
            m_layout->insertWidget(0, widget);
    }
}

これは起動時に1回だけ行われ、ユーザーが右上のQComboBox からポリシーを変更するたびに行われます。

void MainWindow::handlePolicyComboBoxIndexChanged(int index)
{
    QWebEngineProfile::PersistentPermissionsPolicy policy;
    switch (index) {
    case 0:
        policy = QWebEngineProfile::PersistentPermissionsPolicy::AskEveryTime;
        break;
    case 1:
        policy = QWebEngineProfile::PersistentPermissionsPolicy::StoreInMemory;
        break;
    case 2:
        policy = QWebEngineProfile::PersistentPermissionsPolicy::StoreOnDisk;
        break;
    }

    if (policy == m_profile->persistentPermissionsPolicy())
        return;

    for (int i = m_layout->count() - 1; i >= 0; i--) {
        PermissionWidget *widget = qobject_cast<PermissionWidget *>(m_layout->itemAt(i)->widget());
        if (!widget)
            continue;

        widget->deleteLater();
    }

    m_profile->setPersistentPermissionsPolicy(policy);
    loadStoredPermissions();
}

サンプルプロジェクト @ code.qt.io

©2024 The Qt Company Ltd. 本書に含まれる文書の著作権は、それぞれの所有者に帰属します。 ここで提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。