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

Allow clearing cookies for FlutterWebView #1149

Merged
merged 22 commits into from
Feb 7, 2019
Merged

Allow clearing cookies for FlutterWebView #1149

merged 22 commits into from
Feb 7, 2019

Conversation

iskakaushik
Copy link
Contributor

@iskakaushik iskakaushik commented Feb 2, 2019

As a first step to address flutter/flutter#27321

Copy link
Contributor

@amirh amirh left a 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);
Copy link
Contributor

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
Copy link
Contributor

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]
Copy link
Contributor

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];
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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!";
Copy link
Contributor

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?

Copy link
Contributor Author

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 {
Copy link
Contributor

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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explain why

@amirh
Copy link
Contributor

amirh commented Feb 5, 2019

Please also update the change log, and bump the plugin version in pubspec.yaml.
Versioning guidelines are here: https://www.dartlang.org/tools/pub/versioning#semantic-versions

/// 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');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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');
Copy link
Contributor

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

Copy link
Contributor

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.

Copy link
Contributor Author

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._();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
final CookieManager cookieManager = const CookieManager._();
const CookieManager cookieManager = CookieManager._();


static const MethodChannel _channel =
MethodChannel('plugins.flutter.io/cookie_manager');
CookieManager.private(this._channel);
Copy link
Contributor

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 =
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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

Copy link
Contributor Author

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?

Copy link
Contributor

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

Copy link
Contributor Author

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?

Copy link
Contributor

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);
Copy link
Contributor

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() {
Copy link
Contributor

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.

Copy link
Contributor

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.
Copy link
Contributor

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.
Copy link
Contributor

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
Copy link
Contributor

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)

Copy link
Contributor

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]) {
Copy link
Contributor

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.");
Copy link
Contributor

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/

Copy link
Contributor

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');
Copy link
Contributor

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.

Copy link
Contributor Author

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.
Copy link
Contributor

@amirh amirh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@iskakaushik iskakaushik merged commit 38f8198 into flutter:master Feb 7, 2019
@iskakaushik iskakaushik deleted the feature/incognito-web-view branch February 7, 2019 20:43
andreidiaconu pushed a commit to andreidiaconu/plugins that referenced this pull request Feb 17, 2019
andreidiaconu added a commit to andreidiaconu/plugins that referenced this pull request Feb 17, 2019
karantanwar pushed a commit to karantanwar/plugins that referenced this pull request Feb 19, 2019
karantanwar pushed a commit to karantanwar/plugins that referenced this pull request Feb 19, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants