Implementing iOS Promotional Offers with IOS Native

Implementing iOS Promotional Offers with IOS Native

The "promotional offers" is a relatively new cool iOS feature available from iOS 12.2. Recently I finished a feature request from one of the IOS Native plugin users and would like to share some good articles about it and also a few code snippets on how to implement it.

First of all, here is a couple of awesome articles I think you should read before jumping to implementing this feature in your game.

But for now, let's just go to the short description of how to do it.

1. Pull offer info.

Pull the product data but it's id if you haven't got all the product info yet (normally you pull all the product info as a store initialization process.)

var productsRequest = new ISN_SKProductsRequest(new List<string>{"my.product.id"});

Once a request is sent, we can print available discounts for our product.

productsRequest.Start(response =>
{
    if (response.IsSucceeded)
    {
        // We only interested in 1st product
        // since we requesting only 1 is in this sample:
        var product = response.Products[0];
        foreach (var discount in product.Discounts)
        {
            Debug.Log($"Product has available Discount: " +
                $"{discount.LocalizedPrice}");
        }
    }
});

The available discounts are presented by ISN_SKProductDiscount model.

2. Determine Eligibility

In order for an offer to be applied, a user either needs to have an active or lapsed subscription. + any additional eligibility check logic you would like to add based on your app business logic.

3. Sign

This is probably the trickiest part. We need to convert our ISN_SKProductDiscount into an ISN_SKPaymentDiscount. I will post here part of Jacob Eiting guide from Configuring iOS Subscription Offers article.

The constructor for ISN_SKPaymentDiscount provides some clue to what we’ll need to achieve that:

  • identifier — The identifier of the subscription offer
  • keyIdentifier — The identifier of the subscription key used to sign the offer
  • nonce — A throwaway value generated along with the signature
  • signature — The signature itself
  • timestamp — The timestamp when the signature was generated.

First, generate your subscription key, you can do this from the “Users and Access” section of App Store Connect. 

Configuring your key will trigger a one-time download of a p8 file of your private key. Don’t lose it! You will need this key every time you want any user to redeem an offer. Apple provided a signing guide for doing so but it’s light on specifics. But don’t worry! We don’t have to learn the Elliptic Curve Digital Signature Algorithm, we can use Python.

First, install the ecdsa package for Python:

pip install ecdsa

Next we need to convert your p8 key file into a DER file readable by the ecdsa library. Luckily the OpenSSL command line tool can do this.

openssl pkcs8 -nocrypt -in SubscriptionKey_XWSXTGQVX2.p8 -out cert.der -outform der

With the converted key, the following will generate the needed signature:

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, the requested offer is appropriate. This forces the developer to use off device control for granting offers.

Once you’ve generated the signature, nonce and timestamp send these along with the key_id back to your app where we can create an ISN_SKPaymentDiscount.

4. Display an offer

The following code snippet shows how to display an offer using our ISN_SKPaymentDiscount object.

var payment = new ISN_SKMutablePayment(product);
payment.ApplicationUsername = appUserID;
payment.PaymentDiscount = discount;

ISN_SKPaymentQueue.AddPayment(payment);

And that's it, this is how you do it  :)

要查看或添加评论,请登录

Stanislav Osipov的更多文章

  • Foundation Package

    Foundation Package

    I' de like to share some utility methods, and patterns collection package my colleagues and I are using in pretty much…

  • How to build an automated API website for your Unity project or package Part 1

    How to build an automated API website for your Unity project or package Part 1

    I'd like to share my journey on how I build the Stan's Assets API website for our Unity plugins and packages. I am…

    1 条评论
  • Unity UPM Package Template

    Unity UPM Package Template

    Today I would like to share my Unity UPM Package Template repository with you. The purpose of this template is to give…

    1 条评论
  • Publish Unity package with NPMJS

    Publish Unity package with NPMJS

    Unity PackageManager is an awesome tool and it's a shame not to use it! This guide contains step by step instructions…

  • Why should you love bugs?

    Why should you love bugs?

    I like working with bugs and issues. I would like to share with your my experience , and explain why I enjoy it so much.

社区洞察

其他会员也浏览了