Skip to content

Commit

Permalink
Merge pull request #276 from qonversion/release/6.3.0
Browse files Browse the repository at this point in the history
Release 6.3.0
  • Loading branch information
suriksarkisyan committed Jan 10, 2024
2 parents a2c5d58 + 7c94dd3 commit 2d67fa7
Show file tree
Hide file tree
Showing 12 changed files with 285 additions and 66 deletions.
75 changes: 44 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
Qonversion
</h1>

Qonversion is the data platform to power in-app subscription revenue growth.
Qonversion - In-app subscription monetization: implement subscriptions and grow your app’s revenue with A/B experiments

* fast in-app subscriptions implementation
* back-end infrastructure to validate user receipts
* manage cross-platform user access to paid content on your app
* comprehensive subscription analytics
* out-of-the-box integrations with the leading marketing, attribution, and product analytics platforms
* push notifications and in-app messaging to win back lapsed subscribers
* A/B Testing for in-app purchases
* In-app subscription management SDK
* API and webhooks to make your subscription data available where you need it
* Seamless Stripe integration to enable cross-platform access management
* Subscribers CRM with user-level transactions
* Instant access to real-time subscription analytics
* Built-in A/B experiments for subscription business model

<p align="center">
<a href="https://qonversion.io"><img width="90%" src="https://qcdn3.sfo3.digitaloceanspaces.com/github/qonversion_platform.png">
Expand All @@ -21,50 +20,65 @@ Qonversion is the data platform to power in-app subscription revenue growth.
[![MIT License](http://img.shields.io/cocoapods/l/Qonversion.svg?style=flat)](https://qonversion.io)


## How It Works: Product Center
## In-App Subscription Implementation & Management

<p align="center">
<a href="https://documentation.qonversion.io/docs/integrations-overview"><img width="90%" src="https://user-images.githubusercontent.com/13959241/161107203-8ef3ecee-86be-47a2-ac57-b21d3da19339.png">
</a>
</p>

1. Application calls the purchase method of Qonversion SDK.
2. Qonversion SDK communicates with StoreKit or Google Billing Client to make a purchase.
3. If a purchase is successful, the SDK sends a request to Qonversion API for server-to-server purchase validation. Qonversion server receives accurate information on the in-app purchase status and user entitlements.
4. SDK returns control to the application with a processing state.
1. Qonversion SDK provides three simple methods to manage subscriptions:
* Get in-app product details
* Make purchases
* Check subscription status to manage premium access
2. Qonversion communicates with Apple or Google platforms both through SDK and server-side to process native in-app payments and keep subscription statuses up to date.
3. You can use Qonversion webhooks and API in addition to SDK to get user-level data where you need it.

See the [quick start guide documentation](https://documentation.qonversion.io/docs/quickstart).

## Analytics

Monitor your in-app revenue metrics. Understand your customers and make better decisions with precise subscription revenue data.
Qonversion provides advanced subscription analytics out-of-the-box. You can monitor real-time metrics from new users and trial-to-paid conversions to revenue, MRR, ARR, cohort retention and more. Understand your customers and make better decisions with precise subscription analytics.

<p align="center">
<a href="https://documentation.qonversion.io/docs/analytics"><img width="90%" src="https://qonversion.io/img/screenshots/desktop/mobile_subscription_analytics.jpg">
<a href="https://documentation.qonversion.io/docs/analytics"><img width="90%" src="https://files.readme.io/9a4fdf6-Analytics.png">
</a>
</p>

## Integrations

Send subscription data to your favorite platforms Share your mobile and web subscription data using our powerful integrations.
## A/B Experiments

Qonversion's A/B Experiments feature provides everything required to quickly launch paywall and other monetization experiments, analyze results and roll out winning versions without releasing a new app build. Qonversion A/B Experiments include:

* User segmentation by country, install date, app version, free/paying user
* Traffic allocation
* Advanced subscription analytics
* Visualization of A/B experiments results
* Statistical significance of the results
* Roll out winning versions without app release with remote config


<p align="center">
<a href="https://documentation.qonversion.io/docs/integrations-overview"><img width="90%", src="https://qcdn3.sfo3.digitaloceanspaces.com/github/integrations.png">
<a href="https://documentation.qonversion.io/docs/subscription-ab-testing"><img width="90%" src="https://qcdn3.sfo3.digitaloceanspaces.com/github/ab_tests.png">
</a>
</p>

## Personalized push notifications & in-app messaging

Qonversion allows sending automated, personalized push notifications and in-app messages initiated by in-app purchase events. This feature is designed to increase your app's revenue and retention, provide cancellation insights, reduce subscriber churn, and improve your subscribers' user experience.

See more details [here](https://documentation.qonversion.io/docs/paywall-experiments).

See more in the [documentation](https://documentation.qonversion.io/docs/automations)
![](https://qonversion.io/img/@2x/automation/in-app-constructor.gif)
## Integrations

## A/B Testing for in-app purchases
Send user-level subscription data to your favorite platforms.

Boost conversion rates with paywalls and in-app purchases A/B testing. Find the best pricing and paywall variations. Be flexible to prove hypotheses without app releases.
* Amplitude
* Mixpanel
* Appsflyer
* Adjust
* Singular
* CleverTap
* [All other integrations here](qonversion.io/integrations)

<p align="center">
<a href="https://documentation.qonversion.io/docs/subscription-ab-testing"><img width="90%" src="https://user-images.githubusercontent.com/13959241/161716071-b30311b3-b60f-482d-a5d3-c40c1951253b.png">
<a href="https://documentation.qonversion.io/docs/integrations-overview"><img width="90%", src="https://qcdn3.sfo3.digitaloceanspaces.com/github/integrations.png">
</a>
</p>

Expand All @@ -75,18 +89,17 @@ Boost conversion rates with paywalls and in-app purchases A/B testing. Find the
* **Track and increase your revenue.** Qonversion provides detailed real-time revenue analytics including cohort analysis, trial conversion rates, country segmentation, and much more.
* **Integrations with the leading mobile platforms.** Qonversion allows sending data to platforms like AppsFlyer, Adjust, Branch, Tenjin, Facebook Ads, Amplitude, Mixpanel, and many others.
* **Change promoted in-app products.** Change promoted in-app products anytime without app releases.
* **Win back lapsed subscribers.** Qonversion allows sending highly targeted push notifications triggered by server-side subscription events. You can send special offers to users who just canceled a free trial or a subscription. Plus you can deliver in-app messages with a beautiful native design that you create in Qonversion.
* **A/B test** and identify winning in-app purchases, subscriptions or paywals.
* **Cross-device and cross-platform access management.** If you provide user authorization in your app, you can easily set Qonversion to provide premium access to authorized users across devices and operating systems.
* **SDK caches the data.** Qonversion SDK caches purchase data including in-app products and permissions, so the user experience is not affected even with the slow or interrupting network connection.
* **SDK caches the data.** Qonversion SDK caches purchase data including in-app products and entitlements, so the user experience is not affected even with the slow or interrupting network connection.
* **Webhooks.** You can easily send all of the data to your server with Qonversion webhooks.
* **Customer support.** You can always reach out to our customer support and get the help required.

Convinced? Let's go!

## Documentation

Check the [documentation](https://documentation.qonversion.io/docs/quickstart) to learn details on implementing and using Qonversion SDKs.
Check the [full documentation](https://documentation.qonversion.io/docs/quickstart) to learn about implementation details and available features.

#### Help us improve the documentation

Expand All @@ -113,4 +126,4 @@ Contact us via [issues on GitHub](https://github.com/qonversion/react-native-sdk

## License

Qonversion SDK is available under the MIT license.
Qonversion SDK is available under the MIT license.
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ repositories {
dependencies {
//noinspection GradleDynamicVersion
implementation 'com.facebook.react:react-native:+' // From node_modules
implementation "io.qonversion.sandwich:sandwich:3.2.0"
implementation "io.qonversion.sandwich:sandwich:3.3.2"
}

afterEvaluate { project ->
Expand Down
4 changes: 2 additions & 2 deletions example/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export class QonversionSample extends React.PureComponent<{}, StateType> {
}
}

const main: Product = products.get('main');
const main: Product = products.get('weekly');
if (main) {
subscriptionButtonTitle = 'Subscribe for ' + main.prettyPrice + ' / ' + prettyDuration[main.duration];
const entitlement = entitlements.get('plus');
Expand Down Expand Up @@ -146,7 +146,7 @@ export class QonversionSample extends React.PureComponent<{}, StateType> {
style={styles.subscriptionButton}
onPress={() => {
this.setState({loading: true});
Qonversion.getSharedInstance().purchase('main').then(() => {
Qonversion.getSharedInstance().purchase('weekly').then(() => {
this.setState({loading: false, subscriptionButtonTitle: 'Purchased'});
}).catch(error => {
this.setState({loading: false});
Expand Down
20 changes: 10 additions & 10 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ PODS:
- glog (0.3.5)
- libevent (2.1.12)
- OpenSSL-Universal (1.1.1100)
- Qonversion (5.2.0):
- Qonversion/Main (= 5.2.0)
- Qonversion/Main (5.2.0)
- QonversionSandwich (3.2.0):
- Qonversion (= 5.2.0)
- Qonversion (5.5.2):
- Qonversion/Main (= 5.5.2)
- Qonversion/Main (5.5.2)
- QonversionSandwich (3.3.1):
- Qonversion (= 5.5.2)
- RCT-Folly (2021.07.22.00):
- boost
- DoubleConversion
Expand Down Expand Up @@ -289,8 +289,8 @@ PODS:
- React-jsinspector (0.70.5)
- React-logger (0.70.5):
- glog
- react-native-qonversion (6.1.0):
- QonversionSandwich (= 3.2.0)
- react-native-qonversion (6.2.0):
- QonversionSandwich (= 3.3.1)
- React
- React-perflogger (0.70.5)
- React-RCTActionSheet (0.70.5):
Expand Down Expand Up @@ -534,8 +534,8 @@ SPEC CHECKSUMS:
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
Qonversion: 7b56446a98f5a31bbe9a4611c6baa14e0bafa4c8
QonversionSandwich: fac00203d7b082871264b4383d3627fd1ec8d5bf
Qonversion: 290d69d209f83a1defa914912a83fc8897a4af34
QonversionSandwich: a8339feabb3302d6b2dfe9a21372906cfccd507a
RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda
RCTRequired: 21229f84411088e5d8538f21212de49e46cc83e2
RCTTypeSafety: 62eed57a32924b09edaaf170a548d1fc96223086
Expand All @@ -550,7 +550,7 @@ SPEC CHECKSUMS:
React-jsiexecutor: 31564fa6912459921568e8b0e49024285a4d584b
React-jsinspector: badd81696361249893a80477983e697aab3c1a34
React-logger: fdda34dd285bdb0232e059b19d9606fa0ec3bb9c
react-native-qonversion: 354f01c4eb53b94be79ebedb34a8a83788543a8c
react-native-qonversion: 83b17ba32811c66dc8bf1182b3fe782f4ab22fa6
React-perflogger: e68d3795cf5d247a0379735cbac7309adf2fb931
React-RCTActionSheet: 05452c3b281edb27850253db13ecd4c5a65bc247
React-RCTAnimation: 578eebac706428e68466118e84aeacf3a282b4da
Expand Down
10 changes: 5 additions & 5 deletions example/ios/example.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@
TestTargetID = 13B07F861A680F5B00A75B9A;
};
13B07F861A680F5B00A75B9A = {
DevelopmentTeam = MTVL2X9L7N;
DevelopmentTeam = 5ZBNSPDUJ2;
LastSwiftMigration = 1120;
};
2D02E47A1E0B4A5D006451C7 = {
Expand Down Expand Up @@ -720,7 +720,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = example/example.entitlements;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = MTVL2X9L7N;
DEVELOPMENT_TEAM = 5ZBNSPDUJ2;
ENABLE_BITCODE = NO;
EXCLUDED_ARCHS = "";
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
Expand All @@ -736,7 +736,7 @@
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = com.qonversion.sample;
PRODUCT_BUNDLE_IDENTIFIER = io.qonversion.sample;
PRODUCT_NAME = "RN Qonversion";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
Expand All @@ -753,7 +753,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = example/example.entitlements;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = MTVL2X9L7N;
DEVELOPMENT_TEAM = 5ZBNSPDUJ2;
EXCLUDED_ARCHS = "";
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp;
Expand All @@ -764,7 +764,7 @@
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = com.qonversion.sample;
PRODUCT_BUNDLE_IDENTIFIER = io.qonversion.sample;
PRODUCT_NAME = "RN Qonversion";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "react-native-qonversion",
"title": "React Native Qonversion",
"version": "6.2.0",
"version": "6.3.0",
"description": "Qonversion provides full in-app purchases infrastructure, so you do not need to build your own server for receipt validation. Implement in-app subscriptions, validate user receipts, check subscription status, and provide access to your app features and content using our StoreKit wrapper and Google Play Billing wrapper.",
"main": "build/index.js",
"types": "build/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion react-native-qonversion.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ Pod::Spec.new do |s|
s.requires_arc = true

s.dependency "React"
s.dependency "QonversionSandwich", "3.2.0"
s.dependency "QonversionSandwich", "3.3.2"
end
36 changes: 31 additions & 5 deletions src/dto/Entitlement.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {EntitlementSource, EntitlementRenewState} from "./enums";
import {EntitlementSource, EntitlementRenewState, EntitlementGrantType} from "./enums";
import Transaction from "./Transaction";

class Entitlement {
id: string;
Expand All @@ -7,24 +8,49 @@ class Entitlement {
renewState: EntitlementRenewState;
source: EntitlementSource;
startedDate: Date;
renewsCount: number;
grantType: EntitlementGrantType;
transactions: Array<Transaction>;
expirationDate?: Date;
trialStartDate?: Date;
firstPurchaseDate?: Date;
lastPurchaseDate?: Date;
autoRenewDisableDate?: Date;
lastActivatedOfferCode?: string;

constructor(
id: string,
productId: string,
isActive: boolean,
renewState: EntitlementRenewState,
source: EntitlementSource,
startedDate: number,
expirationDate: number | undefined,
startedTimestamp: number,
renewsCount: number,
grantType: EntitlementGrantType,
transactions: Array<Transaction>,
expirationTimestamp: number | undefined,
trialStartTimestamp: number | undefined,
firstPurchaseTimestamp: number | undefined,
lastPurchaseTimestamp: number | undefined,
autoRenewDisableTimestamp: number | undefined,
lastActivatedOfferCode: string | undefined,
) {
this.id = id;
this.productId = productId;
this.isActive = isActive;
this.renewState = renewState;
this.source = source;
this.startedDate = new Date(startedDate);
this.expirationDate = expirationDate ? new Date(expirationDate) : undefined;
this.startedDate = new Date(startedTimestamp);
this.expirationDate = expirationTimestamp ? new Date(expirationTimestamp) : undefined;
this.renewsCount = renewsCount;
this.grantType = grantType;
this.transactions = transactions;
this.expirationDate = expirationTimestamp ? new Date(expirationTimestamp) : undefined;
this.trialStartDate = trialStartTimestamp ? new Date(trialStartTimestamp) : undefined;
this.firstPurchaseDate = firstPurchaseTimestamp ? new Date(firstPurchaseTimestamp) : undefined;
this.lastPurchaseDate = lastPurchaseTimestamp ? new Date(lastPurchaseTimestamp) : undefined;
this.autoRenewDisableDate = autoRenewDisableTimestamp ? new Date(autoRenewDisableTimestamp) : undefined;
this.lastActivatedOfferCode = lastActivatedOfferCode;
}
}

Expand Down
37 changes: 37 additions & 0 deletions src/dto/Transaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {TransactionEnvironment, TransactionOwnershipType, TransactionType} from "./enums";

class Transaction {
originalTransactionId: string;
transactionId: string;
transactionDate: Date;
environment: TransactionEnvironment;
ownershipType: TransactionOwnershipType;
type: TransactionType;
expirationDate?: Date;
transactionRevocationDate?: Date;
offerCode?: string;

constructor(
originalTransactionId: string,
transactionId: string,
transactionTimestamp: number,
environment: TransactionEnvironment,
ownershipType: TransactionOwnershipType,
type: TransactionType,
expirationTimestamp: number | undefined,
transactionRevocationTimestamp: number | undefined,
offerCode: string | undefined,
) {
this.originalTransactionId = originalTransactionId;
this.transactionId = transactionId;
this.transactionDate = new Date(transactionTimestamp);
this.environment = environment;
this.ownershipType = ownershipType;
this.type = type;
this.expirationDate = expirationTimestamp ? new Date(expirationTimestamp) : undefined;
this.transactionRevocationDate = transactionRevocationTimestamp ? new Date(transactionRevocationTimestamp) : undefined;
this.offerCode = offerCode;
}
}

export default Transaction;
Loading

0 comments on commit 2d67fa7

Please sign in to comment.