-
Notifications
You must be signed in to change notification settings - Fork 9.7k
Allow clearing cookies for FlutterWebView #1149
Allow clearing cookies for FlutterWebView #1149
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Looks great overall, left a few nits (mainly on documentation)
/// Removes all cookies, and returns true if cookies were | ||
/// present before clearing, else false. | ||
Future<bool> clearCookies() async { | ||
print(defaultTargetPlatform); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete
static const MethodChannel _channel = | ||
MethodChannel('plugins.flutter.io/cookie_manager'); | ||
|
||
/// Removes all cookies, and returns true if cookies were |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first paragraph will be used in the Dartdoc's table of contents. better to keep it short. I'd just have the summary paragraph say "Clears all cookies."
And then in the next paragraph expand on which webview instances are affected, and in a following paragraph describe the return value.
@@ -319,3 +334,6 @@ void _validateUrlString(String url) { | |||
throw ArgumentError(e); | |||
} | |||
} | |||
|
|||
/// Singleton [CookieManager] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Describe what it is.
also nit: end sentences with period.
@@ -7,6 +8,7 @@ + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar { | |||
FLTWebViewFactory* webviewFactory = | |||
[[FLTWebViewFactory alloc] initWithMessenger:registrar.messenger]; | |||
[registrar registerViewFactory:webviewFactory withId:@"plugins.flutter.io/webview"]; | |||
FLTCookieManager* cookieManager = [[FLTCookieManager alloc] init:registrar.messenger]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's keeping a reference to this instance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the instance is not being used, but the init method needs to be called. Removing the return reference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don't keep a reference what prevents FLTCookieManager from being disposed by the time we got a method channel invocation?
(we are running this with ARC)
|
||
void _onClearCookies(BuildContext context) async { | ||
final bool hadCookies = await cookieManager.clearCookies(); | ||
String message = "There were cookies. Now, they are gone!"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do we know that it worked?
Maybe we could make a JS call to get the list of cookies present it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, for now i verified that flutter.io was setting and deleting cookies. Will add a method to list all cookies.
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; | ||
import io.flutter.plugin.common.MethodChannel.Result; | ||
|
||
public class FlutterCookieManager implements MethodCallHandler { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can we make this package private?
public class FlutterCookieManager implements MethodCallHandler { | ||
|
||
private FlutterCookieManager() { | ||
// Do not instantiate. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
explain why
Please also update the change log, and bump the plugin version in pubspec.yaml. |
/// This is supported for >= IOS 9 and Android api level >= 16. | ||
/// returns true if cookies were present before clearing, else false. | ||
Future<bool> clearCookies() async { | ||
return await _channel.invokeMethod<bool>('clearCookies'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return await _channel.invokeMethod<bool>('clearCookies'); | |
return _channel.invokeMethod<bool>('clearCookies'); |
/// This is supported for >= IOS 9 and Android api level >= 16. | ||
/// returns true if cookies were present before clearing, else false. | ||
Future<bool> clearCookies() async { | ||
return await _channel.invokeMethod<bool>('clearCookies'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the type parameter will make this incompatible with stable, see the other plugin repos
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch, these are risky days for missing these on code reviews. 😨
flutter/flutter#27110 would have been helpful here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ouch, fixed this. Thanks for the flag!
/// Singleton [CookieManager]. | ||
/// | ||
/// Manages cookies pertaining to all [WebView]s. | ||
final CookieManager cookieManager = const CookieManager._(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final CookieManager cookieManager = const CookieManager._(); | |
const CookieManager cookieManager = CookieManager._(); |
|
||
static const MethodChannel _channel = | ||
MethodChannel('plugins.flutter.io/cookie_manager'); | ||
CookieManager.private(this._channel); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't name a constructor .private
, either its private _
or its not
class CookieManager { | ||
factory CookieManager() { | ||
if (_instance == null) { | ||
final MethodChannel methodChannel = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we can set mockMethodCallHandlers for testing, what is the value of providing the channel this way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My original thought was to make this a const field on the class. I wanted to be consistent with Battery plugin, i should maybe look through the test code there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consistency is good to a point, but correctness is better
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
curious, does this approach expose a way of injecting the wrong method channel?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not necessary at all
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i agree that passing in a method channel is not needed for testing, but passing it though this way -- creating it on initialization vs having it static, should be equivalent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally making const fields is frowned upon. since the const is already canonicalized we are only adding overhead to the class. Furthermore, removing the initialization from the factory lets us cut down the code a bit with ??=
:
factory Foo() {
return _instance ??= Foo._();
}
Foo._();
static Foo _instance;
return _instance; | ||
} | ||
|
||
CookieManager.private(this._channel); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the name private has no special meaning.
this should be named _
to make sure it is really private.
@@ -469,6 +469,32 @@ class WebViewController { | |||
} | |||
} | |||
|
|||
/// Manages cookies pertaining to all [WebView]s. | |||
class CookieManager { | |||
factory CookieManager() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs a Dartdoc, it should mention that it returns or created the singleton instance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: not sure if '--' is common in Flutter dartdocs (of if it is grammatically correct), I'd just say:
Returns the singleton cookie manager instance.
The instance is created the first time this factory is called.
|
||
/// Clears all cookies. | ||
/// | ||
/// This is supported for >= IOS 9 and Android api level >= 16. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to mention Android API level (16 is the minimum level supported by Flutter anyway)
/// Clears all cookies. | ||
/// | ||
/// This is supported for >= IOS 9 and Android api level >= 16. | ||
/// returns true if cookies were present before clearing, else false. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: separate the paragraph, start sentence with a capital letter.
/// This is supported for >= IOS 9 and Android api level >= 16. | ||
/// returns true if cookies were present before clearing, else false. | ||
Future<bool> clearCookies() => _channel | ||
// ignore: strong_mode_implicit_dynamic_method |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the same comment we have everywhere(minus the typo 😄 ) so it's easy to find all of these at once (and we need a TODO here anyway)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keep it TODO(amirh), most likely someone will end up searching for all these TODO(amirh):
occurrences at once.
|
||
- (void)clearCookies:(FlutterResult)result { | ||
NSOperatingSystemVersion ios9 = (NSOperatingSystemVersion){9, 0}; | ||
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:ios9]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (@available(iOS 9.0, *)) {
[self clearCookiesIos9AndLater:result]; | ||
} else { | ||
// support for IOS-8 tracked in https://github.com/flutter/flutter/issues/27624. | ||
NSLog(@"Clearing cookies is not supported for Flutter WebViews prior to iOS9."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: s/iOS9/iOS 9/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ping
void _onClearCookies( | ||
WebViewController controller, BuildContext context) async { | ||
final String cookies = | ||
await controller.evaluateJavascript('document.cookie'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about adding a menu entry that just shows a toast with the cookies?
I'd feel more confident to verify that it's working if the button that's showing me the cookies is independent of the button that's deleting the cookies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense.
- Add a more detailed TODO for invokeMethod generic - Fix Dart doc comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This reverts commit 75b959f.
As a first step to address flutter/flutter#27321