Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/remote config #243

Merged
merged 6 commits into from
Jun 29, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 2 additions & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ repositories {
dependencies {
//noinspection GradleDynamicVersion
implementation 'com.facebook.react:react-native:+' // From node_modules
implementation "io.qonversion.sandwich:sandwich:1.5.2"
implementation "io.qonversion.sandwich:sandwich:2.0.0"

}

afterEvaluate { project ->
Expand Down
15 changes: 15 additions & 0 deletions android/src/main/java/com/reactlibrary/QonversionModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,21 @@ public void userInfo(final Promise promise) {
qonversionSandwich.userInfo(Utils.getResultListener(promise));
}

@ReactMethod
public void remoteConfig(final Promise promise) {
qonversionSandwich.remoteConfig(Utils.getResultListener(promise));
}

@ReactMethod
public void attachUserToExperiment(String experimentId, String groupId, final Promise promise) {
qonversionSandwich.attachUserToExperiment(experimentId, groupId, Utils.getResultListener(promise));
}

@ReactMethod
public void detachUserFromExperiment(String experimentId, final Promise promise) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all the arguments can be final

qonversionSandwich.detachUserFromExperiment(experimentId, Utils.getResultListener(promise));
}

@Override
public void onEntitlementsUpdated(@NonNull Map<String, ?> map) {
final WritableMap payload = EntitiesConverter.convertMapToWritableMap(map);
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 (3.3.0):
- Qonversion/Main (= 3.3.0)
- Qonversion/Main (3.3.0)
- QonversionSandwich (1.4.0):
- Qonversion (= 3.3.0)
- Qonversion (4.0.0):
- Qonversion/Main (= 4.0.0)
- Qonversion/Main (4.0.0)
- QonversionSandwich (2.0.0):
- Qonversion (= 4.0.0)
- 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 (4.1.0):
- QonversionSandwich (= 1.4.0)
- react-native-qonversion (4.4.2):
- QonversionSandwich (= 2.0.0)
- 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: 8272c86e8942fd8808da8b23a3fae9365e7d6109
QonversionSandwich: 7370d7d7ea84a8241228a3bcada8fd8123a50c80
Qonversion: ae70809310aa2efc43b7df7770c3a65fdec7407b
QonversionSandwich: 54546f415866c2ce6369c72d8ee9774cc8d15f4d
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: dc97cdfb58d2a5ab6596cbfa75a2ba1994ab6f59
react-native-qonversion: 808ef46b21f83e281956f02e489ddd553a290c7f
React-perflogger: e68d3795cf5d247a0379735cbac7309adf2fb931
React-RCTActionSheet: 05452c3b281edb27850253db13ecd4c5a65bc247
React-RCTAnimation: 578eebac706428e68466118e84aeacf3a282b4da
Expand Down
18 changes: 18 additions & 0 deletions ios/RNQonversion.m
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,24 @@ + (BOOL)requiresMainQueueSetup
}];
}

RCT_EXPORT_METHOD(remoteConfig:(RCTResponseSenderBlock)completion rejecter:(RCTPromiseRejectBlock)reject) {
[_qonversionSandwich remoteConfig:^(NSDictionary<NSString *,id> * _Nullable result, SandwichError * _Nullable error) {
[self handleResult:result error:error completion:completion rejecter:reject];
}];
}

RCT_EXPORT_METHOD(attachUserToExperiment:(NSString *)experimentId groupId:(NSString *)groupId completion:(RCTResponseSenderBlock)completion rejecter:(RCTPromiseRejectBlock)reject) {
[_qonversionSandwich attachUserToExperimentWith:experimentId groupId:groupId completion:^(NSDictionary<NSString *,id> * _Nullable result, SandwichError * _Nullable error) {
[self handleResult:result error:error completion:completion rejecter:reject];
}];
}

RCT_EXPORT_METHOD(detachUserFromExperiment:(NSString *)experimentId completion:(RCTResponseSenderBlock)completion rejecter:(RCTPromiseRejectBlock)reject) {
[_qonversionSandwich detachUserFromExperimentWith:experimentId completion:^(NSDictionary<NSString *,id> * _Nullable result, SandwichError * _Nullable error) {
[self handleResult:result error:error completion:completion rejecter:reject];
}];
}

RCT_EXPORT_METHOD(collectAdvertisingID) {
[_qonversionSandwich collectAdvertisingId];
}
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", "1.5.2"
s.dependency "QonversionSandwich", "2.0.0"
end
25 changes: 25 additions & 0 deletions src/QonversionApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import IntroEligibility from './dto/IntroEligibility';
import User from './dto/User';
import {EntitlementsUpdateListener} from './dto/EntitlementsUpdateListener';
import {PromoPurchasesListener} from './dto/PromoPurchasesListener';
import RemoteConfig from "./dto/RemoteConfig";

interface QonversionApi {

Expand Down Expand Up @@ -246,6 +247,30 @@ interface QonversionApi {
* On iOS 14.0+ shows up a sheet for users to redeem App Store offer codes.
*/
presentCodeRedemptionSheet(): void;

/**
* Returns Qonversion remote config object
* Use this function to get the remote config with specific payload and experiment info.
* @returns the promise with the remote config.
*/
remoteConfig(): Promise<RemoteConfig>

/**
* This function should be used for the test purpose only. Do not forget to delete the usage of this function before the release.
suriksarkisyan marked this conversation as resolved.
Show resolved Hide resolved
* Use this function to attach the user to the experiment.
* @param experimentId identifier of the experiment
* @param groupId identifier of the experiment group
* @returns the promise for success result or throws an error otherwise.
*/
attachUserToExperiment(experimentId: string, groupId: string): Promise<void>

/**
* This function should be used for the test purpose only. Do not forget to delete the usage of this function before the release.
suriksarkisyan marked this conversation as resolved.
Show resolved Hide resolved
* Use this function to detach the user from the experiment.
* @param experimentId identifier of the experiment
* @returns the promise for success result or throws an error otherwise.
*/
detachUserFromExperiment(experimentId: string): Promise<void>
}

export default QonversionApi;
15 changes: 15 additions & 0 deletions src/dto/Experiment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import ExperimentGroup from "./ExperimentGroup";

class Experiment {
id: string;
name: string;
group: ExperimentGroup;

constructor(id: string, name: string, group: ExperimentGroup) {
this.id = id;
this.name = name;
this.group = group;
}
}

export default Experiment;
15 changes: 15 additions & 0 deletions src/dto/ExperimentGroup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { ExperimentGroupType } from "./enums";

class ExperimentGroup {
id: string;
name: string;
type: ExperimentGroupType;

constructor(id: string, name: string, type: ExperimentGroupType) {
this.id = id;
this.name = name;
this.type = type;
}
}

export default ExperimentGroup;
13 changes: 13 additions & 0 deletions src/dto/RemoteConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Experiment from "./Experiment";

class RemoteConfig {
payload: Map<string, Object>;
experiment?: Experiment | null;

constructor(payload: Map<string, Object>, experiment: Experiment | null) {
this.payload = payload;
this.experiment = experiment;
}
}

export default RemoteConfig;
6 changes: 6 additions & 0 deletions src/dto/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ export enum IntroEligibilityStatus {
INELIGIBLE = "intro_or_trial_ineligible",
}

export enum ExperimentGroupType {
UNKNOWN = "unknown",
CONTROL = "control",
TREATMENT = "treatment",
}

export enum ActionResultType {
UNKNOWN = "unknown",
URL = "url",
Expand Down
47 changes: 45 additions & 2 deletions src/internal/Mapper.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {
AutomationsEventType,
EntitlementRenewState,
EntitlementSource,
ExperimentGroupType,
IntroEligibilityStatus,
OfferingTag,
ProductDuration,
ProductDurations,
ProductType,
ProductTypes,
EntitlementRenewState,
SKPeriodUnit,
SKProductDiscountPaymentMode,
SKProductDiscountType,
Expand All @@ -28,6 +29,9 @@ import QonversionError from "../dto/QonversionError";
import AutomationsEvent from "../dto/AutomationsEvent";
import User from '../dto/User';
import {ScreenPresentationConfig} from '../dto/ScreenPresentationConfig';
import Experiment from "../dto/Experiment";
import ExperimentGroup from "../dto/ExperimentGroup";
import RemoteConfig from "../dto/RemoteConfig";

type QProduct = {
id: string;
Expand Down Expand Up @@ -132,6 +136,23 @@ type QUser = {
identityId?: string | null;
};

type QRemoteConfig = {
payload: Map<string, Object>;
experiment?: QExperiment | null;
};

type QExperiment = {
id: string;
name: string;
group: QExperimentGroup;
}

type QExperimentGroup = {
id: string;
name: string;
type: string;
}

const skuDetailsPriceRatio = 1000000;

class Mapper {
Expand Down Expand Up @@ -474,10 +495,32 @@ class Mapper {
)
}

static convertUserInfo(user: QUser) {
static convertUserInfo(user: QUser): User {
return new User(user.qonversionId, user.identityId);
}

static convertRemoteConfig(remoteConfig: QRemoteConfig): RemoteConfig {
let experiment = null;
if (remoteConfig.experiment) {
let groupType = this.convertGroupType(remoteConfig.experiment.group.type);
let group = new ExperimentGroup(remoteConfig.experiment.group.id, remoteConfig.experiment.group.name, groupType);
suriksarkisyan marked this conversation as resolved.
Show resolved Hide resolved
experiment = new Experiment(remoteConfig.experiment.id, remoteConfig.experiment.name, group);
}

return new RemoteConfig(remoteConfig.payload, experiment);
}

static convertGroupType(type: String): ExperimentGroupType {
switch (type) {
case "control":
return ExperimentGroupType.CONTROL;
case "treatment":
return ExperimentGroupType.TREATMENT;
default:
return ExperimentGroupType.UNKNOWN;
}
}

static convertScreenPresentationConfig(config: ScreenPresentationConfig): Object {
return {
presentationStyle: config.presentationStyle,
Expand Down
18 changes: 18 additions & 0 deletions src/internal/QonversionInternal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {PromoPurchasesListener} from '../dto/PromoPurchasesListener';
import User from '../dto/User';
import QonversionApi from '../QonversionApi';
import QonversionConfig from '../QonversionConfig';
import RemoteConfig from "../dto/RemoteConfig";

const {RNQonversion} = NativeModules;

Expand Down Expand Up @@ -265,4 +266,21 @@ export default class QonversionInternal implements QonversionApi {
RNQonversion.presentCodeRedemptionSheet();
}
}

async remoteConfig(): Promise<RemoteConfig> {
const remoteConfig = await RNQonversion.remoteConfig();
const mappedRemoteConfig: RemoteConfig = Mapper.convertRemoteConfig(remoteConfig);

return mappedRemoteConfig;
}

async attachUserToExperiment(experimentId: string, groupId: string): Promise<void> {
await RNQonversion.attachUserToExperiment(experimentId, groupId);
return;
}

async detachUserFromExperiment(experimentId: string): Promise<void> {
await RNQonversion.detachUserFromExperiment(experimentId);
return;
}
}