Android Code : ทำ In App Billing ซื้อของหรือไอเท็มในแอป
สวัสดีครับ ผมมีโอกาสได้ทำเกี่ยวกับ In App Billing ขอเรียกสั้นๆว่า IAB หรือก็คือ การซื้อของในแอป ซื้อไอเท็ม ซื้อเหรียญในเกม จริงๆคำที่คุ้นหูกว่า คือ In-app Purchase แต่จะซ้ำของ iOS เพราะเขาทำมาก่อน ดังนั้น Google เลยเรียก In-app Billing แทน บทความนี้เลยจะบันทึกการทำ IAB สำหรับ android ซึ่งจริงๆการทำ IAB ปกติตามแบบฉบับจริงๆ จะยุ่งยากมาก แต่ว่าโลกก็งดงามสดใสขึ้นมาได้สักพักแล้ว เพราะมีคนทำไลบรารี่ให้ใช้ ดังนั้นเราจะมาใช้ไลบรารี่กัน
สามารถอ่าน รายละเอียดทั้งหมดได้จากตัว library บน github เลยได้เช่นกัน
https://github.com/anjlab/android-inapp-billing-v3
สร้างผลิตภัณฑ์
ก่อนอื่นต้องมี product ให้ซื้อก่อน เข้าไปที่ Developer console (ใครยังไม่มีบัญชี ให้ไปสมัครก่อนนะ)
https://play.google.com/apps/publish/
ไปที่เมนูผลิตภัณฑ์ในแอปพลิเคชัน ถ้ายังไม่มีก็สร้างก่อน
ใส่ไอดีและเลือกประเภท
ประเภทสมัครรับข้อมูล Subscription คือการสมัครแบบเก็บรายเดือน หรือรายปี สร้างได้แล้วจะไม่สามารถแก้ไขราคาได้ต้องระวังให้ดี
ประเภทซื้อสินค้า สามารถเปลี่ยนราคาภายหลังได้ มีทั้งแบบซื้อขาดกับซื้อได้เรื่อยๆ
จัดการตั้งชื่อ ใส่รายละเอียด
ใส่ราคา โดยมันจะมีการคำนวณราคาของเงินสกุลอื่นให้อัตโนมัติ แถมยังปัดให้เลขสวยในสกุลเงินอื่นๆด้วย
เสร็จแล้วก็ทำการบันทึก แล้วก็กดให้มันเปิดใช้งาน (Active)
และจะใช้ 1-2 ชั่วโมง รอให้ active
Public key
สิ่งที่ต้องใช้อีกตัวคือ key ที่ระบุว่าเป็นแอปเรา ให้เข้าไปที่ เมนู บริการและ API จะเห็นว่ามี key Base-64 encoded RSA ยาวๆ
ให้ทำการ copy ไว้
เพิ่ม Dependency
ใน Android Studio อันเชิญไลบรารี่ IAB v3 เข้ามาในโปรเจค ที่ build.gradle
repositories { mavenCentral() } dependencies { compile 'com.anjlab.android.iab.v3:library:1.0.+' }
เพิ่ม Billing Permission
ที่ AndroidManifest.xml เพิ่ม permission เกี่ยวกับการชำระเงิน
<uses-permission android:name="com.android.vending.BILLING" />
เริ่มต้น
ทำการกำหนดค่าตัวแปร global ดังนี้
PRODUCT_ID คือ ไอดี product ที่เราตั้งไว้
LICENSE ก็คือ public key base-64 ยาวๆ
MERCHANT_ID มันคือ ไอดีพ่อค้าของเรา เอาไว้การป้องกันการปลอมแปลง เผื่อมีคนมาเกรียนปลอม response แกล้งว่าส่งมาจาก Google Play (ไม่ต้องใส่ก็ได้ แต่แนะนำให้ใส่)
วิธีการ หา MERCHANT_ID คือ เข้าไปที่
https://payments.google.com/merchant
แน่นอนว่าใครยังไม่มีก็ต้องสมัครก่อน
ให้ไปที่ setting แล้วหา merchantId จากนั้นก็ทำมาใส่ในตัวแปร MERCHANT_ID
จะได้ตัวแปรเบื้องต้นดังนี้
private String PRODUCT_ID = "product" private String LICENSE_KEY = "..." private String MERCHANT_ID = "..."; private BillingProcessor bp; private boolean readyToPurchase = false;
ก่อนเรียก Billing จริงๆ ให้ตรวจสอบก่อนว่า อุปกรณ์รองรับ IAB หรือไม่ ถ้าไปรันใน google play เก่าๆ หรือใน Emulator ที่ไม่มี Google Play อาจจะแครชได้
if (!BillingProcessor.isIabServiceAvailable(getContext())) { Log.d("In-app billing service is unavailable, please upgrade Android Market/Play to version >= 3.9.16"); }
ที่ onCreate ของ Activity ก็เรียกให้ทำการ initBilling หรือตั้งค่าให้กับ Billing
onProductPurchased() จะถูกเรียกเมื่อ หลังจากกดซื้อของแล้ว
onPurchaseHistoryRestored() จะถูกเรียกทันทีหลังจากโหลดข้อมูลการซื้อจาก Google
onBillingError() จะถูกเรียกเมื่อ เกิดปัญหา เช่น อินเตอร์เน็ตเสีย
onBillingInitalized() จะถูกเรียกเมื่อ พร้อมให้ซื้อแล้ว
private void initBilling() { if (!BillingProcessor.isIabServiceAvailable(getContext())) { Log.d("In-app billing service is unavailable, please upgrade Android Market/Play to version >= 3.9.16"); } bp = new BillingProcessor(getContext(), LICENSE_KEY, new BillingProcessor.IBillingHandler() { @Override public void onProductPurchased(String productId, TransactionDetails transactionDetails) { // } @Override public void onPurchaseHistoryRestored() { MyUtil.log("onPurchaseHistoryRestored"); for (String sku : bp.listOwnedProducts()) Log.d("", "Owned Managed Product: " + sku); for (String sku : bp.listOwnedSubscriptions()) Log.d("", "Owned Subscription: " + sku); } @Override public void onBillingError(int errorCode, Throwable throwable) { // } @Override public void onBillingInitialized() { // readyToPurchase = true; } }); bp.loadOwnedPurchasesFromGoogle(); }
เมื่อสร้าง instance สำหรับ IAB แล้วก็ทำการเรียกให้โหลดสินค้าของลูกค้าคนนี้มาจาก Google เก็บไว้ใน cache
bp.loadOwnedPurchasesFromGoogle();
เมื่อเรียก method นี้ onPurchaseHistoryRestored() ของ bp จะถูกเรียกด้วย พร้อม parameter 2 ตัว เป็น list ของ Product ID ที่เคยซื้อ
ผลจากการตรวจสอบการสั่งซื้อ จะถูกส่งมาที่ onActivityResult ของ Activity ก็ให้เรียก method ดังนี้
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { MyUtil.log("onActivityResult in Fragment"); if (!bp.handleActivityResult(requestCode, resultCode, data)) { super.onActivityResult(requestCode, resultCode, data); } }
แต่หากใครเอา bp ไปไว้ใน Fragment ก็ต้องใส่ สองที่ โดยโค้ดด้านบนจะใส่ที่ Fragement
และโค้ดด้านล่างนี้ใส่ที่ Activity หรือก็คือ activity ได้รับ result ก็ส่งต่อไปให้ fragment นั่นแหละ
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); .. .. ((StoreFragment) fragment).onActivityResult(requestCode, resultCode, data); }
แสดงรายละเอียดผลิตภัณฑ์
ต่อมาหลังจากสร้าง Product แล้ว จะลองนำพวกราคา มาแสดงในแอปกัน
มี method get ให้ดึงข้อมูลหลายแบบ
สิ่งที่ต้องรู้คือ คลาสของข้อมูล รายละเอียด product คือคลาส SkuDetail
ดังนั้นเมื่อเรียก getPurchaseListingDetails() เพื่อดึงข้อมูลมาแสดง จะได้ SkuDetail มา
จะประกอบด้วย ชื่อ ราคา รายละเอียด สกุลเงิน (ตามเครื่องผู้ใช้)
อีกตัวคือคลาส TransactionDetail อันนี้จะเป็นข้อมูลประเภทการซื้อ
เช่นประวัติการซื้อ ซื้อเมื่อไหร่ orderId อะไรเป็นต้น
ถ้าอยากแสดงประวัติการซื้อก็เรียก getPurchaseTransactionDetails()
ลองเขียนปุ่มที่กดแล้วจะ log ข้อมูลชื่อ ราคา ออกมา
private void initInstance(View v) { btnUpgrade = (Button) v.findViewById(R.id.btn_upgrade); btnUpgrade.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { upgrade(); } }); } private void upgrade() { if (readyToPurchase) { SkuDetails sku = bp.getPurchaseListingDetails(PRODUCT_ID); if (sku != null) { Log.d( "title = " + sku.title); Log.d( "description = " + sku.description); Log.d( "priceText = " + sku.priceText); Log.d( "currency = " + sku.currency); Log.d( "productId = " + sku.productId); Log.d( "priceValue = " + sku.priceValue); Log.d( "priceLong = " + sku.priceLong); Log.d( "All = " + sku.toString()); }else{ Log.d("sku null"); } } }
การซื้อผลิตภัณฑ์
ซื้อขาด หมายถึงซื้อครั้งเดียว แม้ว่าผู้ใช้จะลบแอปเราไปแล้วก็สามารถมาซื้อซ้ำได้ฟรี
เรียกใช้คำสั่ง purchase และใส่ product id ลงไป
bp.purchase(this, PRODUCT_ID);
หรือจะซื้อแบบซื้อได้เรื่อยๆ เช่น เพรชในเกม จะใช้คำสั่ง consume
bp.consumePurchase(productId);
ซื้อแบบ subscribe คือสมัครรับข้อมูล ใช้ productId ต้องเป็น PRODUCT ของ แบบ subscribtion ด้วย
bp.subscribe(activity,productId);
แบบ subscription คือ จะเก็บเงินรายเดือน / รายปี
แน่นอนว่าพอซื้อเสร็จสิ้นแล้ว method onPriductPurchased() ใน bp จะถูกเรียก เราก็ทำส่งสินค้าให้ผู้ใช้ เช่น ถ้าผู้ใช้กดซื้อเพรชก็เพิ่มเพรชให้ โดยสามารถเช็คจาก parameter productId ว่าซื้ออะไรนั่นเอง
public void onProductPurchased(String productId, TransactionDetails transactionDetails) { // After purchased complete. }
ทดสอบการซื้อ
ต่อมาก็ต้องมาลองซื้อกันครับ หลักการง่ายๆคือ
อัพโหลด apk Releasedไปที่ ALPHA/BETA channel และจะพบว่ามีลิงค์ URL ให้เข้าร่วม ให้ copy ลิงค์นี้ไว้
เอาลิงค์ ส่งให้อีกเครื่อง ที่ไม่ใช่บัญชี Dev ของ IAB นี้
เอาเครื่องนั้น กดเข้าลิงค์ มันจะเปิดเว็บขึ้นมา ให้กดปุ่มเข้าร่วม beta testing ของแอป
แล้วเปิด Store โหลดแอป (beta) มา
ตรงนี้อาจต้องรอสักพัก ถึงจะมีให้โหลด
หลังจากดาวน์โหลดแอปได้แล้ว ก็เข้าแอปทดลองกดซื้อ
ย้ำว่า ถ้าเครื่องเป็นบัญชี Dev เดียวกับ IAB จะซื้อไม่ได้
แอปไม่ได้อยู่บน Release หรือ Alpha / Beta channel ก็จะซื้อไม่ได้เช่นกัน
และอย่าลืม Active Product ใน Dev console ด้วย
ถ้าทำถูกต้องจะสามารถกดซื้อได้
ดูรายการการสั่งซื้อ
เมื่อมีลูกค้ามาซื้อแล้ว เราสามารถมาดู order ได้ที่ Google Developer Console
ที่หัวข้อ OrderManagementPlace
ถ้าอยากยกเลิก order ก็กดคืนเงินได้ แล้ว Google จะโอนเงินคืนให้เต็มจำนวน
รายได้จากการขาย เราจะได้ 70% จะถูก Google แบ่งไป 30% ถือว่าเป็นค่าช่องทางการขาย (เสือนอนกินชัดๆ)
ผู้ใช้เคยซื้ออะไรบ้าง
วิธีก็คือ เรียก method ดังนี้ ก็จะได้ list ของ productId ที่เคยซื้อมาแล้ว
List<String> productOwnedId = bp.listOwnedProducts(); List<String> subscriptionOwnedId = bp.listOwnedSubscriptions();
การสร้าง Promo code
มีลูกเล่นอีกนิด Google play ให้ Dev สามารถสร้าง code ไปแจกเพื่อนๆได้ด้วย เอาไว้ แลกแอปฟรี หรือ แลก product ฟรี
แต่จะต้องเป็น product แบบซื้อขาด
ไปที่ Developer Console > โปรโมชัน > เพิ่มโปรโมชันใหม่
จากนั้นกรอกข้อมูลให้เรียบร้อย ใส่อายุได้มากที่สุดได้ 1 ปี
เสร็จแล้วจะได้ไฟล์ .CSV ที่ข้างในมี Promo code อยู่ตามจำนวนที่ต้องการ
การใช้ Promo code
วิธีนี้ง่ายที่สุด คือเข้าไปที่ Google Play > กดเมนูบนซ้าย > แลก แล้วใส่ code
รหัสนี้สามารถแลกได้เฉพาะสินค้าที่ซื้อขาดเท่านั้นนะ
ทำที่ใส่ Promo code ในแอป
เท่าที่ลองดูวิธีที่ง่ายที่สุดคือ ใช้ Intent URL นี่แหละ
อาจจะทำ EditText ให้ใส่ code ในแอป พอกดปุ่มแล้วก็จะเปิด Intent URL นี้ขึ้นมา มันจะเปิด Google Play ตรวจสอบ Promo code ให้
String code = "XXXX"; String url = "https://play.google.com/redeem?code=" + URLEncoder.encode(code, "UTF-8"); context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
จบแล้ว
การทำ IAB ก็เสร็จสิ้นเพียงเท่านี้ ถ้าใช้ BillingProcess หลายที่ ก็สร้างคลาสแยกขึ้นมา แล้วทำ interface ก็จะช่วยให้จัดการง่ายขึ้น ที่เหลือคือ พอขายได้ ก็ไปถอนเงินในเว็บ payment ขั้นต่ำ 1 USD ใครมีเทคนิคการขาย หรือวิธีสะกดจิตให้คนซื้อดีๆก็มาบอกกันด้วยนะ
ขอบคุณครับ หากคิดว่าบทความมีประโยชน์ก็ช่วยคอมเม้นและแชร์ด้วยนะครับ
ขอให้รวยขอให้รวย ที่มาช่วยงานบุญวันนี้
Reference
https://developer.android.com/training/in-app-billing/preparing-iab-app.html
https://gist.github.com/SuperThomasLab/6d44b4920dbdc8482a2467d95f66c5df
https://github.com/anjlab/android-inapp-billing-v3/issues