I wanted to ask if someone has already implemented the new Offers for the inapp-subscription (auto renewal), the difficulty in creating server-side the system to create this signature using the p8 key with php if possible. I found this on the Apple documentation, I'm not sure understanding it: https://developer.apple.com/documentation/storekit/in-app_purchase/generating_a_signature_for_subscription_offers
Here's a walkthrough from RevenueCat: iOS Subscription Offers
The post contains much more detail, but the signature generation is:
import json
import uuid
import time
import hashlib
import base64
from ecdsa import SigningKey
from ecdsa.util import sigencode_der
bundle_id = 'com.myapp'
key_id = 'XWSXTGQVX2'
product = 'com.myapp.product.a'
offer = 'REFERENCE_CODE' # This is the code set in ASC
application_username = 'user_name' # Should be the same you use when
# making purchases
nonce = uuid.uuid4()
timestamp = int(round(time.time() * 1000))
payload = '\u2063'.join([bundle_id,
key_id,
product,
offer,
application_username,
str(nonce), # Should be lower case
str(timestamp)])
# Read the key file
with open('cert.der', 'rb') as myfile:
der = myfile.read()
signing_key = SigningKey.from_der(der)
signature = signing_key.sign(payload.encode('utf-8'),
hashfunc=hashlib.sha256,
sigencode=sigencode_der)
encoded_signature = base64.b64encode(signature)
print(str(encoded_signature, 'utf-8'), str(nonce), str(timestamp), key_id)
This is just a proof of concept. You will want this on your server and perhaps have some logic to determine, for a given user, if the requested offer is appropriate.
Once you’ve generated the signature, nonce and timestamp send these along with the key_id
back to your app where you can create an SKPaymentDiscount
.
Disclaimer: I work at RevenueCat. We support Subscription Offers out of the box with our SDK, no code-signing required: https://www.revenuecat.com/2019/04/25/signing-ios-subscription-offers
I can confirm that this is working:
<?php
use Ramsey\Uuid\Uuid;
class ItunesSignatureGenerator {
private $appBundleID = 'your.bundle.id';
private $keyIdentifier = 'ZZZZZZZ';
private $itunesPrivateKeyPath = '/path/to/the/file.p8;
/**
* @see https://developer.apple.com/documentation/storekit/in-app_purchase/generating_a_signature_for_subscription_offers
*
* @param $productIdentifier
* @param $offerIdentifier
*
* @return Signature
*/
public function generateSubscriptionOfferSignature($productIdentifier, $offerIdentifier)
{
$nonce = strtolower(Uuid::uuid1()->toString());
$timestamp = time() * 1000;
$applicationUsername = 'username';
$message = implode(
"\u{2063}",
[
$this->appBundleID,
$this->keyIdentifier,
$productIdentifier,
$offerIdentifier,
$applicationUsername,
$nonce,
$timestamp
]
);
$message = $this->sign($message);
return new Signature(
base64_encode($message),
$nonce,
$timestamp,
$this->keyIdentifier
);
}
private function sign($data)
{
$signature = '';
openssl_sign(
$data,
$signature,
openssl_get_privatekey('file://' . $this->itunesPrivateKeyPath),
OPENSSL_ALGO_SHA256
);
return $signature;
}
}
We had a issue on the client side because the device was connected on 2 different itunes account, one regular and one sandbox. It was creating a invalid signature error that didn't make sens. We disconnect the regular account and just use the sandbox account and everything is working.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With