ios – Drawback Producing Signature for Subscription Gives – Error Code 18

0
1
ios – Drawback Producing Signature for Subscription Gives – Error Code 18


I am efficiently utilizing Apple subscriptions in my app, however I am encountering SKErrorCodeDomain error 18 when attempting to use a subscription supply.

I would like apply supply code first time just for subscription.

I’ve tried many answer from on-line search however difficulty will not be fastened.
Under are particulars of what i set in appstore and what i’ve examined.

Subscription Provide Particulars

  • Provide Sort: For the primary month
  • Buyer Eligibility: New, Current, and Expired Subscribers
  • Code Standing: Energetic

Provide Code Creation Steps:

  • App Retailer Join → App → Subscription → Choose Subscription Product → Provide Codes → Add → Add Customized Codes

Signature Era for Promotional Gives

I am following Apple’s documentation to generate a signature:
https://developer.apple.com/documentation/storekit/generating-a-signature-for-promotional-offers

I’ve constructed the payload as instructed:

appBundleId + 'u2063' + keyIdentifier + 'u2063' + productIdentifier + 'u2063' + offerIdentifier + 'u2063' + appAccountToken + 'u2063' + nonce + 'u2063' + timestamp

Keys and Identifiers

  • keyIdentifier, issuerId, and .p8 file are obtained from:
    • App Retailer Join → Customers and Entry → Integrations → In-App Buy
  • Check person created below:
    • App Retailer Join → Customers and Entry → Sandbox → Check Accounts
    • Logged in with this account on the iPhone

What I’ve Tried


Apple’s pattern code to generate a signature

Downloaded from

const specific = require('specific');
const router = specific.Router();

const crypto = require('crypto');
const ECKey = require('ec-key');
const secp256k1 = require('secp256k1');
const uuidv4 = require('uuid/v4');

const KeyEncoder = require('key-encoder');
const keyEncoder = new KeyEncoder('secp256k1');

const fs = require('fs');

perform getKeyID() {
    return "KEYIDXXXXX";
}

router.put up('/supply', perform(req, res) {
    const appBundleID = req.physique.appBundleID;
    const productIdentifier = req.physique.productIdentifier;
    const subscriptionOfferID = req.physique.offerID;
    const applicationUsername = req.physique.applicationUsername;

    const nonce = uuidv4();
    const currentDate = new Date();
    const timestamp = currentDate.getTime();
    const keyID = getKeyID();

    const payload = appBundleID + 'u2063' +
                  keyID + 'u2063' +
                  productIdentifier + 'u2063' +
                  subscriptionOfferID + 'u2063' +
                  applicationUsername  + 'u2063'+
                  nonce + 'u2063' +
                  timestamp;

    // Get the PEM-formatted non-public key string related to the Key ID.
    // const keyString = getKeyStringForID(keyID);
    // Learn the .p8 file
    const keyString = fs.readFileSync('./SubscriptionKey_KEYIDXXXXX.p8', 'utf8');

    // Create an Elliptic Curve Digital Signature Algorithm (ECDSA) object utilizing the non-public key.
    const key = new ECKey(keyString, 'pem');

    // Arrange the cryptographic format used to signal the important thing with the SHA-256 hashing algorithm.
    const cryptoSign = key.createSign('SHA256');

    // Add the payload string to signal.
    cryptoSign.replace(payload);

    /*
        The Node.js crypto library creates a DER-formatted binary worth signature,
        after which base-64 encodes it to create the string that you'll use in StoreKit.
    */
    const signature = cryptoSign.signal('base64');

    /*
        Verify that the signature passes verification by utilizing the ec-key library.
        The verification course of is just like creating the signature, besides it makes use of 'createVerify'
        as a substitute of 'createSign', and after updating it with the payload, it makes use of `confirm` to cross in
        the signature and encoding, as a substitute of `signal` to get the signature.

        This step will not be required, but it surely's helpful to examine when implementing your signature code.
        This helps debug points with signing earlier than sending transactions to Apple.
        If verification succeeds, the subsequent really useful testing step is trying a purchase order
        within the Sandbox atmosphere.
    */
    const verificationResult = key.createVerify('SHA256').replace(payload).confirm(signature, 'base64');
    console.log("Verification outcome: " + verificationResult)

    // Ship the response.
    res.setHeader('Content material-Sort', 'utility/json');
    res.json({ 'keyID': keyID, 'nonce': nonce, 'timestamp': timestamp, 'signature': signature });

});    

module.exports = router;

Postman request and response

Request URL: http://192.168.1.141:3004/supply
Request JSON: {
    "appBundleID":"com.app.bundleid",
    "productIdentifier":"subscription.product.id",
    "offerID":"OFFERCODE1",
    "applicationUsername":"01234b43791ea309a1c3003412bcdaaa09d39a615c379cc246f5f479760629a1"
}
Response JSON: {
    "keyID": "KEYIDXXXXX",
    "nonce": "f98f2cda-c7a6-492f-9f92-e24a6122c0c9",
    "timestamp": 1753510571664,
    "signature": "MEYCIQCnA8UGWhTiCF+F6S55Zl6hpjnm7SC3aAgvmTBmQDnsAgIhAP6xIeRuREyxxx69Ve/qjnONq7pF1cK8TDn82fyePcqz"
}

Xcode Code

func purchase(_ product: SKProduct) {
    let discountOffer = SKPaymentDiscount(
        identifier: "OFFERCODE1",
        keyIdentifier: "KEYIDXXXXX",
        nonce: UUID(uuidString: "f98f2cda-c7a6-492f-9f92-e24a6122c0c9")!,
        signature: "MEYCIQCnA8UGWhTiCF+F6S55Zl6hpjnm7SC3aAgvmTBmQDnsAgIhAP6xIeRuREyxxx69Ve/qjnONq7pF1cK8TDn82fyePcqz",
        timestamp: 1753510571664)
    
    let fee = SKMutablePayment(product: product)
    fee.applicationUsername = "01234b43791ea309a1c3003412bcdaaa09d39a615c379cc246f5f479760629a1"
    fee.paymentDiscount = discountOffer
    SKPaymentQueue.default().add(fee)
}

Difficulty

Even following directions to the documentation and trying numerous mixtures, the supply retains failing with SKErrorCodeDomain error 18.

Has anybody else skilled this? Any strategies as to what could also be amiss or how it may be corrected?

LEAVE A REPLY

Please enter your comment!
Please enter your name here