below link is the official tutorial, you should definitely go through it first
https://github.com/soomla/unity3d-store
Itune Connect Setup:
---------------------------
step1: login to https://itunesconnect.apple.com
step2: Create your app in itune connect, remember the bundle id
step3: Create in app purchase Item
-> say you have 3 in app purchase item, you need to create 3 product ID
step4: Create a sandbox test user in itune connect for you to test the in app purchase
Unity Integration:
------------------------
step1: create a new unity empty project
step2: download and import the Soomla IAP plugin from the unity asset store, its free
step4: create 2 c# file
-> one is mymain.cs
-> one is myasset.cs
before we create the file, let me explain as detail as possible
myasset.cs
----------------
here you define your item type,
Soomla prepared 4 type for you to use (you can see the example at MuffinRushAsset.cs)
1.VirtualCurrency
2. VirtualCurrencyPack
3. SingleUseVG
4. LifetimeVG
So for my example, I am trying to sell 10 gem for $0.99 , 100 gem for $4.99, 1000 gem for $9.99, therefore I am using the "VirtualCurrencyPack"
lets build the code step by step
//////////////////////////////////////////////////////////
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace Soomla.Store.Example
{
public class myasset : IStoreAssets
{
public int GetVersion()
{
return 0;
}
public VirtualCurrency[] GetCurrencies()
{
return new VirtualCurrency[]{};
}
public VirtualGood[] GetGoods()
{
return new VirtualGood[] {};
}
public VirtualCurrencyPack[] GetCurrencyPacks()
{
return new VirtualCurrencyPack[] {};
}
public VirtualCategory[] GetCategories()
{
return new VirtualCategory[]{};
}
}
}
///////////////////////////////////////////////////////////
above is the asset framework for you to start, you cannot reduce or remove anything or it will return error for you
then below is where you define your virtual currency and your virtual currency pack
///////////////////////////////////////////////////////////////////
/** Static Final Members **/
public const string CURRENCY_ITEM_ID = "gems";
public const string TEN_PACK_PRODUCT_ID = "zombiespitgem1";
public const string HUNDRED_PACK_PRODUCT_ID = "zombiespitgem5";
public const string THOUSAND_PACK_PRODUCT_ID = "zombiespitgem10";
/** Virtual Currencies **/
public static VirtualCurrency GEMS_CURRENCY = new VirtualCurrency(
"Gems", // name
"", // description
CURRENCY_ITEM_ID // item id
);
/** Virtual Currency Packs **/
public static VirtualCurrencyPack TENGEM_PACK = new VirtualCurrencyPack(
"10 Gems", // name
"Buy 10 gems", // description
"zombie_10", // item id
10, // number of currencies in the pack
CURRENCY_ITEM_ID, // the currency associated with this pack
new PurchaseWithMarket(TEN_PACK_PRODUCT_ID, 0.99)
);
public static VirtualCurrencyPack HUNDREDGEM_PACK = new VirtualCurrencyPack(
"100 Gems", // name
"Buy 100 gems", // description
"zombie_100", // item id
100, // number of currencies in the pack
CURRENCY_ITEM_ID, // the currency associated with this pack
new PurchaseWithMarket(HUNDRED_PACK_PRODUCT_ID, 4.99)
);
public static VirtualCurrencyPack THOUSANDGEM_PACK = new VirtualCurrencyPack(
"1000 Gems", // name
"Buy 1000 gems", // description
"zombie_1000", // item id
1000, // number of currencies in the pack
CURRENCY_ITEM_ID, // the currency associated with this pack
new PurchaseWithMarket(THOUSAND_PACK_PRODUCT_ID, 9.99)
);
///////////////////////////////////////////////////////
So you can see my "VirtualCurrency" is GEMS_CURRENCY, and my 3 "VirtualCurrencyPack" is TENGEM_PACK, HUNDREDGEM_PACK and THOUSANDGEM_PACK
so make sure you put those on top of the "RETURN".....
one thing to notice is your PRODUCT_ID must match 100% in your itune connect PRODUCT_ID
FINAL myasset.cs look like below
////////////////////////////////////////////////////////////////
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace Soomla.Store.Example
{
public class myasset : IStoreAssets
{
public int GetVersion()
{
return 0;
}
public VirtualCurrency[] GetCurrencies()
{
return new VirtualCurrency[]{GEMS_CURRENCY};
}
public VirtualGood[] GetGoods()
{
return new VirtualGood[] {};
}
public VirtualCurrencyPack[] GetCurrencyPacks()
{
return new VirtualCurrencyPack[] {TENGEM_PACK,HUNDREDGEM_PACK,THOUSANDGEM_PACK};
}
public VirtualCategory[] GetCategories()
{
return new VirtualCategory[]{};
}
/** Static Final Members **/
public const string CURRENCY_ITEM_ID = "gems";
public const string TEN_PACK_PRODUCT_ID = "zombiespitgem1";
public const string HUNDRED_PACK_PRODUCT_ID = "zombiespitgem5";
public const string THOUSAND_PACK_PRODUCT_ID = "zombiespitgem10";
/** Virtual Currencies **/
public static VirtualCurrency GEMS_CURRENCY = new VirtualCurrency(
"Gems", // name
"", // description
CURRENCY_ITEM_ID // item id
);
/** Virtual Currency Packs **/
public static VirtualCurrencyPack TENGEM_PACK = new VirtualCurrencyPack(
"10 Gems", // name
"Buy 10 gems", // description
"zombie_10", // item id
10, // number of currencies in the pack
CURRENCY_ITEM_ID, // the currency associated with this pack
new PurchaseWithMarket(TEN_PACK_PRODUCT_ID, 0.99)
);
public static VirtualCurrencyPack HUNDREDGEM_PACK = new VirtualCurrencyPack(
"100 Gems", // name
"Buy 100 gems", // description
"zombie_100", // item id
100, // number of currencies in the pack
CURRENCY_ITEM_ID, // the currency associated with this pack
new PurchaseWithMarket(HUNDRED_PACK_PRODUCT_ID, 4.99)
);
public static VirtualCurrencyPack THOUSANDGEM_PACK = new VirtualCurrencyPack(
"1000 Gems", // name
"Buy 1000 gems", // description
"zombie_1000", // item id
1000, // number of currencies in the pack
CURRENCY_ITEM_ID, // the currency associated with this pack
new PurchaseWithMarket(THOUSAND_PACK_PRODUCT_ID, 9.99)
);
}
}
mymain.cs
-----------------
here you will try create 3 variable and few button let you click buy
example
Origem = how many gems in appstore when you first start the app
playergem = how many gems in the iphone now
this is because, let say user buy the "10 gem" pack 5 times, the appstore will record "50 gems", so let say the user spend 48 gems in the game, the user left with only 2 gems
so the variable will display
gems= 50
origems = 50
playergem = 2
then let say the user buy another 10 gems
so variable will display
gems = 60
origems = 50
playergem = 2
then our update function must perform the task
if(gems > origems)
playergems + 10
(meaning the user buy another extra 10 gems and so we need to add it into the playergem)
so lets start with the framework
////////////////////////////
using UnityEngine;
using System.Collections;
public class mymain : MonoBehaviour
{
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
}
}
////////////////////
When you first create your mymain.cs, it will look like the above, so lets first add a few button so it look like the screenshot
float originalWidth = 800.0f; // define here the original resolution
float originalHeight = 600.0f; // you used to create the GUI contents
private Vector3 scale;
int gems;
void OnGUI()
{
scale.x = Screen.width/originalWidth; // calculate hor scale
scale.y = Screen.height/originalHeight; // calculate vert scale
scale.z = 1;
GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, scale);
GUI.Box(new Rect(280f, 40f, 500f,300f), "");
GUI.Label(new Rect(300f,50f,1000f,40f),"<size=20>Gems: "+gems+"</size>");
if(GUI.Button (new Rect (300f,150f,250f,30f), "<color=white><size=20>Buy 10 gem $0.99</size></color>"))
{
}
if(GUI.Button (new Rect (300f,200f,250f,30f), "<color=white><size=20>Buy 100 gem $4.99</size></color>"))
{
}
if(GUI.Button (new Rect (300f,250f,250f,30f), "<color=white><size=20>Buy 1000 gem $9.99</size></color>"))
{
}
}
////////////////////
Okay, let me explain the GUI.matrix, because the iphone and ipad has many different kinds of screen resolution, you want your game screen to fit into all kinds of resolution, therefore you must define your original width and original height, and then scale accordingly to different screen sizes
then what i did is to create one variable "gems"
one GUI.box
one GUI.label
three GUI.button
next, we start to add in the soomla integration, so you initialize your asset using the SoomlaStore.Initialize( new myasset());
you can also initialize a few stuff, origems is to get how many gems inside appstore, because maybe the user already bought like 5 times previously so he have a lot of gems in the appstore, but not in his phone because he already used it inside his phone
/////////////////////////////////////
// Use this for initialization
void Start ()
{
//Handle the initialization of store events
StoreEvents.OnSoomlaStoreInitialized += onSoomlaStoreInitialized;
SoomlaStore.Initialize (new myasset()); //Intialize the store
origems= StoreInventory.GetItemBalance("gems"); //you want to know how many gems you got in the appstore
playergems= PlayerPrefs.GetInt("gems"); //you want to know how many gems you got in the playerpref
}
public void onSoomlaStoreInitialized()
{
}
////////////////////
Then, inside each of your buy button, you just use the function
StoreInventory.BuyItem(item_id);
because my item_id is "zombie_10" (check your item id in myasset.cs)
try and catch function is for you to capture log if error occured
//////////////////////////////////////////
try
{
StoreInventory.BuyItem ("zombie_10"); // if success
gems= StoreInventory.GetItemBalance("gems");
}
catch (Exception e) // if fail
{
Debug.Log ("SOOMLA/UNITY" + e.Message);
}
////////////////////
Then, inside your update function , you need to check every 2 second if the purchase is successful by using the function StoreInventory.GetItemBalance(itemid)
because my currency is "gems" so i keep checking if the gem inside appstore is larger than the one original in appstore, so i will then add up my playergem and save it into the playerpref
////////////////////
void Update ()
{
second+=Time.deltaTime;
//check every 2 second
if(second>2)
{
second=0;
gems= StoreInventory.GetItemBalance("gems"); //you want to know how many gems you got
if(gems>origems)
{
origems=gems;
if(playerchoice==1)
{
playergems +=10;
}
else if(playerchoice==2)
{
playergems +=100;
}
else if(playerchoice==3)
{
playergems +=1000;
}
PlayerPrefs.SetInt ("gems",playergems);
}
}
}
///////////////////
FULL CODE BELOW
///////////////////
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using Soomla;
namespace Soomla.Store.Example //Allows for access to Soomla API
{
public class mymain : MonoBehaviour
{
float originalWidth = 800.0f; // define here the original resolution
float originalHeight = 600.0f; // you used to create the GUI contents
private Vector3 scale;
int gems;
int origems; //say inside the store have 100 gem, you buy another 10, become 110, you want to know
int playergems; //say you have 2 gems left and you wanna buy another 10
int playerchoice; //we want to know player click item 1,2 or 3
float second;
private static mymain instance = null;
//public static List<VirtualCurrencyPack> VirtualCurrencyPacks = null;
/// <summary>
/// Initializes the game state before the game starts.
/// </summary>
void Awake()
{
if(instance == null){ //making sure we only initialize one instance.
instance = this;
GameObject.DontDestroyOnLoad(this.gameObject);
} else { //Destroying unused instances.
GameObject.Destroy(this);
}
}
// Use this for initialization
void Start ()
{
//Handle the initialization of store events
StoreEvents.OnSoomlaStoreInitialized += onSoomlaStoreInitialized;
SoomlaStore.Initialize (new myasset()); //Intialize the store
origems= StoreInventory.GetItemBalance("gems"); //you want to know how many gems you got in the appstore
playergems= PlayerPrefs.GetInt("gems"); //you want to know how many gems you got in the playerpref
}
public void onSoomlaStoreInitialized()
{
//VirtualCurrencyPacks = StoreInfo.CurrencyPacks;
}
// Update is called once per frame
void Update ()
{
second+=Time.deltaTime;
//check every 2 second
if(second>2)
{
second=0;
gems= StoreInventory.GetItemBalance("gems"); //you want to know how many gems you got
if(gems>origems)
{
origems=gems;
if(playerchoice==1)
{
playergems +=10;
}
else if(playerchoice==2)
{
playergems +=100;
}
else if(playerchoice==3)
{
playergems +=1000;
}
PlayerPrefs.SetInt ("gems",playergems);
}
}
}
void OnGUI()
{
scale.x = Screen.width/originalWidth; // calculate hor scale
scale.y = Screen.height/originalHeight; // calculate vert scale
scale.z = 1;
GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, scale);
GUI.Box(new Rect(280f, 40f, 500f,300f), "");
GUI.Label(new Rect(300f,40f,1000f,40f),"<size=20>Gems: "+gems+"</size>");
GUI.Label(new Rect(300f,70f,1000f,40f),"<size=20>OriGems: "+origems+"</size>");
GUI.Label(new Rect(300f,100f,1000f,40f),"<size=20>PlayerGems: "+playergems+"</size>");
if(GUI.Button (new Rect (300f,150f,250f,30f), "<color=white><size=20>Buy 10 gem $0.99</size></color>"))
{
//VirtualCurrencyPack pack1 = VirtualCurrencyPacks[0]; //define pack1 so that we know user buy this
playerchoice=1;
try
{
StoreInventory.BuyItem ("zombie_10"); // if success
gems= StoreInventory.GetItemBalance("gems");
}
catch (Exception e) // if fail
{
Debug.Log ("SOOMLA/UNITY" + e.Message);
}
}
if(GUI.Button (new Rect (300f,200f,250f,30f), "<color=white><size=20>Buy 100 gem $4.99</size></color>"))
{
playerchoice=2;
try
{
StoreInventory.BuyItem ("zombie_100"); // if success
gems= StoreInventory.GetItemBalance("gems");
}
catch (Exception e) // if fail
{
Debug.Log ("SOOMLA/UNITY" + e.Message);
}
}
if(GUI.Button (new Rect (300f,250f,250f,30f), "<color=white><size=20>Buy 1000 gem $9.99</size></color>"))
{
playerchoice=3;
try
{
StoreInventory.BuyItem ("zombie_1000"); // if success
gems= StoreInventory.GetItemBalance("gems");
}
catch (Exception e) // if fail
{
Debug.Log ("SOOMLA/UNITY" + e.Message);
}
}
if(GUI.Button (new Rect (300f,300f,400f,30f), "<color=white><size=20>DELETE ALL GEMS FROM APPSTORE</size></color>"))
{
StoreInventory.TakeItem ("gems",10000);
origems=StoreInventory.GetItemBalance("gems");
}
}
}
}
step5: drag the mymain.cs into any object in your scene, then you save your scene in unity
-> I drag it into my camera object, but is up to you
step6: build setting -> build
-> make sure app name 100% match ituneconnect
-> make sure bundle id 100% match ituneconnect
step7: open xcode , plug in your iphone, run
step8: in your iphone, setting -> itune & app store -> LOG OUT apple_ID
step9: go to your games, press the buy button
step10: key in the "TEST USER" apple id you created in itune connect
-> make sure there is a word "SANDBOX ENVIRONMENT" so that you dont get charged
step11: make sure everything working as intended
There you go, hopefully this will help you in your project and good luck =)
Wow..... impressive tutorial..... because of explanation.... Thanks.
ReplyDeleteawesome!u r the greatest!
ReplyDeleteI still would not quit my job though, as there isn't quite as much money in this as people think. Do it on the side until you are earning enough to quit your job. Or if you are still living with your parents and they support you, you could risk it for a few months and see how it goes.
ReplyDelete