Relevant issue is below
hyochan/react-native-iap#2715
I have read the documentation on apple developer regarding promotional offer. I have successfully generated signature, nonce, keyId from backend and passed to client and apply to withOffer section.
It returns a dialog "Unable to Purchase (Please contact developer for support)" After clicking the "Purchase button". It does show the correct promotion info from app store dialog side.
I have already done the following checklist.
- Create Promotional offer from a base plan
- Make sure the sandbox user is an active or elipsed subscriber under the same subscription group
- Make sure I am using the In-App-Purchase key with correct key Id.
- Make sure everything from the server side and client side are synchronized (signature, offer Id, timestamp, productId, nonce, keyId)
- I have double checked the signature I generated. I am using C# web api with ECDSA and SHA256
I am not sure if I have done something wrong or there is a bug here
Do anyone face the same issues here? Thanks
Client code
var applePromotionSignature =
await subscriptionRepository.getAppleSubscriptionSignature(
constants.diamondMemberYearlyPlan,
promotionalOffers.first.id,
);
var offerId =
productIOS!.subscriptionInfoIOS!.promotionalOffers!.first.id;
await sameIAp.requestPurchase(
RequestPurchaseProps.subs((
android: null,
ios: RequestSubscriptionIosProps(
sku: constants.diamondMemberYearlyPlan,
appAccountToken: '',
withOffer: DiscountOfferInputIOS(
identifier: offerId,
keyIdentifier: applePromotionSignature!.keyId,
nonce: applePromotionSignature!.nonce,
signature: applePromotionSignature!.signature,
timestamp: applePromotionSignature!.timestamp,
),
),
useAlternativeBilling: null,
)),
);
Server code in C#
Controller
[HttpGet("Signature/productId/{productId}/offerId/{offerId}")]
public async Task<IActionResult> GetAppleSubscriptionSignature(string productId, string offerId)
{
var keyFileName = _configuration.GetValue<string>("AppleIAPSubscriptionKeyFileName");
var bundleId = _configuration.GetValue<string>("AppleClientId");
var keyId = _configuration.GetValue<string>("AppleIAPPromotionKeyId");
var nonce = Guid.NewGuid().ToString().ToLowerInvariant();
// var nowMs = DateTimeOffset.Now.ToUnixTimeSeconds();
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
var signature = await _subscriptionService.GenerateSignature(keyFileName, bundleId, keyId, productId, offerId, "", nonce, timestamp);
if (signature != null)
{
var appleSubscriptionSignature = new AppleSubscriptionSignature()
{
offerId = offerId,
productId = productId,
keyId = keyId,
nonce = nonce,
signature = signature,
timestamp = timestamp
};
return Ok(appleSubscriptionSignature);
}
return NotFound();
}
Service class
public async Task<string> GenerateSignature(
string keyFileName,
string bundleId,
string keyId,
string productId,
string offerId,
string appAccountTokenOrEmpty,
string nonce,
long timestampMs)
{
// 1) Build the string to sign joined by U+2063 (INVISIBLE SEPARATOR)
const char SEP = '\u2063';
var stringToSign = string.Join(SEP, [
bundleId,
keyId,
productId,
offerId,
appAccountTokenOrEmpty ?? string.Empty,
nonce,
timestampMs.ToString(CultureInfo.InvariantCulture)
]);
// 2) Load P-256 private key from PKCS#8 PEM
using var ecdsa = ECDsa.Create();
var p8PrivateKeyPem = await File.ReadAllTextAsync(keyFileName);
ImportPkcs8Pem(ecdsa, p8PrivateKeyPem);
// 3) Sign with ECDSA-SHA256 and return Base64 (DER)
var data = Encoding.UTF8.GetBytes(stringToSign);
var derSig = ecdsa.SignData(data, HashAlgorithmName.SHA256);
return Convert.ToBase64String(derSig);
}
private static void ImportPkcs8Pem(ECDsa ecdsa, string pem)
{
var pkcs8 = pem
.Replace("-----BEGIN PRIVATE KEY-----", string.Empty)
.Replace("-----END PRIVATE KEY-----", string.Empty)
.Replace("\r", string.Empty)
.Replace("\n", string.Empty)
.Trim();
var keyBytes = Convert.FromBase64String(pkcs8);
ecdsa.ImportPkcs8PrivateKey(keyBytes, out _);
}
📱 version
flutter_inapp_purchase: ^7.0.1
Relevant issue is below
hyochan/react-native-iap#2715
I have read the documentation on apple developer regarding promotional offer. I have successfully generated signature, nonce, keyId from backend and passed to client and apply to withOffer section.
It returns a dialog "Unable to Purchase (Please contact developer for support)" After clicking the "Purchase button". It does show the correct promotion info from app store dialog side.
I have already done the following checklist.
I am not sure if I have done something wrong or there is a bug here
Do anyone face the same issues here? Thanks
Client code
Server code in C#
Controller
Service class
📱 version
flutter_inapp_purchase: ^7.0.1