Skip to content

Commit a5be14b

Browse files
Merge pull request #396 from qonversion/release/10.0.0
Release 10.0.0
2 parents 3369f03 + db0ef47 commit a5be14b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1189
-862
lines changed

.github/workflows/checks.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- uses: subosito/flutter-action@v1
2020
name: Setup Flutter
2121
with:
22-
flutter-version: '3.7.7'
22+
flutter-version: '3.32.4'
2323
channel: 'stable'
2424
- run: flutter pub get
2525
- name: Validation

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
## 10.0.0
2+
### Introducing Qonversion No-Codes Beta!
3+
4+
**Qonversion No-Codes** is a product designed to help you **build and customize** paywall screens **without writing code**.
5+
It allows seamless integration of pre-built subscription UI components, enabling a faster and more flexible way to design paywalls directly within your app.
6+
See more in the [documentation](https://documentation.qonversion.io/docs/getting-started-with-no-code-screens/).
7+
8+
With this update, we are **removing** deprecated **Automations**, so we encourage you to transition your paywalls to the new Qonversion No-Codes.
9+
110
## 9.3.1
211
* Android and iOS stability improvements.
312

android/build.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ buildscript {
55
ext.kotlin_version = '1.6.10'
66
repositories {
77
google()
8+
mavenCentral()
89
jcenter()
910
}
1011

@@ -17,6 +18,7 @@ buildscript {
1718
rootProject.allprojects {
1819
repositories {
1920
google()
21+
mavenCentral()
2022
jcenter()
2123
mavenLocal()
2224
}
@@ -51,6 +53,6 @@ android {
5153

5254
dependencies {
5355
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
54-
implementation "io.qonversion:sandwich:5.2.1"
56+
implementation "io.qonversion:sandwich:6.0.8"
5557
implementation 'com.google.code.gson:gson:2.9.0'
5658
}

android/src/main/kotlin/com/qonversion/flutter/sdk/qonversion_flutter_sdk/AutomationsPlugin.kt

Lines changed: 0 additions & 112 deletions
This file was deleted.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package com.qonversion.flutter.sdk.qonversion_flutter_sdk
2+
3+
import android.content.Context
4+
import io.flutter.plugin.common.BinaryMessenger
5+
import io.flutter.plugin.common.MethodChannel.Result
6+
import io.qonversion.sandwich.BridgeData
7+
import io.qonversion.sandwich.NoCodesEventListener
8+
import io.qonversion.sandwich.NoCodesSandwich
9+
import com.google.gson.Gson
10+
11+
class NoCodesPlugin(private val messenger: BinaryMessenger, private val context: Context) : NoCodesEventListener {
12+
private var noCodesSandwich: NoCodesSandwich? = null
13+
private val gson = Gson()
14+
15+
// Separate event stream handlers for each event type
16+
private var screenShownEventStreamHandler: BaseEventStreamHandler? = null
17+
private var finishedEventStreamHandler: BaseEventStreamHandler? = null
18+
private var actionStartedEventStreamHandler: BaseEventStreamHandler? = null
19+
private var actionFailedEventStreamHandler: BaseEventStreamHandler? = null
20+
private var actionFinishedEventStreamHandler: BaseEventStreamHandler? = null
21+
private var screenFailedToLoadEventStreamHandler: BaseEventStreamHandler? = null
22+
23+
companion object {
24+
private const val SCREEN_SHOWN_EVENT_CHANNEL = "nocodes_screen_shown"
25+
private const val FINISHED_EVENT_CHANNEL = "nocodes_finished"
26+
private const val ACTION_STARTED_EVENT_CHANNEL = "nocodes_action_started"
27+
private const val ACTION_FAILED_EVENT_CHANNEL = "nocodes_action_failed"
28+
private const val ACTION_FINISHED_EVENT_CHANNEL = "nocodes_action_finished"
29+
private const val SCREEN_FAILED_TO_LOAD_EVENT_CHANNEL = "nocodes_screen_failed_to_load"
30+
}
31+
32+
init {
33+
setup()
34+
}
35+
36+
private fun setup() {
37+
// Register separate event channels for each event type
38+
val screenShownListener = BaseListenerWrapper(messenger, SCREEN_SHOWN_EVENT_CHANNEL)
39+
screenShownListener.register()
40+
this.screenShownEventStreamHandler = screenShownListener.eventStreamHandler
41+
42+
val finishedListener = BaseListenerWrapper(messenger, FINISHED_EVENT_CHANNEL)
43+
finishedListener.register()
44+
this.finishedEventStreamHandler = finishedListener.eventStreamHandler
45+
46+
val actionStartedListener = BaseListenerWrapper(messenger, ACTION_STARTED_EVENT_CHANNEL)
47+
actionStartedListener.register()
48+
this.actionStartedEventStreamHandler = actionStartedListener.eventStreamHandler
49+
50+
val actionFailedListener = BaseListenerWrapper(messenger, ACTION_FAILED_EVENT_CHANNEL)
51+
actionFailedListener.register()
52+
this.actionFailedEventStreamHandler = actionFailedListener.eventStreamHandler
53+
54+
val actionFinishedListener = BaseListenerWrapper(messenger, ACTION_FINISHED_EVENT_CHANNEL)
55+
actionFinishedListener.register()
56+
this.actionFinishedEventStreamHandler = actionFinishedListener.eventStreamHandler
57+
58+
val screenFailedToLoadListener = BaseListenerWrapper(messenger, SCREEN_FAILED_TO_LOAD_EVENT_CHANNEL)
59+
screenFailedToLoadListener.register()
60+
this.screenFailedToLoadEventStreamHandler = screenFailedToLoadListener.eventStreamHandler
61+
}
62+
63+
fun initializeNoCodes(projectKey: String, result: Result) {
64+
if (projectKey.isNotEmpty()) {
65+
// Initialize NoCodes Sandwich
66+
noCodesSandwich = NoCodesSandwich()
67+
noCodesSandwich?.initialize(context, projectKey)
68+
noCodesSandwich?.setDelegate(this)
69+
result.success(null)
70+
} else {
71+
result.noNecessaryDataError()
72+
}
73+
}
74+
75+
fun setScreenPresentationConfig(config: Map<String, Any>?, contextKey: String?, result: Result) {
76+
if (config != null) {
77+
noCodesSandwich?.setScreenPresentationConfig(config, contextKey)
78+
result.success(null)
79+
} else {
80+
result.noNecessaryDataError()
81+
}
82+
}
83+
84+
fun showNoCodesScreen(contextKey: String?, result: Result) {
85+
if (contextKey != null) {
86+
noCodesSandwich?.showScreen(contextKey)
87+
result.success(null)
88+
} else {
89+
result.noNecessaryDataError()
90+
}
91+
}
92+
93+
fun closeNoCodes(result: Result) {
94+
noCodesSandwich?.close()
95+
result.success(null)
96+
}
97+
98+
// NoCodesEventListener implementation
99+
override fun onNoCodesEvent(event: NoCodesEventListener.Event, payload: BridgeData?) {
100+
val eventData = mapOf("payload" to (payload ?: emptyMap<String, Any>()))
101+
102+
// Convert to JSON string
103+
val jsonString = gson.toJson(eventData)
104+
105+
when (event) {
106+
NoCodesEventListener.Event.ScreenShown -> {
107+
screenShownEventStreamHandler?.eventSink?.success(jsonString)
108+
}
109+
NoCodesEventListener.Event.Finished -> {
110+
finishedEventStreamHandler?.eventSink?.success(jsonString)
111+
}
112+
NoCodesEventListener.Event.ActionStarted -> {
113+
actionStartedEventStreamHandler?.eventSink?.success(jsonString)
114+
}
115+
NoCodesEventListener.Event.ActionFailed -> {
116+
actionFailedEventStreamHandler?.eventSink?.success(jsonString)
117+
}
118+
NoCodesEventListener.Event.ActionFinished -> {
119+
actionFinishedEventStreamHandler?.eventSink?.success(jsonString)
120+
}
121+
NoCodesEventListener.Event.ScreenFailedToLoad -> {
122+
screenFailedToLoadEventStreamHandler?.eventSink?.success(jsonString)
123+
}
124+
}
125+
}
126+
}

android/src/main/kotlin/com/qonversion/flutter/sdk/qonversion_flutter_sdk/QonversionPlugin.kt

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ import io.qonversion.sandwich.QonversionEventsListener
1717
import io.qonversion.sandwich.QonversionSandwich
1818

1919
class QonversionPlugin : MethodCallHandler, FlutterPlugin, ActivityAware {
20-
private var activity: Activity? = null
2120
private var application: Application? = null
21+
private var activity: Activity? = null
2222
private var channel: MethodChannel? = null
2323
private var updatedEntitlementsStreamHandler: BaseEventStreamHandler? = null
24+
private var noCodesPlugin: NoCodesPlugin? = null
2425

2526
private val qonversionSandwich by lazy {
26-
application?.let {
27+
application?.let {
2728
QonversionSandwich(
2829
it,
2930
object : ActivityProvider {
@@ -35,8 +36,6 @@ class QonversionPlugin : MethodCallHandler, FlutterPlugin, ActivityAware {
3536
} ?: throw IllegalStateException("Failed to initialize Qonversion Sandwich. Application is null.")
3637
}
3738

38-
private lateinit var automationsPlugin: AutomationsPlugin
39-
4039
private val qonversionEventsListener: QonversionEventsListener = object : QonversionEventsListener {
4140
override fun onEntitlementsUpdated(entitlements: BridgeData) {
4241
val payload = Gson().toJson(entitlements)
@@ -109,12 +108,10 @@ class QonversionPlugin : MethodCallHandler, FlutterPlugin, ActivityAware {
109108
"isFallbackFileAccessible" -> {
110109
return isFallbackFileAccessible(result)
111110
}
112-
"automationsSubscribe" -> {
113-
return automationsPlugin.subscribe()
114-
}
115111
"remoteConfigList" -> {
116112
return remoteConfigList(result)
117113
}
114+
"closeNoCodes" -> noCodesPlugin?.closeNoCodes(result)
118115
}
119116

120117
// Methods with args
@@ -135,15 +132,10 @@ class QonversionPlugin : MethodCallHandler, FlutterPlugin, ActivityAware {
135132
"detachUserFromRemoteConfiguration" -> detachUserFromRemoteConfiguration(args, result)
136133
"storeSdkInfo" -> storeSdkInfo(args, result)
137134
"identify" -> identify(args["userId"] as? String, result)
138-
"automationsSetNotificationsToken" -> automationsPlugin.setNotificationsToken(args["notificationsToken"] as? String, result)
139-
"automationsHandleNotification" -> automationsPlugin.handleNotification(args, result)
140-
"automationsGetNotificationCustomPayload" -> automationsPlugin.getNotificationCustomPayload(args, result)
141-
"automationsShowScreen" -> automationsPlugin.showScreen(args["screenId"] as? String, result)
142-
"setScreenPresentationConfig" -> automationsPlugin.setScreenPresentationConfig(
143-
args["configData"] as? Map<String, Any>,
144-
args["screenId"] as? String,
145-
result
146-
)
135+
// NoCodes methods
136+
"initializeNoCodes" -> noCodesPlugin?.initializeNoCodes(args["projectKey"] as? String ?: "", result)
137+
"setScreenPresentationConfig" -> noCodesPlugin?.setScreenPresentationConfig(args["config"] as? Map<String, Any>, args["contextKey"] as? String, result)
138+
"showNoCodesScreen" -> noCodesPlugin?.showNoCodesScreen(args["contextKey"] as? String, result)
147139
else -> result.notImplemented()
148140
}
149141
}
@@ -317,6 +309,13 @@ class QonversionPlugin : MethodCallHandler, FlutterPlugin, ActivityAware {
317309
channel = MethodChannel(messenger, METHOD_CHANNEL)
318310
channel?.setMethodCallHandler(this)
319311

312+
// Register NoCodes plugin
313+
try {
314+
noCodesPlugin = NoCodesPlugin(messenger, application)
315+
} catch (e: Exception) {
316+
println("Failed to initialize NoCodesPlugin: ${e.message}")
317+
}
318+
320319
// Register entitlements update events
321320
val updatedEntitlementsListener = BaseListenerWrapper(messenger, EVENT_CHANNEL_UPDATED_ENTITLEMENTS)
322321
updatedEntitlementsListener.register()
@@ -325,14 +324,13 @@ class QonversionPlugin : MethodCallHandler, FlutterPlugin, ActivityAware {
325324
// Register promo purchases events. Android SDK does not generate any promo purchases yet
326325
val promoPurchasesListener = BaseListenerWrapper(messenger, EVENT_CHANNEL_PROMO_PURCHASES)
327326
promoPurchasesListener.register()
328-
329-
automationsPlugin = AutomationsPlugin(messenger)
330327
}
331328

332329
private fun tearDown() {
333330
channel?.setMethodCallHandler(null)
334331
channel = null
335332
this.updatedEntitlementsStreamHandler = null
333+
this.noCodesPlugin = null
336334
this.application = null
337335
}
338336
}

0 commit comments

Comments
 (0)