From cdfd2b7ee791cb42d3d27e2e5afa0539a8d12f7f Mon Sep 17 00:00:00 2001 From: dab246 Date: Mon, 18 Nov 2024 16:39:12 +0700 Subject: [PATCH] TF-3278 Handle open tmail app deep link but it was installed but not signed in --- android/app/src/main/AndroidManifest.xml | 11 ++++ .../reloadable/reloadable_controller.dart | 10 +++- .../home/presentation/home_controller.dart | 57 +++++++++++++++++++ lib/main/bindings/core/core_bindings.dart | 4 ++ lib/main/deep_links/deep_link_data.dart | 45 +++++++++++++++ lib/main/deep_links/deep_links_manager.dart | 42 ++++++++++++++ lib/main/utils/app_config.dart | 1 + pubspec.lock | 40 +++++++++++++ pubspec.yaml | 2 + 9 files changed, 209 insertions(+), 3 deletions(-) create mode 100644 lib/main/deep_links/deep_link_data.dart create mode 100644 lib/main/deep_links/deep_links_manager.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index e6ef49d68..bb7ec1782 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -90,6 +90,17 @@ + + + + + + + + + (); _iosNotificationManager?.listenClickNotification(); } + + void _registerDeepLinks() { + _deepLinksManager = getBinding(); + } + + Future _handleDeepLinks() async { + final deepLinkData = await _deepLinksManager?.getDeepLinkData(); + log('HomeController::_handleDeepLinks:DeepLinkData = $deepLinkData'); + if (deepLinkData == null) { + goToLogin(); + return; + } + + if (deepLinkData.path == AppConfig.openAppHostDeepLink) { + _handleOpenApp(deepLinkData); + return; + } + + goToLogin(); + } + + void _handleOpenApp(DeepLinkData deepLinkData) { + if (deepLinkData.isValidToken()) { + setDataToInterceptors( + baseUrl: AppConfig.saasJmapServerUrl, + tokenOIDC: deepLinkData.getTokenOIDC(), + oidcConfiguration: OIDCConfiguration( + authority: AppConfig.saasRegistrationUrl, + clientId: OIDCConstant.clientId, + scopes: AppConfig.oidcScopes, + ) + ); + getSessionAction(); + } else { + goToLogin(); + } + } + + @override + void handleFailureViewState(Failure failure) { + if (PlatformInfo.isMobile && isNotSignedIn(failure)) { + _handleDeepLinks(); + } else { + super.handleFailureViewState(failure); + } + } } \ No newline at end of file diff --git a/lib/main/bindings/core/core_bindings.dart b/lib/main/bindings/core/core_bindings.dart index c932c96ba..a3efcc36d 100644 --- a/lib/main/bindings/core/core_bindings.dart +++ b/lib/main/bindings/core/core_bindings.dart @@ -18,6 +18,7 @@ import 'package:tmail_ui_user/features/caching/utils/local_storage_manager.dart' import 'package:tmail_ui_user/features/caching/utils/session_storage_manager.dart'; import 'package:tmail_ui_user/features/sending_queue/presentation/utils/sending_queue_isolate_manager.dart'; import 'package:tmail_ui_user/main/utils/app_config.dart'; +import 'package:tmail_ui_user/main/deep_links/deep_links_manager.dart'; import 'package:tmail_ui_user/main/utils/email_receive_manager.dart'; import 'package:tmail_ui_user/main/utils/ios_notification_manager.dart'; import 'package:tmail_ui_user/main/utils/toast_manager.dart'; @@ -75,6 +76,9 @@ class CoreBindings extends Bindings { if (PlatformInfo.isIOS) { Get.put(IOSNotificationManager()); } + if (PlatformInfo.isMobile) { + Get.put(DeepLinksManager()); + } Get.put(PreviewEmlFileUtils()); } diff --git a/lib/main/deep_links/deep_link_data.dart b/lib/main/deep_links/deep_link_data.dart new file mode 100644 index 000000000..f7ff0ee5d --- /dev/null +++ b/lib/main/deep_links/deep_link_data.dart @@ -0,0 +1,45 @@ +import 'package:equatable/equatable.dart'; +import 'package:model/model.dart'; + +class DeepLinkData with EquatableMixin { + final String path; + final String? accessToken; + final String? refreshToken; + final String? idToken; + final int? expiresIn; + final String? username; + + DeepLinkData({ + required this.path, + this.accessToken, + this.refreshToken, + this.idToken, + this.expiresIn, + this.username, + }); + + bool isValidToken() => accessToken?.isNotEmpty == true && username?.isNotEmpty == true; + + TokenOIDC getTokenOIDC() { + final expiredTime = expiresIn == null + ? null + : DateTime.now().add(Duration(seconds: expiresIn!)); + + return TokenOIDC( + accessToken!, + TokenId(idToken ?? ''), + refreshToken ?? '', + expiredTime: expiredTime, + ); + } + + @override + List get props => [ + path, + accessToken, + refreshToken, + idToken, + expiresIn, + username, + ]; +} diff --git a/lib/main/deep_links/deep_links_manager.dart b/lib/main/deep_links/deep_links_manager.dart new file mode 100644 index 000000000..73d437f97 --- /dev/null +++ b/lib/main/deep_links/deep_links_manager.dart @@ -0,0 +1,42 @@ +import 'dart:async'; + +import 'package:app_links/app_links.dart'; +import 'package:core/utils/app_logger.dart'; +import 'package:tmail_ui_user/features/login/data/network/config/oidc_constant.dart'; +import 'package:tmail_ui_user/main/deep_links/deep_link_data.dart'; + +class DeepLinksManager { + Future getDeepLinkData() async { + final uriLink = await AppLinks().getInitialLink(); + if (uriLink == null) return null; + + final deepLinkData = parseDeepLink(uriLink.toString()); + return deepLinkData; + } + + DeepLinkData? parseDeepLink(String url) { + try { + final uri = Uri.parse(url.replaceFirst(OIDCConstant.twakeWorkplaceUrlScheme, 'https')); + + final accessToken = uri.queryParameters['access_token'] ?? ''; + final refreshToken = uri.queryParameters['refresh_token'] ?? ''; + final idToken = uri.queryParameters['id_token'] ?? ''; + final expiresInStr = uri.queryParameters['expires_in'] ?? ''; + final username = uri.queryParameters['username'] ?? ''; + + final expiresIn = int.tryParse(expiresInStr); + + return DeepLinkData( + path: uri.path, + accessToken: accessToken, + refreshToken: refreshToken, + idToken: idToken, + expiresIn: expiresIn, + username: username, + ); + } catch (e) { + logError('DeepLinksManager::parseDeepLink:Exception = $e'); + return null; + } + } +} \ No newline at end of file diff --git a/lib/main/utils/app_config.dart b/lib/main/utils/app_config.dart index 6c3bcc069..ceedc878f 100644 --- a/lib/main/utils/app_config.dart +++ b/lib/main/utils/app_config.dart @@ -19,6 +19,7 @@ class AppConfig { static const String linagoraPrivacyUrl = 'https://www.linagora.com/en/legal/privacy'; static const String saasRegistrationUrl = 'https://sign-up.twake.app'; static const String saasJmapServerUrl = 'https://jmap.twake.app'; + static const String openAppHostDeepLink = 'openApp'; static String get baseUrl => dotenv.get('SERVER_URL', fallback: ''); static String get domainRedirectUrl => dotenv.get('DOMAIN_REDIRECT_URL', fallback: ''); diff --git a/pubspec.lock b/pubspec.lock index 6c1bc2813..b02679ead 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -25,6 +25,38 @@ packages: url: "https://pub.dev" source: hosted version: "5.13.0" + app_links: + dependency: "direct main" + description: + name: app_links + sha256: ad1a6d598e7e39b46a34f746f9a8b011ee147e4c275d407fa457e7a62f84dd99 + url: "https://pub.dev" + source: hosted + version: "6.3.2" + app_links_linux: + dependency: transitive + description: + name: app_links_linux + sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81 + url: "https://pub.dev" + source: hosted + version: "1.0.3" + app_links_platform_interface: + dependency: transitive + description: + name: app_links_platform_interface + sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + app_links_web: + dependency: transitive + description: + name: app_links_web + sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555 + url: "https://pub.dev" + source: hosted + version: "1.0.4" app_settings: dependency: "direct main" description: @@ -1158,6 +1190,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.1" + gtk: + dependency: transitive + description: + name: gtk + sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c + url: "https://pub.dev" + source: hosted + version: "2.1.0" hive: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 71721246e..37f2286ec 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -251,6 +251,8 @@ dependencies: flutter_web_auth_2: 3.1.1 + app_links: 6.3.2 + duration: 4.0.3 dev_dependencies: