The ONE store unity plug-in is provided to make it easy to apply the ONE store IAP in the Unity development environment. The ONE store unity plug-in includes the method that handles the payment-related functions and the result of calling those functions. The file configuration of plug-in is as follows.
It is developed with Unity 5.6.0f3 version.
ONE store Unity Plugin
ONE store Unity Plugin Configuration
If you download ONE store's unity plug-in through Github, you can check the folders seen below.
ONE store Unity Plugin Sample File Configuration
Application of ONE store Unity Plugin
Apply Unity Plugin
Put the iap_plugin_all_v17.00.00_20171225.aar (or iap_plugin_v17.00.00_20171225.jar, unity_adaptor_v17.00.00_20171225.jar, and AndroidManifest.xml ) in the Asset/Plugins/Android/Onestore.
Or you can use by selecting the Assets/Import Package/Custom Package and importing the IapV17_UnityPluginSample.unityPackage which is attached.
When building, enter packageName as com.onestore.iap.apisample, select signkey01.keystore (check in the Use Existing Keystore) and enter Keystore password: signkey01, choose signkey01 in Key Alias and enter password:signkey01.
Canvas has 10 buttons, and the OnClick of each button is a method within IapUi.cs and connected one-to-one.
Onestore_IapUi GameObject is connecting one script component of Onestore_IapUi.cs.
Onestore_IapCallbackManager GameObject is connecting two script components of Onestore_IapCallbackManager.cs and Onestore_IapResultListener.cs.
Background GameObject simply acts as the background screen.
ONE store Unity Plugin Reference
Basic Operation & Precautions
Android and Unity mutually exchange all data, including PurchaseData, ProudctDetail, the original copy of the purchased in-app products and signature in JSON format. To change in-app product name, payload, public key for the default test, you can modify Onestore_IapUi_IapUi.cs and perform the test.
In the sample app, it is required to check the list of the purchased in-app products and save data after the in-app products are purchased in order to consume the in-app products and change the status of the subscription. And therefore, the PlayerPrefs is used for simple storage and the productId is saved as the key value in JSON format. As for the productId, you can use it by receiving JSON data as the same key value and passing it to Android or changing it into other types.
To use the 'consume' or ManagerRecurring by saving the in-app product information purchased through getPurchase, getbuyIntent, and etc. it is required to develop the in-app product data by using the data structure that the developer desires to create.
Onestore_IapUi.cs and Onestore_IapCallbackManager.cs are responsible for transmission and reception. However, they have Onestore_IapCallMnager and Onestore_IapResultListener separately to easily change the test value without modifying the logic and to conveniently receive the result value such as string and Json in the form of the changed data, including PurchaseData and ProductDetail.
Unlike IapUi, Onestore_IapCallManger has class variables to change the API version when the update is made later. And it has a feature to display an error pop-up on the button operation when initialization has not been performed. Furthermore, when calling from Android to Unity, the following codes are used to designate which game object should be called by importing the com.onestore.iap.sdk.unity.IapPlugin instance to the constructor part and passing it to the constructor parameter. Developers can change the codes according to their needs.
In the IapUi.cs example, when it comes to the 'cancel/reactivate auto', the 'cancel/reactivate' operation has been implemented as a sample to operate alternately on/off due the screen space issue. After this command is performed, recurringState is not changed in the result value which is shown in a pop-up. You can check the updated recurringState only through getPurchase.
Basic Flow from Unity to Android
Basic Flow from Android to Unity
Introduction to ONE store Unity Plugin Methods and Operation
Operation to Initialize Payment
Create PurchaseClient in plugin by passing 'Service Connect : public key', bind ONE store's in-app service and receive the result through the listener. The calling direction is from top to bottom and Unity will call Android.
// Onestore_IapUi.cs (C#)
public void connectService ()
{
var base64EncodedPublicKey = "MIGfMA0GCSqGSIb3D....";
IapCallManager.connectService (base64EncodedPublicKey);
}
// Onestore_IapCallMnager.cs (C#)
public static void connectService (string publicKey)
{
iapRequestAdapter.Call ("connect", publicKey);
}
// ONE store Unity Plugin (Java)
public void connect(String base64EncodedPublicKey) {
Log.d(TAG, "connect - base64EncodedPublicKey " + base64EncodedPublicKey);
mPurchaseClient = new PurchaseClient(getActivity(), base64EncodedPublicKey);
publicKeyBase64 = base64EncodedPublicKey;
mPurchaseClient.connect(mServiceConnectionListener);
}
This is a sequence where Android calls Unity through the connection listener. As a destination to receive the result value from Android to Unity, gameObject has already registered the GameObject named the 'IapCallbackManager' in the constructor part of IapCallManager.cs. With this value, Unity Plugin will pass the result value to this GameObject.
Since Onestore_IapCallbackManager.cs has been registered in the GameObject named 'IapCallbackManager', one of the string parameters of 'onConnected', 'onDisconnected' and 'onErrorNeedUpdateException' will be passed as the callback value to the ServiceConnectionListener method of this file. Each of the string parameters means that 'the service is successfully bound', 'the service is unbound' and 'the OSS is not the latest version or not installed'.
When the 'onConnected' is received through the parameter, serviceAvailableEvent() means a successful connection. And therefore, serviceAvailableEvent() is used to display an error pop-up when the connection is not successful.
Onestore_IapResultListener.cs has also been registered in the GameObject named "IapCallbackManager. During initialization, serviceConnectionEvent(callback) will call the serviceConnectionResult of the Onestore_IapResultListener.cs through Onestore_IapCallbackManager.serviceConnectionEvent += serviceConnectionResult, and will eventually display the connection-related message in the pop-up.
// ONE store Unity Plugin (Java)
PurchaseClient.ServiceConnectionListener mServiceConnectionListener = new PurchaseClient.ServiceConnectionListener() {
@Override
public void onConnected() {
unitySendMessage(gameObject, "ServiceConnectionListener", "onConnected");
}
@Override
public void onDisconnected() {
unitySendMessage(gameObject, "ServiceConnectionListener", "onDisconnected");
}
@Override
public void onErrorNeedUpdateException() {
unitySendMessage(gameObject, "ServiceConnectionListener", "onErrorNeedUpdateException");
}
};
// Onestore_IapCallbackManager.cs (C#)
public static event Action<string> serviceConnectionEvent;
public void ServiceConnectionListener (string callback)
{
if (callback.Contains (preDefinedStrings [CBType.Connected])) {
serviceAvailableEvent ();
}
serviceConnectionEvent (callback);
}
// Onestore_IapResultListener.cs (C#)
Onestore_IapCallbackManager.serviceConnectionEvent += serviceConnectionResult;
void serviceConnectionResult (string result)
{
AndroidNative.showMessage ("serivce connect", result, "ok");
}
Check Support
The calling direction is from top to bottom and Unity will call Android.
// Onestore_IapUi.cs (C#)
public void isBillingSupported ()
{
Onestore_IapCallManager.isBillingSupported ();
}
// Onestore_IapCallMnager.cs (C#)
public static void isBillingSupported ()
{
checkServiceAvailable();
iapRequestAdapter.Call("isBillingSupported", IAP_API_VERSION);
}
// ONE store Unity Plugin (Java)
public void isBillingSupported(int apiVersion) {
if (mPurchaseClient == null) {
Log.i(TAG, "PurchaseClient is not initialized");
return;
}
mPurchaseClient.isBillingSupportedAsync(apiVersion, mBillingSupportedListener);
}
This is a sequence where Android calls Unity through the connection listener. The string types of the result value received from the callback are as follows.
onSuccess: if checking status information is success
onError : if failed, an error code will be passed to the application. A code composed of numbers, and descriptions in the string form are passed in the form of ToString.
onErrorRemoteException: it occurs when a Remote call is requested at the time of unbinding the service.
onErrorSecurityException: it occurs when the application is falsified or abnormal in the APK.
onErrorNeedUpdateException: it occurs when the OSS is not the latest version or not installed.
// ONE store Unity Plugin (Java)
PurchaseClient.BillingSupportedListener mBillingSupportedListener = new PurchaseClient.BillingSupportedListener() {
@Override
public void onSuccess() {
unitySendMessage(gameObject, "BillingSupportedListener", "onSuccess");
}
@Override
public void onError(IapResult result) {
unitySendMessage(gameObject, "BillingSupportedListener", "onError" + result.toString());
}
@Override
public void onErrorRemoteException() {
unitySendMessage(gameObject, "BillingSupportedListener", "onErrorRemoteException");
}
@Override
public void onErrorSecurityException() {
unitySendMessage(gameObject, "BillingSupportedListener", "onErrorSecurityException");
}
@Override
public void onErrorNeedUpdateException() {
unitySendMessage(gameObject, "BillingSupportedListener", "onErrorNeedUpdateException");
}
};
// Onestore_IapCallbackManager.cs (C#)
public static event Action<string> isBillingSupportedEvent;
public void BillingSupportedListener (string callback)
{
isBillingSupportedEvent (callback);
}
{// Onestore_IapResultListener.cs (C#)
IapCallbackManager.isBillingSupportedEvent += isBillingSupportedResult;
void isBillingSupportedResult (string result)
{
AndroidNative.showMessage ("isBillingSupported", result, "ok");
}
Check Purchase History
The calling direction is from top to bottom and Unity will call Android.
// Onestore_IapUi.cs (C#)
public void getPurchases ()
{
Onestore_IapCallManager.getPurchases ();
}
// Onestore_IapCallMnager.cs (C#)
//inapp과 auto 두 가지 상품 타입이 존재하는데 각각 상품에 대해서 각각 따로 호출해야 합니다. 개발사에서 변경 가능한 부분
public static void getPurchases ()
{
checkServiceAvailable ();
iapRequestAdapter.Call ("getPurchase", IAP_API_VERSION, "inapp");
iapRequestAdapter.Call ("getPurchase", IAP_API_VERSION, "auto");
}
// ONE store Unity Plugin (Java)
public void getPurchase(int apiVersion, final String productType) {
if (mPurchaseClient == null) {
Log.d(TAG, "PurchaseClient is not initialized");
return;
}
mPurchaseClient.queryPurchasesAsync(apiVersion, productType, mQueryPurchaseListener);
}
This is a sequence where Android calls Unity through the connection listener. The string types of the result value received from the callback are as follows.
onSuccess: a success response to the 'check purchase information' calling :
if the purchased data exists, the format of “onSuccess” + json (productType: if the in-app product type is the inapp or the auto, purchaseData: the purchase data of the purchased original json, signature: the purchased signature) will be passed. If there is no purchase data, the format of “onSuccess”+ “[]” + producttype(“inapp” or “auto”) will be passed.
onErrorRemoteException
onErrorSecurityException
onErrorNeedUpdateException
onError: if failed, an error code will be passed to the application. A code composed of numbers, and descriptions in the string form are passed in the form of ToString.
The current signature is received from the IapCallbackManager but is not passed here. It is because that the review has been performed by default through the purchase data and signature within the SDK. If the signature is needed, it can be imported from the IapCallbackManager and used. Setting the PlayerPref value is for the test apps, and developers are required to actually manage or save items.
// ONE store Unity Plugin (Java)
PurchaseClient.QueryPurchaseListener mQueryPurchaseListener = new PurchaseClient.QueryPurchaseListener() {
@Override
public void onSuccess(List<PurchaseData> purchaseDataList, String productType) {
if (purchaseDataList.size() > 0) {
for (PurchaseData purchaseData : purchaseDataList) {
unitySendMessage(gameObject, "QueryPurchaseListener", "onSuccess" + JsonUtil.makePurchaseDataToJson(purchaseData, productType));
}
} else {
unitySendMessage(gameObject, "QueryPurchaseListener", "onSuccess" + purchaseDataList + productType);
}
}
@Override
public void onErrorRemoteException() {
unitySendMessage(gameObject, "QueryPurchaseListener", "onErrorRemoteException");
}
@Override
public void onErrorSecurityException() {
unitySendMessage(gameObject, "QueryPurchaseListener", "onErrorSecurityException");
}
@Override
public void onErrorNeedUpdateException() {
unitySendMessage(gameObject, "QueryPurchaseListener", "onErrorNeedUpdateException");
}
@Override
public void onError(IapResult result) {
unitySendMessage(gameObject, "QueryPurchaseListener", "onError" + result.toString());
}
};
// Onestore_IapCallbackManager.cs (C#)
public static event Action<PurchaseData> getPurchaseSuccessEvent;
public static event Action<string> getPurchaseErrorEvent;
public void QueryPurchaseListener (string callback)
{
string data = findStringAfterCBType (callback, CBType.Success);
if (data.Length > 0) {
try {
PurchaseResponse purchaseRes = JsonUtility.FromJson<PurchaseResponse> (data);
PurchaseData purchaseData = JsonUtility.FromJson<PurchaseData> (purchaseRes.purchaseData);
getPurchaseSuccessEvent (purchaseData);
} catch (System.Exception ex) {
Debug.Log ("QueryPurchaseListener Exception " + ex.Message);
getPurchaseErrorEvent (data); //success but no data
}
} else {
//because only the onError is followed by the additional data IapResult, pass the additional data only. Since no additional data exists in the rest of the errors, pass the callback as it is.
string errorData = findStringAfterCBType (callback, CBType.Error);
if (errorData.Length > 0) {
getPurchaseErrorEvent (errorData);
} else {
getPurchaseErrorEvent (callback);
}
}
}
// IapResultListener.cs (C#)
void getPurchaseSuccessResult (PurchaseData result)
{
AndroidNative.showMessage ("getPurchase success", result.ToString (), "ok");
PlayerPrefs.SetString (result.productId, JsonUtility.ToJson (result));
}
void getPurchaseErrorResult (string result)
{
if (result.Contains ("inapp")) {
PlayerPrefs.SetString ("p5000", "");
} else {
PlayerPrefs.SetString ("a100000", "");
}
AndroidNative.showMessage ("getPurchase error", result, "ok");
}
Click 'getProductDetail ' Button : Method for Checking IAP SDK V17 Purchase Information
The calling direction is from top to bottom and Unity will call Android.
// Onestore_IapUi.cs (C#)
public void getProductDetails ()
{
var inapp_products = new string[] {inapp_pId1, inapp_pId2, inapp_pId3};
var auto_products = new string[] {auto_pId1};
IapCallManager.getProductDetails (inapp_products, inapp_type);
IapCallManager.getProductDetails (auto_products, auto_type);
}
// Onestore_IapCallMnager.cs (C#)
public static void getProductDetails (string[] products, string productType)
{
checkServiceAvailable ();
iapRequestAdapter.Call ("getProductDetails", new object[]{IAP_API_VERSION, products, productType});
}
// ONE store Unity Plugin (Java)
public void getProductDetails(int apiVersion, Object[] productItems, String productType) {
if (mPurchaseClient == null) {
Log.d(TAG, "PurchaseClient is not initialized");
return;
}
ArrayList<Object> obj_products = new ArrayList<>(Arrays.asList(productItems));
ArrayList<String> products = new ArrayList<>();
for (Object object : obj_products) {
products.add(object != null ? object.toString() : null);
}
mPurchaseClient.queryProductsAsync(apiVersion, products, productType, mQueryProductsListener);
}
This is a sequence where Android calls Unity through the connection listener. The string types of the result value received from the callback are as follows
onSuccess: a success response to the 'check purchase information' calling, json format. Developers are required to process the information, including the list of in-app products available for purchase and the in-app product type, by receiving data from the end IapResultListener. The sample simply shows the result in a pop-up.
onErrorRemoteException
onErrorSecurityException
onErrorNeedUpdateException
onError: if failed, an error code will be passed to the application. A code composed of numbers, and descriptions in the string form are passed in the form of ToString.
The calling direction is from top to bottom and Unity will call Android. When it comes to the inapp and auto products, only the in-app ID and in-app product type differs in IapUi.cs and the rest of the flow is the same. gameUserId and promotionApplicable is not frequently used in general, and therefore, if developers desire to use it by passing it to the default value ("" , false), they can put it by changing the value in the IapCallManager.
gameUserId - enter the unique identification number of a user who is using the application. This value is used as a key value to determine if it is available to participate in and to use promotions.
promotionApplicable - this delivers if it is available to participate in the promotion.
true : the user who is passed to the gameUserId is allowed to participate in a single promotion only once.
false : the user who is passed to the gameUserId cannot participate in the promotion.
In case of purchase, the Activity in the Plugin is called because the Activity of the service is required and the result value must be received. And the parameter value is saved in the intent and passed.
// Onestore_IapUi.cs (C#)
public void buyProductInapp ()
{
//Up to 100 bytes are allowed for the size of the developPayload.
//'null' is not allowed for developPayload.
IapCallManager.buyProduct (inapp_pId1, inapp_type, devPayload);
}
// Onestore_IapCallMnager.cs (C#)
public static void buyProduct (string productId, string productType, string payload)
{
checkServiceAvailable ();
string gameUserId = "";
bool promotionApplicable = false;
iapRequestAdapter.Call ("launchPurchaseFlow", IAP_API_VERSION, productId, productType, payload, gameUserId, promotionApplicable);
}
// ONE store Unity Plugin (Java)
public void launchPurchaseFlow(int apiVersion, final String productId, final String productType,
final String payload, final String gameUserId, boolean promotionApplicable) {
Intent i = new Intent(getActivity(), IapUnityPluginActivity.class);
i.putExtra("productId", productId);
i.putExtra("productType", productType);
i.putExtra("payload", payload);
i.putExtra("apiVersion", apiVersion);
i.putExtra("gameUserId", gameUserId);
i.putExtra("promotionApplicable", promotionApplicable);
getActivity().startActivity(i);
}
After calling mPurchaseClient.launchPurchaseFlow, receive the result value of the completed purchase through the onActivityResult. Verify if the intent data delivered when the purchase is completed in the mPurchaseClient.handlePurchaseData has been signed with the designated signature, and then pass the result value to the listener which was registered during the purchase.
// ONE store Unity Plugin (Java) : IapUnityPluginActivity
public class IapUnityPluginActivity extends Activity {
private static final int LOGIN_REQUEST_CODE = 1001;
private static final int PURCHASE_REQUEST_CODE = 2001;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent i = getIntent();
final String productId = i.getStringExtra("productId");
final String productType = i.getStringExtra("productType");
final String payload = i.getStringExtra("payload");
final int apiVersion = i.getIntExtra("apiVersion", 5);
final String gameUserId = i.getStringExtra("gameUserId");
final boolean promotionApplicable = i.getBooleanExtra("promotionApplicable", false);
if (TextUtils.isEmpty(productId) == false && TextUtils.isEmpty(productType) == false) {
IapPlugin.INSTANCE.mPurchaseClient.launchPurchaseFlow(
apiVersion,
IapUnityPluginActivity.this,
PURCHASE_REQUEST_CODE,
productId,
"",//productName
productType,
payload,
gameUserId, //String gameUserId
promotionApplicable, //boolean promotionApplicable
IapPlugin.INSTANCE.mPurchaseFlowListener);
}
}
}
// ONE store Unity Plugin (Java) : IapUnityPluginActivity
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d("IapUnityPluginActivity", "onActivityResult requestCode " + requestCode);
switch (requestCode) {
case PURCHASE_REQUEST_CODE:
/*
* The intent data which is received upon calling the launchPurchaseFlowAsync API is parsing the response value through the handlePurchaseData.
* After the parsing, the response result is passed through the PurchaseFlowListener which was delivered upon calling the launchPurchaseFlowAsync.
*/
if (resultCode == RESULT_OK) {
if (IapPlugin.INSTANCE.mPurchaseClient.handlePurchaseData(data) == false) {
// listener is null
}
} else {
// user canceled , do nothing..
}
break;
default:
}
finish();
}
This is a sequence where Android calls Unity through the connection listener. The string types of the result value received from the callback are as follows.
onSuccess - a success response to the 'request purchase'
onErrorRemoteException
onErrorSecurityException
onErrorNeedUpdateException
onError: if failed, an error code will be passed to the application. A code composed of numbers, and descriptions in the string form are passed in the form of ToString.
// ONE store Unity Plugin (Java)
PurchaseClient.PurchaseFlowListener mPurchaseFlowListener = new PurchaseClient.PurchaseFlowListener() {
@Override
public void onSuccess(PurchaseData purchaseData) {
unitySendMessage(gameObject, "PurchaseFlowListener", "onSuccess" + JsonUtil.makePurchaseDataToJson(purchaseData, ""));
}
@Override
public void onErrorRemoteException() {
unitySendMessage(gameObject, "PurchaseFlowListener", "onErrorRemoteException");
}
@Override
public void onErrorSecurityException() {
unitySendMessage(gameObject, "PurchaseFlowListener", "onErrorSecurityException");
}
@Override
public void onErrorNeedUpdateException() {
unitySendMessage(gameObject, "PurchaseFlowListener", "onErrorNeedUpdateException");
}
@Override
public void onError(IapResult result) {
unitySendMessage(gameObject, "PurchaseFlowListener", "onError" + result.toString());
}
};
// Onestore_IapCallbackManager.cs (C#)
public static event Action<PurchaseData> getPurchaseIntentSuccessEvent;
public static event Action<string> getPurchaseIntentErrorEvent;
public void PurchaseFlowListener (string callback)
{
string data = findStringAfterCBType (callback, CBType.Success);
if (data.Length > 0) {
try {
PurchaseResponse purchaseRes = JsonUtility.FromJson<PurchaseResponse> (data);
PurchaseData purchaseData = JsonUtility.FromJson<PurchaseData> (purchaseRes.purchaseData);
getPurchaseIntentSuccessEvent (purchaseData);
} catch (System.Exception ex) {
Debug.Log ("PurchaseFlowListener Exception " + ex.Message);
}
} else {
// because only the onError is followed by the additional data IapResult, pass the additional data only. Since no additional data exists in the rest of the errors, pass the callback as it is.
string errorData = findStringAfterCBType (callback, CBType.Error);
if (errorData.Length > 0) {
getPurchaseIntentErrorEvent (errorData);
} else {
getPurchaseIntentErrorEvent (callback);
}
}
}
// Onestore_IapResultListener.cs (C#)
void getPurchaseIntentSuccessResult (PurchaseData result)
{
AndroidNative.showMessage ("getPurchaseIntent sucess", result.ToString (), "ok");
PlayerPrefs.SetString (result.productId, JsonUtility.ToJson (result));
}
void getPurchaseIntentErrorResult (string result)
{
AndroidNative.showMessage ("getPurchaseIntent error", result, "ok");
}
Consume In-App Products
The calling direction is from top to bottom and Unity will call Android. To perform the 'consume', the JSON data on the purchase in-app product that is saved through getPurchase or buyItem is required. And to import the JSON data, it is required to import the in-app ID as a key value by using the PlayerPrefs and deliver it to Android. Eventually, Android uses Json by converting it into the PurchaseData type.
// Onestore_IapUi.cs (C#)
public void consume ()
{
string inapp_json = PlayerPrefs.GetString (inapp_pId1);
if (inapp_json.Length > 0) {
IapCallManager.consume (inapp_json);
} else {
AndroidNative.showMessage ("error", "no data to consume", "ok");
}
}
// Onestore_IapUi.cs (C#)
public void consume ()
{
string inapp_json = PlayerPrefs.GetString (inapp_pId1);
if (inapp_json.Length > 0) {
IapCallManager.consume (inapp_json);
} else {
AndroidNative.showMessage ("error", "no data to consume", "ok");
}
}
// ONE store Unity Plugin (Java)
public void consumeItem(int apiVersion, final String data) {
if (mPurchaseClient == null) {
Log.d(TAG, "PurchaseClient is not initialized");
return;
}
mPurchaseClient.consumeAsync(apiVersion, JsonUtil.makeJsonToPurchaseData(data), mConsumeListener);
}
This is a sequence where Android calls Unity through the connection listener. The string types of the result value received from the callback are as follows.
onSuccess: a success response to the 'consume' request.
onErrorRemoteException
onErrorSecurityException
onErrorNeedUpdateException
onError: if failed, an error code will be passed to the application. A code composed of numbers, and descriptions in the string form are passed in the form of ToString.
Change Subscription Status (Reservation of Cancellation / Cancellation of the Reservation of the Cancellation)
The calling direction is from top to bottom and Unity will call Android. When it come to the subscription(auto) which is the automatic payment in-app product, if recurringState is 0, that means the automatic payment has already made. You can send the 'cancel' command by sending the 'cancel' parameter which cancels the automatic payment. If recurringState is 1, that means the automatic payment has been cancelled. You can make the automatic payment again by sending the 'reactivate' parameter. In the IapUi.cs example, the 'cancel/reactivate' operation has been implemented as a sample to operate alternately on/off.
// Onestore_IapUi.cs (C#)
public void cancelAutoItem ()
{
string auto_json = PlayerPrefs.GetString (auto_pId1);
PurchaseData response = JsonUtility.FromJson<PurchaseData> (auto_json);
if (auto_json.Length > 0) {
string command = "";
if (response.recurringState == 0) {
command = "cancel";
} else if (response.recurringState == 1) {
command = "reactivate";
}
IapCallManager.manageRecurringAuto (auto_json, command);
} else {
AndroidNative.showMessage ("Warning!!", "no data for manageRecurringAuto", "ok");
}
}
// Onestore_IapCallMnager.cs (C#)
public static void manageRecurringAuto (string auto_json, string command)
{
checkServiceAvailable ();
iapRequestAdapter.Call("manageRecurringAuto", IAP_API_VERSION, auto_json, command);
}
// ONE store Unity Plugin (Java)
// 월정액 상품(auto)의 상태변경(해지예약 / 해지예약 취소)을 진행합니다.
public void manageRecurringAuto(int apiVersion, final String data, final String action) {
if (mPurchaseClient == null) {
Log.d(TAG, "PurchaseClient is not initialized");
return;
}
mPurchaseClient.manageRecurringProductAsync(apiVersion, JsonUtil.makeJsonToPurchaseData(data), action, mManageRecurringProductListener);
}
This is a sequence where Android calls Unity through the connection listener. The string types of the result value received from the callback are as follows.
onSuccess: a success response to the 'change the subscription status' calling
onErrorRemoteException
onErrorSecurityException
onErrorNeedUpdateException
onError: if failed, an error code will be passed to the application. A code composed of numbers, and descriptions in the string form are passed in the form of ToString.
The calling direction is from top to bottom and Unity will call Android. The login check is performed by default before the payment is made. Use this button when login-related errors occur while each command is being executed.
// Onestore_IapUi.cs (C#)
public void login ()
{
IapCallManager.login ();
}
// Onestore_IapCallMnager.cs (C#)
public static void login ()
{
checkServiceAvailable ();
iapRequestAdapter.Call ("launchLoginFlow", IAP_API_VERSION);
}
// ONE store Unity Plugin (Java)
public void launchLoginFlow(int apiVersion) {
if (mPurchaseClient == null) {
Log.d(TAG, "PurchaseClient is not initialized");
return;
}
Intent i = new Intent(getActivity(), IapUnityPluginActivity.class);
i.putExtra("apiVersion", apiVersion);
getActivity().startActivity(i);
}
After calling mPurchaseClient.launchLoginFlow, receive the result value of the completed purchase through the onActivityResult. Parse the intent data delivered when the login is completed in the mPurchaseClient.handleLoginData and then pass success or failure to the end listener.
// ONE store Unity Plugin (Java) : IapUnityPluginActivity
public class IapUnityPluginActivity extends Activity {
private static final int LOGIN_REQUEST_CODE = 1001;
private static final int PURCHASE_REQUEST_CODE = 2001;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent i = getIntent();
final String productId = i.getStringExtra("productId");
final String productType = i.getStringExtra("productType");
final String payload = i.getStringExtra("payload");
final int apiVersion = i.getIntExtra("apiVersion", 5);
final String gameUserId = i.getStringExtra("gameUserId");
final boolean promotionApplicable = i.getBooleanExtra("promotionApplicable", false);
IapPlugin.INSTANCE.mPurchaseClient.launchLoginFlow(
apiVersion,
IapUnityPluginActivity.this,
LOGIN_REQUEST_CODE,
IapPlugin.INSTANCE.mLoginFlowListener);
}
}
// ONE store Unity Plugin (Java) : IapUnityPluginActivity
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d("IapUnityPluginActivity", "onActivityResult requestCode " + requestCode);
switch (requestCode) {
case LOGIN_REQUEST_CODE:
/*
* The intent data which is received upon calling the launchLoginFlow API is parsing the response value through the handleLoginData.
* After the parsing, the response result is passed through the LoginFlowListener which was delivered upon calling the launchLoginFlow.
*/
if (resultCode == RESULT_OK) {
if (IapPlugin.INSTANCE.mPurchaseClient.handleLoginData(data) == false) {
// listener is null
}
} else {
// user canceled , do nothing..
}
break;
}
}
This is a sequence where Android calls Unity through the connection listener. Only one Action event is configured since it consists only of success and error strings. The string types of the result value received from the callback are as follows.
onSuccess: a success response to the login success.
onErrorRemoteException
onErrorSecurityException
onErrorNeedUpdateException
onError: if failed, an error code will be passed to the application. A code composed of numbers, and descriptions in the string form are passed in the form of ToString.
// ONE store Unity Plugin (Java)
PurchaseClient.LoginFlowListener mLoginFlowListener = new PurchaseClient.LoginFlowListener() {
@Override
public void onSuccess() {
unitySendMessage(gameObject, "LoginFlowListener", "onSuccess");
}
@Override
public void onErrorRemoteException() {
unitySendMessage(gameObject, "LoginFlowListener", "onErrorRemoteException");
}
@Override
public void onErrorSecurityException() {
unitySendMessage(gameObject, "LoginFlowListener", "onErrorSecurityException");
}
@Override
public void onErrorNeedUpdateException() {
unitySendMessage(gameObject, "LoginFlowListener", "onErrorNeedUpdateException");
}
@Override
public void onError(IapResult result) {
unitySendMessage(gameObject, "LoginFlowListener", "onErrorNeedUpdateException" + result.toString());
}
};
// Onestore_IapCallbackManager.cs (C#)
public static event Action<string> getLoginIntentEvent;
public void LoginFlowListener (string callback)
{
getLoginIntentEvent (callback);//just pass
}
// Onestore_IapResultListener.cs (C#)
void getLoginIntentEvent (string result)
{
AndroidNative.showMessage ("getLoginIntent ", result.ToString (), "ok");
}
Unbind Payment Operation
The calling direction is from top to bottom and Unity will call Android. Unbind the AIDL service binding.