Skip to content
Merged

2.6.7 #343

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

The changelog for `Superwall`. Also see the [releases](https://github.com/superwall/Superwall-Android/releases) on GitHub.

## 2.6.7

### Enhancements
- Adds permission granting and callbacks to/from paywalls
- Adds `PaywallPreloadStart` and `PaywallPreloadComplete` events

### Fixes
- Fix handling of deep links when paywall is detached
- Enables permission granting from paywall and callbacks
- Fix crash when handling drawer style paywalls with 100% height

## 2.6.6

## Enhancements
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<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_CONTACTS"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-feature
android:name="android.hardware.camera"
android:required="false" />


<application
android:name=".MainApplication"
Expand Down
9 changes: 9 additions & 0 deletions superwall/src/main/java/com/superwall/sdk/Superwall.kt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import com.superwall.sdk.paywall.view.webview.messaging.PaywallWebEvent.Initiate
import com.superwall.sdk.paywall.view.webview.messaging.PaywallWebEvent.OpenedDeepLink
import com.superwall.sdk.paywall.view.webview.messaging.PaywallWebEvent.OpenedURL
import com.superwall.sdk.paywall.view.webview.messaging.PaywallWebEvent.OpenedUrlInChrome
import com.superwall.sdk.paywall.view.webview.messaging.PaywallWebEvent.RequestPermission
import com.superwall.sdk.storage.LatestCustomerInfo
import com.superwall.sdk.storage.ReviewCount
import com.superwall.sdk.storage.ReviewData
Expand Down Expand Up @@ -1408,6 +1409,14 @@ class Superwall(
)
}
}

is RequestPermission -> {
Logger.debug(
LogLevel.debug,
LogScope.paywallView,
message = "Permission requested: ${paywallEvent.permissionType.rawValue}",
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1174,4 +1174,72 @@ sealed class InternalSuperwallEvent(
)
}
}

data class Permission(
val state: State,
val permissionName: String,
val paywallIdentifier: String,
) : InternalSuperwallEvent(
SuperwallEvent.PermissionRequested(permissionName, paywallIdentifier),
) {
enum class State {
Requested,
Granted,
Denied,
}

override val superwallPlacement: SuperwallEvent
get() =
when (state) {
State.Requested ->
SuperwallEvent.PermissionRequested(
permissionName = permissionName,
paywallIdentifier = paywallIdentifier,
)
State.Granted ->
SuperwallEvent.PermissionGranted(
permissionName = permissionName,
paywallIdentifier = paywallIdentifier,
)
State.Denied ->
SuperwallEvent.PermissionDenied(
permissionName = permissionName,
paywallIdentifier = paywallIdentifier,
)
}

override val audienceFilterParams: Map<String, Any> = emptyMap()

override suspend fun getSuperwallParameters(): Map<String, Any> =
mapOf(
"permission_name" to permissionName,
"paywall_identifier" to paywallIdentifier,
)
}

data class PaywallPreload(
val state: State,
val paywallCount: Int,
) : InternalSuperwallEvent(
SuperwallEvent.PaywallPreloadStart(paywallCount),
) {
enum class State {
Start,
Complete,
}

override val superwallPlacement: SuperwallEvent
get() =
when (state) {
State.Start -> SuperwallEvent.PaywallPreloadStart(paywallCount)
State.Complete -> SuperwallEvent.PaywallPreloadComplete(paywallCount)
}

override val audienceFilterParams: Map<String, Any> = emptyMap()

override suspend fun getSuperwallParameters(): Map<String, Any> =
mapOf(
"paywall_count" to paywallCount,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,49 @@ sealed class SuperwallEvent {
get() = SuperwallEvents.CustomerInfoDidChange.rawName
}

// / When a permission is requested from a paywall.
data class PermissionRequested(
val permissionName: String,
val paywallIdentifier: String,
) : SuperwallEvent() {
override val rawName: String
get() = SuperwallEvents.PermissionRequested.rawName
}

// / When a permission is granted after being requested from a paywall.
data class PermissionGranted(
val permissionName: String,
val paywallIdentifier: String,
) : SuperwallEvent() {
override val rawName: String
get() = SuperwallEvents.PermissionGranted.rawName
}

// / When a permission is denied after being requested from a paywall.
data class PermissionDenied(
val permissionName: String,
val paywallIdentifier: String,
) : SuperwallEvent() {
override val rawName: String
get() = SuperwallEvents.PermissionDenied.rawName
}

// / When paywall preloading starts.
data class PaywallPreloadStart(
val paywallCount: Int,
) : SuperwallEvent() {
override val rawName: String
get() = SuperwallEvents.PaywallPreloadStart.rawName
}

// / When paywall preloading completes.
data class PaywallPreloadComplete(
val paywallCount: Int,
) : SuperwallEvent() {
override val rawName: String
get() = SuperwallEvents.PaywallPreloadComplete.rawName
}

open val rawName: String
get() = this.toString()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,9 @@ enum class SuperwallEvents(
ReviewDenied("review_denied"),
IntegrationAttributes("integration_attributes"),
CustomerInfoDidChange("customerInfo_didChange"),
PermissionRequested("permission_requested"),
PermissionGranted("permission_granted"),
PermissionDenied("permission_denied"),
PaywallPreloadStart("paywallPreload_start"),
PaywallPreloadComplete("paywallPreload_complete"),
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.superwall.sdk.config

import android.content.Context
import com.superwall.sdk.analytics.internal.trackable.InternalSuperwallEvent
import com.superwall.sdk.dependencies.RequestFactory
import com.superwall.sdk.dependencies.RuleAttributesFactory
import com.superwall.sdk.misc.IOScope
Expand All @@ -25,6 +26,7 @@ class PaywallPreload(
val storage: LocalStorage,
val assignments: Assignments,
val paywallManager: PaywallManager,
private val track: suspend (InternalSuperwallEvent) -> Unit,
) {
interface Factory :
RequestFactory,
Expand Down Expand Up @@ -57,8 +59,8 @@ class PaywallPreload(
unconfirmedAssignments = assignments.unconfirmedAssignments,
expressionEvaluator = expressionEvaluator,
)
preloadPaywalls(paywallIdentifiers = paywallIds)

preloadPaywalls(paywallIdentifiers = paywallIds)
currentPreloadingTask = null
}
}
Expand All @@ -79,6 +81,14 @@ class PaywallPreload(

// Preloads paywalls referenced by triggers.
private suspend fun preloadPaywalls(paywallIdentifiers: Set<String>) {
val paywallCount = paywallIdentifiers.size
track(
InternalSuperwallEvent.PaywallPreload(
state = InternalSuperwallEvent.PaywallPreload.State.Start,
paywallCount = paywallCount,
),
)

val webviewExists = webViewExists()
if (webviewExists) {
scope.launchWithTracking {
Expand Down Expand Up @@ -116,6 +126,12 @@ class PaywallPreload(
}
// Await all tasks
tasks.awaitAll()
track(
InternalSuperwallEvent.PaywallPreload(
state = InternalSuperwallEvent.PaywallPreload.State.Complete,
paywallCount = paywallCount,
),
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ import com.superwall.sdk.paywall.view.webview.messaging.PaywallMessageHandler
import com.superwall.sdk.paywall.view.webview.templating.models.JsonVariables
import com.superwall.sdk.paywall.view.webview.templating.models.Variables
import com.superwall.sdk.paywall.view.webview.webViewExists
import com.superwall.sdk.permissions.UserPermissions
import com.superwall.sdk.permissions.UserPermissionsImpl
import com.superwall.sdk.review.MockReviewManager
import com.superwall.sdk.review.ReviewManager
import com.superwall.sdk.review.ReviewManagerImpl
Expand Down Expand Up @@ -187,6 +189,7 @@ class DependencyContainer(
val transactionManager: TransactionManager
val googleBillingWrapper: GoogleBillingWrapper
internal val reviewManager: ReviewManager
internal val userPermissions: UserPermissions

var entitlements: Entitlements
internal lateinit var customerInfoManager: CustomerInfoManager
Expand Down Expand Up @@ -381,6 +384,9 @@ class DependencyContainer(
assignments = assignments,
paywallManager = paywallManager,
scope = ioScope,
track = {
Superwall.instance.track(it)
},
)

configManager =
Expand Down Expand Up @@ -590,6 +596,8 @@ class DependencyContainer(
})
}

userPermissions = UserPermissionsImpl(context)

deepLinkRouter =
DeepLinkRouter(
reedemer,
Expand Down Expand Up @@ -699,6 +707,8 @@ class DependencyContainer(
encodeToB64 = {
Base64.encodeToString(it.toByteArray(StandardCharsets.UTF_8), Base64.NO_WRAP)
},
userPermissions = userPermissions,
getActivity = { activityProvider?.getCurrentActivity() },
)

val state =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.superwall.sdk.paywall.view

import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
Expand Down Expand Up @@ -991,11 +992,24 @@ class PaywallView(
}

override fun openDeepLink(url: String) {
var uri = url.toUri()
val uri = url.toUri()
eventDidOccur(PaywallWebEvent.OpenedDeepLink(uri))
val context = encapsulatingActivity?.get()
val deepLinkIntent = Intent(Intent.ACTION_VIEW, uri)
context?.startActivity(deepLinkIntent)
val activityContext = encapsulatingActivity?.get()
val deepLinkIntent =
Intent(Intent.ACTION_VIEW, uri).apply {
if (activityContext == null) {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
}
try {
(activityContext ?: context).startActivity(deepLinkIntent)
} catch (e: ActivityNotFoundException) {
Logger.debug(
logLevel = LogLevel.warn,
scope = LogScope.paywallView,
message = "No activity found to handle deep link: $url",
)
}
}

//region GameController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -520,8 +520,9 @@ class SuperwallPaywallActivity : AppCompatActivity() {
val content = contentView as ViewGroup
val bottomSheetBehavior = BottomSheetBehavior.from(content.getChildAt(0))
if (!isModal) {
bottomSheetBehavior.halfExpandedRatio =
(if (height > 1.0) height / 100 else height).toFloat()
val normalizedHeight = (if (height > 1.0) height / 100 else height).toFloat()
// Clamp to (0, 1) since 0.0 = STATE_COLLAPSED and 1.0 = STATE_EXPANDED
bottomSheetBehavior.halfExpandedRatio = normalizedHeight.coerceIn(0.01f, 0.99f)
} else {
// If it's a Modal, we want it to cover only 95% of the screen when expanded
content.updateLayoutParams {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ class SWWebView(
addJavascriptInterface(messageHandler, "SWAndroid")

val webSettings = this.settings
setWebContentsDebuggingEnabled(false)
setWebContentsDebuggingEnabled(true)
webSettings.javaScriptEnabled = true
webSettings.setSupportZoom(false)
webSettings.builtInZoomControls = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.superwall.sdk.logger.LogLevel
import com.superwall.sdk.logger.LogScope
import com.superwall.sdk.logger.Logger
import com.superwall.sdk.models.paywall.LocalNotificationType
import com.superwall.sdk.permissions.PermissionType
import com.superwall.sdk.storage.core_data.convertFromJsonElement
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
Expand Down Expand Up @@ -108,6 +109,11 @@ sealed class PaywallMessage {
val body: String,
val delay: Long,
) : PaywallMessage()

data class RequestPermission(
val permissionType: PermissionType,
val requestId: String,
) : PaywallMessage()
}

fun parseWrappedPaywallMessages(jsonString: String): Result<WrappedPaywallMessages> =
Expand Down Expand Up @@ -198,6 +204,22 @@ private fun parsePaywallMessage(json: JsonObject): PaywallMessage {
delay = json["delay"]?.jsonPrimitive?.longOrNull ?: 0L,
)

"request_permission" -> {
val permissionTypeRaw =
json["permission_type"]?.jsonPrimitive?.contentOrNull
?: throw IllegalArgumentException("request_permission missing permission_type")
val permissionType =
PermissionType.fromRaw(permissionTypeRaw)
?: throw IllegalArgumentException("Unknown permission_type: $permissionTypeRaw")
val requestId =
json["request_id"]?.jsonPrimitive?.contentOrNull
?: throw IllegalArgumentException("request_permission missing request_id")
PaywallMessage.RequestPermission(
permissionType = permissionType,
requestId = requestId,
)
}

else -> {
throw IllegalArgumentException("Unknown event name: $eventName")
}
Expand Down
Loading
Loading