Commit 77f09dd5 authored by Lorenzo Pichilli's avatar Lorenzo Pichilli

fixed iOS getCookies MyCookieManager, Added limited cookies support on iOS...

fixed iOS getCookies MyCookieManager, Added limited cookies support on iOS below 11.0 using JavaScript
parent 399602e5
......@@ -2,6 +2,7 @@
<library name="Flutter Plugins">
<CLASSES>
<root url="file://$PROJECT_DIR$" />
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2" />
</CLASSES>
<JAVADOC />
<SOURCES />
......
......@@ -3,6 +3,7 @@
- Added support for Dart null-safety feature
- Added Android Hybrid Composition support "Use PlatformViewLink widget for Android WebView" [#462](https://github.com/pichillilorenzo/flutter_inappwebview/pull/462) (thanks to [plateaukao](https://github.com/plateaukao) and [tneotia](https://github.com/tneotia))
- Added `allowUniversalAccessFromFileURLs` and `allowFileAccessFromFileURLs` WebView options also for iOS (also thanks to [liranhao](https://github.com/liranhao))
- Added limited cookies support on iOS below 11.0 using JavaScript
- Updated integration tests
- Merge "Upgraded appcompat to 1.2.0-rc-02" [#465](https://github.com/pichillilorenzo/flutter_inappwebview/pull/465) (thanks to [andreidiaconu](https://github.com/andreidiaconu))
- Merge "Added missing field 'headers' which returned by WebResourceResponse.toMap()" [#490](https://github.com/pichillilorenzo/flutter_inappwebview/pull/490) (thanks to [Doflatango](https://github.com/Doflatango))
......@@ -13,6 +14,7 @@
- Merge "iOS ChromeSafariBrowserManager - Fixing unnecessary casting of rootViewController to FlutterViewController" [#567](https://github.com/pichillilorenzo/flutter_inappwebview/pull/567) (thanks to [gunantosteven](https://github.com/gunantosteven))
- Merge "Fix _channel.invokeMethod name for injectCSSFileFromUrl method" [#645](https://github.com/pichillilorenzo/flutter_inappwebview/pull/645) (thanks to [omralcrt](https://github.com/omralcrt))
- Merge "Add android media intents on wildcard input accept" [#620](https://github.com/pichillilorenzo/flutter_inappwebview/pull/620) (thanks to [cbodin](https://github.com/cbodin))
- Merge "Add ChromeSafariBrowser support for Android 11" [#538](https://github.com/pichillilorenzo/flutter_inappwebview/pull/538) (thanks to [DRSchlaubi](https://github.com/DRSchlaubi))
- Fixed missing properties initialization when using InAppWebViewController.fromInAppBrowser
- Fixed "Issue in Flutter web: 'Unsupported operation: Platform._operatingSystem'" [#507](https://github.com/pichillilorenzo/flutter_inappwebview/issues/507)
- Fixed "window.flutter_inappwebview.callHandler is not a function" [#218](https://github.com/pichillilorenzo/flutter_inappwebview/issues/218)
......
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/.pub-cache/git/plugins-16f3281b04b0db12e609352b1c9544901392e428/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.27/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.1+1/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.4/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/.pub-cache/git/plugins-16f3281b04b0db12e609352b1c9544901392e428/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.27/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.1+1/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.4/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.4+8/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.0.1+2/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.0.4+3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-01-29 00:53:56.206541","version":"1.26.0-13.0.pre.194"}
\ No newline at end of file
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/.pub-cache/git/plugins-16f3281b04b0db12e609352b1c9544901392e428/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.27/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.1+1/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.4/","dependencies":[]}],"android":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/.pub-cache/git/plugins-16f3281b04b0db12e609352b1c9544901392e428/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.27/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.1+1/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.4/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.4+8/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.0.1+2/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.0.4+3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"device_info","dependencies":[]},{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":["device_info"]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-01-30 14:49:49.654803","version":"1.26.0-18.0.pre.90"}
\ No newline at end of file
#
# NOTE: This podspec is NOT to be published. It is only used as a local source!
# This is a generated file; do not edit or check into version control.
#
Pod::Spec.new do |s|
s.name = 'Flutter'
s.version = '1.0.0'
s.summary = 'High-performance, high-fidelity mobile apps.'
s.homepage = 'https://flutter.io'
s.license = { :type => 'MIT' }
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
s.ios.deployment_target = '8.0'
# Framework linking is handled by Flutter tooling, not CocoaPods.
# Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs.
s.vendored_frameworks = 'path/to/nothing'
end
......@@ -254,6 +254,7 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/device_info/device_info.framework",
"${BUILT_PRODUCTS_DIR}/flutter_downloader/flutter_downloader.framework",
"${BUILT_PRODUCTS_DIR}/flutter_inappwebview/flutter_inappwebview.framework",
"${BUILT_PRODUCTS_DIR}/integration_test/integration_test.framework",
......@@ -262,6 +263,7 @@
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info.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}/integration_test.framework",
......
......@@ -146,7 +146,7 @@ class MyCookieManager: NSObject, FlutterPlugin {
if let urlHost = URL(string: url)?.host {
MyCookieManager.httpCookieStore!.getAllCookies { (cookies) in
for cookie in cookies {
if urlHost.hasSuffix(cookie.domain) {
if urlHost.hasSuffix(cookie.domain) || cookie.domain.hasSuffix(urlHost) {
var sameSite: String? = nil
if #available(iOS 13.0, *) {
if let sameSiteValue = cookie.sameSitePolicy?.rawValue {
......
import 'dart:async';
import 'dart:io';
import 'package:device_info/device_info.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'in_app_webview_controller.dart';
import 'headless_in_app_webview.dart';
import 'types.dart';
///Class that implements a singleton object (shared instance) which manages the cookies used by WebView instances.
///On Android, it is implemented using [CookieManager](https://developer.android.com/reference/android/webkit/CookieManager).
///On iOS, it is implemented using [WKHTTPCookieStore](https://developer.apple.com/documentation/webkit/wkhttpcookiestore).
///
///**NOTE for iOS**: available from iOS 11.0+.
///**NOTE for iOS below 11.0 (LIMITED SUPPORT!)**: in this case, almost all of the methods ([CookieManager.deleteAllCookies] is not supported!)
///has been implemented using JavaScript because there is no other way to work with them on iOS below 11.0.
///See https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies for JavaScript restrictions.
class CookieManager {
static CookieManager? _instance;
static const MethodChannel _channel = const MethodChannel(
......@@ -27,10 +34,17 @@ class CookieManager {
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.
///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].
///
///[iosBelow11WebViewController] could be used if you need to set a session-only cookie using JavaScript (so [isHttpOnly] cannot be set, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
///on the current URL of the [WebView] managed by that controller when you need to target iOS below 11. In this case the [url] parameter is ignored.
///
///**NOTE for iOS below 11.0**: If [iosBelow11WebViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
///to set the cookie (session-only cookie won't work! In that case, you should set also [expiresDate] or [maxAge]).
Future<void> setCookie(
{required String url,
required String name,
......@@ -41,7 +55,8 @@ class CookieManager {
int? maxAge,
bool? isSecure,
bool? isHttpOnly,
HTTPCookieSameSitePolicy? sameSite}) async {
HTTPCookieSameSitePolicy? sameSite,
InAppWebViewController? iosBelow11WebViewController}) async {
if (domain == null) domain = _getDomainName(url);
assert(url.isNotEmpty);
......@@ -50,6 +65,56 @@ class CookieManager {
assert(domain.isNotEmpty);
assert(path.isNotEmpty);
if (Platform.isIOS) {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
var version = double.tryParse(iosInfo.systemVersion);
if (version != null && version < 11.0) {
var cookieValue = name + "=" + value + "; Domain=" + domain + "; Path=" + path;
if (expiresDate != null)
cookieValue += "; Expires=" + _getCookieExpirationDate(expiresDate);
if (maxAge != null)
cookieValue += "; Max-Age=" + maxAge.toString();
if (isSecure != null && isSecure)
cookieValue += "; Secure";
if (sameSite != null)
cookieValue += "; SameSite=" + sameSite.toValue();
cookieValue += ";";
if (iosBelow11WebViewController != null) {
InAppWebViewGroupOptions? options = await iosBelow11WebViewController.getOptions();
if (options != null && options.crossPlatform != null &&
options.crossPlatform!.javaScriptEnabled == true) {
await iosBelow11WebViewController.evaluateJavascript(
source: 'document.cookie="$cookieValue"');
return;
}
}
var setCookieCompleter = Completer<void>();
var headlessWebView = new HeadlessInAppWebView(
initialUrl: url,
onLoadStop: (controller, url) async {
await controller.evaluateJavascript(
source: 'document.cookie="$cookieValue"');
setCookieCompleter.complete();
},
);
await headlessWebView.run();
await setCookieCompleter.future;
await headlessWebView.dispose();
return;
}
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('url', () => url);
args.putIfAbsent('name', () => name);
......@@ -66,38 +131,157 @@ class CookieManager {
}
///Gets all the cookies for the given [url].
Future<List<Cookie>> getCookies({required String url}) async {
///
///[iosBelow11WebViewController] is used for getting the cookies (also session-only cookies) using JavaScript (cookies with `isHttpOnly` enabled cannot be found, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
///from the current context of the [WebView] managed by that controller when you need to target iOS below 11. JavaScript must be enabled in order to work.
///In this case the [url] parameter is ignored.
///
///**NOTE for iOS below 11.0**: All the cookies returned this way will have all the properties to `null` except for [Cookie.name] and [Cookie.value].
///If [iosBelow11WebViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
///to get the cookies (session-only cookies and cookies with `isHttpOnly` enabled won't be found!).
Future<List<Cookie>> getCookies({required String url, InAppWebViewController? iosBelow11WebViewController}) async {
assert(url.isNotEmpty);
List<Cookie> cookies = [];
if (Platform.isIOS) {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
var version = double.tryParse(iosInfo.systemVersion);
if (version != null && version < 11.0) {
if (iosBelow11WebViewController != null) {
InAppWebViewGroupOptions? options = await iosBelow11WebViewController.getOptions();
if (options != null && options.crossPlatform != null &&
options.crossPlatform!.javaScriptEnabled == true) {
List<String> documentCookies = (await iosBelow11WebViewController.evaluateJavascript(source: 'document.cookie') as String)
.split(';').map((documentCookie) => documentCookie.trim()).toList();
documentCookies.forEach((documentCookie) {
List<String> cookie = documentCookie.split('=');
cookies.add(Cookie(
name: cookie[0],
value: cookie[1],
)
);
});
return cookies;
}
}
var pageLoaded = Completer<void>();
var headlessWebView = new HeadlessInAppWebView(
initialUrl: url,
onLoadStop: (controller, url) async {
pageLoaded.complete();
},
);
await headlessWebView.run();
await pageLoaded.future;
List<String> documentCookies = (await headlessWebView.webViewController.evaluateJavascript(source: 'document.cookie') as String)
.split(';').map((documentCookie) => documentCookie.trim()).toList();
documentCookies.forEach((documentCookie) {
List<String> cookie = documentCookie.split('=');
cookies.add(Cookie(
name: cookie[0],
value: cookie[1],
)
);
});
await headlessWebView.dispose();
return cookies;
}
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('url', () => url);
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++) {
cookieListMap.forEach((cookieMap) {
cookies.add(Cookie(
name: cookieListMap[i]["name"],
value: cookieListMap[i]["value"],
expiresDate: cookieListMap[i]["expiresDate"],
isSessionOnly: cookieListMap[i]["isSessionOnly"],
domain: cookieListMap[i]["domain"],
name: cookieMap["name"],
value: cookieMap["value"],
expiresDate: cookieMap["expiresDate"],
isSessionOnly: cookieMap["isSessionOnly"],
domain: cookieMap["domain"],
sameSite:
HTTPCookieSameSitePolicy.fromValue(cookieListMap[i]["sameSite"]),
isSecure: cookieListMap[i]["isSecure"],
isHttpOnly: cookieListMap[i]["isHttpOnly"],
path: cookieListMap[i]["path"]));
}
HTTPCookieSameSitePolicy.fromValue(cookieMap["sameSite"]),
isSecure: cookieMap["isSecure"],
isHttpOnly: cookieMap["isHttpOnly"],
path: cookieMap["path"]));
});
return cookies;
}
///Gets a cookie by its [name] for the given [url].
///
///[iosBelow11WebViewController] is used for getting the cookie (also session-only cookie) using JavaScript (cookie with `isHttpOnly` enabled cannot be found, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
///from the current context of the [WebView] managed by that controller when you need to target iOS below 11. JavaScript must be enabled in order to work.
///In this case the [url] parameter is ignored.
///
///**NOTE for iOS below 11.0**: All the cookies returned this way will have all the properties to `null` except for [Cookie.name] and [Cookie.value].
///If [iosBelow11WebViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
///to get the cookie (session-only cookie and cookie with `isHttpOnly` enabled won't be found!).
Future<Cookie?> getCookie(
{required String url, required String name}) async {
{required String url, required String name, InAppWebViewController? iosBelow11WebViewController}) async {
assert(url.isNotEmpty);
assert(name.isNotEmpty);
if (Platform.isIOS) {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
var version = double.tryParse(iosInfo.systemVersion);
if (version != null && version < 11.0) {
if (iosBelow11WebViewController != null) {
InAppWebViewGroupOptions? options = await iosBelow11WebViewController.getOptions();
if (options != null && options.crossPlatform != null &&
options.crossPlatform!.javaScriptEnabled == true) {
List<String> documentCookies = (await iosBelow11WebViewController.evaluateJavascript(source: 'document.cookie') as String)
.split(';').map((documentCookie) => documentCookie.trim()).toList();
for (var i = 0; i < documentCookies.length; i++) {
List<String> cookie = documentCookies[i].split('=');
if (cookie[0] == name)
return Cookie(
name: cookie[0],
value: cookie[1]);
}
return null;
}
}
var pageLoaded = Completer<void>();
var headlessWebView = new HeadlessInAppWebView(
initialUrl: url,
onLoadStop: (controller, url) async {
pageLoaded.complete();
},
);
await headlessWebView.run();
await pageLoaded.future;
List<String> documentCookies = (await headlessWebView.webViewController.evaluateJavascript(source: 'document.cookie') as String)
.split(';').map((documentCookie) => documentCookie.trim()).toList();
await headlessWebView.dispose();
for (var i = 0; i < documentCookies.length; i++) {
List<String> cookie = documentCookies[i].split('=');
if (cookie[0] == name)
return Cookie(
name: cookie[0],
value: cookie[1]);
}
return null;
}
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('url', () => url);
List<dynamic> cookies = await _channel.invokeMethod('getCookies', args);
......@@ -123,18 +307,34 @@ class CookieManager {
///Removes a cookie by its [name] for the given [url], [domain] and [path].
///
///The default value of [path] is `"/"`.
///If [domain] is `null` or empty, its default value will be the domain name of [url].
///If [domain] is empty, its default value will be the domain name of [url].
///
///[iosBelow11WebViewController] is used for deleting the cookie (also session-only cookie) using JavaScript (cookie with `isHttpOnly` enabled cannot be deleted, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
///from the current context of the [WebView] managed by that controller when you need to target iOS below 11. JavaScript must be enabled in order to work.
///In this case the [url] parameter is ignored.
///
///**NOTE for iOS below 11.0**: If [iosBelow11WebViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
///to delete the cookie (session-only cookie and cookie with `isHttpOnly` enabled won't be deleted!).
Future<void> deleteCookie(
{required String url,
required String name,
String domain = "",
String path = "/"}) async {
String path = "/",
InAppWebViewController? iosBelow11WebViewController}) async {
if (domain.isEmpty) domain = _getDomainName(url);
assert(url.isNotEmpty);
assert(name.isNotEmpty);
assert(url.isNotEmpty);
assert(url.isNotEmpty);
if (Platform.isIOS) {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
var version = double.tryParse(iosInfo.systemVersion);
if (version != null && version < 11.0) {
await setCookie(url: url, name: name, value: "", path: path, domain: domain, maxAge: -1, iosBelow11WebViewController: iosBelow11WebViewController);
return;
}
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('url', () => url);
......@@ -147,14 +347,33 @@ class CookieManager {
///Removes all cookies for the given [url], [domain] and [path].
///
///The default value of [path] is `"/"`.
///If [domain] is `null` or empty, its default value will be the domain name of [url].
///If [domain] is empty, its default value will be the domain name of [url].
///
///[iosBelow11WebViewController] is used for deleting the cookies (also session-only cookies) using JavaScript (cookies with `isHttpOnly` enabled cannot be deleted, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
///from the current context of the [WebView] managed by that controller when you need to target iOS below 11. JavaScript must be enabled in order to work.
///In this case the [url] parameter is ignored.
///
///**NOTE for iOS below 11.0**: If [iosBelow11WebViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
///to delete the cookies (session-only cookies and cookies with `isHttpOnly` enabled won't be deleted!).
Future<void> deleteCookies(
{required String url, String domain = "", String path = "/"}) async {
{required String url, String domain = "", String path = "/",
InAppWebViewController? iosBelow11WebViewController}) async {
if (domain.isEmpty) domain = _getDomainName(url);
assert(url.isNotEmpty);
assert(url.isNotEmpty);
assert(url.isNotEmpty);
if (Platform.isIOS) {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
var version = double.tryParse(iosInfo.systemVersion);
if (version != null && version < 11.0) {
List<Cookie> cookies = await getCookies(url: url, iosBelow11WebViewController: iosBelow11WebViewController);
for (var i = 0; i < cookies.length; i++) {
await setCookie(url: url, name: cookies[i].name, value: "", path: path, domain: domain, maxAge: -1, iosBelow11WebViewController: iosBelow11WebViewController);
}
return;
}
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('url', () => url);
......@@ -164,6 +383,8 @@ class CookieManager {
}
///Removes all cookies.
///
///**NOTE for iOS**: available from iOS 11.0+.
Future<void> deleteAllCookies() async {
Map<String, dynamic> args = <String, dynamic>{};
await _channel.invokeMethod('deleteAllCookies', args);
......@@ -176,4 +397,9 @@ class CookieManager {
if (domain == null) return "";
return domain.startsWith("www.") ? domain.substring(4) : domain;
}
String _getCookieExpirationDate(int expiresDate) {
var dateTime = DateTime.fromMillisecondsSinceEpoch(expiresDate).toUtc();
return DateFormat('EEE, d MMM yyyy hh:mm:ss', "en_US").format(dateTime) + ' GMT';
}
}
......@@ -12,6 +12,8 @@ dependencies:
sdk: flutter
uuid: ^3.0.0-nullsafety.0
mime: ^1.0.0-nullsafety.0
intl: ^0.17.0-nullsafety.2
device_info: ^2.0.0-nullsafety.2
dev_dependencies:
flutter_test:
......
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