From d2a76773c209145ca3709846c6cc36e099265737 Mon Sep 17 00:00:00 2001 From: Dariusz Zajac Date: Tue, 29 Sep 2020 10:47:49 +0200 Subject: [PATCH 01/10] feat: Add a bridge for getPlacement method --- ios/QubitSDKModule/QubitSDKModule.m | 10 ++++++++++ ios/QubitSDKModule/QubitSDKModule.swift | 24 ++++++++++++++++++++++++ package.json | 2 +- qubit-sdk-react-native.podspec | 2 +- 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/ios/QubitSDKModule/QubitSDKModule.m b/ios/QubitSDKModule/QubitSDKModule.m index 392c7ed..e2995a0 100644 --- a/ios/QubitSDKModule/QubitSDKModule.m +++ b/ios/QubitSDKModule/QubitSDKModule.m @@ -28,5 +28,15 @@ @interface RCT_EXTERN_REMAP_MODULE(QubitSDK, QubitSDKModule, NSObject) resolver:(RCTPromiseResolveBlock) resolver rejecter:(RCTPromiseRejectBlock) rejecter) RCT_EXTERN_METHOD(experienceShown:(NSString *) callback) +RCT_EXTERN_METHOD(getPlacement: + (NSString *) placementId + mode:(NSString *) mode + attributes:(NSString *) attributes + campaignId:(NSString *) campaignId + experienceId:(NSString *) experienceId + resolver:(RCTPromiseResolveBlock) resolver + rejecter:(RCTPromiseRejectBlock) rejecter) +RCT_EXTERN_METHOD(placementImpression:(NSString *) callback) +RCT_EXTERN_METHOD(placementClickthrough:(NSString *) callback) @end diff --git a/ios/QubitSDKModule/QubitSDKModule.swift b/ios/QubitSDKModule/QubitSDKModule.swift index 5fc9747..94e23ef 100644 --- a/ios/QubitSDKModule/QubitSDKModule.swift +++ b/ios/QubitSDKModule/QubitSDKModule.swift @@ -61,6 +61,30 @@ class QubitSDKModule: NSObject { func experienceShown(callback: String) { QBExperienceEntityCallback(callback: callback).shown() } + + @objc(getPlacement:mode:attributes:campaignId:experienceId:resolver:rejecter:) + func getPlacement(placementId: String, mode: String, attributes: String, campaignId: String, experienceId: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { + QubitSDK.getPlacement(with: placementId, + mode: mode, + attributes: attributes, + campaignId: campaignId, + experienceId: experienceId, + onSuccess: { result in + resolver( result ) + }, onError: { error in + rejecter("Error", "QubitSDKModule: getPlacement failed.", error) + }) + } + + @objc(placementImpression:) + func placementImpression(callback: String) { + QBPlacementEntityCallback(impressionUrl: callback).impression() + } + + @objc(placementClickthrough:) + func placementClickthrough(callback: String) { + QBPlacementEntityCallback(clickthroughUrl: callback).clickthrough() + } @objc static func requiresMainQueueSetup() -> Bool { diff --git a/package.json b/package.json index 3024298..ca733ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "qubit-sdk-react-native", - "version": "1.0.7", + "version": "1.0.11", "description": "React Native bridge for using native Qubit SDK libraries on iOS and Android", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/qubit-sdk-react-native.podspec b/qubit-sdk-react-native.podspec index c2a0c66..9764593 100644 --- a/qubit-sdk-react-native.podspec +++ b/qubit-sdk-react-native.podspec @@ -21,5 +21,5 @@ Pod::Spec.new do |s| s.dependency "React" s.dependency "QubitSDK" - s.swift_versions = ['4.0', '4.1', '4.2', '5.0'] + s.swift_versions = ['4.0', '4.1', '4.2', '5.0', '5.1', '5.2', '5.3'] end From fa892835b2d605b24a125c5537449b8beec74194 Mon Sep 17 00:00:00 2001 From: Jan Hudzik Date: Thu, 22 Oct 2020 13:24:15 +0200 Subject: [PATCH 02/10] Integration of getPlacement() method - Android and common logic --- BridgeAPI.md | 68 ++++++++++++++ README.md | 47 ++++++++++ android/build.gradle | 2 +- .../qubit/reactnative/sdk/QubitSDKModule.java | 94 ++++++++++++++++++- example/App.js | 16 ++++ src/index.ts | 36 ++++++- 6 files changed, 254 insertions(+), 9 deletions(-) diff --git a/BridgeAPI.md b/BridgeAPI.md index 0d955de..1f74cd1 100644 --- a/BridgeAPI.md +++ b/BridgeAPI.md @@ -293,3 +293,71 @@ None ### Example QubitSDK.experienceShown("https://sse.qubit.com/v1/callback?data=igK....n0="); + +------------------------------------------------------- + +## **getPlacement**(placementId, mode, attributes, campaignId, experienceId, placementPromise) + +### Description +Returns Placement for given parameters. + +### Parameters +- placementId + - Type: String + - Constraints: Not null + - Description: Unique ID of the placement. +- mode + - Type: String + - Constraints: Can be one of LIVE/SAMPLE/PREVIEW. + - Description: The mode to fetch placements content with. Defaults to LIVE. +- attributes + - Type: String + - Constraints: Should be string description of JSON or null + - Description: JSON string containing custom attributes to be used to query for the placement. "visitor" attribute will be ignored as it is set by SDK. +- campaignId + - Type: String + - Constraints: Nullable + - Description: Campaign identifier +- experienceId + - Type: String + - Constraints: Nullable + - Description: Experience identifier +- placementPromise + - Type: Promise + - Constraints: Not null + - Description: Promise with query result + +### Result +Promise with a map describing Placement object. Example: + + { + "data": { + "placementContent": { + "content": { + "image": "https://image.store.com/images/example.jpeg", + "message": "Hello World", + "url": "https://www.qubit.com" + }, + "callbacks": { + "impression": "https://api.qubit.com/placements/callback?data=ggW4eyJtZXRhIjp7ImlkIjo", + "clickthrough": "https://api.qubit.com/placements/callback?data=mQW4eyJtZXRhIjp7Imlkx" + } + } + } + } + + +### Exceptions +- Exception is thrown, when SDK is not initialized. + +### Example + async () => { + const placement = await getPlacement( + "placement_id", + "LIVE", + "{ \"color\": \"blue\"}", + "campaign_id", + "experience_id" + ); + ... + } diff --git a/README.md b/README.md index fe7f2ae..dccb30e 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,53 @@ async () => { Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<Experience>>** Promise with an array of Experience objects. +#### getPlacement + +Returns Placement for given parameters. + +##### Parameters + +- `placementId` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Unique ID of the placement. +- `mode` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The mode to fetch placements content with, can be one of LIVE/SAMPLE/PREVIEW. Defaults to LIVE. +- `attributes` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** JSON string containing custom attributes to be used to query for the placement. "visitor" attribute will be ignored as it is set by SDK. +- `campaignId` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Optional. +- `experienceId` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Optional. +- `placementPromise` **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<Placement>** Promise with query result. + + +##### Example + +```javascript +async () => { + const placement = await getPlacement( + "placement_id", + "LIVE", + "{ \"color\": \"blue\"}", + "campaign_id", + "experience_id" + ); + ... +} + +{ + "data": { + "placementContent": { + "content": { + "image": "https://image.store.com/images/example.jpeg", + "message": "Hello World", + "url": "https://www.qubit.com" + }, + "callbacks": { + "impression": "https://api.qubit.com/placements/callback?data=ggW4eyJtZXRhIjp7ImlkIjo", + "clickthrough": "https://api.qubit.com/placements/callback?data=mQW4eyJtZXRhIjp7Imlkx" + } + } + } +} +``` + +Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<Placement>** with a map describing Placement object. + ### Compatibility Qubit SDK React Native is compatible with React Native 0.58 and higher diff --git a/android/build.gradle b/android/build.gradle index c60967d..5df2d85 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -58,6 +58,6 @@ dependencies { implementation "androidx.annotation:annotation:1.0.0" implementation "com.google.code.gson:gson:2.8.2" - implementation 'com.qubit:qubit-sdk-android:1.4.1' + implementation 'com.qubit:qubit-sdk-android:1.5.0' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.0" } diff --git a/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java b/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java index 7cca174..8fcbdc1 100644 --- a/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java +++ b/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java @@ -1,7 +1,7 @@ package com.qubit.reactnative.sdk; import android.util.Log; -import androidx.annotation.NonNull; + import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; @@ -12,18 +12,30 @@ import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.qubit.android.sdk.api.QubitSDK; import com.qubit.android.sdk.api.logging.QBLogLevel; +import com.qubit.android.sdk.api.placement.PlacementCallbackConnector; +import com.qubit.android.sdk.api.placement.PlacementMode; +import com.qubit.android.sdk.api.placement.PlacementPreviewOptions; import com.qubit.android.sdk.api.tracker.event.QBEvent; import com.qubit.android.sdk.api.tracker.event.QBEvents; +import com.qubit.android.sdk.internal.callbacktracker.CallbackRequestTracker; +import com.qubit.android.sdk.internal.callbacktracker.CallbackRequestTrackerImpl; +import com.qubit.android.sdk.internal.callbacktracker.repository.CallbackRequestRepositoryImpl; import com.qubit.android.sdk.internal.experience.Experience; -import com.qubit.android.sdk.internal.experience.callback.CallbackConnector; -import com.qubit.android.sdk.internal.experience.callback.CallbackConnectorImpl; +import com.qubit.android.sdk.internal.experience.callback.ExperienceCallbackConnector; +import com.qubit.android.sdk.internal.experience.callback.ExperienceCallbackConnectorImpl; import com.qubit.android.sdk.internal.experience.model.ExperiencePayload; import com.qubit.android.sdk.internal.lookup.LookupData; +import com.qubit.android.sdk.internal.network.NetworkStateServiceImpl; +import com.qubit.android.sdk.internal.placement.callback.PlacementCallbackConnectorImpl; + import java.util.ArrayList; import java.util.List; +import androidx.annotation.NonNull; + public class QubitSDKModule extends ReactContextBaseJavaModule { private static ReactApplicationContext reactContext; @@ -139,10 +151,82 @@ public void getExperiences(ReadableArray experienceIds, @ReactMethod public void experienceShown(String callback) { - CallbackConnector callbackConnector = new CallbackConnectorImpl(callback, QubitSDK.getDeviceId()); + ExperienceCallbackConnector callbackConnector = new ExperienceCallbackConnectorImpl(callback, QubitSDK.getDeviceId()); callbackConnector.shown(); } + @ReactMethod + public void getPlacement( + String placementId, + String mode, + String attributes, + String campaignId, + String experienceId, + Promise placementPromise + ) { + QubitSDK.getPlacement( + placementId, + matchMode(mode), + getAttributesJson(attributes), + new PlacementPreviewOptions(campaignId, experienceId), + placement -> { + WritableMap placementContentMap = WritableMapConverter.convertJsonToMap(placement.getContent()); + placementPromise.resolve(placementContentMap); + return null; + }, + throwable -> { + placementPromise.reject(throwable); + return null; + } + ); + } + + @ReactMethod + public void placementImpression(String callbackUrl) { + PlacementCallbackConnector callbackConnector = new PlacementCallbackConnectorImpl( + getCallbackRequestTracker(), + callbackUrl, + null + ); + callbackConnector.impression(); + } + + @ReactMethod + public void placementClickthrough(String callbackUrl) { + PlacementCallbackConnector callbackConnector = new PlacementCallbackConnectorImpl( + getCallbackRequestTracker(), + null, + callbackUrl + ); + callbackConnector.clickthrough(); + } + + private CallbackRequestTracker getCallbackRequestTracker() { + return new CallbackRequestTrackerImpl( + new NetworkStateServiceImpl(reactContext), + new CallbackRequestRepositoryImpl(reactContext) + ); + } + + private PlacementMode matchMode(String value) { + switch (value) { + case "SAMPLE": + return PlacementMode.SAMPLE; + case "PREVIEW": + return PlacementMode.PREVIEW; + case "LIVE": + default: + return PlacementMode.LIVE; + } + } + + private JsonObject getAttributesJson(String attributes) { + try { + return new JsonParser().parse(attributes).getAsJsonObject(); + } catch (Exception e) { + return null; + } + } private static QBLogLevel defaultLogLevel = QBLogLevel.WARN; @@ -150,7 +234,7 @@ private QBLogLevel parseLogLevel(String logLevel) { if (logLevel == null || logLevel.isEmpty()) { return defaultLogLevel; } - for(QBLogLevel level : QBLogLevel.values()) { + for (QBLogLevel level : QBLogLevel.values()) { if (level.toString().equalsIgnoreCase(logLevel)) return level; } diff --git a/example/App.js b/example/App.js index eb1a741..4cc54f3 100644 --- a/example/App.js +++ b/example/App.js @@ -42,6 +42,17 @@ class App extends PureComponent { exp.forEach(e => console.log(e)); }; + getPlacement = async () => { + const placement = await QubitSDK.getPlacement( + "tsOujouCSSKJGSCMUsmQRw", + "LIVE", + null, + "1ybrhki9RvKWpA-9veLQSg", + null + ); + console.log(placement); + }; + render() { return ( <> @@ -82,6 +93,11 @@ class App extends PureComponent { Get experiences + + + Get placement + + ) diff --git a/src/index.ts b/src/index.ts index 671af27..ec5a5fd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,10 +16,16 @@ type Experience = { isControl: boolean, id: number, callback: string, - variation: number + variation: number, shown: () => void } +type Placement = { + content: object, + impression: () => void, + clickthrough: () => void +} + class QubitSDK { /** * Initialization of SDK. It should be called as early as possible after application start, only once and before any other interaction with the API. @@ -183,8 +189,32 @@ class QubitSDK { !(ignoreSegments == null), ignoreSegments || false ) - .then(experiences => experiences.map(e => ({...e, shown: () => { NativeModules.QubitSDK.experienceShown(e.callback || '')} }))) + .then(experiences => experiences.map(e => ({ + ...e, + shown: () => { NativeModules.QubitSDK.experienceShown(e.callback || '') } + }))) + } + + + public getPlacement( + placementId: string, + mode?: string, + attributes?: string, + campaignId?: string, + experienceId?: string + ) : Promise { + return NativeModules.QubitSDK.getPlacement( + placementId, + mode, + attributes, + campaignId, + experienceId + ) + .then(placement => ({ + ...placement, + impression: () => { NativeModules.QubitSDK.placementImpression(placement.impression || '') }, + clickthrough: () => { NativeModules.QubitSDK.placementClickthrough(placement.clickthrough || '') } + })) } -} export default new QubitSDK(); From 9074df7ac7a9268ab556f6fa9aad9934ca4a1d97 Mon Sep 17 00:00:00 2001 From: Jan Hudzik Date: Mon, 2 Nov 2020 16:13:42 +0100 Subject: [PATCH 03/10] Updated QubitSDKModule.getPlacement() to return flat placement structure --- .../qubit/reactnative/sdk/QubitSDKModule.java | 11 +++--- src/index.ts | 35 +++++++++++++++++-- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java b/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java index 8fcbdc1..de5444a 100644 --- a/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java +++ b/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java @@ -8,6 +8,7 @@ import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; import com.google.gson.Gson; import com.google.gson.JsonArray; @@ -170,8 +171,10 @@ public void getPlacement( getAttributesJson(attributes), new PlacementPreviewOptions(campaignId, experienceId), placement -> { - WritableMap placementContentMap = WritableMapConverter.convertJsonToMap(placement.getContent()); - placementPromise.resolve(placementContentMap); + JsonObject placementJson = placement.getContent(); + placementJson.addProperty("impressionUrl", placement.getImpressionUrl()); + placementJson.addProperty("clickthroughUrl", placement.getClickthroughUrl()); + placementPromise.resolve(WritableMapConverter.convertJsonToMap(placementJson)); return null; }, throwable -> { @@ -186,7 +189,7 @@ public void placementImpression(String callbackUrl) { PlacementCallbackConnector callbackConnector = new PlacementCallbackConnectorImpl( getCallbackRequestTracker(), callbackUrl, - null + "" ); callbackConnector.impression(); } @@ -195,7 +198,7 @@ public void placementImpression(String callbackUrl) { public void placementClickthrough(String callbackUrl) { PlacementCallbackConnector callbackConnector = new PlacementCallbackConnectorImpl( getCallbackRequestTracker(), - null, + "", callbackUrl ); callbackConnector.clickthrough(); diff --git a/src/index.ts b/src/index.ts index ec5a5fd..edb1726 100644 --- a/src/index.ts +++ b/src/index.ts @@ -195,7 +195,35 @@ class QubitSDK { }))) } - + /** + * Returns Placement for given parameters. + * @param {string} placementId Unique ID of the placement. + * @param {string} [mode] The mode to fetch placements content with, can be one of LIVE/SAMPLE/PREVIEW. Defaults to LIVE. + * @param {string} [attributes] JSON string containing custom attributes to be used to query for the placement. "visitor" attribute will be ignored as it is set by SDK. + * @param {string} [campaignId] Optional. + * @param {string} [experienceId] Optional. + * @returns {Promise} Promise with an object describing Placement object. + * @example + * + * async () => { + * const placement = await getPlacement( + * "placement_id", + * "LIVE", + * "{ \"color\": \"blue\"}", + * "campaign_id", + * "experience_id" + * ); + * ... + * } + * + * { + * "image": "https://image.store.com/images/example.jpeg", + * "message": "Hello World", + * "url": "https://www.qubit.com" + * "impressionUrl": "https://api.qubit.com/placements/callback?data=ggW4eyJtZXRhIjp7ImlkIjo", + * "clickthroughUrl": "https://api.qubit.com/placements/callback?data=mQW4eyJtZXRhIjp7Imlkx" + * } + */ public getPlacement( placementId: string, mode?: string, @@ -212,9 +240,10 @@ class QubitSDK { ) .then(placement => ({ ...placement, - impression: () => { NativeModules.QubitSDK.placementImpression(placement.impression || '') }, - clickthrough: () => { NativeModules.QubitSDK.placementClickthrough(placement.clickthrough || '') } + impression: () => { NativeModules.QubitSDK.placementImpression(placement.impressionUrl || '') }, + clickthrough: () => { NativeModules.QubitSDK.placementClickthrough(placement.clickthroughUrl || '') } })) } +} export default new QubitSDK(); From 810d5d360390e3207de517f450886ecbd411db93 Mon Sep 17 00:00:00 2001 From: Jan Hudzik Date: Mon, 2 Nov 2020 16:14:03 +0100 Subject: [PATCH 04/10] Added missing documentation --- BridgeAPI.md | 93 +++++++++++++++++++++++++++++++++++++------------- README.md | 59 +++++++++++++++----------------- example/App.js | 1 + 3 files changed, 99 insertions(+), 54 deletions(-) diff --git a/BridgeAPI.md b/BridgeAPI.md index 1f74cd1..c53c43a 100644 --- a/BridgeAPI.md +++ b/BridgeAPI.md @@ -28,6 +28,9 @@ native modules for both platforms: Android and iOS. - getLookupData - getExperiences - experienceShown +- getPlacement +- placementImpression +- placementClickthrough ------------------------------------------------------- ## **init(trackingId, logLevel)** @@ -330,21 +333,13 @@ Returns Placement for given parameters. ### Result Promise with a map describing Placement object. Example: - { - "data": { - "placementContent": { - "content": { - "image": "https://image.store.com/images/example.jpeg", - "message": "Hello World", - "url": "https://www.qubit.com" - }, - "callbacks": { - "impression": "https://api.qubit.com/placements/callback?data=ggW4eyJtZXRhIjp7ImlkIjo", - "clickthrough": "https://api.qubit.com/placements/callback?data=mQW4eyJtZXRhIjp7Imlkx" - } - } - } - } + { + "image": "https://image.store.com/images/example.jpeg", + "message": "Hello World", + "url": "https://www.qubit.com" + "impressionUrl": "https://api.qubit.com/placements/callback?data=ggW4eyJtZXRhIjp7ImlkIjo", + "clickthroughUrl": "https://api.qubit.com/placements/callback?data=mQW4eyJtZXRhIjp7Imlkx" + } ### Exceptions @@ -352,12 +347,64 @@ Promise with a map describing Placement object. Example: ### Example async () => { - const placement = await getPlacement( - "placement_id", - "LIVE", - "{ \"color\": \"blue\"}", - "campaign_id", - "experience_id" - ); - ... + const placement = await QubitSDK.getPlacement( + "placement_id", + "LIVE", + "{ \"color\": \"blue\"}", + "campaign_id", + "experience_id" + ); + ... + } + +------------------------------------------------------- + +## placementImpression(callbackUrl) + +### Description +Sends request to URL described by placement impression callback. + +### Parameters +- callbackUrl + - Type: String + - Constraints: Not null + - Description: Impression callback URL. + + +### Result +None + +### Example + async () => { + const placement = await QubitSDK.placementImpression( + "https://some.url.com" + ); + ... + } + +------------------------------------------------------- + +## placementClickthrough(callbackUrl) + +### Description +Sends request to URL described by placement clickthrough callback. + +### Parameters +- callbackUrl + - Type: String + - Constraints: Not null + - Description: Clickthrough callback URL. + + +### Result +None + +### Example + async () => { + const placement = await QubitSDK.placementClickthrough( + "https://some.url.com" + ); + ... } + + diff --git a/README.md b/README.md index dccb30e..c265182 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ Installation of the QubitSDK, to provide event tracking and lookup. To make use ### Installation -1. `$ npm install qubit-sdk-react-native --save` -or -`$ yarn add qubit-sdk-react-native` +1. `$ npm install qubit-sdk-react-native --save` + or + `$ yarn add qubit-sdk-react-native` -2. Navigate to your `/ios` directory and run `pod install` to ensure the `QubitSDK` CocoaPod is installed. Android should require no further installation. +2. Navigate to your `/ios` directory and run `pod install` to ensure the `QubitSDK` CocoaPod is installed. Android should require no further installation. Optional - if you are using React Native < 0.60, you must `link` the library. @@ -54,6 +54,9 @@ and send first event - [getExperiences](#getexperiences) - [Parameters](#parameters-3) - [Examples](#examples-6) +- [getPlacement](#getplacement) + - [Parameters](#parameters-4) + - [Examples](#examples-7) #### start @@ -221,45 +224,39 @@ Returns Placement for given parameters. ##### Parameters - `placementId` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Unique ID of the placement. -- `mode` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The mode to fetch placements content with, can be one of LIVE/SAMPLE/PREVIEW. Defaults to LIVE. -- `attributes` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** JSON string containing custom attributes to be used to query for the placement. "visitor" attribute will be ignored as it is set by SDK. +- `mode` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** The mode to fetch placements content with, can be one of LIVE/SAMPLE/PREVIEW. Defaults to LIVE. +- `attributes` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** JSON string containing custom attributes to be used to query for the placement. "visitor" attribute will be ignored as it is set by SDK. - `campaignId` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Optional. - `experienceId` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Optional. -- `placementPromise` **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<Placement>** Promise with query result. - -##### Example +##### Examples ```javascript async () => { - const placement = await getPlacement( - "placement_id", - "LIVE", - "{ \"color\": \"blue\"}", - "campaign_id", - "experience_id" - ); - ... + const placement = await getPlacement( + "placement_id", + "LIVE", + "{ \"color\": \"blue\"}", + "campaign_id", + "experience_id" + ); + + placement.impression(); + ... + placement.clickthrough(); + ... } { - "data": { - "placementContent": { - "content": { - "image": "https://image.store.com/images/example.jpeg", - "message": "Hello World", - "url": "https://www.qubit.com" - }, - "callbacks": { - "impression": "https://api.qubit.com/placements/callback?data=ggW4eyJtZXRhIjp7ImlkIjo", - "clickthrough": "https://api.qubit.com/placements/callback?data=mQW4eyJtZXRhIjp7Imlkx" - } - } - } + "image": "https://image.store.com/images/example.jpeg", + "message": "Hello World", + "url": "https://www.qubit.com" + "impressionUrl": "https://api.qubit.com/placements/callback?data=ggW4eyJtZXRhIjp7ImlkIjo", + "clickthroughUrl": "https://api.qubit.com/placements/callback?data=mQW4eyJtZXRhIjp7Imlkx" } ``` -Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<Placement>** with a map describing Placement object. +Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<Placement>** Promise with an object describing Placement object. ### Compatibility diff --git a/example/App.js b/example/App.js index 4cc54f3..f6e2059 100644 --- a/example/App.js +++ b/example/App.js @@ -51,6 +51,7 @@ class App extends PureComponent { null ); console.log(placement); + placement.impression(); }; render() { From 7be70214d62013034ab6c42ddc2bb3644520c2e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Balawajder?= Date: Thu, 5 Nov 2020 15:50:27 +0100 Subject: [PATCH 05/10] Fixed QBPlacementEntity result being transferred to RN as dictionary instead of object. --- ios/QubitSDKModule/QubitSDKModule.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/QubitSDKModule/QubitSDKModule.swift b/ios/QubitSDKModule/QubitSDKModule.swift index 94e23ef..e6a597f 100644 --- a/ios/QubitSDKModule/QubitSDKModule.swift +++ b/ios/QubitSDKModule/QubitSDKModule.swift @@ -70,7 +70,7 @@ class QubitSDKModule: NSObject { campaignId: campaignId, experienceId: experienceId, onSuccess: { result in - resolver( result ) + resolver( result.asDictionary ) }, onError: { error in rejecter("Error", "QubitSDKModule: getPlacement failed.", error) }) From 6e5afb8db12d336151ce6ab9e6635014690d31eb Mon Sep 17 00:00:00 2001 From: Jan Hudzik Date: Mon, 9 Nov 2020 10:43:52 +0100 Subject: [PATCH 06/10] Documentation update --- BridgeAPI.md | 4 ---- README.md | 20 ++++++++------------ 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/BridgeAPI.md b/BridgeAPI.md index c53c43a..38a2eb0 100644 --- a/BridgeAPI.md +++ b/BridgeAPI.md @@ -325,10 +325,6 @@ Returns Placement for given parameters. - Type: String - Constraints: Nullable - Description: Experience identifier -- placementPromise - - Type: Promise - - Constraints: Not null - - Description: Promise with query result ### Result Promise with a map describing Placement object. Example: diff --git a/README.md b/README.md index c265182..1786659 100644 --- a/README.md +++ b/README.md @@ -233,18 +233,14 @@ Returns Placement for given parameters. ```javascript async () => { - const placement = await getPlacement( - "placement_id", - "LIVE", - "{ \"color\": \"blue\"}", - "campaign_id", - "experience_id" - ); - - placement.impression(); - ... - placement.clickthrough(); - ... + const placement = await getPlacement( + "placement_id", + "LIVE", + "{ \"color\": \"blue\"}", + "campaign_id", + "experience_id" + ); + ... } { From 928d4245fbd3b51ec150eeaeb52d982dad7e9677 Mon Sep 17 00:00:00 2001 From: Jan Hudzik Date: Mon, 9 Nov 2020 11:44:38 +0100 Subject: [PATCH 07/10] Fixed methods for sending placement callback requests and added invocations to sample app --- .../qubit/reactnative/sdk/QubitSDKModule.java | 16 ++-------- example/App.js | 32 +++++++++++++++++++ src/index.ts | 6 +++- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java b/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java index de5444a..b1fd95c 100644 --- a/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java +++ b/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java @@ -8,7 +8,6 @@ import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; import com.google.gson.Gson; import com.google.gson.JsonArray; @@ -21,15 +20,11 @@ import com.qubit.android.sdk.api.placement.PlacementPreviewOptions; import com.qubit.android.sdk.api.tracker.event.QBEvent; import com.qubit.android.sdk.api.tracker.event.QBEvents; -import com.qubit.android.sdk.internal.callbacktracker.CallbackRequestTracker; -import com.qubit.android.sdk.internal.callbacktracker.CallbackRequestTrackerImpl; -import com.qubit.android.sdk.internal.callbacktracker.repository.CallbackRequestRepositoryImpl; import com.qubit.android.sdk.internal.experience.Experience; import com.qubit.android.sdk.internal.experience.callback.ExperienceCallbackConnector; import com.qubit.android.sdk.internal.experience.callback.ExperienceCallbackConnectorImpl; import com.qubit.android.sdk.internal.experience.model.ExperiencePayload; import com.qubit.android.sdk.internal.lookup.LookupData; -import com.qubit.android.sdk.internal.network.NetworkStateServiceImpl; import com.qubit.android.sdk.internal.placement.callback.PlacementCallbackConnectorImpl; import java.util.ArrayList; @@ -187,7 +182,7 @@ public void getPlacement( @ReactMethod public void placementImpression(String callbackUrl) { PlacementCallbackConnector callbackConnector = new PlacementCallbackConnectorImpl( - getCallbackRequestTracker(), + QubitSDK.getCallbackRequestTracker(), callbackUrl, "" ); @@ -197,20 +192,13 @@ public void placementImpression(String callbackUrl) { @ReactMethod public void placementClickthrough(String callbackUrl) { PlacementCallbackConnector callbackConnector = new PlacementCallbackConnectorImpl( - getCallbackRequestTracker(), + QubitSDK.getCallbackRequestTracker(), "", callbackUrl ); callbackConnector.clickthrough(); } - private CallbackRequestTracker getCallbackRequestTracker() { - return new CallbackRequestTrackerImpl( - new NetworkStateServiceImpl(reactContext), - new CallbackRequestRepositoryImpl(reactContext) - ); - } - private PlacementMode matchMode(String value) { switch (value) { case "SAMPLE": diff --git a/example/App.js b/example/App.js index f6e2059..5e09b18 100644 --- a/example/App.js +++ b/example/App.js @@ -54,6 +54,28 @@ class App extends PureComponent { placement.impression(); }; + sendPlacementImpression = async () => { + const placement = await QubitSDK.getPlacement( + "tsOujouCSSKJGSCMUsmQRw", + "LIVE", + null, + "1ybrhki9RvKWpA-9veLQSg", + null + ); + placement.impression(); + }; + + sendPlacementClickthrough = async () => { + const placement = await QubitSDK.getPlacement( + "tsOujouCSSKJGSCMUsmQRw", + "LIVE", + null, + "1ybrhki9RvKWpA-9veLQSg", + null + ); + placement.clickthrough(); + }; + render() { return ( <> @@ -99,6 +121,16 @@ class App extends PureComponent { Get placement + + + Send placement impression callback + + + + + Send placement clickthrough callback + + ) diff --git a/src/index.ts b/src/index.ts index edb1726..4951f35 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,7 +21,11 @@ type Experience = { } type Placement = { - content: object, + url: string, + message: string, + image: string, + impressionUrl: string, + clickthroughUrl: string, impression: () => void, clickthrough: () => void } From dc107c92154b7f2f2940039f63b6128b6ea896b7 Mon Sep 17 00:00:00 2001 From: Jan Hudzik Date: Mon, 9 Nov 2020 18:00:28 +0100 Subject: [PATCH 08/10] Updated logic and documentation related to placement callback requests --- README.md | 3 +++ .../qubit/reactnative/sdk/QubitSDKModule.java | 16 ++-------------- example/App.js | 1 - src/index.ts | 9 ++++----- 4 files changed, 9 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 1786659..9dcd8d3 100644 --- a/README.md +++ b/README.md @@ -241,6 +241,9 @@ async () => { "experience_id" ); ... + placement.impression(); + ... + placement.clickthrough(); } { diff --git a/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java b/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java index b1fd95c..9ee4fe7 100644 --- a/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java +++ b/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java @@ -15,7 +15,6 @@ import com.google.gson.JsonParser; import com.qubit.android.sdk.api.QubitSDK; import com.qubit.android.sdk.api.logging.QBLogLevel; -import com.qubit.android.sdk.api.placement.PlacementCallbackConnector; import com.qubit.android.sdk.api.placement.PlacementMode; import com.qubit.android.sdk.api.placement.PlacementPreviewOptions; import com.qubit.android.sdk.api.tracker.event.QBEvent; @@ -25,7 +24,6 @@ import com.qubit.android.sdk.internal.experience.callback.ExperienceCallbackConnectorImpl; import com.qubit.android.sdk.internal.experience.model.ExperiencePayload; import com.qubit.android.sdk.internal.lookup.LookupData; -import com.qubit.android.sdk.internal.placement.callback.PlacementCallbackConnectorImpl; import java.util.ArrayList; import java.util.List; @@ -181,22 +179,12 @@ public void getPlacement( @ReactMethod public void placementImpression(String callbackUrl) { - PlacementCallbackConnector callbackConnector = new PlacementCallbackConnectorImpl( - QubitSDK.getCallbackRequestTracker(), - callbackUrl, - "" - ); - callbackConnector.impression(); + QubitSDK.sendCallbackRequest(callbackUrl); } @ReactMethod public void placementClickthrough(String callbackUrl) { - PlacementCallbackConnector callbackConnector = new PlacementCallbackConnectorImpl( - QubitSDK.getCallbackRequestTracker(), - "", - callbackUrl - ); - callbackConnector.clickthrough(); + QubitSDK.sendCallbackRequest(callbackUrl); } private PlacementMode matchMode(String value) { diff --git a/example/App.js b/example/App.js index 5e09b18..f02dabd 100644 --- a/example/App.js +++ b/example/App.js @@ -51,7 +51,6 @@ class App extends PureComponent { null ); console.log(placement); - placement.impression(); }; sendPlacementImpression = async () => { diff --git a/src/index.ts b/src/index.ts index 4951f35..1271327 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,11 +21,7 @@ type Experience = { } type Placement = { - url: string, - message: string, - image: string, - impressionUrl: string, - clickthroughUrl: string, + content: object, impression: () => void, clickthrough: () => void } @@ -218,6 +214,9 @@ class QubitSDK { * "experience_id" * ); * ... + * placement.impression(); + * ... + * placement.clickthrough(); * } * * { From 621e71fa30549d6f6ca0625a50fcd35a45d3af10 Mon Sep 17 00:00:00 2001 From: Jan Hudzik Date: Tue, 10 Nov 2020 21:42:16 +0100 Subject: [PATCH 09/10] Updated logic and documentation related to the structure of the type returned from getPlacement() function --- BridgeAPI.md | 8 +++----- README.md | 6 +----- .../java/com/qubit/reactnative/sdk/QubitSDKModule.java | 3 ++- src/index.ts | 8 ++------ 4 files changed, 8 insertions(+), 17 deletions(-) diff --git a/BridgeAPI.md b/BridgeAPI.md index 38a2eb0..b8f7937 100644 --- a/BridgeAPI.md +++ b/BridgeAPI.md @@ -327,16 +327,14 @@ Returns Placement for given parameters. - Description: Experience identifier ### Result -Promise with a map describing Placement object. Example: +Promise with a map describing Placement object: { - "image": "https://image.store.com/images/example.jpeg", - "message": "Hello World", - "url": "https://www.qubit.com" + "content": { ... } "impressionUrl": "https://api.qubit.com/placements/callback?data=ggW4eyJtZXRhIjp7ImlkIjo", "clickthroughUrl": "https://api.qubit.com/placements/callback?data=mQW4eyJtZXRhIjp7Imlkx" } - +The structure of response content depends on the type of placement that is being called. ### Exceptions - Exception is thrown, when SDK is not initialized. diff --git a/README.md b/README.md index 9dcd8d3..1d72e34 100644 --- a/README.md +++ b/README.md @@ -247,11 +247,7 @@ async () => { } { - "image": "https://image.store.com/images/example.jpeg", - "message": "Hello World", - "url": "https://www.qubit.com" - "impressionUrl": "https://api.qubit.com/placements/callback?data=ggW4eyJtZXRhIjp7ImlkIjo", - "clickthroughUrl": "https://api.qubit.com/placements/callback?data=mQW4eyJtZXRhIjp7Imlkx" + "content": { ... } } ``` diff --git a/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java b/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java index 9ee4fe7..a94c632 100644 --- a/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java +++ b/android/src/main/java/com/qubit/reactnative/sdk/QubitSDKModule.java @@ -164,7 +164,8 @@ public void getPlacement( getAttributesJson(attributes), new PlacementPreviewOptions(campaignId, experienceId), placement -> { - JsonObject placementJson = placement.getContent(); + JsonObject placementJson = new JsonObject(); + placementJson.add("content", placement.getContent()); placementJson.addProperty("impressionUrl", placement.getImpressionUrl()); placementJson.addProperty("clickthroughUrl", placement.getClickthroughUrl()); placementPromise.resolve(WritableMapConverter.convertJsonToMap(placementJson)); diff --git a/src/index.ts b/src/index.ts index 1271327..45f1ff7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -220,11 +220,7 @@ class QubitSDK { * } * * { - * "image": "https://image.store.com/images/example.jpeg", - * "message": "Hello World", - * "url": "https://www.qubit.com" - * "impressionUrl": "https://api.qubit.com/placements/callback?data=ggW4eyJtZXRhIjp7ImlkIjo", - * "clickthroughUrl": "https://api.qubit.com/placements/callback?data=mQW4eyJtZXRhIjp7Imlkx" + * "content": { ... } * } */ public getPlacement( @@ -242,7 +238,7 @@ class QubitSDK { experienceId ) .then(placement => ({ - ...placement, + content: placement.content, impression: () => { NativeModules.QubitSDK.placementImpression(placement.impressionUrl || '') }, clickthrough: () => { NativeModules.QubitSDK.placementClickthrough(placement.clickthroughUrl || '') } })) From a2f6f4cebf81665397b6cc0bf23bfd6223312fb7 Mon Sep 17 00:00:00 2001 From: Henry Porter Date: Sun, 11 Sep 2022 16:03:11 +0100 Subject: [PATCH 10/10] Upgrade SDK versions --- android/build.gradle | 2 +- package.json | 2 +- qubit-sdk-react-native.podspec | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 5df2d85..9bab2ba 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -58,6 +58,6 @@ dependencies { implementation "androidx.annotation:annotation:1.0.0" implementation "com.google.code.gson:gson:2.8.2" - implementation 'com.qubit:qubit-sdk-android:1.5.0' + implementation 'com.qubit:qubit-sdk-android:2.0.1' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.0" } diff --git a/package.json b/package.json index ca733ba..415c55f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "qubit-sdk-react-native", - "version": "1.0.11", + "version": "2.0.0", "description": "React Native bridge for using native Qubit SDK libraries on iOS and Android", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/qubit-sdk-react-native.podspec b/qubit-sdk-react-native.podspec index 9764593..b24cbe8 100644 --- a/qubit-sdk-react-native.podspec +++ b/qubit-sdk-react-native.podspec @@ -20,6 +20,6 @@ Pod::Spec.new do |s| s.requires_arc = true s.dependency "React" - s.dependency "QubitSDK" + s.dependency "QubitSDK", "~> 2.0.0" s.swift_versions = ['4.0', '4.1', '4.2', '5.0', '5.1', '5.2', '5.3'] end