react-native-iap 14.4.10 → 14.4.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +195 -12
- package/ios/HybridRnIap.swift +115 -2
- package/ios/RnIapHelper.swift +32 -1
- package/lib/module/hooks/useIAP.js +24 -3
- package/lib/module/hooks/useIAP.js.map +1 -1
- package/lib/module/index.js +275 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js +18 -0
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils/type-bridge.js +39 -1
- package/lib/module/utils/type-bridge.js.map +1 -1
- package/lib/typescript/plugin/src/withIAP.d.ts +27 -0
- package/lib/typescript/plugin/src/withIAP.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useIAP.d.ts +6 -1
- package/lib/typescript/src/hooks/useIAP.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +133 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/RnIap.nitro.d.ts +101 -2
- package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +116 -13
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/utils/type-bridge.d.ts.map +1 -1
- package/nitrogen/generated/android/NitroIapOnLoad.cpp +2 -0
- package/nitrogen/generated/android/c++/JAlternativeBillingModeAndroid.hpp +62 -0
- package/nitrogen/generated/android/c++/JExternalPurchaseLinkResultIOS.hpp +58 -0
- package/nitrogen/generated/android/c++/JExternalPurchaseNoticeAction.hpp +59 -0
- package/nitrogen/generated/android/c++/JExternalPurchaseNoticeResultIOS.hpp +60 -0
- package/nitrogen/generated/android/c++/JFunc_void_NitroProduct.hpp +2 -0
- package/nitrogen/generated/android/c++/JFunc_void_UserChoiceBillingDetails.hpp +78 -0
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +136 -3
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.hpp +9 -1
- package/nitrogen/generated/android/c++/JInitConnectionConfig.hpp +55 -0
- package/nitrogen/generated/android/c++/JNitroOneTimePurchaseOfferDetail.hpp +61 -0
- package/nitrogen/generated/android/c++/JNitroProduct.hpp +16 -2
- package/nitrogen/generated/android/c++/JNitroPurchase.hpp +74 -2
- package/nitrogen/generated/android/c++/JPurchaseAndroid.hpp +4 -0
- package/nitrogen/generated/android/c++/JPurchaseIOS.hpp +4 -0
- package/nitrogen/generated/android/c++/JUserChoiceBillingDetails.hpp +75 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/AlternativeBillingModeAndroid.kt +22 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/ExternalPurchaseLinkResultIOS.kt +32 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/ExternalPurchaseNoticeAction.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/ExternalPurchaseNoticeResultIOS.kt +32 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Func_void_UserChoiceBillingDetails.kt +81 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/HybridRnIapSpec.kt +43 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/InitConnectionConfig.kt +29 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroOneTimePurchaseOfferDetail.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroProduct.kt +10 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroPurchase.kt +55 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/PurchaseAndroid.kt +3 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/PurchaseIOS.kt +3 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/UserChoiceBillingDetails.kt +32 -0
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.cpp +24 -0
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +174 -0
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +21 -0
- package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +84 -3
- package/nitrogen/generated/ios/swift/AlternativeBillingModeAndroid.swift +44 -0
- package/nitrogen/generated/ios/swift/ExternalPurchaseLinkResultIOS.swift +65 -0
- package/nitrogen/generated/ios/swift/ExternalPurchaseNoticeAction.swift +40 -0
- package/nitrogen/generated/ios/swift/ExternalPurchaseNoticeResultIOS.swift +65 -0
- package/nitrogen/generated/ios/swift/Func_void_ExternalPurchaseLinkResultIOS.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_ExternalPurchaseNoticeResultIOS.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_UserChoiceBillingDetails.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridRnIapSpec.swift +9 -1
- package/nitrogen/generated/ios/swift/HybridRnIapSpec_cxx.swift +168 -2
- package/nitrogen/generated/ios/swift/InitConnectionConfig.swift +47 -0
- package/nitrogen/generated/ios/swift/NitroOneTimePurchaseOfferDetail.swift +57 -0
- package/nitrogen/generated/ios/swift/NitroProduct.swift +91 -1
- package/nitrogen/generated/ios/swift/NitroPurchase.swift +520 -1
- package/nitrogen/generated/ios/swift/PurchaseAndroid.swift +31 -1
- package/nitrogen/generated/ios/swift/PurchaseIOS.swift +31 -1
- package/nitrogen/generated/ios/swift/UserChoiceBillingDetails.swift +58 -0
- package/nitrogen/generated/shared/c++/AlternativeBillingModeAndroid.hpp +80 -0
- package/nitrogen/generated/shared/c++/ExternalPurchaseLinkResultIOS.hpp +72 -0
- package/nitrogen/generated/shared/c++/ExternalPurchaseNoticeAction.hpp +76 -0
- package/nitrogen/generated/shared/c++/ExternalPurchaseNoticeResultIOS.hpp +74 -0
- package/nitrogen/generated/shared/c++/HybridRnIapSpec.cpp +8 -0
- package/nitrogen/generated/shared/c++/HybridRnIapSpec.hpp +22 -2
- package/nitrogen/generated/shared/c++/InitConnectionConfig.hpp +69 -0
- package/nitrogen/generated/shared/c++/NitroOneTimePurchaseOfferDetail.hpp +75 -0
- package/nitrogen/generated/shared/c++/NitroProduct.hpp +17 -2
- package/nitrogen/generated/shared/c++/NitroPurchase.hpp +74 -2
- package/nitrogen/generated/shared/c++/PurchaseAndroid.hpp +5 -1
- package/nitrogen/generated/shared/c++/PurchaseIOS.hpp +5 -1
- package/nitrogen/generated/shared/c++/UserChoiceBillingDetails.hpp +72 -0
- package/openiap-versions.json +3 -3
- package/package.json +3 -3
- package/plugin/build/withIAP.d.ts +27 -0
- package/plugin/build/withIAP.js +91 -1
- package/plugin/src/withIAP.ts +162 -0
- package/src/hooks/useIAP.ts +47 -1
- package/src/index.ts +313 -2
- package/src/specs/RnIap.nitro.ts +131 -1
- package/src/types.ts +124 -13
- package/src/utils/type-bridge.ts +76 -16
package/plugin/build/withIAP.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.default = exports.modifyProjectBuildGradle = void 0;
|
|
3
|
+
exports.default = exports.withIosAlternativeBilling = exports.modifyProjectBuildGradle = void 0;
|
|
4
4
|
const config_plugins_1 = require("expo/config-plugins");
|
|
5
5
|
const node_fs_1 = require("node:fs");
|
|
6
6
|
const node_path_1 = require("node:path");
|
|
@@ -115,6 +115,92 @@ const withIapAndroid = (config) => {
|
|
|
115
115
|
});
|
|
116
116
|
return config;
|
|
117
117
|
};
|
|
118
|
+
/** Add external purchase entitlements and Info.plist configuration */
|
|
119
|
+
const withIosAlternativeBilling = (config, options) => {
|
|
120
|
+
if (!options || !options.countries || options.countries.length === 0) {
|
|
121
|
+
return config;
|
|
122
|
+
}
|
|
123
|
+
// Add entitlements
|
|
124
|
+
config = (0, config_plugins_1.withEntitlementsPlist)(config, (config) => {
|
|
125
|
+
// Always add basic external purchase entitlement when countries are specified
|
|
126
|
+
config.modResults['com.apple.developer.storekit.external-purchase'] = true;
|
|
127
|
+
if (!hasLoggedPluginExecution) {
|
|
128
|
+
console.log('✅ Added com.apple.developer.storekit.external-purchase to entitlements');
|
|
129
|
+
}
|
|
130
|
+
// Add external purchase link entitlement if enabled
|
|
131
|
+
if (options.enableExternalPurchaseLink) {
|
|
132
|
+
config.modResults['com.apple.developer.storekit.external-purchase-link'] =
|
|
133
|
+
true;
|
|
134
|
+
if (!hasLoggedPluginExecution) {
|
|
135
|
+
console.log('✅ Added com.apple.developer.storekit.external-purchase-link to entitlements');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Add streaming entitlement if enabled
|
|
139
|
+
if (options.enableExternalPurchaseLinkStreaming) {
|
|
140
|
+
config.modResults['com.apple.developer.storekit.external-purchase-link-streaming'] = true;
|
|
141
|
+
if (!hasLoggedPluginExecution) {
|
|
142
|
+
console.log('✅ Added com.apple.developer.storekit.external-purchase-link-streaming to entitlements');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return config;
|
|
146
|
+
});
|
|
147
|
+
// Add Info.plist configuration
|
|
148
|
+
config = (0, config_plugins_1.withInfoPlist)(config, (config) => {
|
|
149
|
+
const plist = config.modResults;
|
|
150
|
+
// Helper function to normalize country codes to uppercase
|
|
151
|
+
const normalize = (code) => code.trim().toUpperCase();
|
|
152
|
+
// 1. SKExternalPurchase (Required)
|
|
153
|
+
const normalizedCountries = options.countries?.map(normalize);
|
|
154
|
+
plist.SKExternalPurchase = normalizedCountries;
|
|
155
|
+
if (!hasLoggedPluginExecution) {
|
|
156
|
+
console.log(`✅ Added SKExternalPurchase with countries: ${normalizedCountries?.join(', ')}`);
|
|
157
|
+
}
|
|
158
|
+
// 2. SKExternalPurchaseLink (Optional - iOS 15.4+)
|
|
159
|
+
if (options.links && Object.keys(options.links).length > 0) {
|
|
160
|
+
plist.SKExternalPurchaseLink = Object.fromEntries(Object.entries(options.links).map(([code, url]) => [
|
|
161
|
+
normalize(code),
|
|
162
|
+
url,
|
|
163
|
+
]));
|
|
164
|
+
if (!hasLoggedPluginExecution) {
|
|
165
|
+
console.log(`✅ Added SKExternalPurchaseLink for ${Object.keys(options.links).length} countries`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// 3. SKExternalPurchaseMultiLink (iOS 17.5+)
|
|
169
|
+
if (options.multiLinks && Object.keys(options.multiLinks).length > 0) {
|
|
170
|
+
plist.SKExternalPurchaseMultiLink = Object.fromEntries(Object.entries(options.multiLinks).map(([code, urls]) => [
|
|
171
|
+
normalize(code),
|
|
172
|
+
urls,
|
|
173
|
+
]));
|
|
174
|
+
if (!hasLoggedPluginExecution) {
|
|
175
|
+
console.log(`✅ Added SKExternalPurchaseMultiLink for ${Object.keys(options.multiLinks).length} countries`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// 4. SKExternalPurchaseCustomLinkRegions (iOS 18.1+)
|
|
179
|
+
if (options.customLinkRegions && options.customLinkRegions.length > 0) {
|
|
180
|
+
plist.SKExternalPurchaseCustomLinkRegions =
|
|
181
|
+
options.customLinkRegions.map(normalize);
|
|
182
|
+
if (!hasLoggedPluginExecution) {
|
|
183
|
+
console.log(`✅ Added SKExternalPurchaseCustomLinkRegions: ${options.customLinkRegions
|
|
184
|
+
.map(normalize)
|
|
185
|
+
.join(', ')}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// 5. SKExternalPurchaseLinkStreamingRegions (iOS 18.2+)
|
|
189
|
+
if (options.streamingLinkRegions &&
|
|
190
|
+
options.streamingLinkRegions.length > 0) {
|
|
191
|
+
plist.SKExternalPurchaseLinkStreamingRegions =
|
|
192
|
+
options.streamingLinkRegions.map(normalize);
|
|
193
|
+
if (!hasLoggedPluginExecution) {
|
|
194
|
+
console.log(`✅ Added SKExternalPurchaseLinkStreamingRegions: ${options.streamingLinkRegions
|
|
195
|
+
.map(normalize)
|
|
196
|
+
.join(', ')}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return config;
|
|
200
|
+
});
|
|
201
|
+
return config;
|
|
202
|
+
};
|
|
203
|
+
exports.withIosAlternativeBilling = withIosAlternativeBilling;
|
|
118
204
|
const withIapIosFollyWorkaround = (config, props) => {
|
|
119
205
|
const newKey = props?.ios?.['with-folly-no-coroutines'];
|
|
120
206
|
const oldKey = props?.ios?.['with-folly-no-couroutines'];
|
|
@@ -165,6 +251,10 @@ const withIAP = (config, props) => {
|
|
|
165
251
|
try {
|
|
166
252
|
let result = withIapAndroid(config);
|
|
167
253
|
result = withIapIosFollyWorkaround(result, props);
|
|
254
|
+
// Add iOS alternative billing configuration if provided
|
|
255
|
+
if (props?.iosAlternativeBilling) {
|
|
256
|
+
result = withIosAlternativeBilling(result, props.iosAlternativeBilling);
|
|
257
|
+
}
|
|
168
258
|
// Set flag after first execution to prevent duplicate logs
|
|
169
259
|
hasLoggedPluginExecution = true;
|
|
170
260
|
return result;
|
package/plugin/src/withIAP.ts
CHANGED
|
@@ -4,6 +4,8 @@ import {
|
|
|
4
4
|
withAndroidManifest,
|
|
5
5
|
withAppBuildGradle,
|
|
6
6
|
withPodfile,
|
|
7
|
+
withEntitlementsPlist,
|
|
8
|
+
withInfoPlist,
|
|
7
9
|
} from 'expo/config-plugins';
|
|
8
10
|
import type {ConfigPlugin} from 'expo/config-plugins';
|
|
9
11
|
import type {ExpoConfig} from '@expo/config-types';
|
|
@@ -165,6 +167,154 @@ const withIapAndroid: ConfigPlugin = (config) => {
|
|
|
165
167
|
return config;
|
|
166
168
|
};
|
|
167
169
|
|
|
170
|
+
export interface IosAlternativeBillingConfig {
|
|
171
|
+
/** Country codes where external purchases are supported (ISO 3166-1 alpha-2) */
|
|
172
|
+
countries?: string[];
|
|
173
|
+
/** External purchase URLs per country (iOS 15.4+) */
|
|
174
|
+
links?: Record<string, string>;
|
|
175
|
+
/** Multiple external purchase URLs per country (iOS 17.5+, up to 5 per country) */
|
|
176
|
+
multiLinks?: Record<string, string[]>;
|
|
177
|
+
/** Custom link regions (iOS 18.1+) */
|
|
178
|
+
customLinkRegions?: string[];
|
|
179
|
+
/** Streaming link regions for music apps (iOS 18.2+) */
|
|
180
|
+
streamingLinkRegions?: string[];
|
|
181
|
+
/** Enable external purchase link entitlement */
|
|
182
|
+
enableExternalPurchaseLink?: boolean;
|
|
183
|
+
/** Enable external purchase link streaming entitlement (music apps only) */
|
|
184
|
+
enableExternalPurchaseLinkStreaming?: boolean;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Add external purchase entitlements and Info.plist configuration */
|
|
188
|
+
const withIosAlternativeBilling: ConfigPlugin<
|
|
189
|
+
IosAlternativeBillingConfig | undefined
|
|
190
|
+
> = (config, options) => {
|
|
191
|
+
if (!options || !options.countries || options.countries.length === 0) {
|
|
192
|
+
return config;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Add entitlements
|
|
196
|
+
config = withEntitlementsPlist(config, (config) => {
|
|
197
|
+
// Always add basic external purchase entitlement when countries are specified
|
|
198
|
+
config.modResults['com.apple.developer.storekit.external-purchase'] = true;
|
|
199
|
+
if (!hasLoggedPluginExecution) {
|
|
200
|
+
console.log(
|
|
201
|
+
'✅ Added com.apple.developer.storekit.external-purchase to entitlements',
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Add external purchase link entitlement if enabled
|
|
206
|
+
if (options.enableExternalPurchaseLink) {
|
|
207
|
+
config.modResults['com.apple.developer.storekit.external-purchase-link'] =
|
|
208
|
+
true;
|
|
209
|
+
if (!hasLoggedPluginExecution) {
|
|
210
|
+
console.log(
|
|
211
|
+
'✅ Added com.apple.developer.storekit.external-purchase-link to entitlements',
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Add streaming entitlement if enabled
|
|
217
|
+
if (options.enableExternalPurchaseLinkStreaming) {
|
|
218
|
+
config.modResults[
|
|
219
|
+
'com.apple.developer.storekit.external-purchase-link-streaming'
|
|
220
|
+
] = true;
|
|
221
|
+
if (!hasLoggedPluginExecution) {
|
|
222
|
+
console.log(
|
|
223
|
+
'✅ Added com.apple.developer.storekit.external-purchase-link-streaming to entitlements',
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return config;
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// Add Info.plist configuration
|
|
232
|
+
config = withInfoPlist(config, (config) => {
|
|
233
|
+
const plist = config.modResults;
|
|
234
|
+
|
|
235
|
+
// Helper function to normalize country codes to uppercase
|
|
236
|
+
const normalize = (code: string) => code.trim().toUpperCase();
|
|
237
|
+
|
|
238
|
+
// 1. SKExternalPurchase (Required)
|
|
239
|
+
const normalizedCountries = options.countries?.map(normalize);
|
|
240
|
+
plist.SKExternalPurchase = normalizedCountries;
|
|
241
|
+
if (!hasLoggedPluginExecution) {
|
|
242
|
+
console.log(
|
|
243
|
+
`✅ Added SKExternalPurchase with countries: ${normalizedCountries?.join(
|
|
244
|
+
', ',
|
|
245
|
+
)}`,
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// 2. SKExternalPurchaseLink (Optional - iOS 15.4+)
|
|
250
|
+
if (options.links && Object.keys(options.links).length > 0) {
|
|
251
|
+
plist.SKExternalPurchaseLink = Object.fromEntries(
|
|
252
|
+
Object.entries(options.links).map(([code, url]) => [
|
|
253
|
+
normalize(code),
|
|
254
|
+
url,
|
|
255
|
+
]),
|
|
256
|
+
);
|
|
257
|
+
if (!hasLoggedPluginExecution) {
|
|
258
|
+
console.log(
|
|
259
|
+
`✅ Added SKExternalPurchaseLink for ${
|
|
260
|
+
Object.keys(options.links).length
|
|
261
|
+
} countries`,
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// 3. SKExternalPurchaseMultiLink (iOS 17.5+)
|
|
267
|
+
if (options.multiLinks && Object.keys(options.multiLinks).length > 0) {
|
|
268
|
+
plist.SKExternalPurchaseMultiLink = Object.fromEntries(
|
|
269
|
+
Object.entries(options.multiLinks).map(([code, urls]) => [
|
|
270
|
+
normalize(code),
|
|
271
|
+
urls,
|
|
272
|
+
]),
|
|
273
|
+
);
|
|
274
|
+
if (!hasLoggedPluginExecution) {
|
|
275
|
+
console.log(
|
|
276
|
+
`✅ Added SKExternalPurchaseMultiLink for ${
|
|
277
|
+
Object.keys(options.multiLinks).length
|
|
278
|
+
} countries`,
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// 4. SKExternalPurchaseCustomLinkRegions (iOS 18.1+)
|
|
284
|
+
if (options.customLinkRegions && options.customLinkRegions.length > 0) {
|
|
285
|
+
plist.SKExternalPurchaseCustomLinkRegions =
|
|
286
|
+
options.customLinkRegions.map(normalize);
|
|
287
|
+
if (!hasLoggedPluginExecution) {
|
|
288
|
+
console.log(
|
|
289
|
+
`✅ Added SKExternalPurchaseCustomLinkRegions: ${options.customLinkRegions
|
|
290
|
+
.map(normalize)
|
|
291
|
+
.join(', ')}`,
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// 5. SKExternalPurchaseLinkStreamingRegions (iOS 18.2+)
|
|
297
|
+
if (
|
|
298
|
+
options.streamingLinkRegions &&
|
|
299
|
+
options.streamingLinkRegions.length > 0
|
|
300
|
+
) {
|
|
301
|
+
plist.SKExternalPurchaseLinkStreamingRegions =
|
|
302
|
+
options.streamingLinkRegions.map(normalize);
|
|
303
|
+
if (!hasLoggedPluginExecution) {
|
|
304
|
+
console.log(
|
|
305
|
+
`✅ Added SKExternalPurchaseLinkStreamingRegions: ${options.streamingLinkRegions
|
|
306
|
+
.map(normalize)
|
|
307
|
+
.join(', ')}`,
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return config;
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
return config;
|
|
316
|
+
};
|
|
317
|
+
|
|
168
318
|
type IapPluginProps = {
|
|
169
319
|
ios?: {
|
|
170
320
|
// Enable to inject Folly coroutine-disabling macros into Podfile during prebuild
|
|
@@ -172,6 +322,13 @@ type IapPluginProps = {
|
|
|
172
322
|
// @deprecated Use 'with-folly-no-coroutines'. Kept for backward compatibility.
|
|
173
323
|
'with-folly-no-couroutines'?: boolean;
|
|
174
324
|
};
|
|
325
|
+
/**
|
|
326
|
+
* iOS Alternative Billing configuration.
|
|
327
|
+
* Configure external purchase countries, links, and entitlements.
|
|
328
|
+
* Requires approval from Apple.
|
|
329
|
+
* @platform ios
|
|
330
|
+
*/
|
|
331
|
+
iosAlternativeBilling?: IosAlternativeBillingConfig;
|
|
175
332
|
};
|
|
176
333
|
|
|
177
334
|
const withIapIosFollyWorkaround: ConfigPlugin<IapPluginProps | undefined> = (
|
|
@@ -236,6 +393,10 @@ const withIAP: ConfigPlugin<IapPluginProps | undefined> = (config, props) => {
|
|
|
236
393
|
try {
|
|
237
394
|
let result = withIapAndroid(config);
|
|
238
395
|
result = withIapIosFollyWorkaround(result, props);
|
|
396
|
+
// Add iOS alternative billing configuration if provided
|
|
397
|
+
if (props?.iosAlternativeBilling) {
|
|
398
|
+
result = withIosAlternativeBilling(result, props.iosAlternativeBilling);
|
|
399
|
+
}
|
|
239
400
|
// Set flag after first execution to prevent duplicate logs
|
|
240
401
|
hasLoggedPluginExecution = true;
|
|
241
402
|
return result;
|
|
@@ -270,4 +431,5 @@ const pluginExport: IapPluginCallable = ((
|
|
|
270
431
|
props?: IapPluginProps,
|
|
271
432
|
) => _wrapped(config, props)) as unknown as IapPluginCallable;
|
|
272
433
|
|
|
434
|
+
export {withIosAlternativeBilling};
|
|
273
435
|
export {pluginExport as default};
|
package/src/hooks/useIAP.ts
CHANGED
|
@@ -19,6 +19,10 @@ import {
|
|
|
19
19
|
restorePurchases as restorePurchasesTopLevel,
|
|
20
20
|
getPromotedProductIOS,
|
|
21
21
|
requestPurchaseOnPromotedProductIOS,
|
|
22
|
+
checkAlternativeBillingAvailabilityAndroid,
|
|
23
|
+
showAlternativeBillingDialogAndroid,
|
|
24
|
+
createAlternativeBillingTokenAndroid,
|
|
25
|
+
userChoiceBillingListenerAndroid,
|
|
22
26
|
} from '../';
|
|
23
27
|
|
|
24
28
|
// Types
|
|
@@ -27,6 +31,8 @@ import type {
|
|
|
27
31
|
ProductQueryType,
|
|
28
32
|
RequestPurchaseProps,
|
|
29
33
|
RequestPurchaseResult,
|
|
34
|
+
AlternativeBillingModeAndroid,
|
|
35
|
+
UserChoiceBillingDetails,
|
|
30
36
|
} from '../types';
|
|
31
37
|
import type {
|
|
32
38
|
ActiveSubscription,
|
|
@@ -75,12 +81,20 @@ type UseIap = {
|
|
|
75
81
|
subscriptionIds?: string[],
|
|
76
82
|
) => Promise<ActiveSubscription[]>;
|
|
77
83
|
hasActiveSubscriptions: (subscriptionIds?: string[]) => Promise<boolean>;
|
|
84
|
+
// Alternative billing (Android)
|
|
85
|
+
checkAlternativeBillingAvailabilityAndroid?: () => Promise<boolean>;
|
|
86
|
+
showAlternativeBillingDialogAndroid?: () => Promise<boolean>;
|
|
87
|
+
createAlternativeBillingTokenAndroid?: (
|
|
88
|
+
sku?: string,
|
|
89
|
+
) => Promise<string | null>;
|
|
78
90
|
};
|
|
79
91
|
|
|
80
92
|
export interface UseIapOptions {
|
|
81
93
|
onPurchaseSuccess?: (purchase: Purchase) => void;
|
|
82
94
|
onPurchaseError?: (error: PurchaseError) => void;
|
|
83
95
|
onPromotedProductIOS?: (product: Product) => void;
|
|
96
|
+
onUserChoiceBillingAndroid?: (details: UserChoiceBillingDetails) => void;
|
|
97
|
+
alternativeBillingModeAndroid?: AlternativeBillingModeAndroid;
|
|
84
98
|
}
|
|
85
99
|
|
|
86
100
|
/**
|
|
@@ -133,6 +147,7 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
133
147
|
purchaseUpdate?: EventSubscription;
|
|
134
148
|
purchaseError?: EventSubscription;
|
|
135
149
|
promotedProductIOS?: EventSubscription;
|
|
150
|
+
userChoiceBillingAndroid?: EventSubscription;
|
|
136
151
|
}>({});
|
|
137
152
|
|
|
138
153
|
const subscriptionsRefState = useRef<ProductSubscription[]>([]);
|
|
@@ -346,7 +361,29 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
346
361
|
);
|
|
347
362
|
}
|
|
348
363
|
|
|
349
|
-
|
|
364
|
+
// Add user choice billing listener for Android (if provided)
|
|
365
|
+
if (
|
|
366
|
+
Platform.OS === 'android' &&
|
|
367
|
+
optionsRef.current?.onUserChoiceBillingAndroid
|
|
368
|
+
) {
|
|
369
|
+
subscriptionsRef.current.userChoiceBillingAndroid =
|
|
370
|
+
userChoiceBillingListenerAndroid((details) => {
|
|
371
|
+
if (optionsRef.current?.onUserChoiceBillingAndroid) {
|
|
372
|
+
optionsRef.current.onUserChoiceBillingAndroid(details);
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Initialize connection with config
|
|
378
|
+
const config =
|
|
379
|
+
Platform.OS === 'android' &&
|
|
380
|
+
optionsRef.current?.alternativeBillingModeAndroid
|
|
381
|
+
? {
|
|
382
|
+
alternativeBillingModeAndroid:
|
|
383
|
+
optionsRef.current.alternativeBillingModeAndroid,
|
|
384
|
+
}
|
|
385
|
+
: undefined;
|
|
386
|
+
const result = await initConnection(config);
|
|
350
387
|
setConnected(result);
|
|
351
388
|
if (!result) {
|
|
352
389
|
// Clean up some listeners but leave purchaseError for potential retries
|
|
@@ -364,6 +401,7 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
364
401
|
currentSubscriptions.purchaseUpdate?.remove();
|
|
365
402
|
currentSubscriptions.purchaseError?.remove();
|
|
366
403
|
currentSubscriptions.promotedProductIOS?.remove();
|
|
404
|
+
currentSubscriptions.userChoiceBillingAndroid?.remove();
|
|
367
405
|
// Keep connection alive across screens to avoid race conditions
|
|
368
406
|
setConnected(false);
|
|
369
407
|
};
|
|
@@ -393,5 +431,13 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
393
431
|
requestPurchaseOnPromotedProductIOS,
|
|
394
432
|
getActiveSubscriptions: getActiveSubscriptionsInternal,
|
|
395
433
|
hasActiveSubscriptions: hasActiveSubscriptionsInternal,
|
|
434
|
+
// Alternative billing (Android only)
|
|
435
|
+
...(Platform.OS === 'android'
|
|
436
|
+
? {
|
|
437
|
+
checkAlternativeBillingAvailabilityAndroid,
|
|
438
|
+
showAlternativeBillingDialogAndroid,
|
|
439
|
+
createAlternativeBillingTokenAndroid,
|
|
440
|
+
}
|
|
441
|
+
: {}),
|
|
396
442
|
};
|
|
397
443
|
}
|