Skip to content

Commit

Permalink
Merge pull request #107 from superwall-me/develop
Browse files Browse the repository at this point in the history
3.0.0-beta.4
  • Loading branch information
yusuftor authored Feb 3, 2023
2 parents 62c2ba2 + cf4ea66 commit 2731f75
Show file tree
Hide file tree
Showing 87 changed files with 609 additions and 495 deletions.
22 changes: 21 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
# CHANGELOG

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

## 3.0.0-beta.4

### Breaking Changes

- Moves back to using `Superwall.shared.identify(userId: userId)` and `reset()` instead of logIn/createAccount/logout/reset. This is so that it's easier for integration. However, you can now pass an `IdentityOptions` object to `identify(userId:options)`. This should only be used in advanced use cases. By setting the `restorePaywallAssignments` property of `IdentityOptions` to `true`, it prevents paywalls from showing until after paywall assignments have been restored. If you expect users of your app to switch accounts or delete/reinstall a lot, you'd set this when identifying an existing account.

### Enhancements

- Adds `hasActiveSubscriptionDidChange(to:)` delegate function. If you're letting Superwall handle subscription logic you can use this to receive a callback whenever the user's internal subscription status changes. You can also listen to the published `hasActiveSubscription` variable.
- Adds a completion handler to `Superwall.configure(...)` that lets you know when Superwall has finished configuring. You can also listen to the published `isConfigured` variable.
- If you let Superwall handle your subscription-related logic, we now assume that a non-consumable product on your paywall is a lifetime subscription. If not, you'll need to return a `SubscriptionController` from the delegate.
- `handleDeepLink(_:)` now returns a discardable `Bool` indicating whether the deep link was handled. If you're using `application(_:open:options:)` you can return its value there.
- Adds `togglePaywallSpinner(isHidden:)` to arbitrarily toggle the loading spinner on and off. This is particularly useful when you're doing async work when performing a custom action in `handleCustomPaywallAction(withName:)`.

### Fixes

- Fixes occasional thread safety related crash when loading products.
- Reverts a issue from the last beta where the paywall spinner would move up before the payment sheet appeared.

## 3.0.0-beta.3

### Fixes

- Fixes potential crash due to a using a lazy variable.
Expand Down
22 changes: 11 additions & 11 deletions Examples/SwiftUI/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ Usually, to integrate SuperwallKit into your app, you first need to have configu

Feature | Sample Project Location
--- | ---
🕹 Configuring SuperwallKit | [Services/SuperwallService.swift](Superwall-SwiftUI/Services/SuperwallService.swift#L23)
🕹 Configuring SuperwallKit | [Services/SuperwallService.swift](Superwall-SwiftUI/Services/SuperwallService.swift#L31)
👥 Implementing the delegate | [Services/SuperwallService.swift](Superwall-SwiftUI/Services/SuperwallService.swift#L67)
👉 Tracking an event | [TrackEventModel.swift](Superwall-SwiftUI/TrackEventModel.swift#L46)
👥 Logging In | [Services/SuperwallService.swift](Superwall-SwiftUI/Services/SuperwallService.swift#L32)
👥 Logging Out | [Services/SuperwallService.swift](Superwall-SwiftUI/Services/SuperwallService.swift#L47)
👉 Tracking an event | [TrackEventModel.swift](Superwall-SwiftUI/TrackEventModel.swift#L15)
👥 Identifying account | [Services/SuperwallService.swift](Superwall-SwiftUI/Services/SuperwallService.swift#L31)
👥 Resetting account | [Services/SuperwallService.swift](Superwall-SwiftUI/Services/SuperwallService.swift#L54)

## Requirements

Expand All @@ -31,9 +31,9 @@ Otherwise, you can download it from [https://github.com/realm/SwiftLint](https:/

## Getting Started

Clone or download the SuperwallKit from the [project home page](https://github.com/superwall-me/paywall-ios). Then, open **Superwall-SwiftUI.xcodeproj** in Xcode and take a look at the code inside the [Superwall-SwiftUI](Superwall-SwiftUI) folder.
Clone or download the SuperwallKit from the [project home page](https://github.com/superwall-me/Superwall-iOS). Then, open **Superwall-SwiftUI.xcodeproj** in Xcode and take a look at the code inside the [Superwall-SwiftUI](Superwall-SwiftUI) folder.

Inside the [Services](Superwall-SwiftUI/Services) folder, you'll see some helper classes. [SuperwallService.swift](Superwall-SwiftUI/Services/SuperwallService.swift) handles the setup and delegate methods of the SDK, and [StoreKitService.swift](Superwall-SwiftUI/Services/StoreKitService.swift) handles the purchasing of in-app subscriptions.
Inside the [Services](Superwall-SwiftUI/Services) folder, you'll see some helper classes. [SuperwallService.swift](Superwall-SwiftUI/Services/SuperwallService.swift) handles the setup and delegate methods of the SDK. All subscription-related logic is handled by the SDK but we have included a (commented out) example of how you might implement purchases yourself using StoreKit in [StoreKitService.swift](Superwall-SwiftUI/Services/StoreKitService.swift).

[Superwall_SwiftUI-Products.storekit](Superwall-SwiftUI/Superwall_SwiftUI-Products.storekit) is a StoreKit configuration file that is used to mimic the setup of real products on App Store Connect. This is so you can make test purchases within the sample app without having to set up App Store Connect. In a production app, you will need real products configured in App Store Connect but you can also use a StoreKit configuration file for testing purposes if you wish.

Expand All @@ -45,15 +45,15 @@ Build and run the app and you'll see the welcome screen:
<img src="https://i.imgur.com/jKkBBNW.png" alt="The welcome screen" width="220px" />
</p>

SuperwallKit is [configured](Superwall-SwiftUI/Services/SuperwallService.swift#L22) on app launch, setting an `apiKey` and `delegate`.
SuperwallKit is [configured](Superwall-SwiftUI/Services/SuperwallService.swift#L31) on app launch, setting an `apiKey` and `delegate`.

The SDK sends back events received from the paywall via the delegate methods in [SuperwallService.swift](Superwall-SwiftUI/Services/SuperwallService.swift#L67). You use these methods to make and restore purchases, react to analytical events, as well as tell the SDK whether the user has an active subscription.

## Logging In

On the welcome screen, enter your name in the **text field**. This saves to the Superwall user attributes using [Superwall.shared.setUserAttributes(_:)](Superwall-SwiftUI/Services/SuperwallService.swift#L62). You don't need to set user attributes, but it can be useful if you want to create a rule to present a paywall based on a specific attribute you've set. You can also recall user attributes on your paywall to personalise the messaging.

Tap **Log In**. This logs the user in to Superwall (with a hardcoded userId that we've set), retrieving any paywalls that have already been assigned to them. If you were to create a new account you'd use `Superwall.shared.createAccount(userId:)` instead.
Tap **Log In**. This identifies the user (with a hardcoded userId that we've set), retrieving any paywalls that have already been assigned to them.

You'll see an overview screen:

Expand All @@ -67,9 +67,9 @@ To present a paywall, you **track** an event.

On the [Superwall Dashboard](https://superwall.com/dashboard) you add this event to a Campaign and attach some presentation rules. For this app, we've already done this for you.

When an event is tracked, SuperwallKit evaluates the rules associated with it to determine whether or not to show a paywall. Note that if the delegate method [isUserSubscribed()](Superwall-SwiftUI/SuperwallService.swift#L81) returns `true`, a paywall will not show by default.
When an event is tracked, SuperwallKit evaluates the rules associated with it to determine whether or not to show a paywall.

By calling [Superwall.shared.track(event:params:paywallOverrides:paywallHandler:)](Superwall-SwiftUI/TrackEventModel.swift#L15), you present a paywall in response to the event. For this app, the event is called "MyEvent".
By calling [Superwall.shared.track(event:params:paywallOverrides:paywallHandler:)](Superwall-SwiftUI/TrackEventModel.swift#L15), you present a paywall in response to the event. For this app, the event is called `campaign_trigger`.

On screen you'll see some explanatory text and a button that tracks an event:

Expand All @@ -85,6 +85,6 @@ Tap the **Continue** button in the paywall and "purchase" a subscription. When t

## Support

For an in-depth explanation of how to use the SuperwallKit, you can [view our iOS SDK documentation](https://sdk.superwall.me/documentation/paywall/). If you'd like to view it in Xcode, select **Product ▸ Build Documentation**.
For an in-depth explanation of how to use the SuperwallKit, you can [view our iOS SDK documentation](https://sdk.superwall.me/documentation/superwallkit/). If you'd like to view it in Xcode, select **Product ▸ Build Documentation**.

For general docs that include how to use the Superwall Dashboard, visit [docs.superwall.com](https://docs.superwall.com/docs).
27 changes: 10 additions & 17 deletions Examples/SwiftUI/Superwall-SwiftUI/Services/SuperwallService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,40 +25,33 @@ final class SuperwallService {
// further down:

// Task {
// await StoreKitService.shared.loadSubscriptionState()*/
Superwall.configure(
apiKey: apiKey,
delegate: shared
)
// await StoreKitService.shared.loadSubscriptionState()
// }

Superwall.configure(
apiKey: apiKey,
delegate: shared
)

// Getting our logged in status to Superwall.
shared.isLoggedIn.send(Superwall.shared.isLoggedIn)
}

static func logIn() async {
static func identify() {
do {
try await Superwall.shared.logIn(userId: "abc")
try Superwall.shared.identify(userId: "abc")
} catch let error as IdentityError {
switch error {
case .missingUserId:
print("The provided userId was empty")
case .alreadyLoggedIn:
print("The user is already logged in")
}
} catch {
print("Unexpected error", error)
}
}

static func logOut() async {
do {
try await Superwall.shared.logOut()
} catch LogoutError.notLoggedIn {
print("The user is not logged in")
} catch {
print("Unexpected error", error)
}
static func reset() async {
await Superwall.shared.reset()
}

static func handleDeepLink(_ url: URL) {
Expand Down
2 changes: 1 addition & 1 deletion Examples/SwiftUI/Superwall-SwiftUI/TrackEventModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ final class TrackEventModel {
// private var cancellable: AnyCancellable?

func trackEvent() {
Superwall.shared.track(event: "MyEvent") { paywallState in
Superwall.shared.track(event: "campaign_trigger") { paywallState in
switch paywallState {
case .presented(let paywallInfo):
print("paywall info is", paywallInfo)
Expand Down
2 changes: 1 addition & 1 deletion Examples/SwiftUI/Superwall-SwiftUI/TrackEventView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct TrackEventView: View {
var body: some View {
VStack(spacing: 48) {
InfoView(
text: "The button below tracks an event \"MyEvent\".\n\nThis event has been added to a campaign on the Superwall dashboard.\n\nWhen this event is tracked, the rules in the campaign are evaluated.\n\nThe rules match and cause a paywall to show."
text: "The button below tracks an event \"campaign_trigger\".\n\nThis event has been added to a campaign on the Superwall dashboard.\n\nWhen this event is tracked, the rules in the campaign are evaluated.\n\nThe rules match and cause a paywall to show."
)

Divider()
Expand Down
32 changes: 16 additions & 16 deletions Examples/UIKit+RevenueCat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ Usually, to integrate SuperwallKit into your app, you first need to have configu

Feature | Sample Project Location
--- | ---
🕹 Configuring SuperwallKit and RevenueCat | [PaywallManager.swift](Superwall-UIKit+RevenueCat/PaywallManager.swift#39)
💰 Implementing the Superwall delegate | [PaywallManager.swift](Superwall-UIKit+RevenueCat/PaywallManager.swift#L139)
😺 Implementing the RevenueCat delegate | [PaywallManager.swift](Superwall-UIKit+RevenueCat/PaywallManager.swift#L103)
👉 Presenting a paywall | [TrackEventViewController.swift](Superwall-UIKit+RevenueCat/TrackEventViewController.swift#L59)
👥 Logging In | [PaywallManager.swift](Superwall-UIKit+RevenueCat/PaywallManager.swift#L52)
👥 Logging Out | [PaywallManager.swift](Superwall-UIKit+RevenueCat/PaywallManager.swift#L73)
🕹 Configuring SuperwallKit and RevenueCat | [PaywallManager.swift](Superwall-UIKit+RevenueCat/PaywallManager.swift#37)
😺 Implementing the RevenueCat delegate | [PaywallManager.swift](Superwall-UIKit+RevenueCat/PaywallManager.swift#L144)
💰 Implementing the Superwall delegate | [PaywallManager.swift](Superwall-UIKit+RevenueCat/PaywallManager.swift#L170)
👉 Presenting a paywall | [TrackEventViewController.swift](Superwall-UIKit+RevenueCat/TrackEventViewController.swift#L60)
👥 Logging In | [PaywallManager.swift](Superwall-UIKit+RevenueCat/PaywallManager.swift#L64)
👥 Logging Out | [PaywallManager.swift](Superwall-UIKit+RevenueCat/PaywallManager.swift#L82)

## Requirements

This example app uses:

- UIKit
- RevenueCat 4.14.3
- RevenueCat 4.17.4
- Xcode 14
- iOS 16
- Swift 5.5
Expand All @@ -33,7 +33,7 @@ Otherwise, you can download it from [https://github.com/realm/SwiftLint](https:/

## Getting Started

Clone or download SuperwallKit from the [project home page](https://github.com/superwall-me/paywall-ios). Then, open **Superwall-UIKit+RevenueCat.xcodeproj** in Xcode and take a look at the code inside the [Superwall-UIKit+RevenueCat](Superwall-UIKit+RevenueCat) folder.
Clone or download SuperwallKit from the [project home page](https://github.com/superwall-me/Superwall-iOS). Then, open **Superwall-UIKit+RevenueCat.xcodeproj** in Xcode and take a look at the code inside the [Superwall-UIKit+RevenueCat](Superwall-UIKit+RevenueCat) folder.

You'll see a helper file called [PaywallManager.swift](Superwall-UIKit+RevenueCat/PaywallManager.swift) which handles both SuperwallKit and RevenueCat. This includes configuration, delegation, purchasing, restoring and updating and maintaining the user's subscription status.

Expand All @@ -47,15 +47,15 @@ Build and run the app and you'll see the welcome screen:
<img src="https://user-images.githubusercontent.com/3296904/161958142-c2f195b9-bd43-4f4e-9521-87c6fe4238ec.png" alt="The welcome screen" width="220px" />
</p>

SuperwallKit and RevenueCat are both [configured](Superwall-UIKit+RevenueCat/PaywallManager.swift#L39) on app launch, setting an `apiKey` and `delegate`.
SuperwallKit and RevenueCat are both [configured](Superwall-UIKit+RevenueCat/PaywallManager.swift#L37) on app launch, setting an `apiKey` and `delegate`.

The SDK sends back events received from the paywall via the delegate methods in [PaywallManager.swift](Superwall-UIKit+RevenueCat/PaywallManager.swift#L139). You use these methods to make and restore purchases, react to analytical events, as well as tell Superwall whether the user has an active subscription.
The SDK sends back events received from the paywall via the delegate methods in [PaywallManager.swift](Superwall-UIKit+RevenueCat/PaywallManager.swift#L170). The delegate is responsible for sending back analytical events and providing a `SubscriptionController`. This is a protocol implemented by the PaywallManager that handles all subscription-related logic.

## Logging In

On the welcome screen, enter your name in the **text field**. This saves to the Superwall user attributes using [Superwall.shared.setUserAttributes(_:)](Superwall-UIKit+RevenueCat/PaywallManager.swift#L97). You don't need to set user attributes, but it can be useful if you want to create a rule to present a paywall based on a specific attribute you've set. You can also recall user attributes on your paywall to personalise the messaging.
On the welcome screen, enter your name in the **text field**. This saves to the Superwall user attributes using [Superwall.shared.setUserAttributes(_:)](Superwall-UIKit+RevenueCat/PaywallManager.swift#L102). You don't need to set user attributes, but it can be useful if you want to create a rule to present a paywall based on a specific attribute you've set. You can also recall user attributes on your paywall to personalise the messaging.

Tap **Log In**. This logs the user in to Superwall (with a hardcoded userId that we've set), retrieving any paywalls that have already been assigned to them. If you were to create a new account you'd use `Superwall.shared.createAccount(userId:)` instead.
Tap **Log In**. This identifies the user with Superwall using a hardcoded userId, retrieving any paywalls that have already been assigned to them. It also logs into revenuecat, retrieving the user's subscription status.

You'll see an overview screen:

Expand All @@ -69,9 +69,9 @@ To present a paywall, you **track** an event.

On the [Superwall Dashboard](https://superwall.com/dashboard) you add this event to a Campaign and attach some presentation rules. For this app, we've already done this for you.

When an event is tracked, SuperwallKit evaluates the rules associated with it to determine whether or not to show a paywall. Note that if the delegate method [isUserSubscribed()](Superwall-UIKit+RevenueCat/PaywallManager.swift#L163) returns `true`, a paywall will not show by default.
When an event is tracked, SuperwallKit evaluates the rules associated with it to determine whether or not to show a paywall. Note that if the `SubscriptionController` method [isUserSubscribed()](Superwall-UIKit+RevenueCat/PaywallManager.swift#L122) returns `true`, a paywall will not show by default.

By calling [Superwall.shared.track(event:params:paywallOverrides:paywallHandler:)](Superwall-UIKit+RevenueCat/TrackEventViewController.swift#L59), you present a paywall in response to the event. For this app, the event is called "MyEvent".
By calling [Superwall.shared.track(event:params:paywallOverrides:paywallHandler:)](Superwall-UIKit+RevenueCat/TrackEventViewController.swift#L60), you present a paywall in response to the event. For this app, the event is called `campaign_trigger`.

On screen you'll see some explanatory text and a button that tracks an event:

Expand All @@ -83,10 +83,10 @@ Tap the **Track Event** button and you'll see the paywall. If the event is disab

## Purchasing a subscription

Tap the **Continue** button in the paywall and "purchase" a subscription. When the paywall dismisses, try tracking an event. You'll notice the buttons no longer show the paywall. The paywalls are only presented to users who haven't got an active subscription. To cancel the active subscription for an app that's using a storekit configuration file for testing, delete and reinstall the app.
Tap the **Continue** button in the paywall and "purchase" a subscription. When the paywall dismisses, try tracking an event. You'll notice the buttons no longer show the paywall. The paywalls are only presented to users who haven't got an active subscription. To cancel the active subscription for an app that's using a storekit configuration file for testing, delete and reinstall the app. You will need to wait a few minutes until the subscription expires on RevenueCat's side before trying again.

## Support

For an in-depth explanation of how to use SuperwallKit, you can [view our iOS SDK documentation](https://sdk.superwall.me/documentation/paywall/). If you'd like to view it in Xcode, select **Product ▸ Build Documentation**.
For an in-depth explanation of how to use SuperwallKit, you can [view our iOS SDK documentation](https://sdk.superwall.me/documentation/superwallkit/). If you'd like to view it in Xcode, select **Product ▸ Build Documentation**.

For general docs that include how to use the Superwall Dashboard, visit [docs.superwall.com](https://docs.superwall.com/docs).
Loading

0 comments on commit 2731f75

Please sign in to comment.