Please be aware that our Flutter SDK is in open alpha at the moment!
Available now:
- email login (headless)
- sms login (headless)
- auth flow UI
- profile UI
- EVM embedded wallets
- web3dart integration
- social login
Coming next:
Installation
Simply run the following in your terminal:
flutter pub add dynamic_sdk
This will add a line like this to your package’s pubspec.yaml (and run an implicit flutter pub get):
dependencies:
dynamic_sdk: ^0.0.1-alpha.2
Set up
Getting started with DynamicSDK
takes only three steps:
1. Initialize your client
First you have to start the client singleton with your data in ClientProps
;
import 'package:dynamic_sdk/dynamic_sdk.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
DynamicSDK.init(
props: ClientProps(
environmentId: 'your-environment-id',
appLogoUrl: 'your-logo-url',
appName: 'your-app-name',
),
);
runApp(const MyApp());
}
2. Wait for the SDK to load
Add the DynamicSDK.instance.dynamicWidget
and wait for the SDK to loaded using the DynamicSDK.instance.sdk.readyChanges
stream;
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: Stack(
children: [
// Make sure the SDK is ready before using it
StreamBuilder<bool?>(
stream: DynamicSDK.instance.sdk.readyChanges,
builder: (context, snapshot) {
final sdkReady = snapshot.data ?? false;
return sdkReady
? const MyHomePage(title: 'Flutter Demo Home Page')
: const SizedBox.shrink();
},
),
// DynamicSDK widget must be available all the time
DynamicSDK.instance.dynamicWidget,
],
),
);
}
}
3. Do your stuff
That’s it! Now you are good to go! See below how to authenticate using our UI:
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: SingleChildScrollView(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Column(
children: [
// Listen to auth token changes
StreamBuilder<String?>(
stream: DynamicSDK.instance.auth.tokenChanges,
builder: (context, snapshot) {
final authToken = snapshot.data;
// Show the auth token when logged in
return authToken != null
? Column(
children: [
const LogoutButton(),
const SizedBox(height: 24),
Text('AUTH TOKEN: $authToken'),
],
)
// Show Dynamic UI for sign in
: const LoginButton();
},
),
],
),
],
),
),
),
);
}
}
// Show Dynamic UI for sign in
class LoginButton extends StatelessWidget {
const LoginButton({
super.key,
});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => DynamicSDK.instance.ui.showAuth(),
child: const Text('Dynamic Login'),
);
}
}
// Headless logout function
class LogoutButton extends StatelessWidget {
const LogoutButton({
super.key,
});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => DynamicSDK.instance.auth.logout(),
child: const Text('Logout'),
);
}
}
Available modules
Let’s walk you through the available modules and how to use most of the features.
SDK Module
- Get to know when the SDK is ready to be used by listening to
readyChanges
stream.
StreamBuilder<bool?>(
stream: DynamicSDK.instance.sdk.readyChanges,
builder: (context, snapshot) {
final sdkReady = snapshot.data ?? false;
return sdkReady
? const MyHomePage(title: 'Flutter Demo Home Page')
: const SizedBox.shrink();
},
),
User Interface Module
- Use our interface to sign in
class LoginButton extends StatelessWidget {
const LoginButton({
super.key,
});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => DynamicSDK.instance.ui.showAuth(),
child: const Text('Dynamic Login'),
);
}
}
- Use our interface to see the user’s profile
class UserProfileButton extends StatelessWidget {
const UserProfileButton({
super.key,
});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => DynamicSDK.instance.ui.showUserProfile(),
child: const Text('Show Profile'),
);
}
}
Auth Module (headless authentication)
- Headless e-mail sign in
class EmailLoginButton extends StatelessWidget {
const EmailLoginButton({
super.key,
});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async => await DynamicSDK.instance.auth.email.sendOTP(
'user@email.com'
),
child: const Text('Email Login'),
);
}
}
- Headless SMS sign in
class SMSLoginButton extends StatelessWidget {
const SMSLoginButton({
super.key,
});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async => await DynamicSDK.instance.auth.sms.sendOTP(
PhoneData(
phone: phone, // User's phone number
iso2: 'US',
dialCode: '+1',
),
),
child: const Text('SMS Login'),
);
}
}
- Verity OTP
class VerifyOTPButton extends StatelessWidget {
const VerifyOTPButton({
super.key,
});
@override
Widget build(BuildContext context) {
return ElevatedButton(
// For email use await DynamicSDK.instance.auth.email.verifyOTP(code),
onPressed: () async => await DynamicSDK.instance.auth.sms.verifyOTP(code), // Verification code
child: const Text('Verify Code'),
);
}
}
Wallets Module
- Get network
Future<String> getNetworkInfo({required BaseWallet wallet}) async {
final network = await DynamicSDK.instance.wallets.getNetwork(wallet: wallet);
final name = getNetworkName(network.value);
return name;
}
String getNetworkName(networkId) {
final evm = DynamicSDK.instance.networks.evm;
bool isEvm = evm.any((network) => network.networkId == networkId);
if (isEvm) {
final network = evm.firstWhere(
(network) {
return network.networkId == networkId;
},
);
return network.name;
} else {
return networkId;
}
}
- Switch networks
void switchNetwork({
required BaseWallet wallet,
required int chainId,
}) async {
await DynamicSDK.instance.wallets.switchNetwork(
wallet: wallet,
network: Network(chainId),
);
}
- Sign message
Future<String?> signMessage({
required String message,
required BaseWallet wallet,
}) async {
try {
final signedMessage = await DynamicSDK.instance.wallets.signMessage(
message: message,
wallet: wallet,
);
return signedMessage;
} catch (e) {
print(e);
rethrow;
}
}
Other methods like getBalance
and setPrimary
are as straight forward as the ones above.
You can read more about our client package here.
Responses are generated using AI and may contain mistakes.