Skip to content

[webview_flutter_wkwebview] Extended Web View API on iOS to add flexibility when working with local HTML content #8787

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

agavrilko
Copy link

Overview

The readAccessURLProvider property has been added to the WebKitWebViewControllerCreationParams class. This function allows customization of the path to associated resources when loading a local HTML page using loadFile on iOS.

What Is the Issue

[#136479] readAccessUrl of the webview_flutter_wkwebview should be accessible for customization

The native WKWebView takes two arguments when loading local HTML pages:

  1. The file URL – The local HTML file to be loaded.
  2. The read access URL – A file or directory that WKWebView can access (e.g., .css, .js files).

Currently, the Flutter implementation always sets the parent folder of the specified HTML file as the read access directory. This behavior is not configurable, which limits how local web content can be structured.

For example, the following structure does not work because the .css and .js files are not in the parent directory of the HTML file:

/app_resources/
│── styles/
│    ├── main.css
│
│── scripts/
│    ├── app.js
│
│── pages/
     ├── index.html  (Loaded file)

With the existing behavior, WKWebView cannot access styles/main.css and scripts/app.js because the parent folder of index.html (/pages/) does not contain them.

How This Resolves the Issue

The readAccessURLProvider property has been added to the WebKitWebViewControllerCreationParams class. This property accepts a function that takes the path of the HTML file being loaded and returns the path to the associated resources.

Screenshot at Mar 04 14-49-46

Each time loadFile is called, the controller invokes this function and passes its result as the second argument to the underlying WKWebView implementation.

By default, the function returns the parent directory of the specified HTML file, preserving the existing behavior when no custom provider is set.

Impact on End Users

  1. Developers can now explicitly specify the directory that WKWebView should allow access to when loading a local HTML page, providing greater flexibility in organizing assets.
  2. The existing API signature remains unchanged, ensuring that the update does not require any modifications to existing codebases unless the new functionality is utilized.

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@agavrilko agavrilko requested a review from cbracken as a code owner March 4, 2025 23:00
Copy link

google-cla bot commented Mar 4, 2025

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Copy link
Contributor

@bparrishMines bparrishMines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@agavrilko To follow the pattern of other methods, we should introduce a new platform interface method to webview_flutter_platform_interface. Something like PlatformWebViewController.loadFileWithParams(LoadFileParams). LoadFileParams would contain a url parameter. Then the webview_flutter_wkwebview package can create its own implementation of LoadFileParams with the readAccessUrl parameter because it is unique to iOS/macOS.

@agavrilko
Copy link
Author

Hello @bparrishMines,
Thank you for taking the time to review this MR!
I would like to ensure that I understand your feedback before proceeding.

I initially aimed to introduce this minor update without making any API changes, focusing solely on exposing the functionality that was already present but not accessible to users.
However, based on your comment, it seems you are suggesting a broader update that would introduce new APIs (e.g., LoadFileParams and a new/updated platform interface method).

Based on my understanding, your suggestion would require:

  1. Introducing LoadFileParams at the platform interface level.
  2. Extending the PlatformWebViewController to accept LoadFileParams instead of a plain string.
  3. Adapting webview_flutter_wkwebview with a WebKitLoadFileParams subclass.

webview_design_update

While this design would make the API more consistent and extensible, it would also introduce a breaking change for current users, requiring them to update their code.
That is why I am in doubt.

And if my understanding is correct, should I just update an existing loadFile method or introduce a new one?

@bparrishMines
Copy link
Contributor

@agavrilko I think you should create a new platform interface method named something like: PlatformWebViewController.loadFileWithParams(LoadFileParams). This is consistent with updates to other platform interfaces where we realized in hindsight the method should have taken a class so that we can add parameters later.

Everything else you stated seems correct.

Additionally, after this feature lands, PlatformWebViewController.loadFile can be deprecated and it can just call loadFileWithParams.

@agavrilko agavrilko force-pushed the feature/#136479-readAccessUrl-customization-on-iOS branch from bc4128f to afad597 Compare May 1, 2025 23:55
@agavrilko agavrilko requested a review from LouiseHsu as a code owner May 1, 2025 23:55
@agavrilko agavrilko force-pushed the feature/#136479-readAccessUrl-customization-on-iOS branch from afad597 to e3639a2 Compare May 5, 2025 18:12
@agavrilko
Copy link
Author

Hello @bparrishMines

I'm seeing that the pipeline fails due to a version resolution issue:

Because webview_flutter_example depends on webview_flutter_platform_interface ^2.12.0 which doesn't match any versions, version solving failed.

Could you please advise on the proper workflow for updating versions across the packages?
Also, when you have a moment, could you review the changes to ensure everything aligns with your expectations?

Thank you!

@bparrishMines
Copy link
Contributor

@agavrilko agavrilko force-pushed the feature/#136479-readAccessUrl-customization-on-iOS branch 2 times, most recently from d08642a to bffcb4e Compare May 21, 2025 22:22
@agavrilko agavrilko force-pushed the feature/#136479-readAccessUrl-customization-on-iOS branch from bffcb4e to f3090f0 Compare May 29, 2025 22:35
@agavrilko
Copy link
Author

Hello @bparrishMines,

I need further assistance with this PR.
I expected to see ...you can't publish a package that has dependency overrides..., as stated here.

But it looks like changing _platform_interface and implementations in the same PR is not allowed:

Changed packages: webview_flutter/webview_flutter,webview_flutter_android,webview_flutter_platform_interface,webview_flutter_wkwebview
[0:00] Running for packages/webview_flutter/webview_flutter...
Dart changes are not allowed to other packages in webview_flutter in the same PR as changes to public Dart code in webview_flutter_platform_interface, as this can cause accidental breaking changes to be missed by automated checks. Please split the changes to these two packages into separate PRs.

Should this change be split into 2 different PRs?
If yes, please specify what parts should go to each.

Copy link
Contributor

@bparrishMines bparrishMines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@agavrilko Yes, this PR won't be published as is. The first step is to get this PR approved first, then individual PRs for each package will be created. This allows us to review all the changes together before we start landing seaprate PRs.

/// such as headers (on Android) or resource paths (on iOS/macOS).
///
/// Throws a `PlatformException` if the [absoluteFilePath] does not exist.
Future<void> loadFileWithParams(LoadFileParams params) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method shouldn't be necessary. A user can now use the platform specific loadFileWithParams to add platform specific parameters.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I am property understand this comment.
Do you suggest to remove this method from the WebViewController class?
The loading of the file with custom parameters would look like the following:

switch (controller.platform) {
case final WebKitWebViewController platform:
platform.loadFileWithParams(...)

default:
...
}

Just want to ensure I understand it right.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. WebViewController.loadFileWithParams should be removed and users could use the code snippet you provided to access the platform-specific params. The goal of the app-facing package is to provide a simple and clean API while the platform interface provides a more robust and extendable API.

@@ -131,10 +131,25 @@ class WebViewController {
/// `/Users/username/Documents/www/index.html`.
///
/// Throws a `PlatformException` if the [absoluteFilePath] does not exist.
@Deprecated('Use loadFileWithParams(LocalFileParams params) instead. '
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't need deprecation. This can just change the platform call from platform.loadFile to platform.loadFileWithParams.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

/// Platform-specific implementations can add additional fields by extending
/// this class.
///
/// {@tool sample}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// {@tool sample}

This doesn't actually do anything right now. We just haven't removed them from other classes yet.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

/// final String readAccessPath;
/// }
/// ```
/// {@end-tool}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// {@end-tool}

Same here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

/// this class.
///
/// {@tool sample}
/// This example demonstrates how to extend [LocalFileParams] to provide
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// This example demonstrates how to extend [LocalFileParams] to provide
/// This example demonstrates how to extend [LoadFileParams] to provide

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

class WebKitLoadFileParams extends LoadFileParams {
/// Constructs a [WebKitLoadFileParams], the subclass of a [LoadFileParams].
///
/// The optional [readAccessPath] defines the directory that the WebView is
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this information should be moved to the documentation for the field.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved.

class AndroidLoadFileParams extends LoadFileParams {
/// Constructs a [AndroidLoadFileParams], the subclass of a [LoadFileParams].
///
/// Optionally, [headers] map may be included, which contains key-value pairs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this information should be moved to the field.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved.

/// that will be passed as additional HTTP headers when loading the file.
AndroidLoadFileParams({
required String absoluteFilePath,
this.headers = _defaultHeaders,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should work right?

Suggested change
this.headers = _defaultHeaders,
this.headers = const <String, String>{},

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

@@ -383,15 +425,19 @@ class AndroidWebViewController extends PlatformWebViewController {
_webView.pigeon_instanceManager.getIdentifier(_webView)!;

@override
Future<void> loadFile(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As stated in the iOS implementation as well, we keep loadFile and it should just call loadFileWithParams.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

@@ -274,7 +274,7 @@ void main() {
));
}

test('loadFile without file prefix', () async {
test('Initializing WebView settings on controller creation', () async {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the loadFile method will be kept in AndroidWebViewController, one of the tests for loadFile should be kept.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'loadFile' tests restored under 'loadFile' group.
NOTE: the test on 277 line was not related to the 'loadFile' method, this change just fixes the label.

agavrilko added 2 commits June 3, 2025 16:16
flutter/flutter#136479

• Deprecates `WebViewController.loadFile(String)` in favor of `WebViewController.loadFileWithParams(LoadFileParams)`.
• Introduces `AndroidLoadFileParams` and `WebKitLoadFileParams` to support platform-specific parameters when loading local HTML files on Android and iOS/macOS.
@agavrilko agavrilko force-pushed the feature/#136479-readAccessUrl-customization-on-iOS branch from f3090f0 to 9531f5c Compare June 4, 2025 00:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants