Skip to main content

8.0.0

With RuStore you can integrate payments in your mobile app.

tip

If you don't know where to start read the instruction.

Dependency Resolution

Dependencies for the Android build are automatically connected using the External Dependency Manager tool.

To automatically resolve dependencies, use the command: Assets → External Dependency Manager → Android Resolver → Force Resolve. This operation should be performed every time new versions of plugins are added or when the files Assets/Plugins/Android/mainTemplate.gradle and Assets/Plugins/Android/settingsTemplate.gradle are regenerated.

  • When installing RuStore plugins via a *.unitypackage, the External Dependency Manager does not require any special installation steps.

  • When installing RuStore plugins via the Package Manager, perform the following steps:

    • Open the RuStore Core plugin tab in the Package Manager window: Window → Package Manager → Packages RuStore → RuStore Core.
    • Switch to the Samples tab.
    • Import the External Dependency Manager sample.
  • The latest version of External Dependency Manager can also be obtained from the developer’s repository on GitHub:

    • Open the Package Manager window: Window → Package Manager → + → Add package from git URL....
    • Use the URL https://github.com/googlesamples/unity-jar-resolver.git?path=/upm to add the package.
    • To resolve the error "Google.IOSResolver.dll will not be loaded", install the iOS Build Support module for your Unity version via UnityHub → Installs → Your Unity version → Add modules → iOS Build Support.
<!-- Example error message -->
<Assembly 'Packages/com.google.external-dependency-manager/ExternalDependencyManager/Editor/1.2.182/Google.IOSResolver.dll' will not be loaded due to errors:
Unable to resolve reference 'UnityEditor.iOS.Extensions.Xcode'. Is the assembly missing or incompatible with the current platform?
Reference validation can be disabled in the Plugin Inspector.>

Connect to project

To connect, download RuStoreUnityBillingSDK-version.unitypackage file and import it to the project (Assets > Import Package > Custom Package). The dependencies are connected automatically with External Dependency Manager (included in .unitypackage).

tip

If you use macOS, change Archive Utility settings. Uncheck Keep expanding if possible. Otherwise, the project archive will not be downloaded correctly.

You can also clone the code using Git.

To correctly handle SDK dependencies, perform the following configuration steps:

  1. Open the project settings: Edit → Project Settings → Player → Android Settings.

  2. In the Publishing Settings section, enable the following options:

    • Custom Main Manifest
    • Custom Main Gradle Template
    • Custom Gradle Properties Template
  3. In the Other Settings section, configure the following:

    • Package Name
    • Minimum API Level = 24
    • Target API Level = 34
  4. Open the External Dependency Manager settings: Assets → External Dependency Manager → Android Resolver → Settings, and enable the following options:

    • Use Jetifier
    • Patch mainTemplate.gradle
    • Patch gradleTemplate.properties

Application minification (ProGuard/R8) is not currently supported; it must be disabled in the project settings (File > Build Settings > Player Settings > Publishing Settings > Minify).

Update

Plugin version 6.1.0 and above contain modified directory structure. The modified structure allows to use the advantages of separate builds for project parts Assembly definitions.

Before installation, delete the following folders.

  • Assets > RuStoreSDK > BillingClient > Editor.
  • Assets > RuStoreSDK > Common > Editor.
img

After deletion, import new .unitypackage in your project as during a usual installation (Assets > Import Package > Custom Package).

SDK Initialization

Initialize the library before calling its methods.

In the editor menu select Window > RuStoreSDK > Settings > Billing Client.

RuStoreBillingClient.Instance.Init();

Once you’re required other settings, you can pass them directly from the code.

RuStoreBillingClient initialization
var config =  new RuStoreBillingClientConfig() {
consoleApplicationId = "123456" ,
deeplinkPrefix = "yourappscheme" ,
allowNativeErrorHandling = true,
enableLogs = true
};

RuStoreBillingClient.Instance.Init(config);
Where are app IDs in the RuStore Console?
  1. Navigate to the Applications tab and selected the needed app.
  2. Copy the ID from the URL address of the app page — it is a set of numbers between apps/ and /versions. FOr example, for URL address https://console.rustore.ru/apps/123456/versions the app ID is 123456.

  • deeplinkPrefix — deeplink URL address. You can use any unique name (for example: yourappscheme).
  • allowNativeErrorHandling — allow handling errors using native SDK (see more in Error handling).
  • enableLogs — enable logging.
note
Tye deeplink scheme that is passed in deeplinkPrefix must match the scheme specified in AndroidManifest.xml (see Deeplink processing).

If you need to check that the library is initialized, use RuStoreBillingClient.isInitialized, which returns true if the library is initialized and false if the init function has not been called yet.

var isInitialized = RuStoreBillingClient.Instance.IsInitialized;

RuStore SDK uses deeplink to handle third-party payment applications. This makes it easier to pay with third-party apps and return to your app.

To configure deeplinks functionality in your app and RuStore SDK, define deeplinkScheme in your AndroidManifest file and redefine the onNewIntent method of your activity.

AndroidManifest.xml
<activity
android:name="ru.rustore.unitysdk.RuStoreUnityActivity" android:theme ="@style/UnityThemeSelector" android:exported ="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="yourappscheme"/>
</intent-filter>
</activity>

Replace yourappscheme in the example above with the name of your scheme. For example, ru.package.name.rustore.scheme.

Then, extend the UnityPlayerActivity class and add incoming intent processing in onNewIntent.

RuStoreUnityActivity class example
package ru.rustore.unitysdk;

import android.os.Bundle;
import android.content.Intent;
import ru.rustore.unitysdk.billingclient.RuStoreUnityBillingClient;
import com.unity3d.player.UnityPlayerActivity;

public class RuStoreUnityActivity extends UnityPlayerActivity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
RuStoreUnityBillingClient.onNewIntent(getIntent());
}
}
@Override protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
RuStoreUnityBillingClient.onNewIntent(intent);
}
}

Put the Java file with the UnityPlayerActivity extension code in the project folder Assets. If you already have your own UnityPlayerActivity extension, include the code of onCreate and onNewIntent functions into it.

SDK methods

Retrieving products list

You verified that payments are available and the users are able to make purchases. Now you can request products list. Use the GetProducts method to request the information about products added to your app in RuStore Console.

Calling GetProducts
RuStoreBillingClient.Instance.GetProducts(productsId,
onFailure: (error) => {
// Process error
},
onSuccess: (response) => {
// Process response
}
);

string[] productIds — the list of product IDs. Must not exceed 100 entries.

To specify id of the products needed for the method, do the following.

  1. Open RuStore Console.
  2. Navigate to the Applications tab.
  3. Select the necessary app.
  4. In the left side menu select Monetization.
  5. Select product type: Subscriptions or In-App purchases.
  6. Copy the IDs of the required products. These are product ids.

The method returns products list List<Product>.

Product structure

Product class
public class Product {
public enum ProductStatus {
ACTIVE,
INACTIVE
}
public enum ProductType {
NON_CONSUMABLE,
CONSUMABLE,
SUBSCRIPTION
}
public string productId;
public ProductType productType;
public ProductStatus productStatus;
public string priceLabel;
public int price;
public string currency;
public string language;
public string title;
public string description;
public string imageUrl;
public string promoImageUrl;
public ProductSubscription subscription;
}
  • productId — product ID assigned to product in RuStore Console (mandatory).
  • productType — product type: CONSUMABLE/NON-CONSUMABE/SUBSCRIPTION.
  • productStatus — product status.
  • priceLable — formatted product price, including currency symbol in language.
  • price — price in minimum currency units.
  • currency — ISO 4217 currency code.
  • language — language specified with BCP 47 code.
  • title — product name in language.
  • description — descriptions in language.
  • imageUrl — image URL.
  • promoImageUrl — promo image URL.
  • subscription — subscription description, returns only for subscription products.

Subscription structure

ProductSubscription class
public class ProductSubscription {
public SubscriptionPeriod subscriptionPeriod;
public SubscriptionPeriod freeTrialPeriod;
public SubscriptionPeriod gracePeriod;
public string introductoryPrice;
public string introductoryPriceAmount;
public SubscriptionPeriod introductoryPricePeriod;
}
  • subscriptionPeriod — subscription period.
  • freeTrialPeriod — subscription trial period.
  • gracePeriod — subscription grace period.
  • introductoryPrice — formated introductory price with the currency symbol in the product:language language.
  • introductoryPriceAmount — introductory price in minimum currency units.
  • introductoryPricePeriod — introductory price invoice period.

Structure of the subscription period

SubscriptionPeriod class
public class SubscriptionPeriod {
public int years;
public int months;
public int days;
}
  • years — amount of years.
  • months — amount of months.
  • days — amount of days.

Purchasing product

To purchase product, use the PurchaseProduct method.

Calling PurchaseProduct
RuStoreBillingClient.Instance.PurchaseProduct(
productId: productId,
quantity: 1,
developerPayload: "your payload",
onFailure: (error) => {
// process error
},
onSuccess: (result) => {
// process result
}
);
  • productId: String — product ID assigned to product in RuStore Console (mandatory).
  • orderId: String — payment ID generated by the app (optional). If you specify this parameter in your system, you will receive it via our API. If not specified, will be generated automatically (uuid). 150 characters max.
  • quantity: Int — product amount (optional, value 1 will be used if not specified).
  • developerPayload — string with additional order information, that you can specify on purchase initialization.

Purchase result structure

PaymentResult class
public class PaymentResult {
}

public class PaymentSuccess : PaymentResult {

public string orderId;
public string purchaseId;
public string productId;
public string invoiceId;
public string subscriptionToken;
public bool sandbox;
}

public class PaymentCancelled : PaymentResult {

public string purchaseId;
public bool sandbox;
}

public class PaymentFailure : PaymentResult {

public string purchaseId;
public string invoiceId;
public string orderId;
public int quantity;
public string productId;
public int errorCode;
public bool sandbox;
}

public class InvalidPaymentState : PaymentResult {
}
info

The sandbox parameter defines whether a payment is a test payment. Available values: true or false, where true means a test payment and false — an actual payment.

  • PaymentSuccess - successful purchase result.
  • PaymentFailure - there was a problem during sending payment request or receiving payment status, purchase status unknown.
  • PaymentCancelled — payment request sent, although, the user closed the payment screen on their app, thus, the payment result is unknown.
  • InvalidPaymentState — SDK payments error. May occur due to an incorrect return deeplink.

Confirming (consuming) purchase

Products that require confirmation

Please, keep in mind the purchase type. Confirmation is only needed if your product is CONSUMABLE and can be purchased more than once.

To correctly deliver such products, confirm purchases with the confirmPurchase method. On delivering a product, use server validation. Deliver your product only after the payment (invoice) is in the CONFIRMED status. Use the addOnSuccessListener callback of the confirmPurchase method to deliver products.

Attention!

The PAID status is intermediate and meas that the user's money is put on hold on their card, so you need to confirm the purchase.

The exceptions are SBP or mobile payment — see the explanation below.

When paying for CONSUMABLE products with SBP or mobile payment, one-stage payment is used, although the payment model is as in two-stage payments. It means that what a payment is in the PAID status, when paying with SBP or mobile payment, the money is withdrawn from the buyer's account, as well as the developer's fee is withdrawn from theirs. In this case, if a purchase is canceled from the PAID status the refund is made, not reverse. The developer's fee will not be returned. At the same time, to complete the purchase you still have to confirm purhchase — see the table below.

Payment methodPayment typePayment in the PAID status
  • bank cards;
  • Sber ID;
  • SberPay;
  • T-Pay;
  • VK Pay.
Two-stage
  • Money is on hold on the buyer's account.
  • Developer's fee is not applied.
  • Payment cancellation (reverse) is available.
  • SBP;
  • mobile payment.
One-stage
  • Money is withdrawn from the buyer's account.
  • The developer's fee is applied.
  • If a purchase is canceled form the PAID status the transaction is refunded, not reverse reversed. The developer's fee will not be returned.

ConfirmPurchase request

Us the confirmPurchase method to confirm a purchase. Purchase confirmation request must be accompanied by the delivery of the product. After calling the confirmation method the purchase changes its state to CONSUMED.

Calling ConfirmPurchase
RuStoreBillingClient.Instance.ConfirmPurchase(
purchaseId: "purchaseId" ,
onFailure: (error) => {
// Process error
},
onSuccess: () => {
// Process success
}
);
  • purchaseId — product ID.

Purchase cancellation

To cancel a purchase, use the DeletePurchase method.

Calling DeletePurchase
RuStoreBillingClient.Instance.DeletePurchase(
purchaseId: "purchaseId" ,
onFailure: (error) => {
// Process error
},
onSuccess: () => {
// Process success
}
);
  • purchaseId — product ID.
info

Use this method if your app logic is related to purchase cancellation. The purchase is canceled automatically after a 20-min timeout, or upon a second purchase from the same customer.

Getting purchase information

Go get purchase information, use the getPurchaseInfo method.
Calling getPurchaseInfo
RuStoreBillingClient.Instance.GetPurchaseInfo(
purchaseId: "purchaseId",
onFailure: (error) => {
// Process error
},
onSuccess: (response) => {
// Process response
}
);

The method returns the Purchase object with the purchase information.

Purchase structure

Purchase class
public class Purchase {
public enum PurchaseState
{
CREATED,
INVOICE_CREATED,
CONFIRMED,
PAID,
CANCELLED,
CONSUMED,
CLOSED
}

public string purchaseId;
public string productId;
public Product.ProductType productType;
public string invoiceId;
public string language;
public DateTime purchaseTime;
public string orderId;
public string amountLabel;
public int amount;
public string currency;
public int quantity;
public PurchaseState purchaseState;
public string developerPayload;
public string subscriptionToken;
}
  • purchaseId — product ID.
  • productId — product ID assigned to product in RuStore Console (mandatory).
  • invoiceId — invoice ID.
  • language — language specified with BCP 47 code.
  • purchaseTime — purchase time.
  • orderId — payment ID generated by the app (optional). If you specify this parameter in your system, you will receive it via our API. If not specified, will be generated automatically (uuid). 150 characters max.
  • amountLable — formatted purchase price, including currency symbol.
  • amount — price in minimum currency units.
  • currency — ISO 4217 currency code.
  • quantity — product amount (optional, value 1 will be used if not specified).
  • purchaseState — purchase state:
  • developerPayload — string with additional order information, that you can specify on purchase initialization.
  • subscriptionToken — purchase token for server validation .

Getting purchases list

This method returns purchases with the following statuses. For more informations on possible purchase states see Getting purchase info.

Type/StatusINVOICE_CREATEDCONFIRMEDPAIDPAUSED
CONSUMABLE++
NON-CONSUMABLE++
SUBSCRIPTION+++
note

This method returns incomplete purchases that require attention. Also, it shows confirmed subscriptions and consumable products that cannot be purchased more than once.

Go get the user's purchases list, use the GetPurchases method.

Calling GetPurchases
RuStoreBillingClient.Instance.GetPurchases(
onFailure: (error) => {
// Process error
},
onSuccess: (response) => {
// Process response
}
);

The method returns List<Purchase> response — purchases list.

Purchase structure

Purchase class
public class Purchase {
public enum PurchaseState
{
CREATED,
INVOICE_CREATED,
CONFIRMED,
PAID,
CANCELLED,
CONSUMED,
CLOSED,
PAUSED,
TERMINATED
}

public string purchaseId;
public string productId;
public Product.ProductType productType;
public string invoiceId;
public string language;
public DateTime purchaseTime;
public string orderId;
public string amountLabel;
public int amount;
public string currency;
public int quantity;
public PurchaseState purchaseState;
public string developerPayload;
public string subscriptionToken;
}
  • purchaseId — product ID.
  • productId — product ID assigned to product in RuStore Console (mandatory).
  • invoiceId — invoice ID.
  • language — language specified with BCP 47 code.
  • purchaseTime — purchase time.
  • orderId — payment ID generated by the app (optional). If you specify this parameter in your system, you will receive it via our API. If not specified, will be generated automatically (uuid). 150 characters max.
  • amountLable — formatted purchase price, including currency symbol.
  • amount — price in minimum currency units.
  • currency — ISO 4217 currency code.
  • quantity — product amount (optional, value 1 will be used if not specified).
  • purchaseState — purchase state:
  • developerPayload — string with additional order information, that you can specify on purchase initialization.
  • subscriptionToken — purchase token for server validation .

Check whether RuStore is installed on the device

The IsRuStoreInstalled methods is used to check whether RuStore is installed on the user's device. This check is needed to correctly implement handling of products and purchase. The below SDK methods require user authorization:

If RuStore is not installed on the user's device, each time the authorization screen will be displayed that might have a negative effect on user experience. Thus, if the check shows that RuStore is not installed on the user's device, it makes sense to limit the number of requests that require authorization (for more details see section Receiving payments without RuStore app).

bool isRuStoreInstalled = RuStoreCoreClient.Instance.IsRuStoreInstalled();

Payments availability check

To check payments availability, use the CheckPurchasesAvailability method. If all above conditions are met, PurchaseAvailabilityResult.isAvailable == true is returned. Otherwise, PurchaseAvailabilityResult.isAvailable == false is returned, where PurchaseAvailabilityResult.cause is an error of a failed condition.

All possible errors RuStoreException are described in Error handling. Other errors are returned in onFailure. (See Task API).

Вызов метода CheckPurchasesAvailability
RuStoreBillingClient.Instance.CheckPurchasesAvailability( 
onFailure: (error) => {
// Process error
},
onSuccess: (response) => {
if (response.isAvailable) {
// Process purchases available
} else {
// Process purchases unavailable
}
}
);

Changing interface theme

SDK supports dynamic theme changing via the BillingClientThemeProvider provider.

The current theme can be retrieved with the GetTheme() method.

Calling GetTheme
RuStoreBillingClient.Instance.GetTheme()

You can change the current theme using the SetTheme(BillingClientTheme theme) method.

Calling SetTheme
RuStoreBillingClient.Instance.SetTheme(BillingClientTheme.Dark)

Available themes are listed in BillingClientTheme.

BillingClientTheme
public enum BillingClientTheme {
Dark,
Light,
}

Error handling

Possible errors

  • RuStoreNotInstalledException — RuStore is not installed on the user's device;
  • RuStoreOutdatedException — RuStore version installed on the user's device does not support this SDK;
  • RuStoreUserUnauthorizedException — user is not authorized in RuStore;
  • RuStoreRequestLimitReached — not enough time has passed since the process was last shown;
  • RuStoreReviewExists — this user has already rated your app;
  • RuStoreInvalidReviewInfo — problems with ReviewInfo;
  • RuStoreException — basic RuStore error from which other errors are inherited.

Errors that may occur are processed by the onFailure handler.

Error structure

RuStoreError class
public class RuStoreError {
public string name;
public string description;
}
  • name – error name.
  • description – error description.

Automatic error handling

On calling the PurchaseProduct method, errors are handled automatically.

If allowNativeErrorHandling == true is passed the during SDK initialization, both the Failure handler is called and the user is shown the error dialog.

Kotlin
public fun RuStoreException.resolveForBilling(context: Context)

You can change this behavior after the initialization by setting the AllowNativeErrorHandling property.

C#
RuStoreBillingClient.Instance.AllowNativeErrorHandling = false;