fixed iOS getCookies MyCookieManager, Added limited cookies support on iOS below 11.0 using JavaScript
This commit is contained in:
parent
399602e51d
commit
77f09dd5b5
1
.idea/libraries/Flutter_Plugins.xml
generated
1
.idea/libraries/Flutter_Plugins.xml
generated
@ -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)
|
||||
|
@ -1 +1 @@
|
||||
{"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"}
|
||||
{"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"}
|
18
example/ios/Flutter/Flutter.podspec
Normal file
18
example/ios/Flutter/Flutter.podspec
Normal file
@ -0,0 +1,18 @@
|
||||
#
|
||||
# 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 {
|
||||
|
@ -1,14 +1,21 @@
|
||||
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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user