Skip to content

Commit 2480582

Browse files
authored
Adds shouldPurchasePromoProduct (#98)
1 parent 8b2a5be commit 2480582

File tree

14 files changed

+305
-156
lines changed

14 files changed

+305
-156
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 3.0.2
2+
3+
- Adds `Purchases.addShouldPurchasePromoProduct` to be able to handle purchases started from the Apple App Store.
4+
15
## 3.0.1
26

37
- Updates Android SDK to 3.0.3 which should fix issues with restores and syncs.

VERSIONS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
| Version | iOS version | Android version | Common files version |
22
|---------|-------------|-----------------|----------------------|
3+
| 3.0.2 | 3.0.0 | 3.0.3 | 1.0.3 |
34
| 3.0.1 | 3.0.0 | 3.0.3 | 1.0.1 |
45
| 3.0.0 | 3.0.0 | 3.0.2 | 1.0.1 |
56
| 2.4.1 | 2.6.0 | 2.4.0 | 0.1.4 |

__tests__/index.test.js

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
const {NativeModules} = require("react-native");
1+
const {NativeModules, NativeEventEmitter} = require("react-native");
2+
3+
const nativeEmitter = new NativeEventEmitter();
24

35
describe("Purchases", () => {
46
beforeEach(() => {
@@ -20,11 +22,8 @@ describe("Purchases", () => {
2022

2123
Purchases.addPurchaserInfoUpdateListener(listener);
2224

23-
const nativeEmitter = new NativeEventEmitter();
24-
2525
nativeEmitter.emit("Purchases-PurchaserInfoUpdated", purchaserInfoStub);
2626

27-
expect(listener).toEqual(expect.any(Function));
2827
expect(listener).toHaveBeenCalledWith(purchaserInfoStub);
2928
});
3029

@@ -34,8 +33,6 @@ describe("Purchases", () => {
3433
Purchases.addPurchaserInfoUpdateListener(listener);
3534
Purchases.removePurchaserInfoUpdateListener(listener);
3635

37-
const nativeEmitter = new NativeEventEmitter();
38-
3936
const eventInfo = {
4037
purchaserInfo: purchaserInfoStub,
4138
error: null,
@@ -46,6 +43,65 @@ describe("Purchases", () => {
4643
expect(listener).toHaveBeenCalledTimes(0);
4744
});
4845

46+
it("addShouldPurchasePromoProductListener correctly saves listeners", () => {
47+
const listener = jest.fn();
48+
const Purchases = require("../index").default;
49+
50+
Purchases.addShouldPurchasePromoProductListener(listener);
51+
52+
const nativeEmitter = new NativeEventEmitter();
53+
const eventInfo = {
54+
callbackID: 1,
55+
};
56+
nativeEmitter.emit("Purchases-ShouldPurchasePromoProduct", eventInfo);
57+
58+
expect(listener).toHaveBeenCalledWith(expect.any(Function));
59+
});
60+
61+
it("shouldPurchasePromoProductListener calls deferred purchase", async () => {
62+
const listener = deferredPurchase => {
63+
this.deferredPurchase = deferredPurchase;
64+
};
65+
66+
const Purchases = require("../index").default;
67+
68+
Purchases.addShouldPurchasePromoProductListener(listener);
69+
70+
const nativeEmitter = new NativeEventEmitter();
71+
const eventInfo = {
72+
callbackID: 1,
73+
};
74+
nativeEmitter.emit("Purchases-ShouldPurchasePromoProduct", eventInfo);
75+
76+
NativeModules.RNPurchases.makeDeferredPurchase.mockResolvedValue({
77+
purchasedProductIdentifier: "123",
78+
purchaserInfo: purchaserInfoStub
79+
});
80+
81+
let {purchaserInfo, purchasedProductIdentifier} = await this.deferredPurchase();
82+
83+
expect(NativeModules.RNPurchases.makeDeferredPurchase).toBeCalledWith(1);
84+
expect(purchaserInfo).toEqual(purchaserInfoStub);
85+
expect(purchasedProductIdentifier).toEqual("123");
86+
});
87+
88+
it("removeShouldPurchasePromoProductListener correctly removes a listener", () => {
89+
const Purchases = require("../index").default;
90+
const listener = jest.fn();
91+
Purchases.addShouldPurchasePromoProductListener(listener);
92+
Purchases.removeShouldPurchasePromoProductListener(listener);
93+
94+
const nativeEmitter = new NativeEventEmitter();
95+
96+
const eventInfo = {
97+
callbackID: 1,
98+
};
99+
100+
nativeEmitter.emit("Purchases-ShouldPurchasePromoProduct", eventInfo);
101+
102+
expect(listener).toHaveBeenCalledTimes(0);
103+
});
104+
49105
it("calling setup with something other than string throws exception", () => {
50106
const Purchases = require("../index").default;
51107

android/src/main/java/com/reactlibrary/RNPurchasesConverters.java

Lines changed: 0 additions & 123 deletions
This file was deleted.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package com.reactlibrary
2+
3+
import com.facebook.react.bridge.ReadableArray
4+
import com.facebook.react.bridge.ReadableMap
5+
import com.facebook.react.bridge.ReadableType
6+
import com.facebook.react.bridge.WritableArray
7+
import com.facebook.react.bridge.WritableMap
8+
import com.facebook.react.bridge.WritableNativeArray
9+
import com.facebook.react.bridge.WritableNativeMap
10+
import org.json.JSONArray
11+
import org.json.JSONException
12+
import org.json.JSONObject
13+
14+
internal object RNPurchasesConverters {
15+
@JvmStatic
16+
@Throws(JSONException::class)
17+
fun convertReadableMapToJson(readableMap: ReadableMap?): JSONObject {
18+
val jsonObject = JSONObject()
19+
val iterator = readableMap!!.keySetIterator()
20+
while (iterator.hasNextKey()) {
21+
val key = iterator.nextKey()
22+
when (readableMap.getType(key)) {
23+
ReadableType.Null -> jsonObject.put(key, JSONObject.NULL)
24+
ReadableType.Boolean -> jsonObject.put(key, readableMap.getBoolean(key))
25+
ReadableType.Number -> jsonObject.put(key, readableMap.getDouble(key))
26+
ReadableType.String -> jsonObject.put(key, readableMap.getString(key))
27+
ReadableType.Map -> jsonObject.put(
28+
key,
29+
convertReadableMapToJson(readableMap.getMap(key))
30+
)
31+
ReadableType.Array -> jsonObject.put(
32+
key,
33+
convertReadableArrayToJson(readableMap.getArray(key))
34+
)
35+
}
36+
}
37+
return jsonObject
38+
}
39+
40+
@Throws(JSONException::class)
41+
fun convertReadableArrayToJson(readableArray: ReadableArray?): JSONArray {
42+
val array = JSONArray()
43+
for (i in 0 until readableArray!!.size()) {
44+
when (readableArray.getType(i)) {
45+
ReadableType.Null -> { }
46+
ReadableType.Boolean -> array.put(readableArray.getBoolean(i))
47+
ReadableType.Number -> array.put(readableArray.getDouble(i))
48+
ReadableType.String -> array.put(readableArray.getString(i))
49+
ReadableType.Map -> array.put(convertReadableMapToJson(readableArray.getMap(i)))
50+
ReadableType.Array -> array.put(convertReadableArrayToJson(readableArray.getArray(i)))
51+
}
52+
}
53+
return array
54+
}
55+
56+
private fun convertArrayToWritableArray(array: Array<Any?>): WritableArray {
57+
val writableArray: WritableArray = WritableNativeArray()
58+
for (item in array) {
59+
when (item) {
60+
null -> writableArray.pushNull()
61+
is Boolean -> writableArray.pushBoolean(item)
62+
is Int -> writableArray.pushInt(item)
63+
is Double -> writableArray.pushDouble(item)
64+
is String -> writableArray.pushString(item)
65+
is Map<*, *> -> writableArray.pushMap(convertMapToWriteableMap(item as Map<String, *>))
66+
is Array<*> -> writableArray.pushArray(convertArrayToWritableArray(item as Array<Any?>))
67+
is List<*> -> writableArray.pushArray(convertArrayToWritableArray(item.toTypedArray()))
68+
}
69+
}
70+
return writableArray
71+
}
72+
73+
@JvmStatic
74+
fun convertMapToWriteableMap(map: Map<String, *>): WritableMap {
75+
val writableMap: WritableMap = WritableNativeMap()
76+
for ((key, value) in map) {
77+
when (value) {
78+
null -> writableMap.putNull(key)
79+
is Boolean -> writableMap.putBoolean(key, value)
80+
is Int -> writableMap.putInt(key, value)
81+
is Double -> writableMap.putDouble(key, value)
82+
is String -> writableMap.putString(key, value)
83+
is Map<*, *> -> writableMap.putMap(key, convertMapToWriteableMap(value as Map<String, *>))
84+
is Array<*> -> writableMap.putArray(key, convertArrayToWritableArray(value as Array<Any?>))
85+
is List<*> -> writableMap.putArray(key, convertArrayToWritableArray(value.toTypedArray()))
86+
}
87+
}
88+
return writableMap
89+
}
90+
}

build.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ if (os.type() === "Linux") {
99
);
1010
downloadProcess.stdout.pipe(process.stdout);
1111
const downloadProcessCommon = exec(
12-
"./scripts/download-purchases-common.sh 1.0.1"
12+
"./scripts/download-purchases-common.sh 1.0.3"
1313
);
1414
downloadProcessCommon.stdout.pipe(process.stdout);
1515
} else if (os.type() === "Windows_NT") {

example/app/screens/UpsellScreen.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ export default class UpsellScreen extends React.Component {
4747
this.purchaserInfoUpdateListener = (info) => {
4848
checkIfPro(info, this.props.navigation);
4949
};
50+
this.shouldPurchasePromoProduct = async deferredPurchase => {
51+
this.deferredPurchase = deferredPurchase;
52+
};
5053
Purchases.addPurchaserInfoUpdateListener(this.purchaserInfoUpdateListener);
54+
Purchases.addShouldPurchasePromoProductListener(this.shouldPurchasePromoProduct);
5155
const offerings = await Purchases.getOfferings();
5256
// eslint-disable-next-line no-console
5357
console.log(JSON.stringify(offerings));
@@ -68,6 +72,7 @@ export default class UpsellScreen extends React.Component {
6872

6973
async componentWillUnmount() {
7074
Purchases.removePurchaserInfoUpdateListener(this.purchaserInfoUpdateListener);
75+
Purchases.removeShouldPurchasePromoProductListener(this.shouldPurchasePromoProduct);
7176
}
7277

7378
render() {

example/metro.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ module.exports = {
2424
inlineRequires: false
2525
}
2626
})
27-
}
27+
},
28+
maxWorkers: 2,
2829
};

0 commit comments

Comments
 (0)