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:  
Platform support: The Flutter SDK currently supports iOS and Android only.
Web and desktop platforms are not supported at this time.
 
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: 1.0.0
 
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.