-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[local_auth] Migrate iOS to Pigeon #3974
[local_auth] Migrate iOS to Pigeon #3974
Conversation
packages/local_auth/local_auth_ios/test/local_auth_ios_test.dart
Outdated
Show resolved
Hide resolved
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.
a few questions but overall makes sense
packages/local_auth/local_auth_ios/ios/Classes/FLTLocalAuthPlugin.m
Outdated
Show resolved
Hide resolved
packages/local_auth/local_auth_ios/ios/Classes/FLTLocalAuthPlugin.m
Outdated
Show resolved
Hide resolved
packages/local_auth/local_auth_ios/ios/Classes/FLTLocalAuthPlugin.m
Outdated
Show resolved
Hide resolved
completion([FLAAuthResultDetails makeWithValue:result | ||
errorMessage:authError.localizedDescription | ||
errorDetails:authError.domain], | ||
nil); |
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.
is it more natural to just complete with an NSError here? Or is there any issue for pigeon to handle error case properly?
completion(result, [NSError errorWith...])
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.
oops FlutterError rather.
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.
See comments below.
|
||
class AuthResultDetails { | ||
AuthResultDetails( | ||
{required this.value, this.errorMessage, this.errorDetails}); |
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.
is it standard/recommended to wrap error messages/details in a pigeon method call's return type? this seems a bit tedious.
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'm not sure what you mean by "standard". In practice, it's standard for our plugins to just throw arbitrary PlatformExceptions
from native code and let those escape all the way out to plugin clients do try to do things like match arbitrary strings to figure out what the conceptual errors are. But it shouldn't be.
This design is a logical extension of our recommendation in https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#platform-exception-handling. See the third bullet point in the PR description.
details
is a temporary field that allows making this structural change in the language boundary API separately from the eventual breaking change of reworking the errors/exceptions we return from the plugin.
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 could be missing something, but the signature of completion takes an error, so I assume the "standard" approach is to pass in the error when error occurs:
completion:(void (^)(FLAAuthResultDetails *_Nullable,
FlutterError *_Nullable))completion
About error translation, can we catch the error in local_auth_ios.dart
and translate it, before it escapes into client logic?
In the current approach, however, plugin authors will have to manually include error type/message/details in their custom types, rather than directly using the FlutterError type. This feels a bit tedious to do.
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 could be missing something, but the signature of completion takes an error, so I assume the "standard" approach is to pass in the error when error occurs:
completion:(void (^)(FLAAuthResultDetails *_Nullable, FlutterError *_Nullable))completion
The signature takes an error because that gives Pigeon feature parity with the underlying channel API, such that someone can convert existing implementations to platform channels with minimal changes if they so desire. The existence of the possibility to do something in an API doesn't mean it's always the right way to do everything.
About error translation, can we catch the error in
local_auth_ios.dart
and translate it, before it escapes into client logic?
We could, yes. I explained why I don't want to do that in the part of the PR description that I referred to in my previous comment. Can you explain what about the argument there you disagree with?
In the current approach, however, plugin authors will have to manually include error type/message/details in their custom types, rather than directly using the FlutterError type.
I'm not sure who "plugin authors" is. This is one plugin, which we own. I'm not forcing the entire ecosystem to use this approach if they don't want to.
Also, I've already explained that that's not the case. details
is only there because I don't want this to be a breaking change if clients are relying on exact platform exception details (due to us not having structured errors). That may or may not be true of message
; we'll need to evaluate whether it's useful to preserve as-is in the combined error when the plugin is reworked. I think you are over-indexing on this one particular case that's not representative of the general design. Compare to local_auth_android
, for instance, where we just return an enum because there are no messages or details provided by the OS.
If you really want me to, I can revert that part and go back to throwing PlatformExceptions
directly from native code like we were before, and leave a TODO to recreate this work when we standardize errors. I was trying to do more of that work now and keep iOS more consistent with Android, but it's not required.
This feels a bit tedious to do.
Is it more tedious than defining string constants in both Dart and ObjC for every type that we want to catch and convert, manually verifying that the strings match exactly, and manually verifying that everything we throw is indeed caught in a different file written in a different language?
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 signature takes an error because that gives Pigeon feature parity with the underlying channel API, such that someone can convert existing implementations to platform channels with minimal changes if they so desire.
I did not know that this error
argument is intended for parity with platform channels. Just from the signature alone, I'd expect it to be used whenever an error happens.
We could, yes. I explained why I don't want to do that in the part of the PR description that I referred to in my previous comment. Can you explain what about the argument there you disagree with?
I probably misinterpreted the PR description: it says throwing error, rather than passing the error to completion block. Though you are probably referring to passing the error to completion, which will trigger dart's exception to be thrown.
I'm not sure who "plugin authors" is. This is one plugin, which we own. I'm not forcing the entire ecosystem to use this approach if they don't want to.
I think whatever we do in 1p plugins likely will become something that other plugin authors consider as the "golden standard", so just wanna make sure it's the best practice.
Is it more tedious than defining string constants in both Dart and ObjC for every type that we want to catch and convert, manually verifying that the strings match exactly, and manually verifying that everything we throw is indeed caught in a different file written in a different language?
Good point. This approach is definitely less error-prone than using FlutterError
/PlatformException
. I think extra fields in custom types is worth the benefit then. Are you seeing a world where we don't use FlutterError/PlatformException
at all in 1P plugins with pigeon? (i.e. the completion
's error argument is never used)
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.
Are you seeing a world where we don't use
FlutterError/PlatformException
at all in 1P plugins with pigeon? (i.e. thecompletion
's error argument is never used)
I don't think so at the moment; we'll need to see how things go as we apply the current guidance to more plugins. What it currently says is:
This means that in general, clients of a plugin should not be expected to see raw PlatformExceptions created from error responses in native code. (This is not a strict rule; failure cases that are so obscure that clients would be unlikely to actually have specific handlers for them don't necessarily need to be converted to a common exception type.)
An example of a case where I think this applies would be url_launcher
:
- On iOS, it can throw if you pass an invalid URL according to
NSURL
's definition; this can only happen if you either a) use theString
-based API that we explicitly say in dangerous and you should almost never use and do so incorrectly, or b) manage to need a URL that is a valid DartUri
but not a validNSURL
, which should be exceedingly rare (this is why the String-based API still exists, but I know of only one such case currently and it's very niche). - On Android it can throw if you have no current
Activity
when you try to launch a URL, which would be a pretty weird thing to have happen in actual usage.
I think these both fall under the "unlikely to actually have specific handlers", and there's no cross-platform conceptual thing to map them to because they are so specific, so they seem like valid cases for native errors.
I do expect it to be pretty rare though, as we move toward following the new guidance.
final String? errorMessage; | ||
|
||
/// System-provided error details, if any. | ||
// TODO(stuartmorgan): Remove this when standardizing errors plugin-wide in |
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.
is it because other platforms don't use errorDetails
?
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 because I don't expect there to be anything in this field for these use cases that is actually important enough that we would preserve it for structured errors.
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 LGTM! Don't have anything blocking. Thanks for the explanation.
flutter/packages@1e214d7...83959fb 2023-05-22 JeroenWeener@users.noreply.github.com [in_app_purchases] Fix mismatching method signature strings (flutter/packages#4040) 2023-05-22 tobias@leafnode.se [go_router] Nested stateful navigation with ShellRoute (flutter/packages#2650) 2023-05-22 tobias@leafnode.se [go_router] Nested stateful navigation with ShellRoute (flutter/packages#2650) 2023-05-22 tobias@leafnode.se [go_router] Nested stateful navigation with ShellRoute (flutter/packages#2650) 2023-05-22 engine-flutter-autoroll@skia.org Roll Flutter from 077d644 to ab57304 (18 revisions) (flutter/packages#4051) 2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter from 5ae6438 to 077d644 (23 revisions) (flutter/packages#4043) 2023-05-19 stuartmorgan@google.com [local_auth] Migrate iOS to Pigeon (flutter/packages#3974) 2023-05-19 hamadyalghanim@gmail.com [go_router] fix context extension for replaceNamed (flutter/packages#3927) 2023-05-19 JeroenWeener@users.noreply.github.com [image_picker] Fix crash due to `SecurityException` (flutter/packages#4004) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
* main: (104 commits) [various] Remove unnecessary null checks (flutter#4060) [ci] Add a legacy Android build-all test (flutter#4005) Roll Flutter from ab57304 to 3437189 (5 revisions) (flutter#4062) [go_router] Nested stateful navigation with ShellRoute (flutter#2650) [go_router] Nested stateful navigation with ShellRoute (flutter#2650) [go_router] Nested stateful navigation with ShellRoute (flutter#2650) [in_app_purchases] Fix mismatching method signature strings (flutter#4040) [go_router] Nested stateful navigation with ShellRoute (flutter#2650) [go_router] Nested stateful navigation with ShellRoute (flutter#2650) [go_router] Nested stateful navigation with ShellRoute (flutter#2650) Roll Flutter from 077d644 to ab57304 (18 revisions) (flutter#4051) Roll Flutter from 5ae6438 to 077d644 (23 revisions) (flutter#4043) [local_auth] Migrate iOS to Pigeon (flutter#3974) [go_router] fix context extension for replaceNamed (flutter#3927) [image_picker] Fix crash due to `SecurityException` (flutter#4004) Roll Flutter from d0d1feb to 5ae6438 (42 revisions) (flutter#4038) [ci] Lower iOS LUCI timeouts (flutter#4035) [ci] Increase Android sharding (flutter#4029) [flutter_plugin_android_lifecycle] Fix lints (flutter#4030) [rfw] Fix a typo in the API documentation (flutter#4023) ...
flutter/packages@1e214d7...83959fb 2023-05-22 JeroenWeener@users.noreply.github.com [in_app_purchases] Fix mismatching method signature strings (flutter/packages#4040) 2023-05-22 tobias@leafnode.se [go_router] Nested stateful navigation with ShellRoute (flutter/packages#2650) 2023-05-22 tobias@leafnode.se [go_router] Nested stateful navigation with ShellRoute (flutter/packages#2650) 2023-05-22 tobias@leafnode.se [go_router] Nested stateful navigation with ShellRoute (flutter/packages#2650) 2023-05-22 engine-flutter-autoroll@skia.org Roll Flutter from 077d644 to ab57304 (18 revisions) (flutter/packages#4051) 2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter from 5ae6438 to 077d644 (23 revisions) (flutter/packages#4043) 2023-05-19 stuartmorgan@google.com [local_auth] Migrate iOS to Pigeon (flutter/packages#3974) 2023-05-19 hamadyalghanim@gmail.com [go_router] fix context extension for replaceNamed (flutter/packages#3927) 2023-05-19 JeroenWeener@users.noreply.github.com [image_picker] Fix crash due to `SecurityException` (flutter/packages#4004) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Updates the platform communication to use Pigeon. This includes some changes to the API boundary: - Collected authentication options into an options object; this avoids having a lot of positional boolean arguments (since Pigeon doesn't currently support named arguments). - Collected strings into a strings object, since having them as individual parameters would have been extremely messy. - Changes the `authenticate` return from a bool+exceptions to an enum that encompasses all of the explicitly known failure modes. To avoid a breaking change for clients, the Dart code creates `PlatformException`s that match the old ones, but this will make it much easier to someday make a (cross-platform) breaking change to replace them with better errors per the best practices we have documented on the wiki. Using an enum rather than throwing errors avoids the need to do string matching when we want to eventually translate them into something other than `PlatformException`. The Pigeon file, Dart implementation, and rewritten tests are all based very heavily on the recent Android migration: flutter#3748 I noted several bugs that I noticed in the existing implementation during the migration. I intentionally didn't fix them so this isn't changing behavior at the same time that it's changing so much of the code and tests, but I marked them with TODO comments. Fixes flutter/flutter#117912
Updates the platform communication to use Pigeon. This includes some changes to the API boundary:
authenticate
return from a bool+exceptions to an enum that encompasses all of the explicitly known failure modes. To avoid a breaking change for clients, the Dart code createsPlatformException
s that match the old ones, but this will make it much easier to someday make a (cross-platform) breaking change to replace them with better errors per the best practices we have documented on the wiki. Using an enum rather than throwing errors avoids the need to do string matching when we want to eventually translate them into something other thanPlatformException
.The Pigeon file, Dart implementation, and rewritten tests are all based very heavily on the recent Android migration: #3748
I noted several bugs that I noticed in the existing implementation during the migration. I intentionally didn't fix them so this isn't changing behavior at the same time that it's changing so much of the code and tests, but I marked them with TODO comments.
Fixes flutter/flutter#117912
Pre-launch Checklist
dart format
.)[shared_preferences]
pubspec.yaml
with an appropriate new version according to the pub versioning philosophy, or this PR is exempt from version changes.CHANGELOG.md
to add a description of the change, following repository CHANGELOG style.///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.