💄 Better multi-factor authenticate callback experience

 Support custom app protocol solink://
This commit is contained in:
LittleSheep 2024-06-29 18:09:56 +08:00
parent 6b0f644353
commit fffad00f00
14 changed files with 235 additions and 77 deletions

View File

@ -18,8 +18,10 @@
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon"
android:supportsRtl="true">
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
<receiver android:exported="false"
android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver"/>
<receiver android:exported="false"
android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
@ -41,6 +43,17 @@
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" android:host="solsynth.dev" />
<data android:scheme="https" />
<data android:scheme="solink" />
</intent-filter>
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"

View File

@ -43,10 +43,10 @@ PODS:
- Firebase/Messaging (10.27.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 10.27.0)
- firebase_core (3.1.0):
- firebase_core (3.1.1):
- Firebase/CoreOnly (= 10.27.0)
- Flutter
- firebase_messaging (15.0.1):
- firebase_messaging (15.0.2):
- Firebase/Messaging (= 10.27.0)
- firebase_core
- Flutter
@ -125,6 +125,8 @@ PODS:
- permission_handler_apple (9.3.0):
- Flutter
- PromisesObjC (2.4.0)
- protocol_handler_ios (0.0.1):
- Flutter
- SDWebImage (5.19.2):
- SDWebImage/Core (= 5.19.2)
- SDWebImage/Core (5.19.2)
@ -164,6 +166,7 @@ DEPENDENCIES:
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- protocol_handler_ios (from `.symlinks/plugins/protocol_handler_ios/ios`)
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
@ -218,6 +221,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
protocol_handler_ios:
:path: ".symlinks/plugins/protocol_handler_ios/ios"
sentry_flutter:
:path: ".symlinks/plugins/sentry_flutter/ios"
shared_preferences_foundation:
@ -238,8 +243,8 @@ SPEC CHECKSUMS:
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
Firebase: 26b040b20866a55f55eb3611b9fcf3ae64816b86
firebase_core: 483cfad66d24d8f3c233f31db4263830c625c909
firebase_messaging: e60c0694699d8a2e56a319e043709583f6544123
firebase_core: f8d0424c45e0f1e596811085fc12c638d628457c
firebase_messaging: 8b29edaf5adfd3b52b5bfa5af8128c44164670c6
FirebaseCore: a2b95ae4ce7c83ceecfbbbe3b6f1cddc7415a808
FirebaseCoreInternal: 58d07f1362fddeb0feb6a857d1d1d1c5e558e698
FirebaseInstallations: 60c1d3bc1beef809fd1ad1189a8057a040c59f2e
@ -257,6 +262,7 @@ SPEC CHECKSUMS:
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
protocol_handler_ios: a5db8abc38526ee326988b808be621e5fd568990
SDWebImage: dfe95b2466a9823cf9f0c6d01217c06550d7b29a
Sentry: 016de45ee5ce5fca2a829996f1bfafeb5e62e8b4
sentry_flutter: 5fb57c5b7e6427a9dc1fedde4269eb65823982d4

View File

@ -2,6 +2,19 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string></string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>solink</string>
</array>
</dict>
</array>
<key>FirebaseMessagingAutoInitEnabled</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
@ -55,6 +68,8 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>FlutterDeepLinkingEnabled</key>
<true/>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>

View File

@ -4,5 +4,10 @@
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.associated-domains</key>
<array>
<string>webcredentials:solsynth.dev</string>
<string>applinks:solsynth.dev</string>
</array>
</dict>
</plist>

View File

@ -2,6 +2,7 @@ import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart';
import 'package:get/get.dart';
import 'package:protocol_handler/protocol_handler.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:solian/exts.dart';
import 'package:solian/firebase_options.dart';
@ -17,6 +18,7 @@ import 'package:solian/providers/content/realm.dart';
import 'package:solian/providers/friend.dart';
import 'package:solian/providers/account_status.dart';
import 'package:solian/router.dart';
import 'package:solian/shells/listener_shell.dart';
import 'package:solian/theme.dart';
import 'package:solian/translations.dart';
@ -31,6 +33,8 @@ void main() async {
appRunner: () async {
WidgetsFlutterBinding.ensureInitialized();
await protocolHandler.register('solink');
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
@ -101,8 +105,10 @@ class SolianApp extends StatelessWidget {
});
},
builder: (context, child) {
return ScaffoldMessenger(
return ListenerShell(
child: ScaffoldMessenger(
child: child ?? Container(),
),
);
},
);

View File

@ -41,8 +41,10 @@ class _SignInPopupState extends State<SignInPopup> {
TextButton(
child: Text('next'.tr),
onPressed: () {
const redirect = 'solink://auth?status=done';
launchUrlString(
'${ServiceFinder.services['passport']}/mfa?close=yes&ticketId=${e.ticketId}',
'${ServiceFinder.services['passport']}/mfa?redirect_uri=$redirect&ticketId=${e.ticketId}',
mode: LaunchMode.inAppWebView,
);
Navigator.pop(context);
},

View File

@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:protocol_handler/protocol_handler.dart';
import 'package:url_launcher/url_launcher.dart';
class ListenerShell extends StatefulWidget {
final Widget child;
const ListenerShell({super.key, required this.child});
@override
State<ListenerShell> createState() => _ListenerShellState();
}
class _ListenerShellState extends State<ListenerShell> with ProtocolListener {
@override
void initState() {
protocolHandler.addListener(this);
super.initState();
}
@override
void dispose() {
protocolHandler.removeListener(this);
super.dispose();
}
@override
Widget build(BuildContext context) {
return widget.child;
}
@override
void onProtocolUrlReceived(String url) {
final uri = url.replaceFirst('solink://', '');
if (uri == 'auth?status=done') {
closeInAppWebView();
}
}
}

View File

@ -17,6 +17,7 @@ import livekit_client
import macos_window_utils
import package_info_plus
import path_provider_foundation
import protocol_handler_macos
import sentry_flutter
import shared_preferences_foundation
import sqflite
@ -37,6 +38,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
MacOSWindowUtilsPlugin.register(with: registry.registrar(forPlugin: "MacOSWindowUtilsPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
ProtocolHandlerMacosPlugin.register(with: registry.registrar(forPlugin: "ProtocolHandlerMacosPlugin"))
SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))

View File

@ -2,6 +2,19 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string></string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>solink</string>
</array>
</dict>
</array>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>

View File

@ -13,10 +13,10 @@ packages:
dependency: transitive
description:
name: _flutterfire_internals
sha256: "0816f12bbbd9e21f72ea8592b11bce4a628d4e5cb7a81ff9f1eee4f3dc23206e"
sha256: a315d1c444402c3fa468de626d33a1c666041c87e9e195e8fb355b7084aefcc1
url: "https://pub.dev"
source: hosted
version: "1.3.37"
version: "1.3.38"
analyzer:
dependency: transitive
description:
@ -397,10 +397,10 @@ packages:
dependency: "direct main"
description:
name: firebase_core
sha256: fae4ab4317c2a7afb13d44ef1e3f9f28a630e10016bc5cfe761e8e6a0ed7816a
sha256: "1e06b0538ab3108a61d895ee16951670b491c4a94fce8f2d30e5de7a5eca4b28"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
version: "3.1.1"
firebase_core_platform_interface:
dependency: transitive
description:
@ -421,26 +421,26 @@ packages:
dependency: "direct main"
description:
name: firebase_messaging
sha256: "2d0ea2234ce46030eda2e6922611115ce603adc614ebd8c00e7db06a8929efbb"
sha256: a1eb38242e072118650139f8485a78d8f12e6d9b6ae563808ca0fa406bdebaad
url: "https://pub.dev"
source: hosted
version: "15.0.1"
version: "15.0.2"
firebase_messaging_platform_interface:
dependency: transitive
description:
name: firebase_messaging_platform_interface
sha256: c38c27f58cb6a88b8c145018d0567802376549c32a60098a13f3bdf3ddea326f
sha256: "98faf00cbe125bba136787e1678e7bf213f5e694e8f2615b94ad3d4bdcb0bdc2"
url: "https://pub.dev"
source: hosted
version: "4.5.39"
version: "4.5.40"
firebase_messaging_web:
dependency: transitive
description:
name: firebase_messaging_web
sha256: "8502849c2f232f7db338c052e045442207a0db82bd03ff14be3c80897dd8c26c"
sha256: a38e9ccdd5dc4d7dc9eef0097b6a5a3c24842772035e1be103dc1b81d8d09f7c
url: "https://pub.dev"
source: hosted
version: "3.8.9"
version: "3.8.10"
fixnum:
dependency: transitive
description:
@ -530,10 +530,10 @@ packages:
dependency: "direct main"
description:
name: flutter_local_notifications
sha256: "40e6fbd2da7dcc7ed78432c5cdab1559674b4af035fddbfb2f9a8f9c2112fcef"
sha256: ced76d337f54de33d7d9f06092137b4ac2da5079e00cee8a11a1794ffc7c61c6
url: "https://pub.dev"
source: hosted
version: "17.1.2"
version: "17.2.1"
flutter_local_notifications_linux:
dependency: transitive
description:
@ -546,18 +546,18 @@ packages:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
sha256: "340abf67df238f7f0ef58f4a26d2a83e1ab74c77ab03cd2b2d5018ac64db30b7"
sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66"
url: "https://pub.dev"
source: hosted
version: "7.1.0"
version: "7.2.0"
flutter_markdown:
dependency: "direct main"
description:
name: flutter_markdown
sha256: "85cc6f7daeae537844c92e2d56e2aff61b00095f8f77913b529ea4be12fc45ea"
sha256: "2e8a801b1ded5ea001a4529c97b1f213dcb11c6b20668e081cafb23468593514"
url: "https://pub.dev"
source: hosted
version: "0.7.2+1"
version: "0.7.3"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
@ -960,14 +960,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.5.0"
oauth2:
dependency: "direct main"
description:
name: oauth2
sha256: c4013ef62be37744efdc0861878fd9e9285f34db1f9e331cc34100d7674feb42
url: "https://pub.dev"
source: hosted
version: "2.0.2"
octo_image:
dependency: transitive
description:
@ -1124,10 +1116,10 @@ packages:
dependency: transitive
description:
name: platform_detect
sha256: "08f4ee79c0e1c4858d37e06b22352a3ebdef5466b613749a3adb03e703d4f5b0"
sha256: a62f99417fc4fa2d099ce0ccdbb1bd3977920f2a64292c326271f049d4bc3a4f
url: "https://pub.dev"
source: hosted
version: "2.0.11"
version: "2.1.0"
plugin_platform_interface:
dependency: transitive
description:
@ -1160,6 +1152,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.0"
protocol_handler:
dependency: "direct main"
description:
name: protocol_handler
sha256: dc2e2dcb1e0e313c3f43827ec3fa6d98adee6e17edc0c3923ac67efee87479a9
url: "https://pub.dev"
source: hosted
version: "0.2.0"
protocol_handler_android:
dependency: transitive
description:
name: protocol_handler_android
sha256: "82eb860ca42149e400328f54b85140329a1766d982e94705b68271f6ca73895c"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
protocol_handler_ios:
dependency: transitive
description:
name: protocol_handler_ios
sha256: "0d3a56b8c1926002cb1e32b46b56874759f4dcc8183d389b670864ac041b6ec2"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
protocol_handler_macos:
dependency: transitive
description:
name: protocol_handler_macos
sha256: "6eb8687a84e7da3afbc5660ce046f29d7ecf7976db45a9dadeae6c87147dd710"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
protocol_handler_platform_interface:
dependency: transitive
description:
name: protocol_handler_platform_interface
sha256: "53776b10526fdc25efdf1abcf68baf57fdfdb75342f4101051db521c9e3f3e5b"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
protocol_handler_windows:
dependency: transitive
description:
name: protocol_handler_windows
sha256: d8f3a58938386aca2c76292757392f4d059d09f11439d6d896d876ebe997f2c4
url: "https://pub.dev"
source: hosted
version: "0.2.0"
provider:
dependency: transitive
description:
@ -1361,10 +1401,10 @@ packages:
dependency: transitive
description:
name: sqlite3
sha256: b384f598b813b347c5a7e5ffad82cbaff1bec3d1561af267041e66f6f0899295
sha256: "6d17989c0b06a5870b2190d391925186f944cb943e5262d0d3f778fcfca3bc6e"
url: "https://pub.dev"
source: hosted
version: "2.4.3"
version: "2.4.4"
sqlparser:
dependency: transitive
description:
@ -1409,10 +1449,10 @@ packages:
dependency: transitive
description:
name: strings
sha256: b33f40c4dd3e597bf6d9e7f4f4dc282dad0f19b07d9f320cb5c2183859cbccf5
sha256: "052836499f03897d3860a603b330c1ea3c8a14177b21f34b15a1295f36024aae"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
version: "3.1.2"
synchronized:
dependency: transitive
description:
@ -1561,18 +1601,18 @@ packages:
dependency: "direct main"
description:
name: video_player
sha256: aced48e701e24c02b0b7f881a8819e4937794e46b5a5821005e2bf3b40a324cc
sha256: "3f7694b0fa01ee654f439b1161f3c23cd8e87e15a714fd894307240fe1de1a4a"
url: "https://pub.dev"
source: hosted
version: "2.8.7"
version: "2.9.0"
video_player_android:
dependency: transitive
description:
name: video_player_android
sha256: "9529001630e42988f755772972d5014d30121610700e8e502278a245939f8fc8"
sha256: "3ff2da7e5a9274bef9b5deb9084f73a77920211c463e0e836361b14146e67339"
url: "https://pub.dev"
source: hosted
version: "2.5.0"
version: "2.5.1"
video_player_avfoundation:
dependency: transitive
description:

View File

@ -18,7 +18,6 @@ dependencies:
flutter_markdown: ^0.7.1
flutter_animate: ^4.5.0
flutter_secure_storage: ^9.2.1
oauth2: ^2.0.2
carousel_slider: ^4.2.1
url_launcher: ^6.2.6
infinite_scroll_pagination: ^4.0.0
@ -50,6 +49,7 @@ dependencies:
flutter_acrylic: ^1.1.4
floor: ^1.5.0
sqflite: ^2.3.3+1
protocol_handler: ^0.2.0
dev_dependencies:
flutter_test:
@ -86,3 +86,6 @@ flutter_launcher_icons:
macos:
generate: true
image_path: "assets/icon-padded.png"
msix_config:
protocol_activation: solink

View File

@ -14,6 +14,7 @@
#include <flutter_webrtc/flutter_web_r_t_c_plugin.h>
#include <livekit_client/live_kit_plugin.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h>
#include <protocol_handler_windows/protocol_handler_windows_plugin_c_api.h>
#include <sentry_flutter/sentry_flutter_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>
#include <video_player_win/video_player_win_plugin_c_api.h>
@ -35,6 +36,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("LiveKitPlugin"));
PermissionHandlerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
ProtocolHandlerWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ProtocolHandlerWindowsPluginCApi"));
SentryFlutterPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SentryFlutterPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(

View File

@ -11,6 +11,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
flutter_webrtc
livekit_client
permission_handler_windows
protocol_handler_windows
sentry_flutter
url_launcher_windows
video_player_win

View File

@ -5,8 +5,19 @@
#include "flutter_window.h"
#include "utils.h"
#include <protocol_handler_windows/protocol_handler_windows_plugin_c_api.h>
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
_In_ wchar_t *command_line, _In_ int show_command) {
HWND hwnd = ::FindWindow(L"FLUTTER_RUNNER_WIN32_WINDOW", L"Solian");
if (hwnd != NULL) {
DispatchToProtocolHandler(hwnd);
::ShowWindow(hwnd, SW_NORMAL);
::SetForegroundWindow(hwnd);
return EXIT_FAILURE;
}
// Attach to console when present (e.g., 'flutter run') or create a
// new console when running with a debugger.
if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
@ -19,8 +30,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
flutter::DartProject project(L"data");
std::vector<std::string> command_line_arguments =
GetCommandLineArguments();
std::vector<std::string> command_line_arguments = GetCommandLineArguments();
project.set_dart_entrypoint_arguments(std::move(command_line_arguments));