Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

[webview_flutter] Fix the issue that webview cannot load assets html and local html #2583

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ public void onMethodCall(MethodCall methodCall, Result result) {
case "loadUrl":
loadUrl(methodCall, result);
break;
case "loadAssetHtmlFile":
loadAssetHtmlFile(methodCall, result);
break;
case "loadLocalHtmlFile":
loadLocalHtmlFile(methodCall, result);
break;
case "updateSettings":
updateSettings(methodCall, result);
break;
Expand Down Expand Up @@ -175,6 +181,18 @@ private void loadUrl(MethodCall methodCall, Result result) {
result.success(null);
}

private void loadAssetHtmlFile(MethodCall methodCall, Result result) {
String url = (String) methodCall.arguments;
webView.loadUrl("file:///android_asset/flutter_assets/" + url);
result.success(null);
}

private void loadLocalHtmlFile(MethodCall methodCall, Result result) {
String url = (String) methodCall.arguments;
webView.loadUrl("file:///" + url);
result.success(null);
}

private void canGoBack(Result result) {
result.success(webView.canGoBack());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
@implementation FLTWebViewFlutterPlugin

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FLTWebViewFactory* webviewFactory =
[[FLTWebViewFactory alloc] initWithMessenger:registrar.messenger];
FLTWebViewFactory* webviewFactory = [[FLTWebViewFactory alloc] initWithRegistrar:registrar];
[registrar registerViewFactory:webviewFactory withId:@"plugins.flutter.io/webview"];
[FLTCookieManager registerWithRegistrar:registrar];
}
Expand Down
4 changes: 2 additions & 2 deletions packages/webview_flutter/ios/Classes/FlutterWebView.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id _Nullable)args
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
registrar:(NSObject<FlutterPluginRegistrar>*)registrar;

- (UIView*)view;
@end

@interface FLTWebViewFactory : NSObject <FlutterPlatformViewFactory>
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar;
@end

/**
Expand Down
94 changes: 88 additions & 6 deletions packages/webview_flutter/ios/Classes/FlutterWebView.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@

@implementation FLTWebViewFactory {
NSObject<FlutterBinaryMessenger>* _messenger;
NSObject<FlutterPluginRegistrar>* _registrar;
}

- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
self = [super init];
if (self) {
_messenger = messenger;
_registrar = registrar;
_messenger = registrar.messenger;
}
return self;
}
Expand All @@ -28,7 +30,7 @@ - (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
FLTWebViewController* webviewController = [[FLTWebViewController alloc] initWithFrame:frame
viewIdentifier:viewId
arguments:args
binaryMessenger:_messenger];
registrar:_registrar];
return webviewController;
}

Expand Down Expand Up @@ -64,17 +66,19 @@ @implementation FLTWebViewController {
// The set of registered JavaScript channel names.
NSMutableSet* _javaScriptChannelNames;
FLTWKNavigationDelegate* _navigationDelegate;
NSObject<FlutterPluginRegistrar>* _registrar;
}

- (instancetype)initWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id _Nullable)args
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
registrar:(nonnull NSObject<FlutterPluginRegistrar>*)registrar {
if (self = [super init]) {
_viewId = viewId;

_registrar = registrar;
NSString* channelName = [NSString stringWithFormat:@"plugins.flutter.io/webview_%lld", viewId];
_channel = [FlutterMethodChannel methodChannelWithName:channelName binaryMessenger:messenger];
_channel = [FlutterMethodChannel methodChannelWithName:channelName
binaryMessenger:_registrar.messenger];
_javaScriptChannelNames = [[NSMutableSet alloc] init];

WKUserContentController* userContentController = [[WKUserContentController alloc] init];
Expand Down Expand Up @@ -128,6 +132,10 @@ - (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
[self onUpdateSettings:call result:result];
} else if ([[call method] isEqualToString:@"loadUrl"]) {
[self onLoadUrl:call result:result];
} else if ([[call method] isEqualToString:@"loadAssetHtmlFile"]) {
[self onLoadAssetHtmlFile:call result:result];
} else if ([[call method] isEqualToString:@"loadLocalHtmlFile"]) {
[self onLoadLocalHtmlFile:call result:result];
} else if ([[call method] isEqualToString:@"canGoBack"]) {
[self onCanGoBack:call result:result];
} else if ([[call method] isEqualToString:@"canGoForward"]) {
Expand Down Expand Up @@ -175,6 +183,28 @@ - (void)onLoadUrl:(FlutterMethodCall*)call result:(FlutterResult)result {
}
}

- (void)onLoadAssetHtmlFile:(FlutterMethodCall*)call result:(FlutterResult)result {
NSString* url = [call arguments];
if (![self loadAssetHtmlFile:url]) {
result([FlutterError errorWithCode:@"loadAssetHtmlFile_failed"
message:@"Failed parsing the URL"
details:[NSString stringWithFormat:@"URL was: '%@'", url]]);
} else {
result(nil);
}
}

- (void)onLoadLocalHtmlFile:(FlutterMethodCall*)call result:(FlutterResult)result {
NSString* url = [call arguments];
if (![self loadLocalHtmlFile:url]) {
result([FlutterError errorWithCode:@"loadAssetHtmlFile_failed"
message:@"Failed parsing the URL"
details:[NSString stringWithFormat:@"URL was: '%@'", url]]);
} else {
result(nil);
}
}

- (void)onCanGoBack:(FlutterMethodCall*)call result:(FlutterResult)result {
BOOL canGoBack = [_webView canGoBack];
result([NSNumber numberWithBool:canGoBack]);
Expand Down Expand Up @@ -374,6 +404,58 @@ - (bool)loadUrl:(NSString*)url withHeaders:(NSDictionary<NSString*, NSString*>*)
return true;
}

- (bool)loadAssetHtmlFile:(NSString*)url {
NSArray* array = [url componentsSeparatedByString:@"?"];
NSString* pathString = [array objectAtIndex:0];
NSLog(@"%@%@", @"pathString: ", pathString);
NSString* key = [_registrar lookupKeyForAsset:pathString];
NSURL* baseURL = [[NSBundle mainBundle] URLForResource:key withExtension:nil];
if (!baseURL) {
return false;
}
NSURL* newUrl = baseURL;
if ([array count] > 1) {
NSString* queryString = [array objectAtIndex:1];
NSLog(@"%@%@", @"queryString: ", queryString);
NSString* queryPart = [NSString stringWithFormat:@"%@%@", @"?", queryString];
NSLog(@"%@%@", @"queryPart: ", queryPart);
newUrl = [NSURL URLWithString:queryPart relativeToURL:baseURL];
}
if (@available(iOS 9.0, *)) {
[_webView loadFileURL:newUrl allowingReadAccessToURL:[NSURL URLWithString:@"file:///"]];
} else {
return false;
}
return true;
}

- (bool)loadLocalHtmlFile:(NSString*)url {
NSArray* array = [url componentsSeparatedByString:@"?"];
NSString* pathString = [array objectAtIndex:0];
NSLog(@"%@%@", @"pathString: ", pathString);
NSString* key = [_registrar lookupKeyForAsset:pathString];
NSURL* baseURL = [[NSBundle mainBundle] URLForResource:key withExtension:nil];
if (!baseURL) {
[_webView loadFileURL:[NSURL fileURLWithPath:pathString]
allowingReadAccessToURL:[NSURL fileURLWithPath:pathString]];
return true;
}
NSURL* newUrl = baseURL;
if ([array count] > 1) {
NSString* queryString = [array objectAtIndex:1];
NSLog(@"%@%@", @"queryString: ", queryString);
NSString* queryPart = [NSString stringWithFormat:@"%@%@", @"?", queryString];
NSLog(@"%@%@", @"queryPart: ", queryPart);
newUrl = [NSURL URLWithString:queryPart relativeToURL:baseURL];
}
if (@available(iOS 9.0, *)) {
[_webView loadFileURL:newUrl allowingReadAccessToURL:[NSURL URLWithString:@"file:///"]];
} else {
return false;
}
return true;
}

- (void)registerJavaScriptChannels:(NSSet*)channelNames
controller:(WKUserContentController*)userContentController {
for (NSString* channelName in channelNames) {
Expand Down
20 changes: 20 additions & 0 deletions packages/webview_flutter/lib/platform_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,26 @@ abstract class WebViewPlatformController {
"WebView loadUrl is not implemented on the current platform");
}

/// Load html file from local path
///
/// `url` must not be null.
///
/// Throws an ArgumentError if `url` is not a valid URL string.
Future<void> loadAssetHtmlFile(String url) {
throw UnimplementedError(
"WebView loadAssetHtmlFile is not implemented on the current platform");
}

/// Load html file from local path
///
/// `url` must not be null.
///
/// Throws an ArgumentError if `url` is not a valid URL string.
Future<void> loadLocalHtmlFile(String url) {
throw UnimplementedError(
"WebView loadLocalHtmlFile is not implemented on the current platform");
}

/// Updates the webview settings.
///
/// Any non null field in `settings` will be set as the new setting value.
Expand Down
8 changes: 8 additions & 0 deletions packages/webview_flutter/lib/src/webview_method_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController {
});
}

@override
Future<void> loadAssetHtmlFile(String url) =>
_channel.invokeMethod<String>('loadAssetHtmlFile', url);

@override
Future<void> loadLocalHtmlFile(String url) =>
_channel.invokeMethod<String>('loadLocalHtmlFile', url);

@override
Future<String> currentUrl() => _channel.invokeMethod<String>('currentUrl');

Expand Down
16 changes: 16 additions & 0 deletions packages/webview_flutter/lib/webview_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,22 @@ class WebViewController {
return _webViewPlatformController.loadUrl(url, headers);
}

/// Load html file from assets
///
/// `url` must not be null.
Future<void> loadAssetHtmlFile(String url) async {
assert(url != null);
return _webViewPlatformController.loadAssetHtmlFile(url);
}

/// Load html file from local path
///
/// `url` must not be null.
Future<void> loadLocalHtmlFile(String url) async {
assert(url != null);
return _webViewPlatformController.loadLocalHtmlFile(url);
}

/// Accessor to the current URL that the WebView is displaying.
///
/// If [WebView.initialUrl] was never specified, returns `null`.
Expand Down