From ac063f9140b714533210dcc94853d39fa91b2227 Mon Sep 17 00:00:00 2001
From: simeng-li
Date: Mon, 1 Jul 2024 16:43:37 +0800
Subject: [PATCH] docs(console): update flutter intergration guide (#6125)
improve content
---------
Co-authored-by: Gao Sun
---
.../docs/guides/native-flutter/README.mdx | 363 ++++++++----------
.../docs/guides/native-ios-swift/README.mdx | 4 +-
2 files changed, 172 insertions(+), 195 deletions(-)
diff --git a/packages/console/src/assets/docs/guides/native-flutter/README.mdx b/packages/console/src/assets/docs/guides/native-flutter/README.mdx
index 8abd349a3..b96419945 100644
--- a/packages/console/src/assets/docs/guides/native-flutter/README.mdx
+++ b/packages/console/src/assets/docs/guides/native-flutter/README.mdx
@@ -4,9 +4,19 @@ import Step from '@/mdx-components/Step';
import Tabs from '@mdx/components/Tabs';
import TabItem from '@mdx/components/TabItem';
import InlineNotification from '@/ds-components/InlineNotification';
+import Checkpoint from '../../fragments/_checkpoint.md';
+import RedirectUrisNative, { defaultRedirectUri } from '../../fragments/_redirect-uris-native.mdx';
-
+
+
+
+
+The Logto Flutter SDK is compatible with Android and iOS platforms only.
+
+For Dart v2.x users, please use Logto Flutter SDK v1.x. Logto Flutter SDK v2.x requires Dart v3.0.0 or higher.
+
+
@@ -16,124 +26,165 @@ You can install the `logto_dart_sdk package` directly using the pub package mana
Run the following command under your project root:
```sh
- flutter pub get logto_dart_sdk
+flutter pub get logto_dart_sdk
```
-
+
If you prefer to fork your own version of the SDK, you can clone the repository directly from GitHub.
```sh
- git clone https://github.com/logto-io/dart
+git clone https://github.com/logto-io/dart
```
-
-
-
+### Dependencies and Android settings
flutter_secure_storage
-
-
We use [flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage) to implement the cross-platform persistent secure token storage.
- Keychain is used for iOS
- AES encryption is used for Android.
-### Config Android version:
+**Config Android version**
-In `[project]/android/app/build.gradle` set minSdkVersion to >= 18.
+Set the `android:minSdkVersion` to 18 in your project's `android/app/build.gradle` file.
-```gradle
+```kotlin title="android/app/build.gradle"
android {
- ...
-
- defaultConfig {
- ...
- minSdkVersion 18
- ...
- }
+ {/* ... */}
+ defaultConfig {
+ {/* ... */}
+ minSdkVersion 18
+ }
}
```
+**Disable autobackup**
-### Disable autobackup:
+By default Android may backup data on Google Drive automatically. It can cause the exception `java.security.InvalidKeyException: Failed to unwrap key`.
-
- By default Android backups data on Google Drive. It can cause exception
- `java.security.InvalidKeyException:Failed` to unwrap key.
-
- You will need to either disable `autobackup` or exclude `sharedprefs` used by the
- FlutterSecureStorage plugin.
-
+To avoid this, you can disable auto backup for your app or exclude `sharedprefs` from the `FlutterSecureStorage`.
-1. To disable `autobackup`, go to your app manifest file and set the boolean value `android:allowBackup`:
+1. To disable auto backup, go to your app manifest file and set the `android:allowBackup` and `android:fullBackupContent` attributes to `false`.
- ```xml
-
- ...
-
- ...
-
-
+ ```xml title="AndroidManifest.xml"
+
+
+
+
+
+
+ ```
- ```
+2. Exclude `sharedprefs` from `FlutterSecureStorage`.
-2. To exclude `sharedprefs` for FlutterSecureStorage.
+ If you need to keep the `android:fullBackupContent` for your app rather than disabling it, you can exclude the `sharedprefs` directory from the backup.
- If you need to enable the `android:fullBackupContent` for your app. Set up a backup rule to [exclude](https://developer.android.com/guide/topics/data/autobackup#IncludingFiles) the prefs used by the plugin:
+ See more details in the [Android documentation](https://developer.android.com/identity/data/autobackup#IncludingFiles).
- ```xml
-
-
- ```
+ In your `AndroidManifest.xml` file, add the `android:fullBackupContent` attribute to the `` element, as shown in the following example. This attribute points to an XML file that contains backup rules.
- ```xml
-
-
-
-
- ```
+ ```xml title="AndroidManifest.xml"
+
+
+
+
+
+
+ ```
+
+ Create an XML file called `@xml/backup_rules` in the `res/xml/` directory. In this file, add rules with the `` and `` elements. The following sample backs up all shared preferences except device.xml:
+
+ ```xml title="res/xml/backup_rules.xml"
+
+
+
+
+ ```
Please check [flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage#configure-android-version) for more details.
-
-
+
+
flutter_web_auth
-
+[flutter_web_auth](https://pub.dev/packages/flutter_web_auth) is used behind Logto's flutter SDK. We rely on its webview-based interaction interface to authenticate users.
-[flutter_web_auth](https://pub.dev/packages/flutter_web_auth) is used behind Logto's flutter SDK. We rely on its webview-based interaction interface to open Logto's authorization pages.
+This plugin uses `ASWebAuthenticationSession` on iOS 12+ and macOS 10.15+, `SFAuthenticationSession` on iOS 11, `Chrome Custom Tabs` on Android and opens a new window on Web.
-
+
-Under the hood, this plugin uses `ASWebAuthenticationSession` on iOS 12+ and macOS 10.15+,
-`SFAuthenticationSession` on iOS 11, Chrome Custom Tabs 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.
+
-
+
-Andorid:
+Import the `logto_dart_sdk` package and initialize the `LogtoClient` instance at the root state of your application.
-In order to capture the callback url from Logto's sign-in web page, you will need to register your sign-in redirectUri to the `AndroidManifest.xml`.
+
+ {`import 'package:logto_dart_sdk/logto_dart_sdk.dart';
+import 'package:http/http.dart' as http;
-```xml
+class MyHomePage extends StatefulWidget {
+ const MyHomePage({super.key, required this.title});
+ final String title;
+
+ @override
+ State createState() => _MyHomePageState();
+}
+
+class _MyHomePageState extends State {
+ final logtoConfig = LogtoConfig(
+ endpoint: 'your_logto_endpoint', // Replace with your Logto endpoint
+ appId: 'your_app_id', // Replace with your App ID
+ );
+
+ late LogtoClient logtoClient;
+
+ void _init() async {
+ logtoClient = LogtoClient(
+ config: logtoConfig,
+ httpClient: http.Client(), // Optional: Custom HTTP client
+ );
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ _init();
+ }
+
+ // ...
+}`}
+
+
+
+
+
+
+
+
+- For iOS, the redirect URI scheme does not really matter since the iOS will listen to the redirect URI regardless of if it's registered.
+
+- For Android, in order to capture the callback url from Logto's sign-in web page, you will need to register your sign-in redirectUri to the `AndroidManifest.xml`.
+
+```xml title="AndroidManifest.xml"
@@ -143,72 +194,40 @@ In order to capture the callback url from Logto's sign-in web page, you will nee
```
-
-
-
-
-
-
+
-Import the `logto_dart_sdk` package and initialize the `LogtoClient` instance at the root of your application.
+Let's implement the `signIn` and `signOut` buttons in your application.
-
- {`
-import 'package:logto_dart_sdk/logto_dart_sdk.dart';
-import 'package:http/http.dart' as http;
+
+{`class _MyHomePageState extends State {
+ // ...
-late LogtoClient logtoClient;
+ final redirectUri = '${props.redirectUris[0] ?? defaultRedirectUri}';
-// LogtoConfig
-final logtoConfig = const LogtoConfig(
- endpoint: '${props.endpoint}', // Your Logto endpoint
- appId: '${props.app.id}', // Your App ID
-);
+ @override
+ Widget build(BuildContext context) {
+ Widget signInButton = TextButton(
+ onPressed: () async {
+ await logtoClient.signIn(redirectUri);
+ },
+ child: const Text('Sign In'),
+ );
-void init() async {
- logtoClient = LogtoClient(
- config: logtoConfig,
- httpClient: http.Client(), // Optional http client
- );
-}
-`}
+ Widget signOutButton = TextButton(
+ onPressed: () async {
+ await logtoClient.signOut();
+ },
+ child: const Text('Sign Out'),
+ );
+
+ // ...
+ }
+}`}
-
-
-
-### Configure Redirect URI
-
-
- In the following steps, we assume your app has configured using `io.logo` as your schema .
-
-
-Let's switch to the Application details page of Logto Admin Console. Add a Redirect URI `io.logto://callback` and click "Save changes".
-
-
-
-### Implement a sign-in method
-
-
- {`void signIn() async {
- await logtoClient.signIn('${props.redirectUris[0] ?? 'io.logto://callback'}');
-}
- `}
-
-
-
-
-
-
-### Implement a sign-out method
-
-```dart
-void signOut() async {
- await logtoClient.signOut();
-}
-```
+
The `signOut` method will clear the user's session and remove the token from the secure storage.
@@ -216,85 +235,39 @@ void signOut() async {
-
+
-In Logto SDK, you can use `logtoClient.isAuthenticated` to check the authentication status, if the
-user is signed in, the value will be `true`, otherwise, the value will be `false`.
+In Logto SDK, you can use `logtoClient.isAuthenticated` to check the authentication status, if the user is signed in, the value will be `true`, otherwise, the value will be `false`.
-```dart
- bool isAuthenticated = await logtoClient.isAuthenticated;
-```
+Define a boolean variable `isAuthenticated` in the state of your application to keep track of the authentication status.
-
+```dart title="lib/main.dart"
+class _MyHomePageState extends State{
+ bool isAuthenticated = false;
-
+ // ...
+
+ void render() async {
+ if (await logtoClient.isAuthenticated()) {
+ setState(() {
+ isAuthenticated = true;
+ });
-Now let's wrap up the implementation and test your application.
+ return;
+ }
-
- {`import 'package:logto_dart_sdk/logto_dart_sdk.dart';
-import 'package:http/http.dart' as http;
-
-void main() {
- runApp(const MyApp());
-}
-
-class MyApp extends StatelessWidget {
- const MyApp({Key? key}) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- return const MaterialApp(
- title: 'Flutter Demo',
- home: MyHomePage(title: 'Logto Demo Home Page'),
- );
- }
-}
-
-class MyHomePage extends StatefulWidget {
- const MyHomePage({Key? key, required this.title}) : super(key: key);
- final String title;
-
- @override
- State createState() => _MyHomePageState();
-}
-
-class _MyHomePageState extends State {
- late LogtoClient logtoClient;
- bool? isAuthenticated = false;
-
- // Update the authentication state
- void render() {
- setState(() async {
- isAuthenticated = await logtoClient.isAuthenticated;
+ setState(() {
+ isAuthenticated = false;
});
}
- // LogtoConfig
- final logtoConfig = const LogtoConfig(
- endpoint: '${props.endpoint}',
- appId: '${props.app.id}',
- );
-
- void _init() {
- logtoClient = LogtoClient(
- config: logtoConfig,
- httpClient: http.Client(), // Optional http client
- );
- render();
- }
-
- @override
- void initState() {
- super.initState();
- _init();
- }
-
- @override
+ @overwrite
Widget build(BuildContext context) {
- Widget signInButton = TextButton(
+ // ...
+
+ Widget signInButton = TextButton(
onPressed: () async {
- await logtoClient.signIn('${props.redirectUris[0] ?? 'io.logto://callback'}');
+ await logtoClient.signIn(redirectUri);
render();
},
child: const Text('Sign In'),
@@ -316,7 +289,6 @@ class _MyHomePageState extends State {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
- SelectableText('My Demo App'),
isAuthenticated ? signOutButton : signInButton,
],
),
@@ -324,8 +296,13 @@ class _MyHomePageState extends State {
);
}
}
-`}
-
+```
+
+
+
+
+
+
diff --git a/packages/console/src/assets/docs/guides/native-ios-swift/README.mdx b/packages/console/src/assets/docs/guides/native-ios-swift/README.mdx
index 3e1773e1d..5c75931bf 100644
--- a/packages/console/src/assets/docs/guides/native-ios-swift/README.mdx
+++ b/packages/console/src/assets/docs/guides/native-ios-swift/README.mdx
@@ -5,7 +5,7 @@ import InlineNotification from '@/ds-components/InlineNotification';
import Steps from '@/mdx-components/Steps';
import Step from '@/mdx-components/Step';
import Checkpoint from '../../fragments/_checkpoint.md';
-import RedirectUrisNative from '../../fragments/_redirect-uris-native.mdx';
+import RedirectUrisNative, { defaultRedirectUri } from '../../fragments/_redirect-uris-native.mdx';
@@ -110,7 +110,7 @@ For example, in a SwiftUI app:
Task { [self] in
do {
try await client.signInWithBrowser(redirectUri: "${
- props.redirectUris[0] ?? 'io.logto://callback'
+ props.redirectUris[0] ?? defaultRedirectUri
}")
isAuthenticated = true
} catch let error as LogtoClientErrors.SignIn {