diff --git a/CHANGELOG.md b/CHANGELOG.md
index 70f48a6b..84241adf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 9.1.1
+* iOS error codes improved
+
## 9.1.0
* Added option to set context keys, quantity and other options for purchases. Context keys will allow you to associate the purchase with remote configuration if the product info was loaded from there.
* Deprecated old purchase functions. Use new one instead.
diff --git a/android/build.gradle b/android/build.gradle
index 0277bb8c..4b90c066 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -51,6 +51,6 @@ android {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
- implementation "io.qonversion.sandwich:sandwich:5.1.2"
+ implementation "io.qonversion.sandwich:sandwich:5.1.3"
implementation 'com.google.code.gson:gson:2.9.0'
}
diff --git a/example/android/build.gradle b/example/android/build.gradle
index abd58276..1c4b3235 100644
--- a/example/android/build.gradle
+++ b/example/android/build.gradle
@@ -27,6 +27,6 @@ subprojects {
project.evaluationDependsOn(':app')
}
-task clean(type: Delete) {
+tasks.register("clean", Delete) {
delete rootProject.buildDir
}
diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist
index f2872cf4..8c6e5614 100644
--- a/example/ios/Flutter/AppFrameworkInfo.plist
+++ b/example/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 9.0
+ 12.0
diff --git a/example/ios/Podfile b/example/ios/Podfile
index 5abda76a..eb8b0f9a 100644
--- a/example/ios/Podfile
+++ b/example/ios/Podfile
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
- platform :ios, '10.0'
+ platform :ios, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj
index bdf210d1..cf975ebc 100644
--- a/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/example/ios/Runner.xcodeproj/project.pbxproj
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 50;
+ objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@@ -199,7 +199,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1300;
+ LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
@@ -246,10 +246,12 @@
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
+ "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
@@ -417,7 +419,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -443,8 +445,11 @@
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 10.0;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
@@ -505,7 +510,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -554,7 +559,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -581,8 +586,11 @@
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 10.0;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
@@ -614,8 +622,11 @@
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 10.0;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index 3db53b6e..e67b2808 100644
--- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,6 +1,6 @@
UIViewControllerBasedStatusBarAppearance
+ CADisableMinimumFrameDurationOnPhone
+
+ UIApplicationSupportsIndirectInputEvents
+
diff --git a/example/lib/handling_notification.dart b/example/lib/handling_notification.dart
index 487ac555..405c6a1d 100644
--- a/example/lib/handling_notification.dart
+++ b/example/lib/handling_notification.dart
@@ -9,7 +9,7 @@ import 'constants.dart';
Future showNotification(RemoteMessage message) async {
Map messageData = message.data;
- if (messageData != null && !kIsWeb) {
+ if (!kIsWeb) {
String jsonMessageData = jsonEncode(messageData);
FlutterLocalNotificationsPlugin().show(
@@ -28,7 +28,7 @@ Future showNotification(RemoteMessage message) async {
}
/// This is called when user clicks on the notification
-Future onNotificationClick(Map messageData) async {
+Future onNotificationClick(Map ? messageData) async {
print("onNotificationClick");
if (messageData != null) {
final payload = await Automations.getSharedInstance().getNotificationCustomPayload(messageData);
diff --git a/example/lib/home.dart b/example/lib/home.dart
index 70c6d49b..6b1f45cb 100644
--- a/example/lib/home.dart
+++ b/example/lib/home.dart
@@ -13,14 +13,14 @@ class HomeView extends StatefulWidget {
}
class _HomeViewState extends State {
- Map _entitlements;
- Map _products;
+ Map? _entitlements = null;
+ Map? _products = null;
- StreamSubscription _shownScreensStream;
- StreamSubscription _startedActionsStream;
- StreamSubscription _failedActionsStream;
- StreamSubscription _finishedActionsStream;
- StreamSubscription _finishedAutomationsStream;
+ late StreamSubscription _shownScreensStream;
+ late StreamSubscription _startedActionsStream;
+ late StreamSubscription _failedActionsStream;
+ late StreamSubscription _finishedActionsStream;
+ late StreamSubscription _finishedAutomationsStream;
@override
void initState() {
@@ -31,36 +31,41 @@ class _HomeViewState extends State {
showNotification(message);
});
- FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
+ FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage? message) {
if (message != null) {
- onNotificationClick(message?.data);
+ onNotificationClick(message.data);
}
});
FirebaseMessaging.instance
.getInitialMessage()
- .then((RemoteMessage message) {
+ .then((RemoteMessage? message) {
if (message != null) {
- onNotificationClick(message?.data);
+ onNotificationClick(message.data);
}
});
- _shownScreensStream = Automations.getSharedInstance().shownScreensStream.listen((event) {
+ _shownScreensStream =
+ Automations.getSharedInstance().shownScreensStream.listen((event) {
// do any logic you need
});
- _startedActionsStream = Automations.getSharedInstance().startedActionsStream.listen((event) {
+ _startedActionsStream =
+ Automations.getSharedInstance().startedActionsStream.listen((event) {
// do any logic you need or track event
});
- _failedActionsStream = Automations.getSharedInstance().failedActionsStream.listen((event) {
+ _failedActionsStream =
+ Automations.getSharedInstance().failedActionsStream.listen((event) {
// do any logic you need or track event
});
- _finishedActionsStream = Automations.getSharedInstance().finishedActionsStream.listen((event) {
+ _finishedActionsStream =
+ Automations.getSharedInstance().finishedActionsStream.listen((event) {
if (event.type == ActionResultType.purchase) {
// do any logic you need
}
});
- _finishedAutomationsStream =
- Automations.getSharedInstance().finishedAutomationsStream.listen((event) {
+ _finishedAutomationsStream = Automations.getSharedInstance()
+ .finishedAutomationsStream
+ .listen((event) {
// do any logic you need or track event
});
}
@@ -94,12 +99,16 @@ class _HomeViewState extends State {
..._entitlementsFromMap(_entitlements ?? {}),
Padding(
padding: const EdgeInsets.all(8.0),
- child: FlatButton(
+ child: TextButton(
child: Text('Set custom userId'),
- color: Colors.blue,
- textColor: Colors.white,
- onPressed: () => Qonversion.getSharedInstance().setUserProperty(
- QUserPropertyKey.customUserId, 'userId')),
+ style: ButtonStyle(
+ backgroundColor: WidgetStateProperty.all(Colors.blue),
+ foregroundColor:
+ WidgetStateProperty.all(Colors.white),
+ ),
+ onPressed: () => Qonversion.getSharedInstance()
+ .setUserProperty(
+ QUserPropertyKey.customUserId, 'userId')),
),
Padding(
padding: const EdgeInsets.only(
@@ -107,10 +116,12 @@ class _HomeViewState extends State {
right: 8,
bottom: 8,
),
- child: FlatButton(
+ child: TextButton(
child: Text('Open ProductsView'),
- color: Colors.green,
- textColor: Colors.white,
+ style: ButtonStyle(
+ backgroundColor: WidgetStateProperty.all(Colors.green),
+ foregroundColor: WidgetStateProperty.all(Colors.white),
+ ),
onPressed: () =>
Navigator.of(context).pushNamed('products'),
),
@@ -121,10 +132,12 @@ class _HomeViewState extends State {
right: 8,
bottom: 8,
),
- child: FlatButton(
+ child: TextButton(
child: Text('Open ParamsView'),
- color: Colors.brown,
- textColor: Colors.white,
+ style: ButtonStyle(
+ backgroundColor: WidgetStateProperty.all(Colors.brown),
+ foregroundColor: WidgetStateProperty.all(Colors.white),
+ ),
onPressed: () =>
Navigator.of(context).pushNamed('params'),
),
@@ -136,11 +149,16 @@ class _HomeViewState extends State {
right: 8,
bottom: 8,
),
- child: FlatButton(
+ child: TextButton(
child: Text('Sync Purchases'),
- color: Colors.orange,
- textColor: Colors.white,
- onPressed: () => Qonversion.getSharedInstance().syncPurchases(),
+ style: ButtonStyle(
+ backgroundColor:
+ WidgetStateProperty.all(Colors.orange),
+ foregroundColor:
+ WidgetStateProperty.all(Colors.white),
+ ),
+ onPressed: () =>
+ Qonversion.getSharedInstance().syncPurchases(),
),
),
],
@@ -150,11 +168,11 @@ class _HomeViewState extends State {
}
Future _initPlatformState() async {
- const environment = kDebugMode ? QEnvironment.sandbox : QEnvironment.production;
+ const environment =
+ kDebugMode ? QEnvironment.sandbox : QEnvironment.production;
final config = new QonversionConfigBuilder(
- 'PV77YHL7qnGvsdmpTs7gimsxUvY-Znl2',
- QLaunchMode.subscriptionManagement
- )
+ 'PV77YHL7qnGvsdmpTs7gimsxUvY-Znl2',
+ QLaunchMode.subscriptionManagement)
.setEnvironment(environment)
.build();
Qonversion.initialize(config);
@@ -177,7 +195,7 @@ class _HomeViewState extends State {
}
Future _sendNotificationsToken() async {
- String deviceToken;
+ String? deviceToken;
switch (defaultTargetPlatform) {
case TargetPlatform.android:
{
@@ -202,47 +220,44 @@ class _HomeViewState extends State {
}
List _entitlementsFromMap(Map entitlements) {
- return entitlements.entries
- .map(
- (e) => ListTile(
- title: Text(e.key),
- subtitle: Text(
- e.value.productId ??
- '' + '\n' + e.value.id ??
- '' +
- '\n' +
- e.value.renewState.toString() +
- '\n' +
- (e.value.startedDate?.toString() ?? 'n/a') +
- '\n' +
- (e.value.expirationDate?.toString() ?? 'n/a') +
- '\n' +
- e.value.isActive.toString(),
- ),
- ),
- )
- .toList();
+ return entitlements.entries.map((e) {
+ var title = e.value.productId +
+ '\n' + e.value.id +
+ '\n' + e.value.renewState.toString() +
+ '\n' + (e.value.startedDate?.toString() ?? 'n/a') +
+ '\n' + (e.value.expirationDate?.toString() ?? 'n/a') +
+ '\n' + e.value.isActive.toString();
+
+
+ return ListTile(
+ title: Text(e.key),
+ subtitle: Text(title),
+ );
+ }).toList();
}
List _productsFromMap(Map products) {
- return products.entries
- .map(
- (e) => ListTile(
- title: Text(e.key),
- subtitle: Text(
- e.value.qonversionId ??
- '' + '\n' + e.value.storeId ??
- '' +
- '\n' +
- e.value.subscriptionPeriod.unitCount.toString() +
- ' ' +
- e.value.subscriptionPeriod.unit.toString() +
- '\n' +
- e.value.type.toString() +
- '\n',
- ),
- ),
- )
- .toList();
+ return products.entries.map((e) {
+ var title = e.value.qonversionId;
+ var storeId = e.value.storeId;
+ var subscriptionPeriod = e.value.subscriptionPeriod;
+
+ if (storeId != null) {
+ title += '\n' + storeId;
+ }
+ if (subscriptionPeriod != null) {
+ title += '\n' +
+ subscriptionPeriod.unitCount.toString() +
+ ' ' +
+ subscriptionPeriod.unit.toString() +
+ '\n' +
+ e.value.type.toString();
+ }
+
+ return ListTile(
+ title: Text(e.key),
+ subtitle: Text(title),
+ );
+ }).toList();
}
}
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 1f482101..8eb4961b 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -23,10 +23,10 @@ Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
}
/// Initialize the [FlutterLocalNotificationsPlugin] package.
-FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
+late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
/// Create a [AndroidNotificationChannel] for heads up notifications
-AndroidNotificationChannel channel;
+late AndroidNotificationChannel channel;
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
@@ -46,7 +46,7 @@ Future main() async {
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
var initializationSettingsAndroid =
AndroidInitializationSettings('launch_background');
- var initializationSettingsIOS = IOSInitializationSettings(
+ var initializationSettingsIOS = DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: false);
@@ -54,8 +54,8 @@ Future main() async {
android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
- onSelectNotification: (String payload) async {
- var notificationData = jsonDecode(payload);
+ onDidReceiveNotificationResponse: (NotificationResponse details) async {
+ var notificationData = jsonDecode(details.payload ?? "{}");
onNotificationClick(notificationData);
});
diff --git a/example/lib/params_view.dart b/example/lib/params_view.dart
index e8e817d6..c81bff87 100644
--- a/example/lib/params_view.dart
+++ b/example/lib/params_view.dart
@@ -17,10 +17,12 @@ class ParamsView extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- FlatButton(
+ TextButton(
child: Text('Get user properties'),
- color: Colors.amber,
- textColor: Colors.white,
+ style: ButtonStyle(
+ backgroundColor: WidgetStateProperty.all(Colors.amber),
+ foregroundColor: WidgetStateProperty.all(Colors.white),
+ ),
onPressed: () async {
try {
QUserProperties userProperties =
@@ -36,29 +38,35 @@ class ParamsView extends StatelessWidget {
}
},
),
- FlatButton(
+ TextButton(
child: Text('Set User ID'),
- color: Colors.green,
- textColor: Colors.white,
+ style: ButtonStyle(
+ backgroundColor: WidgetStateProperty.all(Colors.green),
+ foregroundColor: WidgetStateProperty.all(Colors.white),
+ ),
onPressed: () {
Qonversion.getSharedInstance().setUserProperty(QUserPropertyKey.customUserId, 'customId');
print('did set user id');
},
),
- FlatButton(
+ TextButton(
child: Text('Set User Property'),
- color: Colors.blue,
- textColor: Colors.white,
+ style: ButtonStyle(
+ backgroundColor: WidgetStateProperty.all(Colors.blue),
+ foregroundColor: WidgetStateProperty.all(Colors.white),
+ ),
onPressed: () {
Qonversion.getSharedInstance().setCustomUserProperty('customProperty', 'customValue');
print('did set user property');
},
),
for (final v in QUserPropertyKey.values)
- FlatButton(
+ TextButton(
child: Text('Set ${describeEnum(v)}'),
- color: Colors.purple,
- textColor: Colors.white,
+ style: ButtonStyle(
+ backgroundColor: WidgetStateProperty.all(Colors.purple),
+ foregroundColor: WidgetStateProperty.all(Colors.white),
+ ),
onPressed: () {
Qonversion.getSharedInstance().setUserProperty(v, 'email@email.com');
print('did set property');
diff --git a/example/lib/products_view.dart b/example/lib/products_view.dart
index ac12c22c..81e23357 100644
--- a/example/lib/products_view.dart
+++ b/example/lib/products_view.dart
@@ -1,5 +1,6 @@
import 'dart:async';
+import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/material.dart';
import 'package:qonversion_flutter/qonversion_flutter.dart';
@@ -10,9 +11,9 @@ class ProductsView extends StatefulWidget {
class _ProductsViewState extends State {
var _products = [];
- QOfferings _offerings;
- StreamSubscription