sm_ai_support 1.0.6
sm_ai_support: ^1.0.6 copied to clipboard
A comprehensive Flutter package for integrating AI-powered customer support with real-time chat, media sharing, and multi-language support.
π SM AI Support #
A comprehensive Flutter package for integrating AI-powered customer support into your mobile applications
Real-time chat β’ Media sharing β’ Multi-language β’ Tenant-based customization
Features β’ Installation β’ Quick Start β’ Documentation β’ Examples
β¨ Features #
π― Core Functionality #
- π¬ Real-time Chat - WebSocket-powered instant messaging with delivery status and typing indicators
- π€ AI-Powered Support - Intelligent responses and automated assistance
- π± Advanced Media Support - Share images, videos, files, and documents
- Automatic image compression and optimization
- Chunked file upload for large files
- Support for multiple file types (PDF, DOC, DOCX, XLS, XLSX, images, videos)
- Upload progress tracking with cancellation support
- π Multi-language - Built-in English and Arabic support with RTL layout
- π€ Flexible Authentication - Anonymous and authenticated user flows with auto-login support
- π Auto-Login - Seamless authentication for existing app users without OTP
- π Session Management - Organized conversation history with persistence and search
π’ Enterprise Ready #
- ποΈ Multi-tenant Architecture - Perfect for SaaS applications
- π¨ Dynamic Theming - Automatic branding fetch from tenant configuration
- π Secure Communications - End-to-end encryption and HMAC signatures
- π Analytics Ready - Built-in tracking and monitoring capabilities
- β‘ High Performance - Optimized for large-scale deployments
π¨ User Experience #
- π± Responsive Design - Optimized for all screen sizes and orientations
- π Customizable UI - Tenant-specific branding and color schemes
- β¨ Smooth Animations - Polished transitions and loading states
- βΏ Accessibility - Screen reader compatibility and semantic labels
- π Theme Support - Light and dark mode compatibility
π¦ Installation #
Add this to your package's pubspec.yaml file:
dependencies:
sm_ai_support: ^0.0.1
Then run:
flutter pub get
Platform Requirements #
| Platform | Minimum Version |
|---|---|
| Flutter | 1.17.0+ |
| Dart | 3.8.1+ |
| iOS | 12.0+ |
| Android | API 21+ (Android 5.0) |
Required Permissions #
Android (android/app/src/main/AndroidManifest.xml):
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<!-- Storage permissions for Android 12 and below -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<!-- Media permissions for Android 13 and above -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
Android Queries (Add to android/app/src/main/AndroidManifest.xml inside <manifest> tag):
<queries>
<!-- Required for file_picker to pick files -->
<intent>
<action android:name="android.intent.action.GET_CONTENT"/>
</intent>
<!-- Required for open_filex to open files -->
<intent>
<action android:name="android.intent.action.VIEW"/>
<data android:mimeType="*/*"/>
</intent>
<!-- Camera intent -->
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE"/>
</intent>
</queries>
iOS (ios/Runner/Info.plist):
<key>NSCameraUsageDescription</key>
<string>We need access to your camera to take photos for support</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need access to your photo library to select images for support</string>
<key>NSMicrophoneUsageDescription</key>
<string>We need access to your microphone for audio messages</string>
π Quick Start #
1. Import the package #
import 'package:sm_ai_support/sm_ai_support.dart';
2. Basic Implementation #
import 'package:flutter/material.dart';
import 'package:sm_ai_support/sm_ai_support.dart';
class SupportPage extends StatelessWidget {
const SupportPage({super.key});
@override
Widget build(BuildContext context) {
return SMSupport(
parentContext: context,
smSupportData: SMSupportData(
appName: 'Your App Name',
locale: SMSupportLocale.en, // or SMSupportLocale.ar
tenantId: 'your_tenant_id',
apiKey: 'your_api_key_here', // Required for authentication
secretKey: 'your_secret_key_here', // Required: For HMAC request signing
baseUrl: 'https://your-api-server.com/api/core', // REST API base URL
socketBaseUrl: 'wss://your-api-server.com/ws', // WebSocket base URL
),
);
}
}
3. Navigate to Support #
// From anywhere in your app
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SupportPage()),
);
π Documentation #
Configuration Options #
SMSupportData Parameters
| Parameter | Type | Required | Description | Default |
|---|---|---|---|---|
appName |
String |
β | Your application name | - |
locale |
SMSupportLocale |
β | Language preference (en/ar) | - |
tenantId |
String |
β | Your unique tenant identifier | - |
apiKey |
String |
β | API key for authentication (stored securely) | - |
secretKey |
String |
β | Secret key for HMAC request signing (stored securely) | - |
baseUrl |
String |
β | Base URL for REST API endpoints (e.g., https://api.example.com/api/core) |
- |
socketBaseUrl |
String |
β | Base URL for WebSocket connections (e.g., wss://api.example.com/ws) |
- |
customer |
CustomerData? |
β | Optional customer data for automatic login | null |
Available Locales
// English interface (LTR)
SMSupportLocale.en
// Arabic interface (RTL)
SMSupportLocale.ar
Advanced Configuration #
Secure Configuration
SMSupport(
parentContext: context,
smSupportData: SMSupportData(
appName: 'My App',
locale: SMSupportLocale.en,
tenantId: 'tenant_123',
apiKey: 'your_secure_api_key',
secretKey: 'your_hmac_secret',
baseUrl: 'https://your-api-server.com/api/core',
socketBaseUrl: 'wss://your-api-server.com/ws',
),
)
Security Features
The package automatically handles secure storage of sensitive data and request signing:
- API Key: Stored using
flutter_secure_storagefor secure authentication - Secret Key: Used for HMAC-SHA256 request signing to ensure request integrity
- HMAC Signatures: All API requests are automatically signed with HMAC-SHA256
- Automatic Cleanup: Keys are cleared when the app is uninstalled
- Secure Storage: Uses platform-specific secure storage (iOS Keychain, Android EncryptedSharedPreferences)
// Check if configuration is initialized
final hasApiKey = await SMConfig.hasAPIKey();
final hasSecretKey = await SMConfig.hasSecretKey();
// Get stored keys (if needed for debugging)
final apiKey = await SMConfig.getAPIKey();
final secretKey = await SMConfig.getSecretKey();
// Clear individual keys
await SMConfig.clearAPIKey();
await SMConfig.clearSecretKey();
// Clear all secure data (for logout/reset)
await SMConfig.clearAllSecureData();
HMAC Request Signing:
All HTTP requests are automatically signed using HMAC-SHA256. The signature is computed from:
- Request timestamp (Unix timestamp in seconds)
- HTTP method (GET, POST, etc.)
- Request path
- Request body (for POST/PUT requests)
The signature is sent in the X-Signature header, and the timestamp in the X-Timestamp header. This ensures:
- Request authenticity
- Protection against replay attacks
- Request integrity verification
Auto-Login Feature
The package supports automatic user authentication without requiring OTP verification. This is useful when you already have authenticated users in your app and want to seamlessly integrate the support system.
Basic Auto-Login:
import 'package:sm_ai_support/sm_ai_support.dart';
SMSupport(
parentContext: context,
smSupportData: SMSupportData(
appName: 'My App',
locale: SMSupportLocale.en,
tenantId: 'tenant_123',
apiKey: 'your_api_key',
secretKey: 'your_secret_key',
baseUrl: 'https://your-api-server.com/api/core',
socketBaseUrl: 'wss://your-api-server.com/ws',
// Auto-login with customer data
customer: CustomerData(
countryCode: '+966', // Country code (e.g., +1, +44, +966)
phone: '501234567', // Phone number without country code
name: 'John Doe', // Customer name
),
),
)
How Auto-Login Works:
- When you provide
customerdata inSMSupportData, the package automatically authenticates the user during initialization - The API endpoint
/in-app/auto-loginis called with:phone: Combined country code + phone number (e.g., "+966501234567")name: Customer name
- On successful authentication:
- User receives an authentication token (same as OTP verification)
- Token is securely stored for future sessions
- Any anonymous sessions are automatically assigned to the authenticated user
- User can immediately access all authenticated features
- If auto-login fails:
- Error is logged but doesn't block initialization
- User can still use the support system as an anonymous user
Real-World Example:
class UserSupportPage extends StatelessWidget {
final User currentUser; // Your app's user model
const UserSupportPage({super.key, required this.currentUser});
@override
Widget build(BuildContext context) {
return SMSupport(
parentContext: context,
smSupportData: SMSupportData(
appName: 'My App',
locale: SMSupportLocale.en,
tenantId: 'tenant_123',
apiKey: 'your_api_key',
secretKey: 'your_secret_key',
baseUrl: 'https://your-api-server.com/api/core',
socketBaseUrl: 'wss://your-api-server.com/ws',
// Seamlessly login with existing user data
customer: CustomerData(
countryCode: currentUser.countryCode,
phone: currentUser.phoneNumber,
name: currentUser.fullName,
),
),
);
}
}
Benefits:
- π Seamless Experience: No need for users to authenticate again
- π Session Continuity: Preserves conversation history across sessions
- π Secure: Uses the same authentication mechanism as OTP verification
- β‘ Fast: Instant authentication without user interaction
- π― Flexible: Falls back gracefully if authentication fails
CustomerData Model:
CustomerData({
required String countryCode, // Country code with + (e.g., "+1", "+966")
required String phone, // Phone number without country code
required String name, // Customer's full name
})
π‘ Examples #
Complete Integration Example #
import 'package:flutter/material.dart';
import 'package:sm_ai_support/sm_ai_support.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SM AI Support Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('My Awesome App'),
actions: [
// Support button in app bar
IconButton(
icon: const Icon(Icons.support_agent),
onPressed: () => _openSupport(context),
tooltip: 'Get Support',
),
],
),
body: const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.home, size: 100, color: Colors.blue),
SizedBox(height: 20),
Text(
'Welcome to My App!',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
SizedBox(height: 10),
Text('Need help? Tap the support icon above.'),
],
),
),
// Floating support button
floatingActionButton: FloatingActionButton.extended(
onPressed: () => _openSupport(context),
icon: const Icon(Icons.chat),
label: const Text('Support'),
),
);
}
void _openSupport(BuildContext context) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SMSupport(
parentContext: context,
smSupportData: SMSupportData(
appName: 'My Awesome App',
locale: SMSupportLocale.en,
tenantId: 'your_tenant_id',
apiKey: 'your_api_key_here',
secretKey: 'your_secret_key_here', // Required
baseUrl: 'https://your-api-server.com/api/core',
socketBaseUrl: 'wss://your-api-server.com/ws',
),
),
),
);
}
}
Multi-language Support #
class LocalizedSupportPage extends StatelessWidget {
final bool isArabic;
const LocalizedSupportPage({super.key, this.isArabic = false});
@override
Widget build(BuildContext context) {
return SMSupport(
parentContext: context,
smSupportData: SMSupportData(
appName: isArabic ? 'ΨͺΨ·Ψ¨ΩΩΩ Ψ§ΩΨ±Ψ§Ψ¦ΨΉ' : 'My Awesome App',
locale: isArabic ? SMSupportLocale.ar : SMSupportLocale.en,
tenantId: 'your_tenant_id',
apiKey: 'your_api_key_here',
secretKey: 'your_secret_key_here', // Required
baseUrl: 'https://your-api-server.com/api/core',
socketBaseUrl: 'wss://your-api-server.com/ws',
),
);
}
}
Real-World Integration Example #
class ProductionSupportPage extends StatelessWidget {
final String userLocale;
const ProductionSupportPage({super.key, required this.userLocale});
@override
Widget build(BuildContext context) {
return SMSupport(
parentContext: context,
smSupportData: SMSupportData(
appName: 'Production App',
locale: userLocale == 'ar' ? SMSupportLocale.ar : SMSupportLocale.en,
tenantId: 'prod_tenant_123',
apiKey: const String.fromEnvironment('SM_SUPPORT_API_KEY'),
secretKey: const String.fromEnvironment('SM_SUPPORT_SECRET_KEY'),
baseUrl: const String.fromEnvironment(
'SM_SUPPORT_BASE_URL',
defaultValue: 'https://api.example.com/api/core',
),
socketBaseUrl: const String.fromEnvironment(
'SM_SUPPORT_SOCKET_URL',
defaultValue: 'wss://api.example.com/ws',
),
),
);
}
}
// Usage with environment variables:
// flutter run --dart-define=SM_SUPPORT_API_KEY=your_key \
// --dart-define=SM_SUPPORT_SECRET_KEY=your_secret \
// --dart-define=SM_SUPPORT_BASE_URL=https://api.example.com/api/core \
// --dart-define=SM_SUPPORT_SOCKET_URL=wss://api.example.com/ws
ποΈ Architecture #
Package Structure #
sm_ai_support/
βββ π± Core Components
β βββ π¨ UI Widgets & Themes
β βββ π Network Layer (Dio + Socket.IO)
β βββ πΎ Data Models & Storage
β βββ π Security & Authentication (HMAC + Secure Storage)
β βββ π€ Media Upload (Chunked & Streaming)
βββ π Features
β βββ π¬ Real-time Chat (WebSocket)
β βββ π Media Management (Image, Video, File)
β βββ π Session Handling
β βββ π·οΈ Category System
βββ π Internationalization
βββ πΊπΈ English (LTR)
βββ πΈπ¦ Arabic (RTL)
Key Dependencies #
- State Management:
flutter_bloc- BLoC pattern for reactive state management - Networking:
dio- HTTP client with interceptors and request signing - WebSocket:
socket_io_client- Real-time bidirectional communication - Secure Storage:
flutter_secure_storage- Platform-specific encrypted storage - Media Handling:
image_picker,file_picker,cached_network_image - Video Playback:
video_player,chewie- Video player with controls - Localization:
flutter_localizations,intl- Multi-language support
State Management #
The package uses BLoC pattern for reactive state management:
SMSupportCubit- Main application stateSingleSessionCubit- Individual chat session state- Automatic state persistence and restoration
Network Architecture #
- REST API (Dio) - Configuration, authentication, file uploads with HMAC signing
- WebSocket (Socket.IO) - Real-time messaging, typing indicators, and status updates
- Automatic Reconnection - Handles network interruptions gracefully
- Request Signing - All requests are automatically signed with HMAC-SHA256
- Error Handling - Comprehensive error handling with user-friendly messages
- Retry Logic - Automatic retry for failed requests with exponential backoff
π§ Advanced Features #
Security Features #
- π HMAC-SHA256 Signatures - Automatic request signing for authentication and integrity
- π Secure Storage - Platform-specific encrypted storage (iOS Keychain, Android EncryptedSharedPreferences)
- π‘οΈ Input Validation - XSS and injection protection
- π API Key Management - Secure credential storage and retrieval
- β±οΈ Replay Attack Prevention - Timestamp-based request validation
- π± Transport Security - HTTPS/WSS encrypted communications
Media Upload Features #
- π€ Chunked Upload - Large files are automatically split into chunks for reliable upload
- π Progress Tracking - Real-time upload progress with percentage and cancel option
- πΌοΈ Image Optimization - Automatic compression and resizing for faster uploads
- πΉ Video Support - Upload and playback of video files with custom player
- π Document Support - PDF, DOC, DOCX, XLS, XLSX file uploads
- β‘ Upload Queue - Multiple files can be queued and uploaded sequentially
- π Retry Logic - Automatic retry on failed uploads with exponential backoff
- β Cancellation - Users can cancel ongoing uploads at any time
Performance Optimizations #
- β‘ Lazy Loading - On-demand resource loading
- πΌοΈ Image Caching - Efficient media management with
cached_network_image - π¦ Minimal Dependencies - Optimized package size
- π Connection Pooling - Optimized network usage with Dio
- π± Memory Management - Efficient handling of large media files
- βοΈ Background Processing - Media compression and upload in isolates
Monitoring & Analytics #
- π Usage Metrics - Built-in analytics hooks
- π Error Tracking - Comprehensive error reporting
- π Performance Monitoring - Real-time performance metrics
- π Debug Tools - Development and testing utilities
π οΈ Development #
Running the Example #
cd example
flutter pub get
flutter run
Testing #
flutter test
Contributing #
We welcome contributions! Please see our Contributing Guide for details.
π API Reference #
Core Classes #
SMSupport Widget
The main widget that provides the support interface.
SMSupport({
required BuildContext parentContext,
required SMSupportData smSupportData,
Key? key,
})
SMSupportData Model
Configuration data for the support system.
SMSupportData({
required String appName, // Your application name
required SMSupportLocale locale, // UI language (en or ar)
required String tenantId, // Your tenant identifier
required String apiKey, // API authentication key
required String secretKey, // HMAC signing secret key
required String baseUrl, // REST API base URL (e.g., 'https://api.example.com/api/core')
required String socketBaseUrl, // WebSocket base URL (e.g., 'wss://api.example.com/ws')
CustomerData? customer, // Optional: Auto-login customer data
})
CustomerData Model
Customer data for automatic authentication.
CustomerData({
required String countryCode, // Country code with + (e.g., "+1", "+966")
required String phone, // Phone number without country code
required String name, // Customer's full name
})
// Example:
const customer = CustomerData(
countryCode: '+966',
phone: '501234567',
name: 'John Doe',
);
// Provides fullPhoneNumber getter: "+966501234567"
print(customer.fullPhoneNumber);
Services #
SMConfig
Manages secure configuration and API keys.
// Check if configuration is initialized
final hasApiKey = await SMConfig.hasAPIKey();
final hasSecretKey = await SMConfig.hasSecretKey();
// Get stored keys (if needed)
final apiKey = await SMConfig.getAPIKey();
final secretKey = await SMConfig.getSecretKey();
// Clear individual keys
await SMConfig.clearAPIKey();
await SMConfig.clearSecretKey();
// Clear all secure data (for logout/reset)
await SMConfig.clearAllSecureData();
AuthManager
Handles user authentication and session management.
// Initialize authentication system
await AuthManager.init();
WebSocketService
Manages real-time communication for chat functionality.
final wsService = WebSocketService();
// WebSocket connection is handled automatically by the package
π Troubleshooting #
Common Issues #
Build Errors
Problem: Compilation errors after installation
# Solution: Clean and rebuild
flutter clean
flutter pub get
flutter run
Network Issues
Problem: Connection timeouts or SSL errors
// Solution: Ensure proper configuration with all required parameters
SMSupportData(
appName: 'My App',
locale: SMSupportLocale.en,
tenantId: 'your_tenant_id',
apiKey: 'valid_api_key_here', // Required
secretKey: 'valid_secret_key_here', // Required
baseUrl: 'https://api.example.com/api/core', // Required
socketBaseUrl: 'wss://api.example.com/ws', // Required
)
Localization Issues
Problem: Text not displaying in correct language
// Solution: Ensure proper locale setup in your main app
MaterialApp(
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
Locale('en', 'US'),
Locale('ar', 'SA'),
],
// ... rest of config
)
Permission Issues
Problem: Camera or file picker not working
Solution: Ensure you've added the required permissions (see Required Permissions section above)
For runtime permissions:
// The package automatically handles permission requests
// Just ensure the permissions are declared in your manifest files
Problem: Image picker crashes on Android 13+
Solution: Add the new photo picker permissions:
<!-- Android 13+ -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
Upload Issues
Problem: File upload fails or times out
Solution:
- Check your network connection
- Verify your API key and secret key are correct
- Ensure your server's upload size limits are sufficient
- For large files, the package automatically uses chunked upload
π License #
This project is licensed under the MIT License - see the LICENSE file for details.
π Acknowledgments #
- Built with β€οΈ by the [Unicode Team]
- Powered by Flutter and Dart
π Changelog #
See CHANGELOG.md for a detailed history of changes.
Made with β€οΈ by the Unicode Team