วิธีเตรียม Account สำหรับทดสอบ In-app Purchase by

31
Aug
1

เนื่องจากการทำ In-app purchase นั้น จะต้องมีการสร้าง product ขึ้นมาก่อนว่าชื่ออะไร ราคาเท่าไหร่ ทั้งฝั่ง iOS และ Android เรามาดูขั้นตอนกัน

Android

  1. Login เข้า https://play.google.com/apps/publish/
  2. เลือก Settings (Icon ฟันเฟือง)
  3. เลือก Account details
  4. ที่ License Testing ใส่ email ของ google account ที่จะให้เป็น tester ทดสอบได้แล้วกด save
  5. ตรง Merchant Account หน้าเดียวกันจะมีส่วนเชื่อมต่อกับ Google Wallet กด link ไปหากยังไม่ได้สร้างไว้ ระบบจะให้กรอกข้อมูลเพื่อสร้างเอาไว้รับเงินจากผู้ใช้
  6. สร้าง app ใหม่เพื่อทดสอบ หรือเลือก app เดิมที่มีอยู่
  7. Upload APK ที่มีการขอ Permission In-app Billing (หากแค่ทดสอบให้ upload เข้า alpha channel)
  8. เลือก In-app Products ที่เมนูทางซ้ายหลังเลือก app ที่เราต้องการใส่ in-app purchase
  9. ถ้าไม่มีปัญหาจะมีปุ่ม Add new product ให้กดได้ หากไม่มี ให้ทำข้อ 7 ใหม่
  10. กด Add new product แล้วเลือกเป็น Managed Product (สำหรับ API v3) แล้วใส่ Product ID เช่น com.lvup.item1
  11. กรอกข้อมูลต่างๆ ให้ครบแล้วกด Save
  12. ที่ข้างๆ ปุ่มเซพ เลือกจาก Inactive เป็น Activate เพื่อเริ่มใช้งาน
  13. สถาะ app ที่จะใช้ in-app ต้องเป็น Published เท่านั้น (ถ้ายังไม่ต้องการปล่อยให้ใช้ Alpha Channel ได้ แม้กด publish ก็ไม่เป็นไร)
  14. รอระบบ google update สักหลายชั่วโมงหน่อย ( 2-3 ชม.) แล้วทดสอบยิง In-app จากตัว app ของเราได้เลย
  15. กดเมนู Services & APIs (ใต้ In-app Products) จะมีส่วน YOUR LICENSE KEY FOR THIS APPLICATION ซึ่งให้ license key ส่วนนี้ไปใช้กับ library in-app purchase ที่เราใช้งาน
  16. upload apk ที่ใส่ license key ขึ้นไปเพื่อทดสอบ
  17. ทดสอบ reserved item ที่ google จองเอาไว้ให้ทดสอบโดยเฉพาะได้ตามหน้านี้
  18. ทดสอบ in-app จาก app ของเรา
  19. ข้อควรระวัง หมายเลข Build หรือ Bundle Version Code จะต้องเป็นเลข Build ที่เคย upload ขึ้น Store ไปแล้วเท่านั้น ห้ามใช้เลขที่มากเกินจริงจากที่มีใน Store (ถ้ามี script เปลี่ยนเลข Build อัตโนมัติควรระวังเป็นอย่างยิ่ง) ไม่อย่างนั้นจะเจอ error ฟ้องว่าหา item ชิ้นนี้ไม่พบ และห้ามใช้เลขที่ยังไม่ได้ใส่ permission billing ลงไป ไม่อย่างนั้นจะไม่สามารถใช้การได้

iOS

  1. login เข้า https://itunesconnect.apple.com
  2. เข้า Manage users
  3. เลือก Test User
  4. Add New User กรอกรายละเอียดแล้วเซพ ขั้นตอนนี้เป็นการสร้าง account เอาไว้ทดสอบ in-app
  5. กลับมาที่หน้าแรก เลือก Manage your apps
  6. สร้าง app ใหม่เพื่อทดสอบ หรือเลือก app เดิมที่มีอยู่
  7. เข้าไปใน app นั้นๆ แล้วเลือก Manage In-App Purchases ทางขวา
  8. เลือก Create New
  9. เลือก Consumable
  10. กรอกข้อมูลต่างๆ
  11. สำหรับ Price Tier จะเป็นส่วนเลือกว่าราคาเท่าไร ซึ่ง apple บังคับไม่ให้เราตั้งราคาเองได้อิสระ ต้องตั้งตาม apple กำหนดเท่านั้น โดยจะมี Tier ธรรมดา (ถ้า US ราคา 0.99 ราคาสกุลเงินอื่นจะแปลงจาก 0.99 มาตรงๆ) และ Alternate Tier (ราคาในสกุลเงินอื่นๆ จะพยายามลงท้ายด้วยเลข 9 ให้ ไม่ได้แปลงมาจากราคา US ตรงๆ กำไรอาจลดลงเล็กน้อย)
  12. กรอกครบกด Save ให้พนักงาน Apple ไป Review (Ready to submit) * ห้ามลืม upload screenshot for review ไม่งั้นจะทดสอบซื้อไม่ได้ อาจ upload รูปหลอกๆ ไปก่อน ค่อยมาแก้ไขเป็นรูปจริงที่หลังได้
  13. ที่ Device ที่จะทดสอบ ให้กด Setting -> Store Settings -> Sign out
  14. เปิด app ของเราขึ้นมาทดสอบ in-app โดยกดซื้อ
  15. ระบบจะปรากฏให้ใส่ account ก็กรอก test user ที่สร้างในข้อ 4 ไป
  16. กดซื้อเพื่อทดสอบ

เรียนรู้ การใช้งาน LogCat เพื่อหา error by

31
Aug
0

การโค้ดแอนดรอยด์ หรือ โปรแกรมใดๆ กับ error ผมว่าเป็นของคู่กันนะ ถ้าเราสามารถหา Error , เหตุผลของการ error ได้ การแก้ปัญหา Error ก็ไม่ใช่เรื่องยากถ้าเป็นใน eclipse แต่ที่เราจะพูดกันในวันนี้คือ Unity เวลา run ในเครื่องจริง(Android) ที่เรามีเครื่องมือในการค้นหา ข้อผิดผลาด Error ที่ชื่อว่า LogCat เอาไว้ค้นหา Error และ เหตุผมของการ Error

C:\>cd AndroidSDK\platform-tools
C:\AndroidSDK\platform-tools\> adb.exe logcat

STEP 1:

เปิด Terminal window(ก็ cmd.exe นั้นและ)

STEP 2:

C:\>cd AndroidSDK\platform-tools อันนี้ก็แล้วแต่เครื่องใครลงไว้ที่ไหนนะครับ

STEP 3:

C:\AndroidSDK\platform-tools\>adb logcat -s Unity

การเขียน Log ในแอป

ในการเขียนแอป การทราบว่า ตอนนี้แอนเราทำงานไปถึง ขั้นไหนแล้ว เพื่อการ Monitor การทำงานของแอป การเขียน Log ลงไปในโค้ดจึงมีความจำเป็น
ก็ใน c# ก็ Debug.Log (“OnClickToggleFemale”);  หรือ  Debug.Log (“Test ” , “OnClickToggleFemale”);  ครับยังไงก็ลองเอาไปเล่นกันดูนะครับ

[Unity] วิธีการส่งต่อโปรเจ็คหรือส่วนหนึ่งของโปรเจ็คโดยที่ไม่ติดไฟล์ขยะเหมือนกับการคัดลอก/วาง by

31
Aug
0

หลังจากที่ทาง Mobile Devs เรา ได้เผชิญความยากลำบากในการส่งต่อโปรเจ็ค หรือส่วนใดส่วนหนึ่งของโปรเจ็ค Unity เพราะแต่ก่อนจะใช้การ Copy/Paste ซึ่งโฟลเดอร์ของโปรเจ็คยูนิตี้นั้นมีไฟล์ขยะมากมาย ยิ่งถ้าเป็นโปรเจ็คขนาดใหญ่นี่มีโอกาส Copy/Paste นานหลายนาทีเลยทีเดียว แต่แล้ววันหนึ่ง Mr. Tosawat นามสมมติได้เสนอวิธีการส่งต่อโปรเจ็คด้วยการ Export Package… ซึ่งอาจจะใช้ได้ก็เป็นได้ ผมก็เป็นหนึ่งในผู้ร่วมทดสอบและก็ค้นพบว่า นอกจากวิธีจะกำจัดไฟล์ขยะ ส่งต่อได้ไว แล้วยังมีปัญหาตามมาน้อยที่สุดด้วย (แต่ก็อาจจะยังมีบ้าง) เกริ่นมานาน วิธีก็มีง่ายๆ เท่านี้แหละครับ

สังเกตได้ว่าขนาดจองโปรเจคมันใหญ่ยิ่งนัก

• ขั้นแรกให้เราเลือกที่โฟลเดอร์ที่เราต้องการจะส่งต่อ ถ้าทั้งหมดก็เลือกที่ Assets ได้เลย

• จากนั้นก็ไปที่ Assets -> Export Package…

หรือจะเข้ามาเลือกที่ส่วนนี้ก็ได้ (และสามารถเลือกบางส่วนออกไปได้)

ตั้งชื่อให้เรียบร้อย

จะเห็นได้ว่าขนาดไฟล์นั้นมัน!! เล็กกว่าการคัดลอกโฟลเดอร์หลายเท่าตัว

• จากนั้นก็ให้เราไปที่โปรเจ็คใหม่แล้วจัดการ Import ที่ Assets -> Import Package -> Custom Package…

เลือกทั้งหมด หรือเลือกบางส่วนที่จะนำมาใช้ได้

เท่านี้ข้อมูลทั้งหมดของโปรเจคนั้นก็จะมาอยู่ในโปรเจคใหม่เรียบร้อยแล้วครับผม

มาครบกันทั้งหมู่บ้าน

 

ลงสีทับเส้นใน SAI ง่ายๆด้วย Opacity Lock by

31
Aug
0

ผมเคยมีปัญหาว่าจะลงสีทับเส้นยังไงดี ตอนแรกสุดเลยใช้วิธีโง่มากคือ select ทั้ง layer แล้วลงสีไปใน selection นั้น ซึ่งไม่เวิร์คเลย เพราะตรงขอบๆของ selection มันจะแตกๆ

ต่อมาได้รู้จักกับ Ctrl+Alt+G ของ Photoshop ชีวิตก็ดีขึ้นมา

เคยเขียนเรื่องนี้แล้วที่ http://blog.levelup.in.th/2012/06/28/how-to-color-hair-simply-%E0%B8%A5%E0%B8%87%E0%B8%AA%E0%B8%B5%E0%B8%9C%E0%B8%A1%E0%B8%87%E0%B9%88%E0%B8%B2%E0%B8%A2%E0%B9%86/

แต่กระนั้น ก็ยังคงนึกว่าทำได้แต่ใน Photoshop ผมเลยต้องวาดเส้นลงสีจุดอื่นๆใน SAI แล้วค่อยย้ายไปลงสีเฉพาะเส้นใน Photoshop มาซักระยะ

แต่วันนี้ก็พึ่งมารู้ว่าใน SAI แม่งก็ทำได้นี่หว่า วิธีการเป็นดังนี้ครับ

1. ติ๊ก Opacity Lock ที่ Layer เส้น

2.ลงมือปาดสีเข้าไป

3.เสร็จ

Unity Soomla Android In App Purchase(IAP) by

31
Aug
0

วันนี้เราจะมาสอนวิธีการใส่ In App Purchase ใน App ของเรากันนะครับ โดยใช้ Library ที่ชื่อว่า Soomla นะครับ ซึ่งตัว Soomla นี้เป็น Library ที่สามารถทำ In App Purchase ได้ทั้งฝั่ง Android และ iOS เลยนะครับ แต่วันนี้เป็นของฝั่ง Android นะครับ ของ iOS จะยกไปไว้คราวหน้านะครัช

วิธี Import Library และ Settings ค่าก่อนเริ่มต้น

  • ขั้นแรก ให้ Download Soomla จากที่นี่ ก่อนนะครับ
  • Import Soomla จาก Unity package ที่ Download มาใน Project ของเรานะครับ
  • Build Project ให้เป็น .apk และ Upload ขึ้นไปบน Google Console
    ** ต้องใส่ Keystore, Keystore password, เลือก Alias และใส่ Alias password ให้ครบก่อน (ใส่ได้ที่ Build Settings => Player Settings => Publishing Settings)
    *** หากยังไม่มี Keystore แนะนำให้ไปสร้างจากเครื่องที่เป็น iOS เพราะจากประสบการณ์ที่ผ่านมาเคยสร้างจากเครื่อง Windows แล้ว Keystore ใช้ไม่ได้ Sign ไม่ผ่าน – -”
  • เพิ่ม In App Products ใน Google Console อย่าลืมตั้งเป็น Active
    ** ตรงนี้กว่าที่ In App Products จะสามารถใช้ได้จริงอาจจะกินเวลาหลายชั่วโมงหรือ เป็นวันก็เป็นได้
  • เพิ่ม Testing Google Account ใน Google Developer Console (อันอื่นที่ไม่ใช้ Developer Account)
  • ใน Unity หลังจาก Import Soomla Package เสร็จแล้ว ใน Tap Window จะมี ตัวเลือก Soomla เพิ่มขึ้นมา ให้เลือก และ เลือก Edit Settings (Window => Soomla => Edit Settings) ใส่ Soomla Secret (ใส่แล้วห้ามเปลี่ยนอีก) และ ในตัวเลือก Google Play ใส่ API Key ที่ได้จากใน Google Developer Console

ต่อไปเป็นตัวอย่างการนำ Library Soomla มาใช้นะครับ

  • สร้าง C# Script ใหม่ให้ชื่อว่า StoreAssets ซึ่งสืบทอดมาจาก IStoreAssets อีกทีนะครับ Script นี้จะมีหน้าที่ในการกำหนดค่าต่างๆเกี่ยวกับ Products ของเรานะครับ จะเพิ่มหรือแก้ไข Products ก็มาแก้ใน Script นี้เลยนะครับ

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using Soomla.Store;

    public class StoreAssets : IStoreAssets {

    public int GetVersion() {
    return 0;
    }

    public VirtualCurrency[] GetCurrencies() {
    return new VirtualCurrency[]{};
    }

    public VirtualGood[] GetGoods() {
    return new VirtualGood[] {ITEM1, ITEM2, ITEM3, PURCHASED};
    }

    public VirtualCurrencyPack[] GetCurrencyPacks() {
    return new VirtualCurrencyPack[] {};
    }

    public VirtualCategory[] GetCategories() {
    return new VirtualCategory[]{};
    }

    public NonConsumableItem[] GetNonConsumableItems() {
    return new NonConsumableItem[]{NO_ADDS_NONCONS, CANCELED, REFUNDED, ITEM_UNAVAILABLE};//add Names
    }

    /** Static Final members **/

    public const string NO_ADDS_NONCONS_PRODUCT_ID = "no_ads";

    public const string MY_TEST1_PRODUCT_ID = "item1";
    public const string MY_TEST2_PRODUCT_ID = "item2";
    public const string MY_TEST3_PRODUCT_ID = "item3";

    public const string ANDROID_TEST_PURCHASED_ID = "android.test.purchased";
    public const string ANDROID_TEST_CANCELED_ID = "android.test.canceled";
    public const string ANDROID_TEST_REFUNDED_ID = "android.test.refunded";
    public const string ANDROID_TEST_ITEM_UNAVAILABLE_ID = "android.test.item_unavailable";

    /** Market MANAGED Items **/

    public static NonConsumableItem NO_ADDS_NONCONS = new NonConsumableItem(
    "No Ads",//Name
    "Test purchase of MANAGED item.",//Description
    "no_ads",//id
    new PurchaseWithMarket(new MarketItem(NO_ADDS_NONCONS_PRODUCT_ID, MarketItem.Consumable.NONCONSUMABLE , 0.99))
    );
    public static VirtualGood ITEM1 = new SingleUseVG(
    "Item 1", // name
    "Test purchase of Item 1.", // description
    "item1", // id
    new PurchaseWithMarket(new MarketItem(MY_TEST1_PRODUCT_ID, MarketItem.Consumable.CONSUMABLE , 0.99f))
    );
    public static VirtualGood ITEM2 = new SingleUseVG(
    "Item 2", // name
    "Test purchase of Item 2.", // description
    "item2", // id
    new PurchaseWithMarket(new MarketItem(MY_TEST2_PRODUCT_ID, MarketItem.Consumable.NONCONSUMABLE , 0.99f))
    );
    public static VirtualGood ITEM3 = new SingleUseVG(
    "Item 3", // name
    "Test purchase of Item 3.", // description
    "item3", // id
    new PurchaseWithMarket(new MarketItem(MY_TEST3_PRODUCT_ID, MarketItem.Consumable.NONCONSUMABLE , 0.99f))
    );
    public static VirtualGood PURCHASED = new SingleUseVG(
    "ANDROID TEST PURCHASED", // name
    "Description for: android.test.purchased.", // description
    ANDROID_TEST_PURCHASED_ID, // id
    new PurchaseWithMarket(new MarketItem(ANDROID_TEST_PURCHASED_ID, MarketItem.Consumable.NONCONSUMABLE , 0.99f))
    );
    public static NonConsumableItem CANCELED = new NonConsumableItem(
    "ANDROID TEST CANCELED", // name
    "Description for: android.test.canceled.", // description
    ANDROID_TEST_CANCELED_ID, // id
    new PurchaseWithMarket(new MarketItem(ANDROID_TEST_CANCELED_ID, MarketItem.Consumable.NONCONSUMABLE , 0.99f))
    );
    public static NonConsumableItem REFUNDED = new NonConsumableItem(
    "ANDROID TEST REFUNDED", // name
    "Description for: android.test.refunded.", // description
    ANDROID_TEST_REFUNDED_ID, // id
    new PurchaseWithMarket(new MarketItem(ANDROID_TEST_REFUNDED_ID, MarketItem.Consumable.NONCONSUMABLE , 0.99f))
    );
    public static NonConsumableItem ITEM_UNAVAILABLE = new NonConsumableItem(
    "ANDROID TEST ITEM_UNAVAILABLE", // name
    "Description for: android.test.item_unavailable.", // description
    ANDROID_TEST_ITEM_UNAVAILABLE_ID, // id
    new PurchaseWithMarket(new MarketItem(ANDROID_TEST_ITEM_UNAVAILABLE_ID, MarketItem.Consumable.NONCONSUMABLE , 0.99f))
    );
    }

  • สร้าง C# Script ให้ชื่อว่า Foo     Script นี้มีหน้าที่ดัก Event ต่างๆ
    using UnityEngine;
    using System.Collections;
    using Soomla;
    using Soomla.Store;

    public class Foo : MonoBehaviour {

    public UILabel Label;

    // Use this for initialization
    void Start () {
    StoreEvents.OnMarketPurchaseStarted += OnMarketPurchaseStarted;
    StoreEvents.OnMarketPurchase += OnMarketPurchase;
    StoreEvents.OnItemPurchaseStarted += OnItemPurchaseStarted;
    StoreEvents.OnItemPurchased += OnItemPurchased;
    StoreEvents.OnSoomlaStoreInitialized += OnSoomlaStoreInitialized;
    StoreEvents.OnUnexpectedErrorInStore += OnUnexpectedErrorInStore;

    SoomlaStore.Initialize(new StoreAssets());
    }

    string s = "";

    public void OnMarketPurchaseStarted( PurchasableVirtualItem pvi ) {
    Debug.Log( "OnMarketPurchaseStarted: " + pvi.ItemId );
    s += "OnMarketPurchaseStarted: " + pvi.ItemId+"\n";

    Label.text = s;
    }
    public void OnMarketPurchase( PurchasableVirtualItem pvi, string purchaseToken, string payload ) {
    Debug.Log( "OnMarketPurchase: " + pvi.ItemId + ", " + purchaseToken + ", " + payload);
    s += "OnMarketPurchase: " + pvi.ItemId + ", " + purchaseToken+ ", " + payload+"\n";

    Label.text = s;
    }
    public void OnItemPurchaseStarted( PurchasableVirtualItem pvi ) {
    Debug.Log( "OnItemPurchaseStarted: " + pvi.ItemId );
    s += "OnItemPurchaseStarted: " + pvi.ItemId+"\n";

    Label.text = s;
    }
    public void OnItemPurchased( PurchasableVirtualItem pvi, string payload ) {
    Debug.Log( "OnItemPurchased: " + pvi.ItemId + ", " + payload);
    s += "OnItemPurchased: " + pvi.ItemId + ", " + payload+"\n";

    Label.text = s;
    }
    public void OnSoomlaStoreInitialized(){
    Debug.Log( "OnSoomlaStoreInitialized" );
    s += "OnSoomlaStoreInitialized"+"\n";

    Label.text = s;
    }
    public void OnUnexpectedErrorInStore( string err ) {
    Debug.Log( "OnUnexpectedErrorInStore" + err );
    s += "OnUnexpectedErrorInStore" + err+"\n";

    Label.text = s;
    }
    public void buyItem1(){
    Debug.Log ("buy item1 click");
    s += "buy item1 click"+"\n";

    Label.text = s;

    //SoomlaStore.BuyMarketItem(StoreAssets.ITEM1.ItemId, "");
    StoreInventory.BuyItem( StoreAssets.ITEM1.ItemId );
    }
    public void buyItem2(){
    Debug.Log ("buy item2 click");
    s += "buy item2 click"+"\n";

    Label.text = s;

    //SoomlaStore.BuyMarketItem(StoreAssets.ITEM2.ItemId, "");
    StoreInventory.BuyItem( StoreAssets.ITEM2.ItemId );
    }
    public void buyItem3(){
    Debug.Log ("buy item3 click");
    s += "buy item3 click"+"\n";

    Label.text = s;

    //SoomlaStore.BuyMarketItem(StoreAssets.ITEM3.ItemId, "");
    StoreInventory.BuyItem( StoreAssets.ITEM3.ItemId );
    }

    public void buyPurchased(){
    Debug.Log ("buy purchased click");
    s += "buy purchased click"+"\n";

    Label.text = s;

    //SoomlaStore.BuyMarketItem(StoreAssets.PURCHASED.ItemId, "");
    StoreInventory.BuyItem( StoreAssets.PURCHASED.ItemId );
    }
    public void buyCanceled(){
    Debug.Log ("buy canceled click");
    StoreInventory.BuyItem( StoreAssets.CANCELED.ItemId );
    //SoomlaStore.BuyMarketItem(StoreAssets.ITEM2.ItemId, "");
    }
    public void buyRefunded(){
    Debug.Log ("buy refunded click");
    StoreInventory.BuyItem( StoreAssets.REFUNDED.ItemId );
    //SoomlaStore.BuyMarketItem(StoreAssets.ITEM2.ItemId, "");
    }
    public void buyItem_unavailable(){
    Debug.Log ("buy item_unavailable click");
    StoreInventory.BuyItem( StoreAssets.ITEM_UNAVAILABLE.ItemId );
    //SoomlaStore.BuyMarketItem(StoreAssets.ITEM2.ItemId, "");
    }
    }

  • สร้าง GameObject เปล่าขึ้นมา แล้วลาก Script Foo ใส่ไปใน GameObject นี้
  • ลาก Prefab ชื่อ StoreEvents และ CoreEvents ใส่ใน Scene ของเรา
    ** Prefab อยู่ใน Soomla => Prefabs
  • สร้างปุ่มที่เรียก Event BuyItem1 หรือ Item ไหนที่เราต้องการ
  • Build Project และ Upload ขึ้นไปที่ Google Developer Console และนำ .apk ตัวเดียวกันนี้ไป Install ลงในมือถือ Android และลองเล่น In App Purchase ดู ถึงตอนนี้ก็น่าจะใช้ได้แล้วนะคร้าฟฟ
    ** หากยังใช้ไม่ได้ ให้รอเวลาอาจจะติดที่ In App Products ยังไม่ Active ก็ได้ครับ ใช้เวลานานอยู่เหมือนกัน
กู้เงิน | เศรษฐกิจพอเพียง | สินเชื่อบุคคล | สมัครบัตรกดเงินสด | สินเชื่อ | เงินกู้ด่วน | ยืมเงินทรูมูฟ | เงินด่วนนอกระบบ