tyrads_sdk 4.0.0
tyrads_sdk: ^4.0.0 copied to clipboard
Show TyrAds offer wall.
import 'dart:developer';
import 'package:example/env/env.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tyrads_sdk/tyrads_sdk.dart';
import 'dart:io';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await initializeTyrads();
runApp(const MyApp());
}
bool _isTyradsInitialized = false;
const String _defaultUserId = 'acmo_user_01';
final GlobalKey<NavigatorState> hostNavKey = GlobalKey<NavigatorState>();
const List<Map<String, String>> configOptions = [
{'label': 'Tyrreward', 'value': 'tyrreward'},
{'label': 'Belanda 1', 'value': 'belanda1'},
{'label': 'Belanda 2', 'value': 'belanda2'},
{'label': 'Belanda 3', 'value': 'belanda3'},
];
Map<String, String> _getConfigKeys(String selectedConfig) {
final isAndroid = defaultTargetPlatform == TargetPlatform.android;
switch (selectedConfig) {
case 'tyrreward':
return isAndroid
? {
'apiKey': Env.ANDROID_TYRREWARD_SDK_KEY,
'apiSecret': Env.ANDROID_TYRREWARD_SDK_SECRET,
'encKey': Env.ANDROID_TYRREWARD_SDK_ENC_KEY
}
: {
'apiKey': Env.IOS_TYRREWARD_SDK_KEY,
'apiSecret': Env.IOS_TYRREWARD_SDK_SECRET,
'encKey': Env.IOS_TYRREWARD_SDK_ENC_KEY
};
case 'belanda2':
return isAndroid
? {
'apiKey': Env.ANDROID_BELANDA2_TYRADS_SDK_KEY,
'apiSecret': Env.ANDROID_BELANDA2_TYRADS_SDK_SECRET,
'encKey': Env.ANDROID_BELANDA2_TYRADS_SDK_ENC_KEY
}
: {
'apiKey': Env.IOS_BELANDA2_TYRADS_SDK_KEY,
'apiSecret': Env.IOS_BELANDA2_TYRADS_SDK_SECRET,
'encKey': Env.IOS_BELANDA2_TYRADS_SDK_ENC_KEY
};
case 'belanda3':
return isAndroid
? {
'apiKey': Env.ANDROID_BELANDA3_TYRADS_SDK_KEY,
'apiSecret': Env.ANDROID_BELANDA3_TYRADS_SDK_SECRET,
'encKey': Env.ANDROID_BELANDA3_TYRADS_SDK_ENC_KEY
}
: {
'apiKey': Env.IOS_BELANDA3_TYRADS_SDK_KEY,
'apiSecret': Env.IOS_BELANDA3_TYRADS_SDK_SECRET,
'encKey': Env.IOS_BELANDA3_TYRADS_SDK_ENC_KEY
};
case 'belanda1':
default:
return isAndroid
? {
'apiKey': Env.ANDROID_BELANDA1_TYRADS_SDK_KEY,
'apiSecret': Env.ANDROID_BELANDA1_TYRADS_SDK_SECRET,
'encKey': Env.ANDROID_BELANDA1_TYRADS_SDK_ENC_KEY
}
: {
'apiKey': Env.IOS_BELANDA1_TYRADS_SDK_KEY,
'apiSecret': Env.IOS_BELANDA1_TYRADS_SDK_SECRET,
'encKey': Env.IOS_BELANDA1_TYRADS_SDK_ENC_KEY
};
}
}
Future<String> _getUserId() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('tyrads_user_id') ?? _defaultUserId;
}
Future<void> _saveUserId(String userId) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('tyrads_user_id', userId);
}
String? _previousApiKey;
String? _previousApiSecret;
String? _previousEncKey;
String? _previousEngagementId;
String? _previousPlacementId;
String? _previousUserID;
int? _previousAge;
int? _previousGender;
bool? _previousSkipInitialPages;
Future<void> initializeTyrads({
String? apiKey,
String? apiSecret,
String? encKey,
String? engagementId,
String? placementId,
String? userID,
int? age,
int? gender,
bool skipInitialPages = false,
}) async {
final prefs = await SharedPreferences.getInstance();
final configKeys = _getConfigKeys(
prefs.getString('selectedConfig') ?? 'belanda1');
final finalApiKey =
(apiKey != null && apiKey.isNotEmpty) ? apiKey : configKeys['apiKey']!;
final finalApiSecret = (apiSecret != null && apiSecret.isNotEmpty)
? apiSecret
: configKeys['apiSecret']!;
final finalEncKey =
(encKey != null && encKey.isNotEmpty) ? encKey : configKeys['encKey']!;
final finalUserId =
(userID != null && userID.isNotEmpty) ? userID : await _getUserId();
if (_isTyradsInitialized &&
_previousApiKey == finalApiKey &&
_previousApiSecret == finalApiSecret &&
_previousEncKey == finalEncKey &&
_previousEngagementId == engagementId &&
_previousPlacementId == placementId &&
_previousUserID == finalUserId &&
_previousAge == age &&
_previousGender == gender &&
_previousSkipInitialPages == skipInitialPages) {
return;
}
log("apiKey: $finalApiKey");
log("apiSecret: $finalApiSecret");
log("encKey: $finalEncKey");
log("engagementId: $engagementId");
log("placementId: $placementId");
log("userID: $finalUserId");
log("age: $age");
log("gender: $gender");
log("skipInitialPages: $skipInitialPages");
await Tyrads.instance.init(
navigatorKey: hostNavKey,
apiKey: finalApiKey,
apiSecret: finalApiSecret,
encryptionKey: finalEncKey,
engagementId: engagementId,
placementId: placementId,
config: Platform.isAndroid
? TyradsConfig(skipInitialPages: skipInitialPages)
: null,
userInfo: TyradsUserInfo(
email: "example@tyrads.com",
phoneNumber: "001234567890",
userGroup: "High purchase user",
age: age,
gender: gender,
),
mediaSourceInfo: TyradsMediaSourceInfo(
mediaSourceName: "Facebook",
mediaCampaignName: "Summer2023Promo",
mediaSourceId: "FB001",
mediaSubSourceId: "FB001_Stories",
incentivized: false,
mediaAdsetName: "YoungAdults25-34",
mediaAdsetId: "AD001",
mediaCreativeName: "SummerSale_Video",
mediaCreativeId: "CR001",
sub1: "ReferralCode123",
sub2: "OrganicInstall",
sub3: "HighValueUser",
sub4: "FirstTimeUser",
sub5: "iOSDevice",
),
);
await Tyrads.instance.loginUser(userID: finalUserId);
await _saveUserId(
finalUserId); // only userId is persisted — keys always come from Env
Tyrads.instance.setCallback(TyradsCallbackType.campaignDetail, (data) {
debugPrint("TyradsCallbackType.campaignDetail: $data");
});
Tyrads.instance.setCallback(TyradsCallbackType.campaignActivated, (data) {
debugPrint("TyradsCallbackType.activated: $data");
});
_previousApiKey = finalApiKey;
_previousApiSecret = finalApiSecret;
_previousEncKey = finalEncKey;
_previousEngagementId = engagementId;
_previousPlacementId = placementId;
_previousUserID = finalUserId;
_previousAge = age;
_previousGender = gender;
_isTyradsInitialized = true;
_previousSkipInitialPages = skipInitialPages;
debugPrint('Tyrads initialized successfully');
}
void clearTyradsCache() {
_previousApiKey = null;
_previousApiSecret = null;
_previousEncKey = null;
_previousEngagementId = null;
_previousPlacementId = null;
_previousUserID = null;
_previousAge = null;
_previousGender = null;
_isTyradsInitialized = false;
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: hostNavKey,
title: 'Tyrrewards SDK Demo',
theme: ThemeData.light(),
home: Builder(builder: (context) {
return const MyHomePage(title: "Tyrads SDK");
}),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late TextEditingController apiKeyController;
late TextEditingController apiSecretController;
late TextEditingController encKeyController;
late TextEditingController engagementIdController;
late TextEditingController placementIdController;
late TextEditingController userIDController;
bool loading = false;
int style = 1;
int initialPageMode = 1;
String selectedConfig = 'belanda1';
int? selectedAge;
int? selectedGender;
int widgetKey = 0;
bool isReady = false;
@override
void initState() {
super.initState();
apiKeyController = TextEditingController();
apiSecretController = TextEditingController();
encKeyController = TextEditingController();
engagementIdController = TextEditingController();
placementIdController = TextEditingController();
userIDController = TextEditingController();
_loadStoredCredentials();
}
Future<void> _loadStoredCredentials() async {
final prefs = await SharedPreferences.getInstance();
final storedConfig = prefs.getString('selectedConfig');
final configToUse = storedConfig ?? selectedConfig;
if (storedConfig != null && storedConfig != selectedConfig) {
setState(() {
selectedConfig = storedConfig;
});
}
final configKeys = _getConfigKeys(configToUse);
final userId = prefs.getString('tyrads_user_id') ?? _defaultUserId;
setState(() {
apiKeyController.text = configKeys['apiKey']!;
apiSecretController.text = configKeys['apiSecret']!;
encKeyController.text = configKeys['encKey']!;
userIDController.text = userId;
isReady = true;
});
}
Future<void> _onConfigChange(String value) async {
final newKeys = _getConfigKeys(value);
setState(() {
selectedConfig = value;
apiKeyController.text = newKeys['apiKey']!;
apiSecretController.text = newKeys['apiSecret']!;
encKeyController.text = newKeys['encKey']!;
isReady = false;
});
final prefs = await SharedPreferences.getInstance();
await prefs.setString('selectedConfig', value);
clearTyradsCache();
await initializeTyrads(
apiKey: newKeys['apiKey']!,
apiSecret: newKeys['apiSecret']!,
encKey: newKeys['encKey']!,
);
setState(() {
widgetKey++;
isReady = true;
});
}
void _showOfferwall() async {
final apiKey = apiKeyController.text.trim();
final apiSecret = apiSecretController.text.trim();
final userID = userIDController.text.trim();
bool hasApiKey = apiKey.isNotEmpty;
bool hasApiSecret = apiSecret.isNotEmpty;
bool hasUserID = userID.isNotEmpty;
if ((hasApiKey && !hasApiSecret) ||
(hasApiSecret && !hasApiKey) ||
(hasUserID && (hasApiKey ^ hasApiSecret))) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'Please enter both API Key and Secret if either is used.')),
);
return;
}
setState(() {
loading = true;
});
await Tyrads.instance.initializationWait.future;
await initializeTyrads(
apiKey: apiKeyController.text,
apiSecret: apiSecretController.text,
encKey: encKeyController.text,
engagementId: engagementIdController.text,
placementId: placementIdController.text,
userID: userIDController.text,
age: selectedAge,
gender: selectedGender,
skipInitialPages: initialPageMode == 2,
);
setState(() {
loading = false;
});
Tyrads.instance.showOffers();
}
@override
void dispose() {
super.dispose();
apiKeyController.dispose();
apiSecretController.dispose();
encKeyController.dispose();
engagementIdController.dispose();
placementIdController.dispose();
userIDController.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (isReady)
KeyedSubtree(
key: ValueKey(widgetKey),
child: PremiumOffersWidget(
widgetStyle: style == 1
? PremiumWidgetStyles.list
: PremiumWidgetStyles.sliderCards,
),
)
else
Container(
width: double.maxFinite,
height: 200,
decoration: BoxDecoration(
color: Colors.grey.shade200,
borderRadius: BorderRadius.circular(8),
),
child: const Center(
child: CircularProgressIndicator(),
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: Platform.isAndroid
? MainAxisAlignment.spaceEvenly
: MainAxisAlignment.center,
children: [
DropdownButton(
value: style,
items: const [
DropdownMenuItem(value: 1, child: Text("List View")),
DropdownMenuItem(value: 2, child: Text("Slide Cards")),
],
onChanged: (value) {
setState(() {
style = value ?? 1;
});
},
),
Visibility(
visible: Platform.isAndroid,
child: DropdownButton(
value: initialPageMode,
items: const [
DropdownMenuItem(
value: 1, child: Text("Show Initial Pages")),
DropdownMenuItem(
value: 2, child: Text("Hide Initial Pages")),
],
onChanged: (value) async {
setState(() {
initialPageMode = value ?? 1;
});
await initializeTyrads(
apiKey: apiKeyController.text.isEmpty
? null
: apiKeyController.text,
apiSecret: apiSecretController.text.isEmpty
? null
: apiSecretController.text,
encKey: encKeyController.text.isEmpty
? null
: encKeyController.text,
engagementId: engagementIdController.text.isEmpty
? null
: engagementIdController.text,
userID: userIDController.text.isEmpty
? null
: userIDController.text,
age: selectedAge,
gender: selectedGender,
skipInitialPages: initialPageMode == 2,
);
setState(() {
widgetKey++;
});
},
),
),
],
),
const SizedBox(height: 16),
SizedBox(
width: double.maxFinite,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Select Config:',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Color(0xFF333333),
),
),
const SizedBox(height: 5),
ButtonTheme(
alignedDropdown: true,
child: DropdownButtonFormField<String>(
initialValue: selectedConfig,
decoration: const InputDecoration(
border: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(8)),
borderSide: BorderSide(color: Color(0xFFCCCCCC)),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 12, vertical: 12),
filled: true,
fillColor: Colors.white,
),
items: configOptions.map((option) {
return DropdownMenuItem<String>(
value: option['value'],
child: Text(option['label']!,
style: const TextStyle(color: Colors.black)),
);
}).toList(),
onChanged: (value) {
if (value != null) _onConfigChange(value);
},
),
),
const SizedBox(height: 4),
Text(
'Platform: ${Platform.isAndroid ? 'Android' : 'iOS'} | Config: ${selectedConfig.toUpperCase()}',
style: const TextStyle(
fontSize: 12,
color: Color(0xFF666666),
fontStyle: FontStyle.italic,
),
),
],
),
),
const SizedBox(height: 10),
Row(
children: [
Expanded(
child: DropdownButtonFormField<int>(
initialValue: selectedAge,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Age',
contentPadding:
EdgeInsets.symmetric(horizontal: 12, vertical: 8),
),
items:
List.generate(83, (index) => index + 18).map((age) {
return DropdownMenuItem(
value: age,
child: Text(age.toString()),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedAge = value;
});
},
),
),
const SizedBox(width: 10),
Expanded(
child: DropdownButtonFormField<int>(
initialValue: selectedGender,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Gender',
contentPadding:
EdgeInsets.symmetric(horizontal: 12, vertical: 8),
),
items: const [
DropdownMenuItem(value: 1, child: Text("Male")),
DropdownMenuItem(value: 2, child: Text("Female")),
],
onChanged: (value) {
setState(() {
selectedGender = value;
});
},
),
),
],
),
const SizedBox(height: 10),
SizedBox(
width: double.maxFinite,
child: TextField(
controller: apiKeyController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: "Api_Key (Optional)",
),
),
),
const SizedBox(height: 10),
SizedBox(
width: double.maxFinite,
child: TextField(
controller: apiSecretController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: "Api_Secret (Optional)",
),
),
),
const SizedBox(height: 10),
SizedBox(
width: double.maxFinite,
child: TextField(
controller: encKeyController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: "Encryption Key (Optional)",
),
),
),
const SizedBox(height: 10),
Row(
children: [
Expanded(
child: TextField(
controller: engagementIdController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: "Engagement Id (Optional)",
),
),
),
const SizedBox(width: 10),
Expanded(
child: TextField(
controller: placementIdController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: "Placement Id (Optional)",
),
),
),
],
),
const SizedBox(height: 10),
SizedBox(
width: double.maxFinite,
child: TextField(
controller: userIDController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: "Custom user Id or empty for anonymous user",
),
),
),
const SizedBox(height: 10),
OutlinedButton(
onPressed: loading ? null : _showOfferwall,
child: Row(
mainAxisSize: MainAxisSize.min,
spacing: 12,
children: [
if (loading)
const SizedBox(
height: 22,
width: 22,
child: CircularProgressIndicator()),
const Text("Show offerwall"),
],
),
),
],
),
),
),
),
);
}
}