build: Android's built-in Kotlin, the three plugins applying KGP themselves patched in third_party/
AGP 9 compiles Kotlin itself (android.builtInKotlin=true in every app), and warns that applying the Kotlin Gradle Plugin will soon fail. flutter_web_auth_2 5.1.0, keyboard_height_plugin 0.3.0 and flutter_tts 4.2.5 still apply it unconditionally, so their pub releases are copied into third_party/ with only their android/build.gradle changed, and the root overrides them by path (third_party/README.md says when to drop each). The servers' images copy third_party/, as pub refuses an override whose path is missing. third_party/ isn't our own code: left out of the analysis and the format check. All four apps' APKs build without the warning. A Kotlin daemon's session file that slipped into Train's android/ goes, and every app's android/.gitignore keeps .kotlin/ out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
396e010949
commit
438ce20dbf
36 changed files with 8440 additions and 23 deletions
406
third_party/flutter_web_auth_2/CHANGELOG.md
vendored
Normal file
406
third_party/flutter_web_auth_2/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,406 @@
|
|||
## 6.0.0-alpha.7
|
||||
|
||||
- 🐛 Handle missing `authUri`/`callbackScheme` gracefully (Thanks to [@md-shohan-ahmed](https://github.com/md-shohan-ahmed) in [#209](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/209), related to [#207](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/207))
|
||||
|
||||
## 5.1.0
|
||||
|
||||
- 🐛 Catch `SecurityException` when launching the auth tab (Thanks to [@hokeroid](https://github.com/hokeroid) in [#212](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/212), related to [#211](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/211))
|
||||
- 🐛 Handle missing `authUri`/`callbackScheme` gracefully (Thanks to [@md-shohan-ahmed](https://github.com/md-shohan-ahmed) in [#209](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/209), related to [#207](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/207))
|
||||
|
||||
## 6.0.0-alpha.6
|
||||
|
||||
- 🐛 Catch `SecurityException` when launching the auth tab (Thanks to [@hokeroid](https://github.com/hokeroid) in [#212](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/212), related to [#211](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/211))
|
||||
|
||||
## 6.0.0-alpha.5
|
||||
|
||||
- 🌹 Allow `window_to_front` versions `1.x`
|
||||
- 🌹 Bump `melos` to `8.x`
|
||||
|
||||
## 6.0.0-alpha.4
|
||||
|
||||
- 💥 Drop support for `web` versions `0.x`
|
||||
- 🌹 Bump `window_to_front` to `0.1.0`
|
||||
|
||||
## 6.0.0-alpha.3
|
||||
|
||||
- 🐛 Refactor error handling to use Swift `Error` type for improved compatibility (Thanks to [@Abhishek-Khanal](https://github.com/Abhishek-Khanal) in [#204](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/204))
|
||||
|
||||
## 6.0.0-alpha.2
|
||||
|
||||
- 💥 Bump Flutter and Dart SDK constraints to `3.44.0` and `3.12.0` stable, respectively
|
||||
- 🌹 Enhancement: provide detailed error information in FlutterError responses for iOS and macOS (Thanks to [@Abhishek-Khanal](https://github.com/Abhishek-Khanal) in [#200](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/200))
|
||||
- 🌹 Migrate iOS plugin to UIScene lifecycle (Thanks to [@alihamza0173](https://github.com/alihamza0173) in [#201](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/201))
|
||||
|
||||
## 6.0.0-alpha.1
|
||||
|
||||
- 🌹 Bump `desktop_webview_window` to `0.3.0`
|
||||
|
||||
## 5.0.3
|
||||
|
||||
- 🌹 Bump `desktop_webview_window` to `0.3.0`
|
||||
|
||||
## 6.0.0-alpha.0
|
||||
|
||||
- 💥 Bump Flutter and Dart SDK constraints to `3.44.0` and `3.12.0` betas, respectively
|
||||
- 💥 Regenerate entire project skeleton (also migrates to built-in Kotlin)
|
||||
- 💥 Rename `cleanUpDanglingCalls` -> `clearAllDanglingCalls` (unification)
|
||||
|
||||
## 5.0.2
|
||||
|
||||
- 🐛 Fix possible NPE on Android (Thanks to [@henry11996](https://github.com/henry11996) in [#196](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/196))
|
||||
- 🌹 Dummy implementation for `cleanUpDanglingCalls` on web to prevent unneeded crashes
|
||||
|
||||
## 5.0.1
|
||||
|
||||
- 🐛 Fix crash on Android and implement proper feedback if no browser is installed (Thanks to [@Mino5531](https://github.com/Mino5531) in [#190](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/190))
|
||||
|
||||
## 5.0.0
|
||||
|
||||
*No changes - just the official version release!*
|
||||
|
||||
## 5.0.0-alpha.7
|
||||
|
||||
- 🌹 Update Android intricacies
|
||||
- 🐛 Revert to `CustomTabsIntent` when needed (Thanks to [@StevenSorial](https://github.com/StevenSorial) in [#181](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/181))
|
||||
|
||||
## 5.0.0-alpha.6
|
||||
|
||||
- 🌹 Fix ephemeral web views on Android; re-introduces `preferEphemeral` on Android for more iOS/Android parity (Thanks to [@ApofisXII](https://github.com/ApofisXII) in [#180](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/180), related to [#169](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/169))
|
||||
|
||||
## 5.0.0-alpha.5
|
||||
|
||||
- 🌹 Include more error details on iOS (Thanks to [@PawlikMichal25](https://github.com/PawlikMichal25) in [#179](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/179), related to [#178](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/178))
|
||||
|
||||
## 5.0.0-alpha.4
|
||||
|
||||
- 🌹 Update melos to regular `7.x` releases
|
||||
- 🌹 Update linter to `6.x`
|
||||
- 🌹 Fix a few Android warnings (Gradle `9.x` complaints)
|
||||
|
||||
## 5.0.0-alpha.3
|
||||
|
||||
- 💥 Migrate to Swift Package Manager - see [here](https://docs.flutter.dev/packages-and-plugins/swift-package-manager/for-app-developers) for more info (Thanks to [@lishaduck](https://github.com/lishaduck) in [#165](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/165))
|
||||
|
||||
## 5.0.0-alpha.2
|
||||
|
||||
- 💥 Even newer Android authentication approach (Thanks to [@titanous](https://github.com/titanous) in [#163](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/163))
|
||||
- 🌹 Add auto-close to old server method default landing page on Windows and Linux
|
||||
|
||||
## 5.0.0-alpha.1
|
||||
|
||||
- 🌹 Added migration guide for `5.x` and updated migration guide for `4.x`
|
||||
|
||||
## 5.0.0-alpha.0
|
||||
|
||||
- 💥 Update melos to `7.x` (requires SDK `>=3.5.0`)
|
||||
- 💥 New Android authentication approach (Thanks to [@Mino5531](https://github.com/Mino5531) in [#156](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/156))
|
||||
|
||||
## 4.1.0
|
||||
|
||||
- 🌹 Add host and path comparator to webview implementation (related to [#146](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/146))
|
||||
- 🐛 Hopefully fix WASM compatibility
|
||||
|
||||
## 4.0.2
|
||||
|
||||
- 🌹 Improve README (additions to migration guide and Google scopes)
|
||||
|
||||
## 4.0.1
|
||||
|
||||
- 🌹 Update `flutter_lints` to `5.x` - should not really change anything!
|
||||
|
||||
## 4.0.0
|
||||
|
||||
*No changes - just the official version release!*
|
||||
|
||||
## 4.0.0-alpha.9
|
||||
|
||||
- 🐛 Fix Chrome always taking precedence on Android (Thanks to [@obrand69](https://github.com/obrand69) in [#125](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/125))
|
||||
|
||||
## 4.0.0-alpha.8
|
||||
|
||||
- 🌹 Allow also `web` versions `0.5.x` again (Thanks to [@Rexios80](https://github.com/Rexios80) in [#118](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/118))
|
||||
- 🌹 Improve documentation
|
||||
|
||||
## 4.0.0-alpha.7
|
||||
|
||||
- 🎉 Enable `ASWebAuthenticationSession.Callback.https` support to fix Universal Links on iOS (Thanks to [@GabrielDamasceno](https://github.com/GabrielDamasceno) in [#117](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/117), related to [#65](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/65) and [#104](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/104))
|
||||
- 🌹 Update `web` to `1.x`
|
||||
|
||||
## 4.0.0-alpha.6
|
||||
|
||||
- 🌹 Allow custom browser priority and rework Android code (Thanks to [@kecson](https://github.com/kecson) in [#111](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/111))
|
||||
- 🌹 Enable partial `ASWebAuthenticationSession.Callback` support (related to [#104](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/104))
|
||||
|
||||
## 4.0.0-alpha.5
|
||||
|
||||
- 💥 Remove Android embedding v1 support (in accordance with Flutter `3.22.0`)
|
||||
- 💥 Increase Android min SDK to `21` (in accordance with Flutter `3.22.0`)
|
||||
- 💥 Increase Android JVM version to `11` (in accordance with Flutter `3.22.0`)
|
||||
- 🌹 Update AndroidX browser to `1.8.0`
|
||||
- 🌹 Migrate Android and Web examples to newest standards
|
||||
|
||||
## 4.0.0-alpha.4
|
||||
|
||||
- 🐛 Fix recursion errors in Flutter `3.22.0`
|
||||
- 🌹 Update dependencies (`melos` and `flutter_lints`)
|
||||
|
||||
## 3.1.2
|
||||
|
||||
- 🐛 Fix recursion errors in Flutter `3.22.0`
|
||||
- 🌹 Update `melos` to `5.1.0` to have cleaner CI commands
|
||||
|
||||
## 4.0.0-alpha.3
|
||||
|
||||
- 🐛 Fix `iframe` approach
|
||||
- 🌹 Update `melos` to `5.1.0` to have cleaner CI commands
|
||||
|
||||
## 4.0.0-alpha.2
|
||||
|
||||
- 🌹 Migrate to `web` package
|
||||
|
||||
## 4.0.0-alpha.1
|
||||
|
||||
- 🌹 Fix lint for Flutter 3.19.x
|
||||
|
||||
## 4.0.0-alpha.0
|
||||
|
||||
- 🎉 Add Webview approach for Windows and Linux (Thanks to [@Mino5531](https://github.com/Mino5531) in [#92](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/92))
|
||||
|
||||
## 3.1.1
|
||||
|
||||
- 🐛 Fix null-safe options (again)
|
||||
|
||||
## 3.1.0
|
||||
|
||||
- 🎉 Implement `iframe` authentication approach (Thanks to [@rundfunk47](https://github.com/rundfunk47) in [#88](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/88))
|
||||
- 🌹 Fix lint for Flutter 3.16.x
|
||||
|
||||
## 3.0.4
|
||||
|
||||
- 🐛 Fix null-safe options
|
||||
|
||||
## 3.0.3
|
||||
|
||||
- 🌹 Fix Web implementation not being found properly (See [#82](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/82))
|
||||
|
||||
## 3.0.2
|
||||
|
||||
- 🌹 Fix deprecations in Gradle 8.x
|
||||
|
||||
## 3.0.1
|
||||
|
||||
- 🌹 Better null-safe options
|
||||
|
||||
## 3.0.0
|
||||
|
||||
- 💥 Release next major version, yay!
|
||||
- 🐛 Fix Apple implementations
|
||||
|
||||
## 3.0.0-alpha.6
|
||||
|
||||
- 🐛 Trying a few attempts to fix iOS implementations
|
||||
|
||||
## 3.0.0-alpha.5
|
||||
|
||||
- 🌹 Fix iOS "screenshot"
|
||||
- 🐛 Trying a few attempts to fix iOS and MacOS implementations
|
||||
|
||||
## 3.0.0-alpha.4
|
||||
|
||||
- 🐛 Trying a few attempts to fix iOS and MacOS implementations
|
||||
|
||||
## 3.0.0-alpha.3
|
||||
|
||||
- 🌹 Add more entries to the pubspec
|
||||
- 🌹 Add reference to `android_intent_plus`
|
||||
|
||||
## 3.0.0-alpha.2
|
||||
|
||||
- 🎉 Customizable landing page on Windows and Linux
|
||||
- 🌹 Update some files from official Flutter template
|
||||
|
||||
## 3.0.0-alpha.1
|
||||
|
||||
- 🐛 Update platform interface version
|
||||
|
||||
## 3.0.0-alpha.0
|
||||
|
||||
- 💥 Bump Dart SDK constraints to `>=2.15.0`
|
||||
- 💥 Huge refactor with more configuration possibilities
|
||||
- 🎉 Add `melos` to project
|
||||
- 🌹 Cleanup Android implementation
|
||||
|
||||
## 2.2.1
|
||||
|
||||
- 🌹 Timeouts (5 minutes) on Web throw real errors now
|
||||
|
||||
## 2.2.0
|
||||
|
||||
- 🎉 Add fallback for `window.opener` being `null` on Web (See [#58](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/58)) **(See enhanced/better setup instructions for Web in the README!)**
|
||||
- 🌹 Add delay to example
|
||||
- 🌹 Bring back support for older AGP versions
|
||||
- 🐛 Fix `compileOptions` on Android (See [#59](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/59))
|
||||
|
||||
## 2.1.5
|
||||
|
||||
- 🌹 Fix example support for Dart `3.x`
|
||||
- 🐛 Implement protocol handler to supply `ASPresentationAnchor` (See [#51](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/51))
|
||||
|
||||
## 2.1.4
|
||||
|
||||
- 🌹 Fix support for Dart `3.x`
|
||||
- 🌹 Support AGP `8.x` namespace declaration
|
||||
- 🌹 Fix web example to work "properly"
|
||||
- 🐛 Update `flutter_web_auth_2_platform_interface` to require `2.1.4` at least
|
||||
|
||||
## 2.1.3
|
||||
|
||||
- 🌹 Add `contextArgs` for web implementations (See [#40](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/40))
|
||||
|
||||
## 2.1.2
|
||||
|
||||
- 🐛 Downgrade Kotlin to fix some compatibility issues
|
||||
|
||||
## 2.1.1
|
||||
|
||||
- 🌹 Fix formatting
|
||||
|
||||
## 2.1.0
|
||||
|
||||
- 🎉 Add support for Linux ([#31](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/31))
|
||||
- 🌹 Get rid of dependency on `win32` and `ffi` by using `window_to_front` instead
|
||||
- 🌹 Update linter rules
|
||||
- 🌹 Update Android dependencies
|
||||
|
||||
## 2.0.4
|
||||
|
||||
- 🐛 Partially fix ([#135](https://github.com/LinusU/flutter_web_auth/issues/135))
|
||||
- 🌹 Support `win32` versions `2.7.0` until `4.x`
|
||||
- 🌹 Fix typos in README
|
||||
|
||||
## 2.0.3
|
||||
|
||||
- 🌹 Add Universal link support ([#26](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/26))
|
||||
- 🌹 Some small documentation changes
|
||||
|
||||
## 2.0.2
|
||||
|
||||
- 🐛 Fix windows callback verification ([#22](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/22))
|
||||
- 🐛 Force-update platform interface ([#21](https://github.com/ThexXTURBOXx/flutter_web_auth_2/pull/21))
|
||||
|
||||
## 2.0.1
|
||||
|
||||
- 🌹 Merge upstream changes (most notably troubleshooting documentation)
|
||||
- 🌹 Added `redirectOriginOverride` for web implementations (By [Rexios80](https://github.com/Rexios80))
|
||||
- 🌹 Fix some documentation and changelogs
|
||||
|
||||
## 2.0.0
|
||||
|
||||
- 💥 Full two-package federated plugin refactor
|
||||
|
||||
## 1.1.2
|
||||
|
||||
- 🌹 Support `win32` versions `2.7.0` until `3.x`
|
||||
|
||||
## 1.1.1
|
||||
|
||||
- 🐛 Fix Windows support and support for future platforms
|
||||
- 🐛 Fix example on Windows
|
||||
- 🌹 `127.0.0.1` is now also a supported callback URL host on Windows
|
||||
- 🌹 Cleaned up platform implementations
|
||||
|
||||
## 1.1.0
|
||||
|
||||
- 🌹 Tested `flutter_web_auth_2` with Flutter `3.3.0`, seems to work!
|
||||
- 🌹 Update `win32` to `3.0.0` (relevant only for Windows users)
|
||||
- 🌹 Add `android:exported` tag to documentation *before* users start to complain
|
||||
- 🌹 Overhauled example layout
|
||||
|
||||
## 1.0.1
|
||||
|
||||
- 🐛 Remove path dependency
|
||||
- 🌹 Add migration guide README
|
||||
- 🌹 Add more documentation
|
||||
|
||||
## 1.0.0
|
||||
|
||||
- 💥 Old project, new maintainers! Due to the lack of updates in the main project, we forked the project and will update it as time passes!
|
||||
- 💥 Update to Flutter 3 ([#118](https://github.com/LinusU/flutter_web_auth/pull/118))
|
||||
- 💥 Federated plugin refactor ([#98](https://github.com/LinusU/flutter_web_auth/pull/98))
|
||||
- 💥 Windows support (By [Jon-Salmon](https://github.com/Jon-Salmon/flutter_web_auth/tree/windows-implementation))
|
||||
- 🎉 Add support for ephemeral sessions on MacOS ([#112](https://github.com/LinusU/flutter_web_auth/pull/112))
|
||||
|
||||
## 0.4.1
|
||||
|
||||
- 🎉 Add support for Flutter "add to app" ([#106](https://github.com/LinusU/flutter_web_auth/pull/106))
|
||||
|
||||
## 0.4.0
|
||||
|
||||
- 💥 Upgrade to Android V2 embedding ([#87](https://github.com/LinusU/flutter_web_auth/pull/87))
|
||||
|
||||
Migration guide:
|
||||
|
||||
Make sure that you are running a recent version of Flutter before upgrading.
|
||||
|
||||
## 0.3.2
|
||||
|
||||
- 🎉 Add Web support ([#77](https://github.com/LinusU/flutter_web_auth/pull/77))
|
||||
|
||||
## 0.3.1
|
||||
|
||||
- 🎉 Add support for Android Plugin API v2 ([#67](https://github.com/LinusU/flutter_web_auth/pull/67))
|
||||
- 🎉 Add support for ephemeral sessions ([#64](https://github.com/LinusU/flutter_web_auth/pull/64))
|
||||
- 🌹 Avoid deprecated RaisedButton in example ([#75](https://github.com/LinusU/flutter_web_auth/pull/75))
|
||||
- 🌹 Cleanup metadata
|
||||
|
||||
## 0.3.0
|
||||
|
||||
- 💥 Add null safety support ([#60](https://github.com/LinusU/flutter_web_auth/pull/60))
|
||||
|
||||
Migration guide:
|
||||
|
||||
This version drops support for Flutter 1.x, please upgrade to Flutter 2 for continued support.
|
||||
|
||||
## 0.2.4
|
||||
|
||||
- 🐛 Fix building on iOS ([#36](https://github.com/LinusU/flutter_web_auth/pull/36))
|
||||
|
||||
## 0.2.3
|
||||
|
||||
- 🐛 Remove NoHistory flag ([#33](https://github.com/LinusU/flutter_web_auth/pull/33))
|
||||
- 🐛 Fix building on iOS 8, 9, and 10 ([#29](https://github.com/LinusU/flutter_web_auth/pull/29))
|
||||
- 🐛 Always terminate 'authenticate' callbacks on Android ([#28](https://github.com/LinusU/flutter_web_auth/pull/28))
|
||||
|
||||
## 0.2.2
|
||||
|
||||
- 🐛 Fix propagation of "CANCELED" error on iOS ([#31](https://github.com/LinusU/flutter_web_auth/pull/31))
|
||||
|
||||
## 0.2.1
|
||||
|
||||
- 🐛 Fix AndroidX build issues ([#27](https://github.com/LinusU/flutter_web_auth/pull/27))
|
||||
|
||||
## 0.2.0
|
||||
|
||||
- 💥 Add macOS support ([#20](https://github.com/LinusU/flutter_web_auth/pull/20))
|
||||
|
||||
Migration guide:
|
||||
|
||||
This version drops support for Flutter 1.9 and older, please upgrade to Flutter 1.12 for continued support.
|
||||
|
||||
## 0.1.3
|
||||
|
||||
- 🎉 Update the kotlin plugin version to 1.3.61
|
||||
|
||||
## 0.1.2
|
||||
|
||||
- 🎉 Add support for iOS 13
|
||||
|
||||
## 0.1.1
|
||||
|
||||
- 🐛 Add swift_version to the Podspec
|
||||
- 🐛 Update Gradle and Kotlin versions
|
||||
- 🐛 Add missing link in readme
|
||||
|
||||
## 0.1.0
|
||||
|
||||
- 🎉 Add initial implementation
|
||||
9
third_party/flutter_web_auth_2/LICENSE
vendored
Normal file
9
third_party/flutter_web_auth_2/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Linus Unnebäck
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
396
third_party/flutter_web_auth_2/README.md
vendored
Normal file
396
third_party/flutter_web_auth_2/README.md
vendored
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
# Web Auth 2 for Flutter
|
||||
|
||||
**This project is a continuation of [flutter_web_auth](https://github.com/LinusU/flutter_web_auth) by Linus Unnebäck with many new features and bug fixes.**
|
||||
|
||||
[](https://github.com/invertase/melos)
|
||||
|
||||
A Flutter plugin for authenticating a user with a web service, even if the web service is run by a third party. Most commonly used with OAuth2, but can be used with any web flow that can redirect to a custom scheme.
|
||||
|
||||
In the background, this plugin uses [`ASWebAuthenticationSession`](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession) on iOS 12+ and macOS 10.15+, [`SFAuthenticationSession`](https://developer.apple.com/documentation/safariservices/sfauthenticationsession) on iOS 11, [Chrome Auth Tab](https://developer.chrome.com/docs/android/custom-tabs/guide-auth-tab) on Android and opens a new window on Web. You can build it with iOS 8+, but it is currently only supported by iOS 11 or higher.
|
||||
|
||||
<!-- TODO: Replace with a nicer GIF
|
||||
| **iOS** | **Android** |
|
||||
| ---------------------- | ------------------------------ |
|
||||
|  |  |
|
||||
|
||||
| **macOS** |
|
||||
| -------------------------- |
|
||||
|  |
|
||||
-->
|
||||
|
||||
## Usage
|
||||
|
||||
Add the following snippet to your `pubspec.yaml` and follow the [Setup guide](#setup):
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
flutter_web_auth_2: ^5.0.0
|
||||
```
|
||||
|
||||
To authenticate against your own custom site:
|
||||
|
||||
```dart
|
||||
import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';
|
||||
|
||||
// Present the dialog to the user
|
||||
final result = await FlutterWebAuth2.authenticate(url: "https://my-custom-app.com/connect", callbackUrlScheme: "my-custom-app");
|
||||
|
||||
// Extract token from resulting url
|
||||
final token = Uri.parse(result).queryParameters['token'];
|
||||
```
|
||||
|
||||
To authenticate the user using Google's OAuth2:
|
||||
|
||||
```dart
|
||||
import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';
|
||||
|
||||
import 'dart:convert' show jsonDecode;
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
// App specific variables
|
||||
final googleClientId = 'XXXXXXXXXXXX-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com';
|
||||
final callbackUrlScheme = 'com.googleusercontent.apps.XXXXXXXXXXXX-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
|
||||
|
||||
// Construct the url
|
||||
final url = Uri.https('accounts.google.com', '/o/oauth2/v2/auth', {
|
||||
'response_type': 'code',
|
||||
'client_id': googleClientId,
|
||||
'redirect_uri': '$callbackUrlScheme:/',
|
||||
'scope': 'email',
|
||||
});
|
||||
|
||||
// Present the dialog to the user
|
||||
final result = await FlutterWebAuth2.authenticate(url: url.toString(), callbackUrlScheme: callbackUrlScheme);
|
||||
|
||||
// Extract code from resulting url
|
||||
final code = Uri.parse(result).queryParameters['code'];
|
||||
|
||||
// Construct an Uri to Google's oauth2 endpoint
|
||||
final url = Uri.https('www.googleapis.com', 'oauth2/v4/token');
|
||||
|
||||
// Use this code to get an access token
|
||||
final response = await http.post(url, body: {
|
||||
'client_id': googleClientId,
|
||||
'redirect_uri': '$callbackUrlScheme:/',
|
||||
'grant_type': 'authorization_code',
|
||||
'code': code,
|
||||
});
|
||||
|
||||
// Get the access token from the response
|
||||
final accessToken = jsonDecode(response.body)['access_token'] as String;
|
||||
```
|
||||
|
||||
**Note (Google multiple scopes):** To use multiple scopes with Google, you need to encode them as a single string, separated by spaces (`%20`). For example, `scope: 'email https://www.googleapis.com/auth/userinfo.profile'`. Here is [a list of all supported scopes](https://developers.google.com/identity/protocols/oauth2/scopes).
|
||||
|
||||
**Note (ephemeral auth):** Due to a [known Chrome bug](https://issuetracker.google.com/issues/444173718), when setting `preferEphemeral: true` on Android with Chrome < 141, the package will launch an auth session with older implementation to avoid crashes.
|
||||
|
||||
## Migration
|
||||
|
||||
### Upgrading to `5.x`
|
||||
|
||||
The following constraints have been added in `5.0.0`:
|
||||
- The existing Android approach has been replaced with a new (improved) one (no migration necessary; is automatically used)
|
||||
- Android now uses Auth Tab: `httpsHost` and `httpsPath` are now required on Android if you are using a `https` in `callbackUrlScheme`
|
||||
- On Android, issues with `taskAffinity`s have been fixed and it is strongly advised to set `android:taskAffinity=""` for all exported `Activity`s (this usually includes your `MainActivity` and `flutter_web_auth_2`'s `CallbackActivity`)
|
||||
- Dart SDK `>=3.5.0` is now required (due to migration to melos `7.x`)
|
||||
- If you want ephemeral authentication on Android, use `preferEphemeral` instead of `ephemeralIntentFlags` as `intentFlags` have other influences now
|
||||
|
||||
### Upgrading to `4.x`
|
||||
|
||||
Generally, the following constraints have been added in version `4.0.0`:
|
||||
- Android embedding v1 support has been removed (it was deprecated already long ago)
|
||||
- Android min SDK and JVM version has been increased to 21 and 11, respectively (in accordance with
|
||||
Flutter `3.22.0`)
|
||||
- Migrated away from deprecated iOS and macOS functions (now iOS 17.4 and macOS 14.4 are required!)
|
||||
|
||||
Version `4.0.0` also introduced a new approach for Linux and Windows to authenticate users - using
|
||||
Webview APIs. Hence, you only need to change your code if you are targeting Linux or Windows.
|
||||
If you are fine with still using the old version, here is what you need to change:
|
||||
- Pass `useWebview: false` into the options of your call to `authenticate`, like so:
|
||||
```dart
|
||||
final result = await FlutterWebAuth2.authenticate(
|
||||
url: url,
|
||||
callbackUrlScheme: 'foobar',
|
||||
options: const FlutterWebAuth2Options(useWebview: false),
|
||||
);
|
||||
```
|
||||
|
||||
If you want to use the new approach (**default behaviour!**), you need to do a bit more:
|
||||
- Follow the "Getting started" guide of
|
||||
[desktop_webview_window](https://pub.dev/packages/desktop_webview_window#getting-started)
|
||||
- Make sure that your users know about the new requirements, as described
|
||||
[here](https://pub.dev/packages/desktop_webview_window)
|
||||
|
||||
Last, but not least, version `4.0.0` also added *full* support for Universal links on iOS and macOS!
|
||||
In order to do this, two additional options have been added (which are *required* if
|
||||
`callbackUrlScheme` is `https`!):
|
||||
- `httpsHost` is the host of the callback URL
|
||||
- `httpsPath` is the path of the callback URL
|
||||
|
||||
### Upgrading to `3.x`
|
||||
|
||||
Version `3.0.0` featured a huge refactor which made it possible to maintain even more configuration
|
||||
possibilities. Even platform-specific ones! If you want to upgrade, you need to do the following:
|
||||
- Follow the [Setup] within this README again for your platform and do it from scratch (there might
|
||||
be changes!)
|
||||
- Dart SDK constraints have been updated to `>=2.15.0`.
|
||||
- The configuration parameters have been removed from the `authenticate` function. Now, you have to
|
||||
pass a `FlutterWebAuth2Options` object with those options in it instead:
|
||||
- `contextArgs`: This is now called `windowName` within `FlutterWebAuth2Options`.
|
||||
- `redirectOriginOverride`: This is now called `debugOrigin` within `FlutterWebAuth2Options`.
|
||||
- `preferEphemeral`: This has been split into the two named parameters `preferEphemeral` (for
|
||||
iOS and MacOS) and `intentFlags` (for Android) within `FlutterWebAuth2Options`. The former works
|
||||
exactly the same. However, if you want the old behaviour using `preferEphemeral` on Android, use
|
||||
the `ephemeralIntentFlags` constant as value for `intentFlags`. **(THIS WAS REVERTED IN 5.x)**
|
||||
|
||||
### Upgrading from `flutter_web_auth`
|
||||
|
||||
If you used `flutter_web_auth` correctly (and without extra hackage) before, it should be sufficient to replace the following strings *everywhere* (yes, also in `AndroidManifest.xml` for example):
|
||||
- `FlutterWebAuth` -> `FlutterWebAuth2`
|
||||
- `flutter_web_auth` -> `flutter_web_auth_2`
|
||||
|
||||
If you are using versions `>= 3.0.0`, you also need to follow the migration guide(s) above!
|
||||
|
||||
If you are still unsure or something is not working as well as before, please [open a new issue](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/new/choose).
|
||||
|
||||
### Built-in KGP/AGP 9+ support
|
||||
|
||||
If you need to use built-in Kotlin Gradle plugin or Android Gradle Plugin 9+, use versions `6.x`.
|
||||
|
||||
## Setup
|
||||
|
||||
Setup is the same as for any Flutter plugin, with the following caveats:
|
||||
|
||||
### Android
|
||||
|
||||
In order to capture the callback url, the following `activity` needs to be added to your `AndroidManifest.xml`. Be sure to replace `YOUR_CALLBACK_URL_SCHEME_HERE` with your actual callback url scheme.
|
||||
|
||||
```xml
|
||||
<manifest>
|
||||
<application>
|
||||
|
||||
<activity
|
||||
android:name="com.linusu.flutter_web_auth_2.CallbackActivity"
|
||||
android:exported="true"
|
||||
android:taskAffinity="">
|
||||
<intent-filter android:label="flutter_web_auth_2">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="YOUR_CALLBACK_URL_SCHEME_HERE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
```
|
||||
|
||||
If you are using `http` or `https` as your callback scheme, you also need to specify a host etc.
|
||||
See [c:geo](https://github.com/cgeo/cgeo/blob/d7ab67629ac4798adaae194e563afe7df134fcd0/main/AndroidManifest.xml#L164) as an example for this.
|
||||
|
||||
### iOS
|
||||
|
||||
For "normal" authentication, just use this library as usual; there is nothing special to do!
|
||||
|
||||
To authenticate using [Universal Links](https://developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html)
|
||||
on iOS, use `https` as the provided `callbackUrlScheme`:
|
||||
|
||||
```dart
|
||||
final result = await FlutterWebAuth2.authenticate(url: "https://my-custom-app.com/connect", callbackUrlScheme: "https");
|
||||
```
|
||||
|
||||
### Web
|
||||
|
||||
On the Web platform, an endpoint must be created that captures the callback URL and sends it to the application using the JavaScript `postMessage()` method. In the `./web` folder of the project, create an HTML file named, e.g. `auth.html` with content:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<title>Authentication complete</title>
|
||||
<p>Authentication is complete. If this does not happen automatically, please close the window.</p>
|
||||
<script>
|
||||
function postAuthenticationMessage() {
|
||||
const message = {
|
||||
'flutter-web-auth-2': window.location.href
|
||||
};
|
||||
|
||||
if (window.opener) {
|
||||
window.opener.postMessage(message, window.location.origin);
|
||||
window.close();
|
||||
} else if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage(message, window.location.origin);
|
||||
} else {
|
||||
localStorage.setItem('flutter-web-auth-2', window.location.href);
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
|
||||
postAuthenticationMessage();
|
||||
</script>
|
||||
```
|
||||
|
||||
This HTML file is designed to handle both traditional `window`-based and `iframe`-based authentication flows. The JavaScript code checks the context and sends the authentication response accordingly.
|
||||
|
||||
The redirect URL passed to the authentication service must be the same as the URL the application is running on (schema, host, port if necessary) and the path must point to the generated HTML file, in this case `/auth.html`. The `callbackUrlScheme` parameter of the `authenticate()` method does not take this into account, so it is possible to use a schema for native platforms in the code.
|
||||
|
||||
For the Sign in with Apple in web_message response mode, postMessage from https://appleid.apple.com is also captured, and the authorisation object is returned as a URL fragment encoded as a query string (for compatibility with other providers).
|
||||
|
||||
Additional parameters for the URL open call can be passed in the `authenticate` function using the `windowName` parameter from the options. The `silentAuth` parameter can be used to enable silent authentication within a hidden `iframe`, rather than opening a new window or tab. This is particularly useful for scenarios where a full-page redirect is not desirable. Setting this parameter to `true` allows for a seamless user experience by performing authentication in the background, making it ideal for token refreshes or maintaining user sessions without requiring explicit interaction from the user.
|
||||
|
||||
### Windows and Linux
|
||||
|
||||
When using `useWebview: false`, there is a limitation that the callback URL scheme must start with `http://localhost:{port}`.
|
||||
|
||||
When specifying `useWebview: true` (which is the default behaviour), you need to make sure to follow [desktop_webview_window's guide](https://pub.dev/packages/desktop_webview_window).
|
||||
Also be aware that your users might need to install a Webview API (which is preinstalled on Windows 11 and some Windows 10 and Linux installations).
|
||||
For details, see also desktop_webview_window's guide above.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
When you use this package for the first time, you may experience some problems. These are some of the most common solutions:
|
||||
|
||||
### General troubleshooting steps
|
||||
|
||||
1. Stop the application if it is running.
|
||||
2. Run the following commands:
|
||||
- `flutter clean`
|
||||
- `flutter pub upgrade`
|
||||
3. Rerun the application after executing the above commands. Sometimes, they work wonders!
|
||||
|
||||
### Troubleshooting `callbackUrlScheme`
|
||||
|
||||
- `callbackUrlScheme` must be a valid schema string or else this library won't work
|
||||
- A valid RFC 3986 URL scheme must consist of "a letter and followed by any combination of letters, digits, plus "`+`", period "`.`", or hyphen "`-`"
|
||||
- scheme = `ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )`
|
||||
- This means you can not use underscore "`_`", space "` `" or uppercase "`ABCDEF...`". It must also not start with a number. See [RFC3986#page-17](https://www.rfc-editor.org/rfc/rfc3986#page-17)
|
||||
- Examples of VALID `callbackUrlScheme`s are `callback-scheme`, `another.scheme`, `examplescheme`
|
||||
- Examples of INVALID `callbackUrlScheme`s are `callback_scheme`,`1another.scheme`, `exampleScheme`
|
||||
|
||||
### Troubleshooting Flutter App
|
||||
|
||||
- You have to tell the `FlutterWebAuth2.authenticate` function what your `callbackUrlScheme` is.
|
||||
- Example: If your `callbackUrlScheme` is `valid-callback-scheme`, your dart code will look like
|
||||
|
||||
```dart
|
||||
import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';
|
||||
|
||||
// Present the dialog to the user
|
||||
final result = await FlutterWebAuth2.authenticate(url: "https://my-custom-app.com/connect", callbackUrlScheme: "valid-callback-scheme");
|
||||
```
|
||||
|
||||
### Troubleshooting Android
|
||||
|
||||
- You will need to update your `AndroidManifest.xml` to include the `com.linusu.flutter_web_auth_2.CallbackActivity` activity, something like
|
||||
|
||||
```xml
|
||||
<manifest>
|
||||
<application>
|
||||
|
||||
<!-- add the com.linusu.flutter_web_auth_2.CallbackActivity activity -->
|
||||
<activity
|
||||
android:name="com.linusu.flutter_web_auth_2.CallbackActivity"
|
||||
android:exported="true"
|
||||
android:taskAffinity="">
|
||||
<intent-filter android:label="flutter_web_auth_2">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="YOUR_CALLBACK_URL_SCHEME_HERE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
```
|
||||
|
||||
- Example of a valid `AndroidManifest.xml` with VALID `callbackUrlScheme`. In the example below our `callbackUrlScheme` is `valid-callback-scheme`.
|
||||
|
||||
```xml
|
||||
<manifest>
|
||||
<application>
|
||||
<activity
|
||||
android:name="com.linusu.flutter_web_auth_2.CallbackActivity"
|
||||
android:exported="true"
|
||||
android:taskAffinity="">
|
||||
<intent-filter android:label="flutter_web_auth_2">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="valid-callback-scheme" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
```
|
||||
|
||||
- If you are targeting S+ (SDK version 31 and above) you need to provide an explicit value for `android:exported`. If you followed earlier installation instructions, this was not included. Make sure that you add `android:exported="true"` to the `com.linusu.flutter_web_auth.CallbackActivity` activity in your `AndroidManifest.xml` file.
|
||||
|
||||
```diff
|
||||
- <activity android:name="com.linusu.flutter_web_auth_2.CallbackActivity">
|
||||
+ <activity
|
||||
+ android:name="com.linusu.flutter_web_auth_2.CallbackActivity"
|
||||
+ android:exported="true"
|
||||
+ android:taskAffinity="">
|
||||
```
|
||||
|
||||
- If you want to have a callback URL with `http` or `https` scheme, you also need to specify a host etc.
|
||||
See [c:geo](https://github.com/cgeo/cgeo/blob/d7ab67629ac4798adaae194e563afe7df134fcd0/main/AndroidManifest.xml#L164) as an example for this.
|
||||
- In older versions of this package, there was a known problem with task affinities and launch modes (see [#113](https://github.com/ThexXTURBOXx/flutter_web_auth_2/issues/113)). In order to ensure that `flutter_web_auth_2` works correctly on these versions (prior to `5.0.0-alpha.2`), set `android:launchMode="singleTop"` and remove any `android:taskAffinity` entries. This configuration is guaranteed to work. In newer versions, this should not cause problems!
|
||||
|
||||
### Troubleshooting OAuth redirects
|
||||
|
||||
- Your OAuth Provider must redirect to the valid `callbackUrlScheme` + `://`. This mean if your `callbackUrlScheme` is `validscheme`, your OAuth Provider must redirect to `validscheme://`
|
||||
- Example with `PHP`:
|
||||
```php
|
||||
<?php
|
||||
|
||||
header("Location: validscheme://?data1=value1&data2=value2");
|
||||
```
|
||||
|
||||
### Troubleshooting HTML redirects
|
||||
|
||||
- If you are using HTML hyperlinks, it must be a valid `callbackUrlScheme` + `://`. This means that if your `callbackUrlScheme` is `customappname`, your HTML hyperlink should be `customappname://`
|
||||
- Example with `HTML`:
|
||||
|
||||
```html
|
||||
<a href="customappname://?data1=value1&data2=value2">Go Back to App</a>
|
||||
```
|
||||
|
||||
### Troubleshooting passing data to app
|
||||
|
||||
- You can pass data back to your app by adding GET query parameters. This is done by adding a `name=value` type of data after your `callbackUrlScheme` + `://` + `?`
|
||||
- Example to pass `access-token` to your app:
|
||||
|
||||
```text
|
||||
my-callback-schema://?access-token=jdu9292s
|
||||
```
|
||||
|
||||
- You can pass multiple dates by concatenating them with `&`:
|
||||
|
||||
```text
|
||||
my-callback-schema://?data1=value1&data2=value2
|
||||
```
|
||||
|
||||
- Example to pass `access-token` and `user_id` to your app:
|
||||
|
||||
```text
|
||||
my-callback-schema://?access-token=jdu9292s&user_id=23
|
||||
```
|
||||
|
||||
- You can get the data in your app through `Uri.parse(result).queryParameters`:
|
||||
|
||||
```dart
|
||||
// Present the dialog to the user
|
||||
final result = await FlutterWebAuth2.authenticate(url: "https://my-custom-app.com/connect", callbackUrlScheme: "valid-callback-scheme");
|
||||
// Extract token from resulting url
|
||||
String accessToken = Uri.parse(result).queryParameters['access-token'];
|
||||
String userId = Uri.parse(result).queryParameters['user_id'];
|
||||
```
|
||||
|
||||
### Cannot open keyboard on iOS
|
||||
|
||||
This seems to be a bug in `ASWebAuthenticationSession` and no workarounds have been found yet. Please see issue [#120](https://github.com/LinusU/flutter_web_auth/issues/120) for more info.
|
||||
|
||||
### Error on macOS if Chrome is default browser
|
||||
|
||||
This seems to be a bug in `ASWebAuthenticationSession` and no workarounds have been found yet. Please see issue [#136](https://github.com/LinusU/flutter_web_auth/issues/136) for more info.
|
||||
59
third_party/flutter_web_auth_2/android/build.gradle
vendored
Normal file
59
third_party/flutter_web_auth_2/android/build.gradle
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
group = 'com.linusu.flutter_web_auth_2'
|
||||
version = '1.0-SNAPSHOT'
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '2.1.0'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.13.0'
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdk = 36
|
||||
|
||||
if (project.android.hasProperty("namespace")) {
|
||||
namespace = 'com.linusu.flutter_web_auth_2'
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 21
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.browser:browser:1.9.0'
|
||||
implementation 'androidx.activity:activity-ktx:1.10.1'
|
||||
}
|
||||
}
|
||||
|
||||
// Halkyon's patch (4 Nov 2026): Kotlin built into the Android Gradle plugin
|
||||
// (AGP 9, android.builtInKotlin=true) rather than the Kotlin Gradle plugin
|
||||
// applied here, as Flutter's guide for plugin authors has it.
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11
|
||||
}
|
||||
}
|
||||
3
third_party/flutter_web_auth_2/android/gradle.properties
vendored
Normal file
3
third_party/flutter_web_auth_2/android/gradle.properties
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
BIN
third_party/flutter_web_auth_2/android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
third_party/flutter_web_auth_2/android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
third_party/flutter_web_auth_2/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
third_party/flutter_web_auth_2/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
251
third_party/flutter_web_auth_2/android/gradlew
vendored
Normal file
251
third_party/flutter_web_auth_2/android/gradlew
vendored
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
94
third_party/flutter_web_auth_2/android/gradlew.bat
vendored
Executable file
94
third_party/flutter_web_auth_2/android/gradlew.bat
vendored
Executable file
|
|
@ -0,0 +1,94 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
1
third_party/flutter_web_auth_2/android/settings.gradle
vendored
Normal file
1
third_party/flutter_web_auth_2/android/settings.gradle
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
rootProject.name = 'flutter_web_auth_2'
|
||||
17
third_party/flutter_web_auth_2/android/src/main/AndroidManifest.xml
vendored
Normal file
17
third_party/flutter_web_auth_2/android/src/main/AndroidManifest.xml
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.linusu.flutter_web_auth_2">
|
||||
|
||||
<application>
|
||||
<activity android:name="com.linusu.flutter_web_auth_2.AuthenticationManagementActivity" />
|
||||
</application>
|
||||
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.support.customtabs.action.CustomTabsService" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<data android:scheme="https" />
|
||||
</intent>
|
||||
</queries>
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
package com.linusu.flutter_web_auth_2
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.browser.auth.AuthTabIntent
|
||||
import androidx.browser.auth.AuthTabIntent.AuthResult
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError", "UnsafeOptInUsageWarning")
|
||||
class AuthenticationManagementActivity : ComponentActivity() {
|
||||
companion object {
|
||||
const val KEY_AUTH_STARTED: String = "authStarted"
|
||||
const val KEY_AUTH_URI: String = "authUri"
|
||||
const val KEY_AUTH_OPTION_INTENT_FLAGS: String = "authOptionsIntentFlags"
|
||||
const val KEY_AUTH_OPTION_TARGET_PACKAGE: String = "authOptionsTargetPackage"
|
||||
const val KEY_AUTH_OPTION_PREFER_EPHEMERAL: String = "authOptionsPreferEphemeral"
|
||||
const val KEY_AUTH_CALLBACK_SCHEME: String = "authCallbackScheme"
|
||||
const val KEY_AUTH_CALLBACK_HOST: String = "authCallbackHost"
|
||||
const val KEY_AUTH_CALLBACK_PATH: String = "authCallbackPath"
|
||||
|
||||
fun createResponseHandlingIntent(context: Context): Intent {
|
||||
val intent = Intent(context, AuthenticationManagementActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
return intent
|
||||
}
|
||||
}
|
||||
|
||||
private var authStarted: Boolean = false
|
||||
private var hasValidState: Boolean = false
|
||||
private lateinit var authenticationUri: Uri
|
||||
private var intentFlags: Int = 0
|
||||
private var targetPackage: String? = null
|
||||
private var preferEphemeral: Boolean = false
|
||||
private lateinit var callbackScheme: String
|
||||
private var callbackHost: String? = null
|
||||
private var callbackPath: String? = null
|
||||
|
||||
private lateinit var authLauncher: ActivityResultLauncher<Intent>
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// Register the activity result launcher
|
||||
authLauncher = AuthTabIntent.registerActivityResultLauncher(this, this::handleAuthResult)
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
extractState(intent.extras)
|
||||
} else {
|
||||
extractState(savedInstanceState)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleAuthResult(result: AuthResult) {
|
||||
val callback = FlutterWebAuth2Plugin.callbacks[callbackScheme]
|
||||
if (callback == null) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
when (result.resultCode) {
|
||||
AuthTabIntent.RESULT_OK -> {
|
||||
val uri = result.resultUri
|
||||
if (uri != null) {
|
||||
callback.success(uri.toString())
|
||||
} else {
|
||||
callback.error("FAILED", "Authentication returned no URI", null)
|
||||
}
|
||||
}
|
||||
|
||||
AuthTabIntent.RESULT_CANCELED -> {
|
||||
callback.error("CANCELED", "User canceled authentication", null)
|
||||
}
|
||||
|
||||
else -> {
|
||||
callback.error("FAILED", "Authentication failed with code: ${result.resultCode}", null)
|
||||
}
|
||||
}
|
||||
|
||||
FlutterWebAuth2Plugin.callbacks.remove(callbackScheme)
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
// If we couldn't restore a valid authentication state (e.g. the app process was
|
||||
// killed while the user was completing authentication in an external browser),
|
||||
// extractState() has already finished this activity. Bail out here instead of
|
||||
// touching the not-yet-initialized fields below.
|
||||
if (!hasValidState) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!authStarted) {
|
||||
|
||||
val intentBuilder = if (shouldUseAuthTabs()) {
|
||||
Log.d(LOG_TAG, "Using AuthTabIntent")
|
||||
AuthTabBuilderWrapper(AuthTabIntent.Builder())
|
||||
} else {
|
||||
Log.d(LOG_TAG, "Using CustomTabsIntent")
|
||||
CtBuilderWrapper(CustomTabsIntent.Builder())
|
||||
}
|
||||
|
||||
// Set ephemeral browsing if requested and supported
|
||||
if (preferEphemeral) {
|
||||
try {
|
||||
intentBuilder.setEphemeralBrowsingEnabled(true)
|
||||
Log.d(LOG_TAG, "Ephemeral browsing enabled")
|
||||
} catch (e: Exception) {
|
||||
Log.w(LOG_TAG, "Failed to enable ephemeral browsing: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
val intent = intentBuilder.build()
|
||||
|
||||
intent.intent.addFlags(intentFlags)
|
||||
if (targetPackage != null) {
|
||||
intent.intent.setPackage(targetPackage)
|
||||
}
|
||||
|
||||
try {
|
||||
if (callbackScheme == "https" && callbackHost != null && callbackPath != null) {
|
||||
Log.d(LOG_TAG, "Using https host and path: $callbackHost, $callbackPath")
|
||||
intent.launch(this, authLauncher, authenticationUri, callbackHost!!, callbackPath!!)
|
||||
} else {
|
||||
Log.d(LOG_TAG, "Using custom scheme: $callbackScheme")
|
||||
intent.launch(this, authLauncher, authenticationUri, callbackScheme)
|
||||
}
|
||||
} catch (e: android.content.ActivityNotFoundException){
|
||||
Log.e(LOG_TAG, "Failed to start authentication. No browser available (Activity not found)")
|
||||
val callback = FlutterWebAuth2Plugin.callbacks[callbackScheme]
|
||||
callback?.error("NO_BROWSER", "No valid browser available for authentication.", e.message)
|
||||
FlutterWebAuth2Plugin.callbacks.remove(callbackScheme)
|
||||
finish()
|
||||
} catch (e: SecurityException) {
|
||||
// Some apps register themselves as browsers but do not export their
|
||||
// intent-handling activity; launching the tab then throws instead of
|
||||
// ActivityNotFoundException. Fail the attempt like the no-browser case
|
||||
// rather than crashing the host app.
|
||||
Log.e(LOG_TAG, "Failed to start authentication. Most likely, the selected browser activity is not exported (SecurityException)")
|
||||
val callback = FlutterWebAuth2Plugin.callbacks[callbackScheme]
|
||||
callback?.error("SECURITY_EXCEPTION", "Selected browser cannot be accessed for authentication.", e.message)
|
||||
FlutterWebAuth2Plugin.callbacks.remove(callbackScheme)
|
||||
finish()
|
||||
}
|
||||
|
||||
authStarted = true
|
||||
return
|
||||
}
|
||||
/* If the authentication was already started and we've returned here, the user either
|
||||
* completed or cancelled authentication.
|
||||
* Either way we want to return to our original flutter activity, so just finish here
|
||||
*/
|
||||
finish()
|
||||
}
|
||||
|
||||
fun shouldUseAuthTabs(): Boolean {
|
||||
|
||||
if (!preferEphemeral || targetPackage == null) return true
|
||||
val packageMajorVersion = getInstalledVersion(targetPackage!!)?.substringBefore(".")?.toIntOrNull() ?: 0
|
||||
Log.d(LOG_TAG, "Chosen package: $targetPackage with version: $packageMajorVersion")
|
||||
|
||||
val chromePackages = setOf(
|
||||
PackageNames.CHROME_STABLE,
|
||||
PackageNames.CHROME_BETA,
|
||||
PackageNames.CHROME_DEV,
|
||||
)
|
||||
|
||||
if (chromePackages.contains(targetPackage)) {
|
||||
return packageMajorVersion >= 141
|
||||
} else if (targetPackage == PackageNames.MICROSOFT_EDGE) {
|
||||
return packageMajorVersion >= 141
|
||||
} else if (targetPackage == PackageNames.SAMSUNG_INTERNET) {
|
||||
return packageMajorVersion >= 28
|
||||
} else if (targetPackage == PackageNames.FIREFOX) {
|
||||
return packageMajorVersion >= 143
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putBoolean(KEY_AUTH_STARTED, authStarted)
|
||||
outState.putParcelable(KEY_AUTH_URI, authenticationUri)
|
||||
outState.putInt(KEY_AUTH_OPTION_INTENT_FLAGS, intentFlags)
|
||||
outState.putString(KEY_AUTH_OPTION_TARGET_PACKAGE, targetPackage)
|
||||
outState.putBoolean(KEY_AUTH_OPTION_PREFER_EPHEMERAL, preferEphemeral)
|
||||
outState.putString(KEY_AUTH_CALLBACK_SCHEME, callbackScheme)
|
||||
outState.putString(KEY_AUTH_CALLBACK_HOST, callbackHost)
|
||||
outState.putString(KEY_AUTH_CALLBACK_PATH, callbackPath)
|
||||
}
|
||||
|
||||
private fun extractState(state: Bundle?) {
|
||||
if (state == null) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
val scheme = state.getString(KEY_AUTH_CALLBACK_SCHEME)
|
||||
val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
state.getParcelable(KEY_AUTH_URI, Uri::class.java)
|
||||
} else {
|
||||
@Suppress("deprecation")
|
||||
state.getParcelable(KEY_AUTH_URI)
|
||||
}
|
||||
|
||||
if (uri == null || scheme == null) {
|
||||
// This can happen when Android recreates this activity from an incomplete
|
||||
// saved-state Bundle after the app's process was killed (e.g. low memory)
|
||||
// while the user was completing authentication in an external browser.
|
||||
// Finish gracefully instead of crashing the host app, and resolve any
|
||||
// still-pending callback with an error so callers don't hang forever.
|
||||
Log.e(
|
||||
LOG_TAG,
|
||||
"Unable to restore authentication state (missing authUri and/or " +
|
||||
"callbackScheme), likely due to process death. Finishing gracefully"
|
||||
)
|
||||
if (scheme != null) {
|
||||
FlutterWebAuth2Plugin.callbacks[scheme]?.error(
|
||||
"CANNOT_RESTORE",
|
||||
"Authentication session was lost, likely because the app was killed in the background. Please try again.",
|
||||
null
|
||||
)
|
||||
FlutterWebAuth2Plugin.callbacks.remove(scheme)
|
||||
}
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
authStarted = state.getBoolean(KEY_AUTH_STARTED, false)
|
||||
authenticationUri = uri
|
||||
intentFlags = state.getInt(KEY_AUTH_OPTION_INTENT_FLAGS, 0)
|
||||
targetPackage = state.getString(KEY_AUTH_OPTION_TARGET_PACKAGE)
|
||||
preferEphemeral = state.getBoolean(KEY_AUTH_OPTION_PREFER_EPHEMERAL, false)
|
||||
callbackScheme = scheme
|
||||
callbackHost = state.getString(KEY_AUTH_CALLBACK_HOST)
|
||||
callbackPath = state.getString(KEY_AUTH_CALLBACK_PATH)
|
||||
hasValidState = true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package com.linusu.flutter_web_auth_2
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
|
||||
class CallbackActivity : Activity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val url = intent?.data ?: fixAutoVerifyNotWorks(intent)
|
||||
val scheme = url?.scheme
|
||||
|
||||
if (scheme != null) {
|
||||
FlutterWebAuth2Plugin.callbacks.remove(scheme)?.success(url.toString())
|
||||
}
|
||||
startActivity(AuthenticationManagementActivity.createResponseHandlingIntent(this))
|
||||
finish()
|
||||
}
|
||||
|
||||
|
||||
/** Fix sometimes android:autoVerify="true" cannot works when it can't access Google after installation.
|
||||
* See https://stackoverflow.com/questions/76383106/auto-verify-not-always-working-in-app-links-using-android
|
||||
*
|
||||
* must register in AndroidManifest.xml :
|
||||
* <intent-filter>
|
||||
* <action android:name="android.intent.action.SEND" />
|
||||
* <category android:name="android.intent.category.DEFAULT" />
|
||||
* <data android:mimeType="text/plain" />
|
||||
*</intent-filter>
|
||||
*/
|
||||
private fun fixAutoVerifyNotWorks(intent: Intent?): Uri? {
|
||||
if (intent?.action == Intent.ACTION_SEND && "text/plain" == intent.type) {
|
||||
return intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
|
||||
try {
|
||||
//scheme://host/path#id_token=xxx
|
||||
return Uri.parse(it)
|
||||
} catch (e: Exception) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
package com.linusu.flutter_web_auth_2
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.browser.customtabs.CustomTabsClient
|
||||
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
||||
import io.flutter.plugin.common.BinaryMessenger
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||
import io.flutter.plugin.common.MethodChannel.Result
|
||||
|
||||
class FlutterWebAuth2Plugin(
|
||||
private var context: Context? = null,
|
||||
private var channel: MethodChannel? = null,
|
||||
private var activity: Activity? = null,
|
||||
) : MethodCallHandler, FlutterPlugin, ActivityAware {
|
||||
companion object {
|
||||
val callbacks = mutableMapOf<String, Result>()
|
||||
}
|
||||
|
||||
private fun initInstance(messenger: BinaryMessenger, context: Context) {
|
||||
this.context = context
|
||||
channel = MethodChannel(messenger, "flutter_web_auth_2")
|
||||
channel?.setMethodCallHandler(this)
|
||||
}
|
||||
|
||||
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
||||
initInstance(binding.binaryMessenger, binding.applicationContext)
|
||||
}
|
||||
|
||||
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
||||
context = null
|
||||
channel = null
|
||||
}
|
||||
|
||||
override fun onMethodCall(call: MethodCall, resultCallback: Result) {
|
||||
when (call.method) {
|
||||
"authenticate" -> {
|
||||
val url = Uri.parse(call.argument("url"))
|
||||
val callbackUrlScheme: String = call.argument<String>("callbackUrlScheme")!!
|
||||
val options = call.argument<Map<String, Any>>("options")!!
|
||||
|
||||
callbacks[callbackUrlScheme] = resultCallback
|
||||
activity?.startActivity(Intent(activity, AuthenticationManagementActivity::class.java).apply {
|
||||
putExtra(AuthenticationManagementActivity.KEY_AUTH_URI, url)
|
||||
putExtra(AuthenticationManagementActivity.KEY_AUTH_OPTION_INTENT_FLAGS, options["intentFlags"] as Int)
|
||||
putExtra(AuthenticationManagementActivity.KEY_AUTH_OPTION_TARGET_PACKAGE, findTargetBrowserPackageName(options))
|
||||
putExtra(AuthenticationManagementActivity.KEY_AUTH_CALLBACK_SCHEME, callbackUrlScheme)
|
||||
putExtra(AuthenticationManagementActivity.KEY_AUTH_CALLBACK_HOST, options["httpsHost"] as String?)
|
||||
putExtra(AuthenticationManagementActivity.KEY_AUTH_CALLBACK_PATH, options["httpsPath"] as String?)
|
||||
putExtra(AuthenticationManagementActivity.KEY_AUTH_OPTION_PREFER_EPHEMERAL, options["preferEphemeral"] as Boolean? ?: false)
|
||||
})
|
||||
}
|
||||
|
||||
"cleanUpDanglingCalls" -> {
|
||||
callbacks.forEach { (_, danglingResultCallback) ->
|
||||
danglingResultCallback.error("CANCELED", "User canceled login", null)
|
||||
}
|
||||
callbacks.clear()
|
||||
resultCallback.success(null)
|
||||
}
|
||||
|
||||
else -> resultCallback.notImplemented()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
|
||||
activity = binding.activity
|
||||
}
|
||||
|
||||
override fun onDetachedFromActivityForConfigChanges() {
|
||||
onDetachedFromActivity()
|
||||
}
|
||||
|
||||
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
|
||||
onAttachedToActivity(binding)
|
||||
}
|
||||
|
||||
override fun onDetachedFromActivity() {
|
||||
activity = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Find Support CustomTabs Browser.
|
||||
*
|
||||
* Priority:
|
||||
* 1. Custom Browser Order (if supported)
|
||||
* 2. default Browser
|
||||
* 3. Installed Browsers (if supported)
|
||||
* 4. null (System backup aka. some obscure browser that may work)
|
||||
*/
|
||||
private fun findTargetBrowserPackageName(options: Map<String, Any>): String? {
|
||||
val context = requireNotNull(context) { "Context is null" }
|
||||
|
||||
val selectedPackage = (options["customTabsPackageOrder"] as? Iterable<*>)
|
||||
?.mapNotNull { (it as? String)?.trim() }
|
||||
?.filter { it.isNotEmpty() }
|
||||
?.firstOrNull { isSupportCustomTabs(it) }
|
||||
|
||||
if (selectedPackage != null) {
|
||||
return selectedPackage
|
||||
}
|
||||
|
||||
// Check default browser
|
||||
val defaultBrowserSupported = CustomTabsClient.getPackageName(context, emptyList<String>())
|
||||
if (defaultBrowserSupported != null) {
|
||||
return defaultBrowserSupported
|
||||
}
|
||||
// Check installed browser
|
||||
val matchedBrowser = getInstalledBrowsers().firstOrNull { isSupportCustomTabs(it) }
|
||||
|
||||
// Don't fall back to Chrome here. It is not installed anyway because it would already be in matchedBrowser.
|
||||
// Instead, fall back to null so we can use the system backup (if one is available).
|
||||
return matchedBrowser
|
||||
}
|
||||
|
||||
private fun getInstalledBrowsers(): List<String> {
|
||||
val context = requireNotNull(context) { "Context is null" }
|
||||
|
||||
// Get all apps that can handle VIEW intents
|
||||
val activityIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://"))
|
||||
val viewIntentHandlers = context.getPackagesForIntent(activityIntent)
|
||||
|
||||
val preferredKnownBrowsers = listOf(
|
||||
PackageNames.CHROME_STABLE,
|
||||
PackageNames.CHROME_BETA,
|
||||
PackageNames.SAMSUNG_INTERNET,
|
||||
PackageNames.MICROSOFT_EDGE,
|
||||
PackageNames.FIREFOX,
|
||||
PackageNames.CHROME_DEV,
|
||||
)
|
||||
|
||||
val preferred = mutableListOf<String>()
|
||||
val others = mutableListOf<String>()
|
||||
val pushToEnd = mutableListOf<String>() // for the least-favorite apps
|
||||
|
||||
for (pkg in viewIntentHandlers) {
|
||||
if (preferredKnownBrowsers.contains(pkg)) preferred += pkg
|
||||
else others += pkg
|
||||
}
|
||||
|
||||
preferred.sortBy { preferredKnownBrowsers.indexOf(it) }
|
||||
|
||||
return buildList {
|
||||
addAll(preferred)
|
||||
addAll(others)
|
||||
addAll(pushToEnd)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSupportCustomTabs(packageName: String): Boolean {
|
||||
val value = CustomTabsClient.getPackageName(
|
||||
context!!,
|
||||
arrayListOf(packageName),
|
||||
true
|
||||
)
|
||||
return value == packageName
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.linusu.flutter_web_auth_2
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.os.Binder
|
||||
import android.os.IBinder
|
||||
|
||||
class KeepAliveService: Service() {
|
||||
companion object {
|
||||
val binder = Binder()
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent): IBinder {
|
||||
return binder
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package com.linusu.flutter_web_auth_2
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.browser.auth.AuthTabIntent
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
|
||||
interface TabBuilderWrapper {
|
||||
fun setEphemeralBrowsingEnabled(enabled: Boolean): TabBuilderWrapper
|
||||
fun build(): IntentWrapper
|
||||
}
|
||||
|
||||
interface IntentWrapper {
|
||||
val intent: Intent
|
||||
fun launch(activity: Activity, launcher: ActivityResultLauncher<Intent>, url: Uri, redirectHost: String, redirectPath: String)
|
||||
fun launch(activity: Activity, launcher: ActivityResultLauncher<Intent>, url: Uri, redirectScheme: String)
|
||||
}
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError", "UnsafeOptInUsageWarning")
|
||||
class CtBuilderWrapper(private val b: CustomTabsIntent.Builder) : TabBuilderWrapper {
|
||||
override fun setEphemeralBrowsingEnabled(enabled: Boolean) = apply { b.setEphemeralBrowsingEnabled(enabled) }
|
||||
|
||||
override fun build(): IntentWrapper {
|
||||
val intent = b.build()
|
||||
return object : IntentWrapper {
|
||||
|
||||
override val intent: Intent
|
||||
get() = intent.intent
|
||||
|
||||
override fun launch(activity: Activity, launcher: ActivityResultLauncher<Intent>, url: Uri, redirectHost: String, redirectPath: String) {
|
||||
intent.launchUrl(activity, url)
|
||||
}
|
||||
|
||||
override fun launch(activity: Activity, launcher: ActivityResultLauncher<Intent>, url: Uri, redirectScheme: String) {
|
||||
intent.launchUrl(activity, url)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError", "UnsafeOptInUsageWarning")
|
||||
class AuthTabBuilderWrapper(private val b: AuthTabIntent.Builder) : TabBuilderWrapper {
|
||||
|
||||
override fun setEphemeralBrowsingEnabled(enabled: Boolean) = apply { b.setEphemeralBrowsingEnabled(enabled) }
|
||||
|
||||
override fun build(): IntentWrapper {
|
||||
val intent = b.build()
|
||||
return object : IntentWrapper {
|
||||
|
||||
override val intent: Intent
|
||||
get() = intent.intent
|
||||
|
||||
override fun launch(activity: Activity, launcher: ActivityResultLauncher<Intent>, url: Uri, redirectHost: String, redirectPath: String) {
|
||||
intent.launch(launcher, url, redirectHost, redirectPath)
|
||||
}
|
||||
|
||||
override fun launch(activity: Activity, launcher: ActivityResultLauncher<Intent>, url: Uri, redirectScheme: String) {
|
||||
intent.launch(launcher, url, redirectScheme)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
45
third_party/flutter_web_auth_2/android/src/main/kotlin/com/linusu/flutter_web_auth_2/Utils.kt
vendored
Normal file
45
third_party/flutter_web_auth_2/android/src/main/kotlin/com/linusu/flutter_web_auth_2/Utils.kt
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package com.linusu.flutter_web_auth_2
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
|
||||
object PackageNames {
|
||||
const val CHROME_STABLE = "com.android.chrome"
|
||||
const val CHROME_BETA = "com.chrome.beta"
|
||||
const val CHROME_DEV = "com.chrome.dev"
|
||||
const val MICROSOFT_EDGE = "com.microsoft.emmx"
|
||||
const val FIREFOX = "org.mozilla.firefox"
|
||||
const val SAMSUNG_INTERNET = "com.sec.android.app.sbrowser"
|
||||
}
|
||||
|
||||
val Any.LOG_TAG: String
|
||||
get() = "flutter_web_auth_2"
|
||||
|
||||
fun Context.getInstalledVersion(packageName: String): String? {
|
||||
try {
|
||||
val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
packageManager.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0))
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
packageManager.getPackageInfo(packageName, 0)
|
||||
}
|
||||
return packageInfo.versionName
|
||||
} catch (_: Exception) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.getPackagesForIntent(intent: Intent): List<String> {
|
||||
try {
|
||||
val list = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
packageManager.queryIntentActivities(intent, PackageManager.MATCH_ALL)
|
||||
} else {
|
||||
packageManager.queryIntentActivities(intent, 0)
|
||||
}
|
||||
return list.map { it.activityInfo.packageName }
|
||||
} catch (_: Exception) {
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
23
third_party/flutter_web_auth_2/ios/flutter_web_auth_2.podspec
vendored
Normal file
23
third_party/flutter_web_auth_2/ios/flutter_web_auth_2.podspec
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#
|
||||
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
|
||||
# Run `pod lib lint flutter_web_auth_2.podspec` to validate before publishing.
|
||||
#
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'flutter_web_auth_2'
|
||||
s.version = '5.0.0'
|
||||
s.summary = 'Flutter plugin for authenticating a user with a web service.'
|
||||
s.description = <<-DESC
|
||||
Flutter plugin for authenticating a user with a web service.
|
||||
DESC
|
||||
s.homepage = 'https://github.com/ThexXTURBOXx/flutter_web_auth_2'
|
||||
s.license = { :file => '../LICENSE' }
|
||||
s.author = { 'Nico Mexis' => 'nico.mexis@kabelmail.de' }
|
||||
s.source = { :path => '.' }
|
||||
s.source_files = 'flutter_web_auth_2/Sources/flutter_web_auth_2/**/*.swift'
|
||||
s.dependency 'Flutter'
|
||||
s.platform = :ios, '11.0'
|
||||
|
||||
# Flutter.framework does not contain a i386 slice.
|
||||
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
|
||||
s.swift_version = '5.9'
|
||||
end
|
||||
22
third_party/flutter_web_auth_2/ios/flutter_web_auth_2/Package.swift
vendored
Normal file
22
third_party/flutter_web_auth_2/ios/flutter_web_auth_2/Package.swift
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// swift-tools-version: 5.9
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "flutter_web_auth_2",
|
||||
platforms: [
|
||||
.iOS("11.0")
|
||||
],
|
||||
products: [
|
||||
.library(name: "flutter-web-auth-2", targets: ["flutter_web_auth_2"])
|
||||
],
|
||||
dependencies: [],
|
||||
targets: [
|
||||
.target(
|
||||
name: "flutter_web_auth_2",
|
||||
dependencies: [],
|
||||
resources: []
|
||||
)
|
||||
]
|
||||
)
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
import AuthenticationServices
|
||||
import Flutter
|
||||
import SafariServices
|
||||
import UIKit
|
||||
|
||||
public class FlutterWebAuth2Plugin: NSObject, FlutterPlugin {
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
let channel = FlutterMethodChannel(name: "flutter_web_auth_2", binaryMessenger: registrar.messenger())
|
||||
let instance = FlutterWebAuth2Plugin()
|
||||
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||
registrar.addApplicationDelegate(instance)
|
||||
}
|
||||
|
||||
var completionHandler: ((URL?, Error?) -> Void)?
|
||||
|
||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
if call.method == "authenticate",
|
||||
let arguments = call.arguments as? [String: AnyObject],
|
||||
let urlString = arguments["url"] as? String,
|
||||
let url = URL(string: urlString),
|
||||
let callbackURLScheme = arguments["callbackUrlScheme"] as? String,
|
||||
let options = arguments["options"] as? [String: AnyObject]
|
||||
{
|
||||
var sessionToKeepAlive: Any? // if we do not keep the session alive, it will get closed immediately while showing the dialog
|
||||
completionHandler = { (url: URL?, err: Error?) in
|
||||
self.completionHandler = nil
|
||||
|
||||
if (sessionToKeepAlive != nil) {
|
||||
if #available(iOS 12, *) {
|
||||
(sessionToKeepAlive as! ASWebAuthenticationSession).cancel()
|
||||
} else if #available(iOS 11, *) {
|
||||
(sessionToKeepAlive as! SFAuthenticationSession).cancel()
|
||||
}
|
||||
sessionToKeepAlive = nil
|
||||
}
|
||||
|
||||
if let err = err {
|
||||
if #available(iOS 12, *) {
|
||||
if case ASWebAuthenticationSessionError.canceledLogin = err {
|
||||
result(
|
||||
FlutterError(
|
||||
code: "CANCELED",
|
||||
message: "User canceled login",
|
||||
details: [
|
||||
"domain": (err as NSError).domain,
|
||||
"code": (err as NSError).code,
|
||||
"description": err.localizedDescription
|
||||
]
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if #available(iOS 11, *) {
|
||||
if case SFAuthenticationError.canceledLogin = err {
|
||||
result(
|
||||
FlutterError(
|
||||
code: "CANCELED",
|
||||
message: "User canceled login",
|
||||
details: [
|
||||
"domain": (err as NSError).domain,
|
||||
"code": (err as NSError).code,
|
||||
"description": err.localizedDescription
|
||||
]
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
result(FlutterError(code: "EUNKNOWN", message: err.localizedDescription, details: nil))
|
||||
return
|
||||
}
|
||||
|
||||
guard let url = url else {
|
||||
result(FlutterError(code: "EUNKNOWN", message: "URL was null, but no error provided.", details: nil))
|
||||
return
|
||||
}
|
||||
|
||||
result(url.absoluteString)
|
||||
}
|
||||
|
||||
if #available(iOS 12, *) {
|
||||
var _session: ASWebAuthenticationSession? = nil
|
||||
if #available(iOS 17.4, *) {
|
||||
if (callbackURLScheme == "https") {
|
||||
guard let host = options["httpsHost"] as? String else {
|
||||
result(FlutterError.invalidHttpsHostError)
|
||||
return
|
||||
}
|
||||
|
||||
guard let path = options["httpsPath"] as? String else {
|
||||
result(FlutterError.invalidHttpsPathError)
|
||||
return
|
||||
}
|
||||
|
||||
_session = ASWebAuthenticationSession(url: url, callback: ASWebAuthenticationSession.Callback.https(host: host, path: path), completionHandler: completionHandler!)
|
||||
} else {
|
||||
_session = ASWebAuthenticationSession(url: url, callback: ASWebAuthenticationSession.Callback.customScheme(callbackURLScheme), completionHandler: completionHandler!)
|
||||
}
|
||||
} else {
|
||||
_session = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackURLScheme, completionHandler: completionHandler!)
|
||||
}
|
||||
let session = _session!
|
||||
|
||||
if #available(iOS 13, *) {
|
||||
var rootViewController: UIViewController? = nil
|
||||
|
||||
// FlutterViewController
|
||||
if (rootViewController == nil) {
|
||||
rootViewController = UIApplication.shared.delegate?.window??.rootViewController as? FlutterViewController
|
||||
}
|
||||
|
||||
// UIViewController
|
||||
if (rootViewController == nil) {
|
||||
rootViewController = UIApplication.shared.keyWindow?.rootViewController
|
||||
}
|
||||
|
||||
// ACQUIRE_ROOT_VIEW_CONTROLLER_FAILED
|
||||
if (rootViewController == nil) {
|
||||
result(FlutterError.acquireRootViewControllerFailed)
|
||||
return
|
||||
}
|
||||
|
||||
while let presentedViewController = rootViewController!.presentedViewController {
|
||||
rootViewController = presentedViewController
|
||||
}
|
||||
if let nav = rootViewController as? UINavigationController {
|
||||
rootViewController = nav.visibleViewController ?? rootViewController
|
||||
}
|
||||
|
||||
guard let contextProvider = rootViewController as? ASWebAuthenticationPresentationContextProviding else {
|
||||
result(FlutterError.acquireRootViewControllerFailed)
|
||||
return
|
||||
}
|
||||
session.presentationContextProvider = contextProvider
|
||||
if let preferEphemeral = options["preferEphemeral"] as? Bool {
|
||||
session.prefersEphemeralWebBrowserSession = preferEphemeral
|
||||
}
|
||||
}
|
||||
|
||||
session.start()
|
||||
sessionToKeepAlive = session
|
||||
} else if #available(iOS 11, *) {
|
||||
let session = SFAuthenticationSession(url: url, callbackURLScheme: callbackURLScheme, completionHandler: completionHandler!)
|
||||
session.start()
|
||||
sessionToKeepAlive = session
|
||||
} else {
|
||||
result(FlutterError(code: "FAILED", message: "This plugin does currently not support iOS lower than iOS 11", details: nil))
|
||||
}
|
||||
} else if call.method == "cleanUpDanglingCalls" {
|
||||
// we do not keep track of old callbacks on iOS, so nothing to do here
|
||||
result(nil)
|
||||
} else {
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
public func application(
|
||||
_ application: UIApplication,
|
||||
continue userActivity: NSUserActivity,
|
||||
restorationHandler: @escaping ([Any]) -> Void) -> Bool
|
||||
{
|
||||
switch userActivity.activityType {
|
||||
case NSUserActivityTypeBrowsingWeb:
|
||||
guard let url = userActivity.webpageURL, let completionHandler = completionHandler else {
|
||||
return false
|
||||
}
|
||||
completionHandler(url, nil)
|
||||
return true
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 13, *)
|
||||
extension FlutterViewController: ASWebAuthenticationPresentationContextProviding {
|
||||
public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
|
||||
return view.window!
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension FlutterError {
|
||||
static var acquireRootViewControllerFailed: FlutterError {
|
||||
return FlutterError(code: "ACQUIRE_ROOT_VIEW_CONTROLLER_FAILED", message: "Failed to acquire root view controller", details: nil)
|
||||
}
|
||||
|
||||
static var invalidHttpsHostError: FlutterError {
|
||||
return FlutterError(code: "INVALID_HTTPS_HOST_ERROR", message: "Failed to retrieve host for https scheme", details: nil)
|
||||
}
|
||||
|
||||
static var invalidHttpsPathError: FlutterError {
|
||||
return FlutterError(code: "INVALID_HTTPS_PATH_ERROR", message: "Failed to retrieve path for https scheme", details: nil)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue