Commit ade4480c authored by Lorenzo Pichilli's avatar Lorenzo Pichilli

Fixed error 'java.lang.ClassCastException: cannot be cast to...

Fixed error 'java.lang.ClassCastException:  cannot be cast to android.view.WindowManagerImpl' on Android when using native alert dialogs, updated README.md with Xcode version required
parent a56b2128
This diff is collapsed.
## 2.0.1+1
- Fixed error "java.lang.ClassCastException: $Proxy1 cannot be cast to android.view.WindowManagerImpl" on Android when using native alert dialogs
## 2.0.1
- Added `onPermissionRequest` event. This event is fired when the webview is requesting permission to access the specified resources and the permission currently isn't granted or denied (available only on Android).
......
......@@ -14,7 +14,7 @@ A Flutter plugin that allows you to add an inline webview or open an in-app brow
- Dart sdk: ">=2.0.0-dev.68.0 <3.0.0"
- Flutter: ">=1.9.1+hotfix.5 <2.0.0"
- Android: `minSdkVersion 17`
- iOS: `--ios-language swift`
- iOS: `--ios-language swift`, Xcode version `>= 11`
### Note for Android
......@@ -440,7 +440,7 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
* `onSafeBrowsingHit`: Event fired when the webview notifies that a loading URL has been flagged by Safe Browsing (available only on Android).
* `onReceivedHttpAuthRequest`: Event fired when the WebView received an HTTP authentication request. The default behavior is to cancel the request.
* `onReceivedServerTrustAuthRequest`: Event fired when the WebView need to perform server trust authentication (certificate validation).
* `onReceivedClientCertRequest`: Notify the host application to handle a SSL client certificate request.
* `onReceivedClientCertRequest`: Notify the host application to handle an SSL client certificate request.
* `onFindResultReceived`: Event fired as find-on-page operations progress.
* `shouldInterceptAjaxRequest`: Event fired when an `XMLHttpRequest` is sent to a server.
* `onAjaxReadyStateChange`: Event fired whenever the `readyState` attribute of an `XMLHttpRequest` changes.
......
......@@ -164,7 +164,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
}
};
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(view.getContext(), R.style.Theme_AppCompat_Dialog_Alert);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(registrar.activeContext(), R.style.Theme_AppCompat_Dialog_Alert);
alertDialogBuilder.setMessage(alertMessage);
if (confirmButtonTitle != null && !confirmButtonTitle.isEmpty()) {
alertDialogBuilder.setPositiveButton(confirmButtonTitle, clickListener);
......@@ -255,7 +255,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
}
};
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(view.getContext(), R.style.Theme_AppCompat_Dialog_Alert);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(registrar.activeContext(), R.style.Theme_AppCompat_Dialog_Alert);
alertDialogBuilder.setMessage(alertMessage);
if (confirmButtonTitle != null && !confirmButtonTitle.isEmpty()) {
alertDialogBuilder.setPositiveButton(confirmButtonTitle, confirmClickListener);
......@@ -372,7 +372,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
}
};
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(view.getContext(), R.style.Theme_AppCompat_Dialog_Alert);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(registrar.activeContext(), R.style.Theme_AppCompat_Dialog_Alert);
alertDialogBuilder.setMessage(alertMessage);
if (confirmButtonTitle != null && !confirmButtonTitle.isEmpty()) {
alertDialogBuilder.setPositiveButton(confirmButtonTitle, confirmClickListener);
......
......@@ -2,9 +2,10 @@
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/lorenzopichilli/flutter"
export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example"
export "FLUTTER_TARGET=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/test_driver/app.dart"
export "FLUTTER_TARGET=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build/ios"
export "FLUTTER_FRAMEWORK_DIR=/Users/lorenzopichilli/flutter/bin/cache/artifacts/engine/ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "TRACK_WIDGET_CREATION=true"
......@@ -268,6 +268,8 @@
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/Reachability/Reachability.framework",
"${BUILT_PRODUCTS_DIR}/connectivity/connectivity.framework",
"${BUILT_PRODUCTS_DIR}/flutter_downloader/flutter_downloader.framework",
"${BUILT_PRODUCTS_DIR}/flutter_inappwebview/flutter_inappwebview.framework",
"${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework",
......@@ -275,6 +277,8 @@
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_downloader.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_inappwebview.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework",
......
......@@ -22,6 +22,7 @@ dependencies:
flutter_downloader: ^1.3.2
path_provider: ^1.4.0
permission_handler: ^3.3.0
connectivity: ^0.4.5+6
flutter_inappwebview:
path: ../
......
......@@ -27,7 +27,7 @@ class InAppWebViewOnLoadErrorTestState extends WidgetTestState {
Expanded(
child: Container(
child: InAppWebView(
initialUrl: "http://not-existing-domain.org/",
initialUrl: "https://not-existing-domain.org/",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions(
......
......@@ -6,7 +6,8 @@ import 'package:flutter/services.dart';
import 'types.dart' show ListenerCallback;
class ChannelManager {
static const MethodChannel channel = const MethodChannel('com.pichillilorenzo/flutter_inappbrowser');
static const MethodChannel channel =
const MethodChannel('com.pichillilorenzo/flutter_inappbrowser');
static bool initialized = false;
static final listeners = HashMap<String, ListenerCallback>();
......@@ -16,13 +17,12 @@ class ChannelManager {
}
static void addListener(String key, ListenerCallback callback) {
if (!initialized)
init();
if (!initialized) init();
listeners.putIfAbsent(key, () => callback);
}
static void init () {
static void init() {
channel.setMethodCallHandler(_handleMethod);
initialized = true;
}
}
\ No newline at end of file
}
......@@ -20,7 +20,7 @@ class ChromeSafariBrowser {
bool _isOpened = false;
///Initialize the [ChromeSafariBrowser] instance with an [InAppBrowser] fallback instance or `null`.
ChromeSafariBrowser ({bFallback}) {
ChromeSafariBrowser({bFallback}) {
uuid = uuidGenerator.v4();
browserFallback = bFallback;
ChannelManager.addListener(uuid, handleMethod);
......@@ -28,7 +28,7 @@ class ChromeSafariBrowser {
}
Future<dynamic> handleMethod(MethodCall call) async {
switch(call.method) {
switch (call.method) {
case "onChromeSafariBrowserOpened":
onOpened();
break;
......@@ -53,7 +53,11 @@ class ChromeSafariBrowser {
///[headersFallback]: The additional header of the [InAppBrowser] instance fallback to be used in the HTTP request for this URL, specified as a map from name to value.
///
///[optionsFallback]: Options used by the [InAppBrowser] instance fallback.
Future<void> open({@required String url, ChromeSafariBrowserClassOptions options, Map<String, String> headersFallback = const {}, InAppBrowserClassOptions optionsFallback}) async {
Future<void> open(
{@required String url,
ChromeSafariBrowserClassOptions options,
Map<String, String> headersFallback = const {},
InAppBrowserClassOptions optionsFallback}) async {
assert(url != null && url.isNotEmpty);
this.throwIsAlreadyOpened(message: 'Cannot open $url!');
......@@ -65,21 +69,33 @@ class ChromeSafariBrowser {
Map<String, dynamic> optionsFallbackMap = {};
if (optionsFallback != null) {
optionsFallbackMap.addAll(optionsFallback.inAppBrowserOptions?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback.inAppWebViewWidgetOptions?.inAppWebViewOptions?.toMap() ?? {});
optionsFallbackMap
.addAll(optionsFallback.inAppBrowserOptions?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback
.inAppWebViewWidgetOptions?.inAppWebViewOptions
?.toMap() ??
{});
if (Platform.isAndroid) {
optionsFallbackMap.addAll(optionsFallback.androidInAppBrowserOptions?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback.inAppWebViewWidgetOptions?.androidInAppWebViewOptions?.toMap() ?? {});
}
else if (Platform.isIOS) {
optionsFallbackMap.addAll(optionsFallback.iosInAppBrowserOptions?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback.inAppWebViewWidgetOptions?.iosInAppWebViewOptions?.toMap() ?? {});
optionsFallbackMap
.addAll(optionsFallback.androidInAppBrowserOptions?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback
.inAppWebViewWidgetOptions?.androidInAppWebViewOptions
?.toMap() ??
{});
} else if (Platform.isIOS) {
optionsFallbackMap
.addAll(optionsFallback.iosInAppBrowserOptions?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback
.inAppWebViewWidgetOptions?.iosInAppWebViewOptions
?.toMap() ??
{});
}
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('uuidFallback', () => (browserFallback != null) ? browserFallback.uuid : '');
args.putIfAbsent('uuidFallback',
() => (browserFallback != null) ? browserFallback.uuid : '');
args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => headersFallback);
args.putIfAbsent('options', () => optionsMap);
......@@ -91,19 +107,13 @@ class ChromeSafariBrowser {
}
///Event fires when the [ChromeSafariBrowser] is opened.
void onOpened() {
}
void onOpened() {}
///Event fires when the [ChromeSafariBrowser] is loaded.
void onLoaded() {
}
void onLoaded() {}
///Event fires when the [ChromeSafariBrowser] is closed.
void onClosed() {
}
void onClosed() {}
///Returns `true` if the [ChromeSafariBrowser] instance is opened, otherwise `false`.
bool isOpened() {
......@@ -112,13 +122,17 @@ class ChromeSafariBrowser {
void throwIsAlreadyOpened({String message = ''}) {
if (this.isOpened()) {
throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is already opened.']);
throw Exception([
'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is already opened.'
]);
}
}
void throwIsNotOpened({String message = ''}) {
if (!this.isOpened()) {
throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is not opened.']);
throw Exception([
'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is not opened.'
]);
}
}
}
\ No newline at end of file
}
......@@ -11,27 +11,22 @@ import 'types.dart';
class ContentBlocker {
///Trigger of the content blocker. The trigger tells to the WebView when to perform the corresponding action.
ContentBlockerTrigger trigger;
///Action associated to the trigger. The action tells to the WebView what to do when the trigger is matched.
ContentBlockerAction action;
ContentBlocker({@required this.trigger,@required this.action});
ContentBlocker({@required this.trigger, @required this.action});
Map<String, Map<String, dynamic>> toMap() {
return {
"trigger": trigger.toMap(),
"action": action.toMap()
};
return {"trigger": trigger.toMap(), "action": action.toMap()};
}
static ContentBlocker fromMap(Map<dynamic, Map<dynamic, dynamic>> map) {
return ContentBlocker(
trigger: ContentBlockerTrigger.fromMap(
Map<String, dynamic>.from(map["trigger"])
),
Map<String, dynamic>.from(map["trigger"])),
action: ContentBlockerAction.fromMap(
Map<String, dynamic>.from(map["action"])
)
);
Map<String, dynamic>.from(map["action"])));
}
}
......@@ -42,29 +37,42 @@ class ContentBlocker {
class ContentBlockerTrigger {
///A regular expression pattern to match the URL against.
String urlFilter;
///Used only by iOS. A Boolean value. The default value is false.
bool urlFilterIsCaseSensitive;
///A list of [ContentBlockerTriggerResourceType] representing the resource types (how the browser intends to use the resource) that the rule should match.
///If not specified, the rule matches all resource types.
List<ContentBlockerTriggerResourceType> resourceType;
///A list of strings matched to a URL's domain; limits action to a list of specific domains.
///Values must be lowercase ASCII, or punycode for non-ASCII. Add * in front to match domain and subdomains. Can't be used with [ContentBlockerTrigger.unlessDomain].
List<String> ifDomain;
///A list of strings matched to a URL's domain; acts on any site except domains in a provided list.
///Values must be lowercase ASCII, or punycode for non-ASCII. Add * in front to match domain and subdomains. Can't be used with [ContentBlockerTrigger.ifDomain].
List<String> unlessDomain;
///A list of [ContentBlockerTriggerLoadType] that can include one of two mutually exclusive values. If not specified, the rule matches all load types.
List<ContentBlockerTriggerLoadType> loadType;
///A list of strings matched to the entire main document URL; limits the action to a specific list of URL patterns.
///Values must be lowercase ASCII, or punycode for non-ASCII. Can't be used with [ContentBlockerTrigger.unlessTopUrl].
List<String> ifTopUrl;
///An array of strings matched to the entire main document URL; acts on any site except URL patterns in provided list.
///Values must be lowercase ASCII, or punycode for non-ASCII. Can't be used with [ContentBlockerTrigger.ifTopUrl].
List<String> unlessTopUrl;
ContentBlockerTrigger({@required String urlFilter, bool urlFilterIsCaseSensitive = false, List<ContentBlockerTriggerResourceType> resourceType = const [],
List<String> ifDomain = const [], List<String> unlessDomain = const [], List<ContentBlockerTriggerLoadType> loadType = const [],
List<String> ifTopUrl = const [], List<String> unlessTopUrl = const []}) {
ContentBlockerTrigger(
{@required String urlFilter,
bool urlFilterIsCaseSensitive = false,
List<ContentBlockerTriggerResourceType> resourceType = const [],
List<String> ifDomain = const [],
List<String> unlessDomain = const [],
List<ContentBlockerTriggerLoadType> loadType = const [],
List<String> ifTopUrl = const [],
List<String> unlessTopUrl = const []}) {
this.urlFilter = urlFilter;
assert(this.urlFilter != null);
this.resourceType = resourceType;
......@@ -101,7 +109,9 @@ class ContentBlockerTrigger {
};
map.keys
.where((key) => map[key] == null || (map[key] is List && (map[key] as List).length == 0)) // filter keys
.where((key) =>
map[key] == null ||
(map[key] is List && (map[key] as List).length == 0)) // filter keys
.toList() // create a copy to avoid concurrent modifications
.forEach(map.remove);
......@@ -112,7 +122,8 @@ class ContentBlockerTrigger {
List<ContentBlockerTriggerResourceType> resourceType = [];
List<ContentBlockerTriggerLoadType> loadType = [];
List<String> resourceTypeStringList = List<String>.from(map["resource-type"] ?? []);
List<String> resourceTypeStringList =
List<String>.from(map["resource-type"] ?? []);
resourceTypeStringList.forEach((type) {
resourceType.add(ContentBlockerTriggerResourceType.fromValue(type));
});
......@@ -130,8 +141,7 @@ class ContentBlockerTrigger {
resourceType: resourceType,
loadType: loadType,
ifTopUrl: List<String>.from(map["if-top-url"] ?? []),
unlessTopUrl: List<String>.from(map["unless-top-url"] ?? [])
);
unlessTopUrl: List<String>.from(map["unless-top-url"] ?? []));
}
}
......@@ -143,11 +153,13 @@ class ContentBlockerTrigger {
class ContentBlockerAction {
///Type of the action.
ContentBlockerActionType type;
///If the action type is [ContentBlockerActionType.CSS_DISPLAY_NONE], then also the [selector] property is required, otherwise it is ignored.
///It specify a string that defines a selector list. Use CSS identifiers as the individual selector values, separated by commas.
String selector;
ContentBlockerAction({@required ContentBlockerActionType type, String selector}) {
ContentBlockerAction(
{@required ContentBlockerActionType type, String selector}) {
this.type = type;
assert(this.type != null);
if (this.type == ContentBlockerActionType.CSS_DISPLAY_NONE) {
......@@ -157,13 +169,12 @@ class ContentBlockerAction {
}
Map<String, dynamic> toMap() {
Map<String, dynamic> map = {
"type": type.toValue(),
"selector": selector
};
Map<String, dynamic> map = {"type": type.toValue(), "selector": selector};
map.keys
.where((key) => map[key] == null || (map[key] is List && (map[key] as List).length == 0)) // filter keys
.where((key) =>
map[key] == null ||
(map[key] is List && (map[key] as List).length == 0)) // filter keys
.toList() // create a copy to avoid concurrent modifications
.forEach(map.remove);
......@@ -173,7 +184,6 @@ class ContentBlockerAction {
static ContentBlockerAction fromMap(Map<String, dynamic> map) {
return ContentBlockerAction(
type: ContentBlockerActionType.fromValue(map["type"]),
selector: map["selector"]
);
selector: map["selector"]);
}
}
\ No newline at end of file
}
......@@ -10,7 +10,8 @@ import 'types.dart';
///**NOTE for iOS**: available from iOS 11.0+.
class CookieManager {
static CookieManager _instance;
static const MethodChannel _channel = const MethodChannel('com.pichillilorenzo/flutter_inappwebview_cookiemanager');
static const MethodChannel _channel = const MethodChannel(
'com.pichillilorenzo/flutter_inappwebview_cookiemanager');
///Gets the cookie manager shared instance.
static CookieManager instance() {
......@@ -23,21 +24,22 @@ class CookieManager {
return _instance;
}
static Future<dynamic> _handleMethod(MethodCall call) async {
}
static Future<dynamic> _handleMethod(MethodCall call) async {}
///Sets a cookie for the given [url]. Any existing cookie with the same [host], [path] and [name] will be replaced with the new cookie. The cookie being set will be ignored if it is expired.
///
///The default value of [path] is `"/"`.
///If [domain] is `null`, its default value will be the domain name of [url].
Future<void> setCookie({@required String url, @required String name, @required String value,
String domain,
String path = "/",
int expiresDate,
int maxAge,
bool isSecure }) async {
if (domain == null)
domain = _getDomainName(url);
Future<void> setCookie(
{@required String url,
@required String name,
@required String value,
String domain,
String path = "/",
int expiresDate,
int maxAge,
bool isSecure}) async {
if (domain == null) domain = _getDomainName(url);
assert(url != null && url.isNotEmpty);
assert(name != null && name.isNotEmpty);
......@@ -64,17 +66,20 @@ class CookieManager {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('url', () => url);
List<dynamic> cookieListMap = await _channel.invokeMethod('getCookies', args);
List<dynamic> cookieListMap =
await _channel.invokeMethod('getCookies', args);
cookieListMap = cookieListMap.cast<Map<dynamic, dynamic>>();
List<Cookie> cookies = [];
for(var i = 0; i < cookieListMap.length; i++) {
cookies.add(Cookie(name: cookieListMap[i]["name"], value: cookieListMap[i]["value"]));
for (var i = 0; i < cookieListMap.length; i++) {
cookies.add(Cookie(
name: cookieListMap[i]["name"], value: cookieListMap[i]["value"]));
}
return cookies;
}
///Gets a cookie by its [name] for the given [url].
Future<Cookie> getCookie({@required String url, @required String name}) async {
Future<Cookie> getCookie(
{@required String url, @required String name}) async {
assert(url != null && url.isNotEmpty);
assert(name != null && name.isNotEmpty);
......@@ -82,7 +87,7 @@ class CookieManager {
args.putIfAbsent('url', () => url);
List<dynamic> cookies = await _channel.invokeMethod('getCookies', args);
cookies = cookies.cast<Map<dynamic, dynamic>>();
for(var i = 0; i < cookies.length; i++) {
for (var i = 0; i < cookies.length; i++) {
cookies[i] = cookies[i].cast<String, dynamic>();
if (cookies[i]["name"] == name)
return Cookie(name: cookies[i]["name"], value: cookies[i]["value"]);
......@@ -94,9 +99,12 @@ class CookieManager {
///
///The default value of [path] is `"/"`.
///If [domain] is `null` or empty, its default value will be the domain name of [url].
Future<void> deleteCookie({@required String url, @required String name, String domain = "", String path = "/"}) async {
if (domain == null || domain.isEmpty)
domain = _getDomainName(url);
Future<void> deleteCookie(
{@required String url,
@required String name,
String domain = "",
String path = "/"}) async {
if (domain == null || domain.isEmpty) domain = _getDomainName(url);
assert(url != null && url.isNotEmpty);
assert(name != null && name.isNotEmpty);
......@@ -115,9 +123,9 @@ class CookieManager {
///
///The default value of [path] is `"/"`.
///If [domain] is `null` or empty, its default value will be the domain name of [url].
Future<void> deleteCookies({@required String url, String domain = "", String path = "/"}) async {
if (domain == null || domain.isEmpty)
domain = _getDomainName(url);
Future<void> deleteCookies(
{@required String url, String domain = "", String path = "/"}) async {
if (domain == null || domain.isEmpty) domain = _getDomainName(url);
assert(url != null && url.isNotEmpty);
assert(domain != null && url.isNotEmpty);
......@@ -139,8 +147,7 @@ class CookieManager {
String _getDomainName(String url) {
Uri uri = Uri.parse(url);
String domain = uri.host;
if (domain == null)
return "";
if (domain == null) return "";
return domain.startsWith("www.") ? domain.substring(4) : domain;
}
}
\ No newline at end of file
}
......@@ -11,7 +11,8 @@ import 'package:flutter/services.dart';
///doesn't offer the same functionalities as iOS `URLCredentialStorage`.
class HttpAuthCredentialDatabase {
static HttpAuthCredentialDatabase _instance;
static const MethodChannel _channel = const MethodChannel('com.pichillilorenzo/flutter_inappwebview_credential_database');
static const MethodChannel _channel = const MethodChannel(
'com.pichillilorenzo/flutter_inappwebview_credential_database');
///Gets the database shared instance.
static HttpAuthCredentialDatabase instance() {
......@@ -24,44 +25,57 @@ class HttpAuthCredentialDatabase {
return _instance;
}
static Future<dynamic> _handleMethod(MethodCall call) async {
}
static Future<dynamic> _handleMethod(MethodCall call) async {}
///Gets a map list of all HTTP auth credentials saved.
///Each map contains the key `protectionSpace` of type [ProtectionSpace]
///and the key `credentials` of type `List<HttpAuthCredential>` that contains all the HTTP auth credentials saved for that `protectionSpace`.
Future<List<Map<String, dynamic>>> getAllAuthCredentials() async {
Map<String, dynamic> args = <String, dynamic>{};
List<dynamic> allCredentials = await _channel.invokeMethod('getAllAuthCredentials', args);
List<dynamic> allCredentials =
await _channel.invokeMethod('getAllAuthCredentials', args);
List<Map<String, dynamic>> result = [];
for (Map<dynamic, dynamic> map in allCredentials) {
Map<dynamic, dynamic> protectionSpace = map["protectionSpace"];
List<dynamic> credentials = map["credentials"];
result.add({
"protectionSpace": ProtectionSpace(host: protectionSpace["host"], protocol: protectionSpace["protocol"], realm: protectionSpace["realm"], port: protectionSpace["port"]),
"credentials": credentials.map((credential) => HttpAuthCredential(username: credential["username"], password: credential["password"])).toList()
"protectionSpace": ProtectionSpace(
host: protectionSpace["host"],
protocol: protectionSpace["protocol"],
realm: protectionSpace["realm"],
port: protectionSpace["port"]),
"credentials": credentials
.map((credential) => HttpAuthCredential(
username: credential["username"],
password: credential["password"]))
.toList()
});
}
return result;
}
///Gets all the HTTP auth credentials saved for that [protectionSpace].
Future<List<HttpAuthCredential>> getHttpAuthCredentials({@required ProtectionSpace protectionSpace}) async {
Future<List<HttpAuthCredential>> getHttpAuthCredentials(
{@required ProtectionSpace protectionSpace}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("host", () => protectionSpace.host);
args.putIfAbsent("protocol", () => protectionSpace.protocol);
args.putIfAbsent("realm", () => protectionSpace.realm);
args.putIfAbsent("port", () => protectionSpace.port);
List<dynamic> credentialList = await _channel.invokeMethod('getHttpAuthCredentials', args);
List<dynamic> credentialList =
await _channel.invokeMethod('getHttpAuthCredentials', args);
List<HttpAuthCredential> credentials = [];
for (Map<dynamic, dynamic> credential in credentialList) {
credentials.add(HttpAuthCredential(username: credential["username"], password: credential["password"]));
credentials.add(HttpAuthCredential(
username: credential["username"], password: credential["password"]));
}
return credentials;
}
///Saves an HTTP auth [credential] for that [protectionSpace].
Future<void> setHttpAuthCredential({@required ProtectionSpace protectionSpace, @required HttpAuthCredential credential}) async {
Future<void> setHttpAuthCredential(
{@required ProtectionSpace protectionSpace,
@required HttpAuthCredential credential}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("host", () => protectionSpace.host);
args.putIfAbsent("protocol", () => protectionSpace.protocol);
......@@ -73,7 +87,9 @@ class HttpAuthCredentialDatabase {
}
///Removes an HTTP auth [credential] for that [protectionSpace].
Future<void> removeHttpAuthCredential({@required ProtectionSpace protectionSpace, @required HttpAuthCredential credential}) async {
Future<void> removeHttpAuthCredential(
{@required ProtectionSpace protectionSpace,
@required HttpAuthCredential credential}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("host", () => protectionSpace.host);
args.putIfAbsent("protocol", () => protectionSpace.protocol);
......@@ -85,7 +101,8 @@ class HttpAuthCredentialDatabase {
}
///Removes all the HTTP auth credentials saved for that [protectionSpace].
Future<void> removeHttpAuthCredentials({@required ProtectionSpace protectionSpace}) async {
Future<void> removeHttpAuthCredentials(
{@required ProtectionSpace protectionSpace}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("host", () => protectionSpace.host);
args.putIfAbsent("protocol", () => protectionSpace.protocol);
......@@ -99,4 +116,4 @@ class HttpAuthCredentialDatabase {
Map<String, dynamic> args = <String, dynamic>{};
await _channel.invokeMethod('clearAllAuthCredentials', args);
}
}
\ No newline at end of file
}
This diff is collapsed.
......@@ -8,7 +8,6 @@ import 'package:mime/mime.dart';
///
///This class allows you to create a simple server on `http://localhost:[port]/` in order to be able to load your assets file on a server. The default [port] value is `8080`.
class InAppLocalhostServer {
HttpServer _server;
int _port = 8080;
......@@ -28,7 +27,6 @@ class InAppLocalhostServer {
///```
///The `NSAllowsLocalNetworking` key is available since **iOS 10**.
Future<void> start() async {
if (this._server != null) {
throw Exception('Server already started on http://localhost:$_port');
}
......@@ -48,8 +46,7 @@ class InAppLocalhostServer {
path += (path.endsWith('/')) ? 'index.html' : '';
try {
body = (await rootBundle.load(path))
.buffer.asUint8List();
body = (await rootBundle.load(path)).buffer.asUint8List();
} catch (e) {
print(e.toString());
request.response.close();
......@@ -57,14 +54,17 @@ class InAppLocalhostServer {
}
var contentType = ['text', 'html'];
if (!request.requestedUri.path.endsWith('/') && request.requestedUri.pathSegments.isNotEmpty) {
var mimeType = lookupMimeType(request.requestedUri.path, headerBytes: body);
if (!request.requestedUri.path.endsWith('/') &&
request.requestedUri.pathSegments.isNotEmpty) {
var mimeType =
lookupMimeType(request.requestedUri.path, headerBytes: body);
if (mimeType != null) {
contentType = mimeType.split('/');
}
}
request.response.headers.contentType = new ContentType(contentType[0], contentType[1], charset: 'utf-8');
request.response.headers.contentType =
new ContentType(contentType[0], contentType[1], charset: 'utf-8');
request.response.add(body);
request.response.close();
});
......@@ -84,5 +84,4 @@ class InAppLocalhostServer {
this._server = null;
}
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
name: flutter_inappwebview
description: A Flutter plugin that allows you to add an inline webview or open an in-app browser window.
version: 2.0.1
version: 2.0.1+1
author: Lorenzo Pichilli <pichillilorenzo@gmail.com>
homepage: https://github.com/pichillilorenzo/flutter_inappwebview
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment