آموزش پرداخت درون برنامه ای بازار ، صفر تا صد
:: مستندات بازار به روز شده است ! ، ممکن است بخش هایی از این آموزش با مستندات جدید تطابق نداشته باشد ! ، بازار همچنین REST API اش رو در مستندات اش اضافه کرده ، که برای برسی و تایید صحت پرداخت از سرور ، استفاده میشه :)
تغییرات آموزش جدید !
- آموزش بروز و کامل شد
- توضیحات بیشتری در مورد مصرف خرید اضافه شد
- سوالات دوستان ویرایش شد و پاسخ در خود سوال اضافه شد.
- تاپیک تمیز شد و پرسش و پاسخ های غیر مرتبط و تکراری حذف شد
توصیه میکنم با کلیک روی علامت زنگوله در این تاپیک مشترک بشید تا از تغییرات اش مطلع بشید
احتمالا شما هم قبول دارید که مستند سازی بازار در مورد پرداخت درون برنامه ای بسیار ضعیف هست و طبق مکاتبه ای که من با بازار داشتم خودشون هم این رو قبول دارند !
" بله حق با شماست، ما در حال حاضر مشغول آمادهسازی سند راهنمای پرداخت درونبرنامهای برای محیطهای غیربومی هستیم، با اتمام این پروژه، اسناد را بازبینی خواهیم کرد."
پس تصمیم گرفتم اطلاعات ام رو با شما به اشتراک بزارم :)
همون طور که اطلاع دارید ، بازار قابلیتی داره به نام پرداخت درون برنامه ای ، که به شما اجازه فروش محتوای دیجیتال رو میده ، حالا این محتوا میتونه به دو نوع باشه
- محتوای قابل مصرف (تمام شدنی – مثل خربد سوخت برای خودرو)
- محتوای غیر قابل مصرف (تمام نشدنی – مثل ارتقا به کاربر ویژه )
گام اول ، آماده سازی محیط توسعه !
ما در طول این پروژه از پکیج هایی که بازار در اختیارمون قرار داده استفاده میکنیم ، چون در سورس کد این پکیچ ها override وجود نداره و در محیط توسعه ی ما وجود override اجباری هست و نبودش خطایی رو ایجاد میکنه که باعث میشه برنامه اجرا نشه باید برای حل این مشکل به این سوال مراجعه کنید
بهترین کار ، استفاده تنظیم رویwarning هست ، چرا که ignore دیگه چیزی به ما نشون نمیده و این به دلایلی که استاد ذکر کردند خوب نیست !
بعد از انجام این کار ، دیگه مشکلی با فایل هایی که میخوایم وارد پروژه کنیم نداریم
این فایل رو دانلود کنید ، در پوشه ی Src پروژه تون از حالت فشرده خارج کنید ، ساختار پوشه ی Src شما باید به این شکل باشه
(ir پکیچ خودم هست ، ممکنه برای شما متفاوت باشه)
خوب حالا وارد محیط ایکلیپس بشید ، در قسمتی که پروژه ها رو میبینید ، ( workspace - package) راست کلیک و Refresh کنید ، ساختار پوشه ی Src باید به این شکل باشه (ir.negano.wallpapaer پکیچ کد های خودم هست ، مال شما اسمش فرق داره ، مهم نیست )
می بینید که دیگه اروری نیست (اگ باشه ، ارور های ساده و قابل حل هست ، یا هشدار که مهم نیست !)
گام بعد کدنویسی !
فعلا طبق مستندات ، غیر قابل استناد بازار میریم جلو !
مجوز پرداخت درون برنامه ای رو به Manifest اضافه کنید
<uses-permission android:name="com.farsitel.bazaar.permission.PAY_THROUGH_BAZAAR" />
پروژه را اجرا کنید ، اگه مشکلی نداشت ، وارد بازار بشید ، همین APK که تا اینجا بدست اومده رو آپلود کنید ، بعد آپلود متوجه میشید که این یکی با بقیه یه فرقایی داره !
البته نیازی به اضافه کردن پکیچ ها هم نبود ! ، یعنی وقتی مجوز درون پرداخت در Manifest باشه ، این قسمت فعال میشه پس اگه مشکل آپلود دارید میتونید اول یه برنامه ی جدید و فقط با مجوز اینترنت و بازار آپلود کنید (کم حجم تر میشه ! )
وارد می شید ، در قسمت محصولات ، محصول جدید ایجاد کنید ، خود بازار هم توضیح داده ، اما بازم میگم ، شناسهٔ کالا رو هرچی دوست دارید بزارید ، مثلا من میزارم "wallpaper2" - اگه مشکلی داشتید مستندات بازار برای مدیریت محصولات رو بخونید ( لینک )
حالا که محصول رو ساختید ، به 2 تا چیز نیاز دارید
- شناسه محصول
- کلید RSA
کلید RSA برنامه تون رو میتونید در قسمت ، برنامه های فروشنده > کلید RSA دریافت کنید ، یک رشته ی عجیب و طولانی
خوب به قول وردپرس "بزن بریم !"
اکتیویتی ای می خواین کاربر رو از اون به بازار منتقل کنید رو بسازید !
بازار میگیه این 5 فیلد رو به اکتیوتی اضافه کنید ، من میگم هرکدوم چیه !
// تگی که هر انقاقی بیفته با اون لاگ چاپ میکنه static final String TAG = ""; // شناسه ی محصول
// For me : "wallpaper2" as I told !
// بلـــــــــــــه فک کردی فقط خودت انگلیسی بلدی ! static final String SKU_PREMIUM = ""; // آیا کاربر ویژه هست ؟
// بیشتر هدفشون استفاده ازش در آخر کاره که اگه درست انجام شد
// true بشه boolean mIsPremium = false; // این مقدار تاثیری در خروجی نداره ، خود بازار هم نمی دونه چیه ! static final int RC_REQUEST =0 ; IabHelper mHelper;
برای استفاده از سرویس بازار ، ما باید اون رو Prepare کنیم ، برای انجام این آماده سازی ، بازار کد نا مشخصی نوشته بود که همین باعث کرش می شد !
چرا می گم کد نامشخص بود !
در این سیستم پرداخت امکان این وجود داره تا در شروع برنامه ، سریع سرور بازار چک بشه که آیا قبلا پرداخت کرده یا نه اما بازار به جای اینکه بگه این کد رو در شروع برنامه بزارید ، گفته در onCreate بزارید ! ، وقتی شما وارد صفحه پرداخت میشید ، سریع دکمه پرداخت رو میزنید ، چون هنوز نتیجه اون کوئری ( queryInventoryAsync ) نیومده ، در واقع سیستم آماده نیست ، پس کرش میکنه !
راهکار من چی بود ؟
ما 2 بار نیاز داریم درخواست آماده سازی بدیم ، یه بار موقع شروع برنامه که باید وضعیت prefrences ها رو بروز کنه ، یه بار هم تو صفحه پرداخت که باید سرویس رو برای پرداخت آماده کنه ، من تابع زیر رو تو کلاس G نوشتم
public static boolean prepareBazaarInAppBilling(final boolean requireUpdatePrefrences,
final QueryInventoryFinishedListener mGotInventoryListener) { try { mHelper = new IabHelper(G.context, base64EncodedPublicKey); Log.d(TAG, "Starting setup."); IabHelper.OnIabSetupFinishedListener listener =
new IabHelper.OnIabSetupFinishedListener() { @Override public void onIabSetupFinished(IabResult result) { Log.d(TAG, "Setup finished."); if ( !result.isSuccess()) { Log.d(TAG, "Problem setting up In-app Billing: " + result); } if (requireUpdatePrefrences && mGotInventoryListener != null) { mHelper.queryInventoryAsync(mGotInventoryListener); } } }; mHelper.startSetup(listener); return true; } catch (Exception e) { e.printStackTrace(); return false; } }
چون این تابع به همون کلید و RSA و اینها نیاز داره من اونها رو تو کلاس G تعریف کردم ، پس ما به بازار کاری نداریم که میگه تو oncreate اکتیویتی پرداخت تعریف کنید
حالا من این تابع رو یه بار تو صفحه ی splash برنامه فراخوانی میکنم ، که تا splash رو نشون بده ، بازار هم آمار رو به ما بده پس تو اکتیویتی اسپلش اینجوری کد میزنم
QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
@Override
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
if ( !result.isFailure()) {
boolean state = inventory.hasPurchase(G.SKU_PREMIUM);
Log.i(G.TAG, "Bazaar say isPremiumUser is : " + state);
G.setPremiumState(state);
}
goToNextActivity();
}
};
G.prepareBazaarInAppBilling(true, mGotInventoryListener);
بهش میگم true , mGotInventoryListener یعنی بله نیاز دارم آماده سازی کنی و و و ...> وضعیت رو از بازار بگیری.
وقتی کارش تمو شد ، لیسنری که بهش دادم رو صدا میزنه ، منم گفتم اگه موفق به دریافت شده بودی ، تابع setPremiumState رو صدا بزن و بهش بگو مقدار رو بزار مقداری که بازار میگه (یعنی به بازار میگه آقا کاربر ویژه است یا نه ؟ میگه True یا False)
تابع setPremiumState هم میره تو Prefrence ها جواب بازار رو ثبت میکنه ، یعنی اگه کاربر مقدار ها رو دستی تغییر بده ، بازم موقع شروع اگه به نت وصل باشه ، وضعیت واقعی ایش رو از بازار میگیریم !
حالا در onCreate در اکتیویتی پرداخت کافی هست بگیم
G.prepareBazaarInAppBilling(false, null);
یعنی نرو سرور رو چک کن ، چون لزومی نداره ، یه بار اول برنامه چک کردیم ، اگه کاربر اینجا بلافاصله روی پرداخت کلیک کنه ، مشکلی پیش نمیاد و میره واسه پرداخت.
باید یک سری listener برای عملیات تعریف کنیم که از رویداد ها آگاه بشیم ، که بازار ( گوگل پلی دیگه ، بازار فقط کپی کرده ) به این شکل تعریف کرده بهتون میگم چی کار کرده ! (اما فعلا استفاده نکنید ، نمونه ی من هم ببینید )
QueryInventoryFinishedListener mGotInventoryListener = new QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
Log.d(TAG, "Query inventory finished.");
if (result.isFailure()) {
Log.d(TAG, "Failed to query inventory: " + result);
return;
}
else {
Log.d(TAG, "Query inventory was successful.");
// does the user have the premium upgrade?
mIsPremium = inventory.hasPurchase(SKU_PREMIUM);
// update UI accordingly
Log.d(TAG, "User is " + (mIsPremium ? "PREMIUM" : "NOT PREMIUM"));
}
Log.d(TAG, "Initial inventory query finished; enabling main UI.");
}
};
OnIabPurchaseFinishedListener mPurchaseFinishedListener = new OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
if (result.isFailure()) {
Log.d(TAG, "Error purchasing: " + result);
return;
}
else if (purchase.getSku().equals(SKU_PREMIUM)) {
// give user access to premium content and update the UI
}
}
};
ما مثل بازار نیومدیم تو صفحه ی پرداخت وضعیت سرور رو برسی کنیم و خیلی حرفه ای تر در شروع برنامه برسی میکنیم پس به mGotInventoryListener در اکتیویتی پرداخت نیازی نیست و در اسپلش ازش استفاده کردیم !
لیسنر onIabPurchaseFinished که واسه تموم شدن پرداخت هست ، یعنی کلا وقتی از بازار برگشت این لیستر فراخوانی میشه که من اون سوئیج بی روح (تو ورژن قبلی آموزش ) رو با دو تا توست ساده عوض کردم !
OnIabPurchaseFinishedListener mPurchaseFinishedListener = new OnIabPurchaseFinishedListener() {
@Override
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
// نتیجه یک فییلور / خطا بوده ؟
if (result.isFailure()) {
Log.d(G.TAG, "Error purchasing: " + result);
Toast.makeText(G.context, "پرداخت انجام نشد", Toast.LENGTH_LONG).show();
return;
}
else if (purchase.getSku().equals(G.SKU_PREMIUM)) {
G.setPremiumState(true);
Toast.makeText(G.context,
"با تشکر ، شما با موفقیت به کاربر ویژه ارتقا پیدا کردید",
Toast.LENGTH_LONG).show();
finish(); // صفحه ی پرادخت رو میبندیم
}
}
};
شما میتونید بر اساس این سند توست های کامل تری چاپ کنید و کاربر رو بیشتر در جریان بزارید !
حالا کافیه تو هر رویدادی که دوست دارید (مثل کلیک شدن یک دکمه ) این کد رو قرار بدید
btnGoToBazaar.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
try {
G.mHelper.launchPurchaseFlow(ActivityPayment.this,
G.SKU_PREMIUM, 0, mPurchaseFinishedListener);
}
catch (Exception e) {
e.printStackTrace();
Toast.makeText(G.context,
"Some Error Happend , Restart App please...",
Toast.LENGTH_SHORT).show();
}
}
});
خوب دید که من تو کچ کردن خطا هم توست میدم ، یعنی اگه خطا داشت کاربر نگه کار نمیکنه ، پیام دادم دوباره تلاش کن یا برنامه را ری استارت کن !
در نهایت هم باید این کد رو عینا بزاریم آخر اکتیویتی پرداخت
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if ( !G.mHelper.handleActivityResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (G.mHelper != null)
G.mHelper.dispose();
G.mHelper = null;
}
خوب ، اونایی که فقط واسه دسترسی ویژه میخواستن ، دیگه وقتشه برن به سلامت ، موفق باشید D:
مصرف کردن یک خرید ( اولین بار هست اینقدر توضیح میدم ، خود باز اصلا کد نمونه واسش نداده ! )
کاربر شما وقتی یک بار محصولی مثل "wallpaper2" را بخره ، دیگه بلافاصله بعد از باز شدن بازار ، بازار پاسخ مثبت میده و میگه آره ، پرداخت انجام شد ، و تمام اطلاعت مربوط به پرداخت قبلیش هست ، اما خوب ما میخوایم کاربر 10 دفعه بتونه بنزین بزنه ! :))
برای مصرف کردن خرید ، شما باید یک جدول در بانک تون درست کنید و محصولاتی که واسش پرداخت انجام شده رو در جدول ذخیره کنید. جدول ها به این شکل هستن
Products Table
-----------------------------------------
ID | name | SKU (کدی که از بازار گرفتی)
-----------------------------------------
1 | A | 0001
2 | B | 0002
paid products
-----------------------------------------
ID | prductID | itemType | signature | json | isConsume
1 | 2 | Value | value | JSON Value | 1
2 | 4 | Value | value | JSON Value | 0
ما برای اینکه بتونیم هر وقت خواستیم فرایند مصرف رو انجام بدیم باید ورودی ها رو ذخیره کنیم یـــــــــــــــــا برای اینکه مصرف اش کنیم ، یه بار اول درخواست خرید اش رو بدیم که بازار همین مقدار ها رو در قالب یک purchase به ما بده !
برای اینکه بتونید بعدا این خرید رو مصرف کنید ، باید در زمان خرید ( همون جای که من توست موفقیت رو نشون میدم ) به این شکل عمل کنید و این مقدار ها رو در بانک بریزید :)
String itemType = purchase.getItemType(); String signature = purchase.getSignature(); String json = purchase.getOriginalJson();
برای مصرف کردن خرید ، بعد از فراخوانی درخواست آماده سازی ، درخواست مصرف رو به mHelper میدیم !
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
G.prepareBazaarInAppBilling(false, null);
purchases purchase = new Purchase(itemType, jsonPurchaseInfo, signature)
G.mHelper.consumeAsync(purchases,lisetner);
}
});
این هم لیسنر اش :
IabHelper.OnConsumeFinishedListener listener = new IabHelper.OnConsumeFinishedListener() {
@Override
public void onConsumeFinished(Purchase purchase, IabResult result) {
// TODO Auto-generated method stub
if(result.isSuccess()){
// Consumed !
}
}
};
من وقتی میخام صفحه پرداختم رو اجرا کنم این خطا میاد و کرش میکنه : این خطا واسه چیه؟
06-15 11:30:38.733: E/AndroidRuntime(1579): java.lang.RuntimeException:
Unable to start activity
ComponentInfo{....pardakht/....Pardakht}:
java.lang.IllegalStateException: IAB helper is not set up. Can't
perform operation: launchPurchaseFlow
پاسخ A.L.U
علت خطا آماده نبودن Helper هست ، همون طور که در آموزش جدید توضیح دادم و با تابعی که نوشتم فقط در شروع برنامه بازار رو برسی میکنیم ، پس دیگه در صفحه پرداخت نیاز به لودینگ نداره و کاربر میتونه سریع پرداخت رو انجام بده.
بهتر هست قبل از شروع پرداخت از نصب بودن بازار مطمئن بشیم
public static boolean isPackageInstalled(String packagename) {
PackageManager pm = context.getPackageManager();
try {
pm.getPackageInfo(packagename, PackageManager.GET_ACTIVITIES);
return true;
}
catch (NameNotFoundException e) {
return false;
}
}
if (isPackageInstalled("com.farsitel.bazaar")) {
// بازار نصب است
}
توضیح کامل تر در : 4 امین محتوا (سومین پاسخ)
سلام، ببخشید من هی این تاپیک رو میارم بالا. پرداخت برنامه من دست شد و گذاشتمش بازار جهت بررسی اما یهو امروز دیدم باز کرش میکنه، این شد که سریع از حالت بررسی خارجش کردم، شانس آوردم تایی نشده بود.(این تاخیرهای بازار یجا مفید واقع شد!)
الان این پیغام رو میده :
06-22 16:47:26.292: E/AndroidRuntime(2246): java.lang.IllegalStateException:
Can't start async operation (launchPurchaseFlow)
because another async operation(refresh inventory) is in progress.
شماره خطی هم که خطا داره همون خطیه که بازار رو فراخوانی میکنم .
ممنون میشم راهنمایی کنید،
آموزش با توضیحات این پاسخ ام بازنویسی شد !
سلام ، بالاخره امتحان های من تموم شد و فرصت شد تا به عنوان شروع مجدد طبق قولی که به دوستان دادم ، یه سری توضیحات اضافه در مورد پرداخت درون برنامه ای بازار بدم ، خوب اینها فقط اظهار نظر شخصی من هست ، پس اگر اشتباه میکنم ، لطفا اساتید من رو به مسیر درست هدایت کنند :)
بازار یه سری کد رو از سورس کد های گوگل پلی کور کورانه کپی کرده و طبق اون این سیستم رو راه اندازی کرده و مشکلات زیادی هم داره که خودشون بهتر از ما به این موضوع واقف هستن ، اما ما خودمون هم باید طبق منطق خودمون سیستم رو برسی کنیم ، که من این کار رو انجام دادم و برداشت ام این بود !
1- چرا باید در هنگام باز شدن اکتیویتی پرداخت درخواستی به سرور ارسال بشه ؟
بازار اصرار داره در onCreate ما یک متد رو به شکل زیر فراخوانی کنیم ، در طول اجرا این متد هم یک دیالوگ لودینگ نشون بدیم :|
mHelper.queryInventoryAsync(mGotInventoryListener);
چرا من با این کار مخالف ام ؟
- ما معمولا قبل از باز شدن صفحه ی پرداخت به اطلاعات ویژه بودن یا نبودن کاربر درسترسی داریم ، پس نیازی نیست به بازار درخواست بدیم که یه برسی سریع داشته باشه !
- فرض رو بر این بگیریم ، کاربر برنامه رو حذف کرده و دوباره نصب کرده ، اگر این کار رو انجام ندیم چی میشه ؟ ، خوب هیچی ، برنامه به عنوان کاربر معمولی ، کاربر رو به صفحه پرداخت هدایت میکنه ، کاربر روی دکمه ی پرداخت کلیک میکنه اما بازار بلافاصله متوجه میشه کاربر قبلا پرداختی داشته ، بنابراین ، ResultCode 0 یعنی موفق و Token خرید قبلی رو در پاسخ بر میگردونه.
با حذف اون قسمت دیگه حتی باز شدن صفحه ی پرداخت در onCreate اکتیویتی هم باعث کرش نمیشه ، علت کرش ها این بود که هنوز بازار در حال انجام اون عملیات هست و ما به جای نشون دادن لودینگ میخوایم پرداخت رو انجام بدیدم !
با این کار دیگه به mGotInventoryListener هم نیازی نداریم و سورس کد کوتاه تر میشه !
پیش از شروع پرداخت ، برسی کنید که آیا بازار بر روی دستگاه نصب است یا خیر !
در صورتی که بازار نصب نباشه ، عملا کار ما بیهوده است یعنی پرداخت غیر قابل انجام هست ، با این تابع میتونیم از نصب بودن هر پکیجی مطمئن بشیم :)
public boolean isPackageInstalled(String PackageName) {
PackageManager manager = getPackageManager();
boolean isAppInstalled = false;
try {
manager.getPackageInfo(PackageName, PackageManager.GET_ACTIVITIES);
isAppInstalled = true;
}
catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return isAppInstalled;
}
مثلا برای برسی نصب بودن بازار به این شکل عمل میکنیم :
if (isPackageInstalled("com.farsitel.bazaar")) {
// Bazar is installed
}
else {
// Bazar is not installed
}
پس اگر بازار نصب بود باید عملیات پرداخت را شروع کنیم ! ، اما ممکنه هر خطایی اتفاق بی افته شایع ترین نوع خطا مربوط به همون Async نبودن هست (مورد اول ، queryInventoryAsync ) پس ما احتمالا کمتر کرش داریم (چون از اون استفاده نمی کنیم ) ، اما بازم نمیشه خطاهای احتمالی رو نادیده گرفت ، پس با یه Try , Catch از کرش کردن برنامه جلوگیری می کنیم
if (isPackageInstalled("com.farsitel.bazaar")) {
// Bazar is installed
try {
mHelper.launchPurchaseFlow(this, SKU_PREMIUM, 0, mPurchaseFinishedListener);
}
catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Reopen App and Try Again", Toast.LENGTH_SHORT).show();
}
}
else {
// Bazar is not installed
//open Bazzar Home Page To Download It !
}
و دیگر هیچ !
سلام
یه سوال داشتم، من یک دیالوگ دارم که توش 4 تا محصول متفاوت از هم هست، کاربر میتونه با دکمه های رادیویی یک محصول رو انتخاب و پرداخت کنه، قیمت محصولات هم متفاوته. ازونجایی که مقدار دهی موقع ساختن اکتیویتی انجام میشه، من چطوری میتونم مقدار SKU_PREMIUM رو توی دیالوگ تغییر بدم؟
پاسخ A.L.U
بر اساس آموزش جدید ، ما SKU_Premium رو در کلاس G تعریف کردیم ، پس بر اساس شرایط می تونه تغییر کنه بعد فرایند پرداخت رو شروع کنید !
کلید RSA هم که در تمام برنامه یکسان هست و نیازی به تغییرش نیست !
سلام
چند عدد سوال دارم :-)
1 - من میخوام بدونم حساب کاربر چقدر پول توش هست ؟ یعنی قبل از اینکه تموم بشه متوجه بشم و اخطار بدم که مثلا 10 بار دیگه بیشتر نمیتونه استفاده کنه ، بره شارژ کنه
2 - مقدار شارژ را میخوام بتونم خودم مشخص کنم. مثلا یک بار بگم 1000 تومان یک بار 10000 تومان
3 - فرض کنیم برنامه ما هزینه ماهیانه برای شارژ میگیره و میخوایم بعد از 30 روز حساب طرف از حالت پریمیوم در بیاد چه باید کرد؟
4 - اگر بخوایم برنامه در هنگاه پرداخت به ما گزینه بده که میخوای با بازار پرداخت کنی یا گوگل یا سیستمهای بانکی چه باید کرد؟
5 - فرض کنید برنامه ای مثل فروش شارژ نوشته ایم ، شارژ 2000 تومانی را که بفروشیم باز هم 600 تومان را بازار بر میدارد ؟ هزینه تمام شده شارژ بیشتر از 1400 میشود. در حالت فروش چگونه میتوانیم از این سرویس استفاده کنیم ؟
پاسخ A.L.U
- تا جایی که من میدونم شدنی نیست یعنی نمیشه از بازار بپرسی این کاربر ما چقدر پول داره !
- میتونید محصولات متفاوت ایجاد کنید و بر اساس پاسخی که به سوال قبل دادم ، در زمان اجرا محصول رو عوض کنید اما طبق مکاتبه ای که با بازار داشتم ، فعلا پرداخت مبلغی که در زمان اجرا تعیین بشه ، ممکن نیست
- بازار نوع محصول اکانت ماهیانه - اکانت سالیانه رو اضافه کرده ، طبق آموزش جدید ، وقتی در لحظه ی شروع از بازار سوال کنیم آیا ویژه هست یا نه و برنامه رو براساس اون پیش ببریم ، دقیقا یک ماه یا یک سال بعد از پرداخت ، برنامه غیر فعال میشه !
- باید سیستم بانکی خودتون رو پیدا کنید !
- بله ، اما بازار گفته در این موارد باهاش مکاتبه کنید !
سلام و خسته نباشید خدمت همه دوستان
این پرداخت درون برنامه ای هم داستانی شده واسه ما، لامثب هر جاشو میچسبی از ی جای دیگش میزنه بیرون!
من به یک کرش جدیدی برخوردم که توو لیست کرش های بالا نبود؛ وقتی کاربر رو با یک دکمه به صفحه بازار میفرستم اگر طرف وارد حسابش نشده باشه و دکمه برگشت رو بزنه، برنامه کرش میکنه !(و اگر توو حسابش باشه هیچ مشکلی پیش نمیاد!) چطور میشه از این کرش جلوگیری کرد؟!
سلام دادش یگانه عزیز میخاستم ببینم از پرداخت درون برنامه ای این قسمت کالاهای مصرفی رو بیشتر توضیح میدید گفتید از این کد استفاده کنیم
mHelper.consumeAsync(info, consumeFinishedListener);
حالا یه مثال کوچیک اگه ازش بزنید ممنون میشم کجا از این کد استفاده کنیم
پاسخ A.L.U
در آموزش جدید ، این مورد رو بیشتر توضیح دادم ، اما باز هم بین علما در این مورد اختلاف زیاد هست :))
بازار هم مثل همیشه پاسخ اش اینه :
"ما پرداخت درون برنامه ای خود را بر اساس پرداخت درون برنامه ای گوگل پیاده کرده ایم ، می توانید از مستندات گوگل استفاده کنید"
سلام بر همه اساتید من طبق دستور العمل پیش رفتم . 5 تا فیلد بازار رو گزاشتم قبل از oncreate و اون کدها رو هم که گفته شد طبق مستندات بازاره گزاشتم بعد از oncreate . کلید RSA رو هم توی گیومه گزاشتم . چند جا ایراد import گرفت که برطرف شد . اما ایراد آخر اینه که به mGotInventoryListener ایراد می گیره و میگه یا باید local variable بکنیش یا فیلدش بکنی و چند راه دیگه که گفتم فیلدش کن مشکل حل شد حالا باید چه کار کنم ؟ برنامه هم بدون مشکل اجرا شد . تا اینجای کار رو اومدم و بقیه اش رو نرفتم . یعنی نمی دونم باید چه کار کنم . ببینید در کل من یک صفحه پرداخت دارم که یک کلید توشه به نام btnpurchase حالا از این به بعد چیه و لیسنری که باید برای دکمه نوشته بشه چیه و چه کاری قراره بکنه ؟ ممنون دوستان لطفا به زبون ساده راهنمایی کنید ... عکسم هر کاری کردم آپلود نشد ولی کد رو میزارم :
import util.IabHelper;
import util.IabHelper.QueryInventoryFinishedListener;
import util.IabResult;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class ActivityPurchase extends Activity {
static final String TAG = "";
static final String SKU_PREMIUM = "";
boolean mIsPremium = false;
static final int RC_REQUEST =0 ;
IabHelper mHelper;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.purchase);
String base64EncodedPublicKey = "RSA code here ";
mHelper = new IabHelper(this, base64EncodedPublicKey);
Log.d(TAG, "Starting setup.");
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
private QueryInventoryFinishedListener mGotInventoryListener;
public void onIabSetupFinished(IabResult result) {
Log.d(TAG, "Setup finished.");
if (!result.isSuccess()) {
// Oh noes, there was a problem.
Log.d(TAG, "Problem setting up In-app Billing: " + result);
}
// Hooray, IAB is fully set up!
mHelper.queryInventoryAsync(mGotInventoryListener);
}
});
Button btnpurchase = (Button) findViewById(R.id.btnpurchase);
// btnpurchase.setOnClickListener(new OnClickListener() {
//
// @Override
// public void onClick(View arg0) {
// // TODO Auto-generated method stub
// Intent intent = new Intent(ActivityPurchase.this, ActivityIndex.class);
// ActivityPurchase.this.startActivity(intent);
// ActivityPurchase.this.finish();
//
// }
// });
}
}
پاسخ A.L.U
شما باید کارهای گفته شده در 6 امین محتوا (5 امین پاسخ) را انجام بدید و یک OnIabPurchaseFinishedListener بنویسید !
سلام دوستان، طبق دستوراتی که توی پست اومده داخل اکتیوتی منو یک رابطی قرار دادم که با اون کاربر به صفحه خرید منتقل میشه اما مشکل NullPointer Exception دارم !
پاسخ A.L.U
در آموزش جدید به این خطا اشاره کردم :
- مطمئن بشید که تابع prepareBazaarInAppBilling یا همون آماده سازی درون پرداخت بازار در oncreate فراخوانی شده و mHelper در اون نقطه null نیست
- برسی کنید آیا بازار نصب هست (بالا تر با تابع isPackageInstalled توضیح دادم ) من خودم در این حالت اگه بازار نصب نباشه ، دکمه پرداخت رو مخفی میکنم و دکمه دانلود بازار رو نمایش میدم :)
- مجوز بازار را در برنامه قرار بدید
بچه ها بازار ایمیل من رو جواب داد:
حالا من از قسمت "طی پرداخت یا خرید به مشکلی برخورد کرده اید؟" با اکانت خودم وارد شدم، دیدم توکن خرید هام هست، اما ما چجوری از این توکن در برنامه برای تشخیص اینکه آیا برنامه ما قبلا توسط کاربر خریداری شده یا نه استفاده کنیم؟
پاسخ A.L.U
بعد از برسی ، مشخص شد قسمت ارسال SKU به سرور بازار مشکل داشت
مجتبی ممنونم بابت توضیحات و زحمتی که کشیدی
آقا من خیلی مشکل دارم... حدودا 80% مطالب رو نمی فهمم چون اصلا هیچ دیدی نصبت به پرداخت درون برنامه ای ندارم.
مثلا من یه برنامه دارم که 100نا تصویر آنلاین نمایش میده حالا میخوام کاری کنم که کسانی که پول ندادند فقط 20تا تصویر رو ببینند چیکار باید کنم الان؟
سوال بعدیم که splash چیه که تو آموزش گفتی splash...
سوال دیگم اینه که برای پرداخت درون برنامه ای باید یک اکتیویتی ایجاد کنم و از داخل اون اکتیویتی کاربر پرداخت کنه؟ حالا این اکتیویتی وقتی کاربر پول رو پرداخت می کنه دیگه نمایش داده نمیشه؟ چه جوری :))
سوال آخر هم اینکه من یه برنامه مثل قسمت اول آموزش (تا جایی که تو manifest جواز بازار رو می نویسیم) ساختم و برای بازار ارسال کردم حالا چه جوری پاکش کنم؟ چون برنامه الکی بود...
ممنون میشم اگه راهنماییم کنید
سوالات hosseinAmini
- Splash رو دوستان توضیح دادن ، منظور صفحه ی نمایش لوگوی برنامه بود ، که ما میتونیم از یک تایم 2 ثانیه ی استفاده کنیم و کار برسی وضعیت کاربر از بازار رو در اونجا شروع کنیم
- شما با کلیک کردن رو یه دکمه وارد اکتیویتی پرداخت میشین ! ، پس وقتی اون دکمه مخفی بشه ، مثل این هست که اون اکتیویتی دیگه وجود نداره ! ، View.setVisibility(View.GONE)z
- من که خیلی با بازار کار نمیکنم ، ولی از دوستان شنیدم باید بهشون ایمیل بزنید :)
سوالات mohammad
- goToNextActivity متدی هست که نوشته بودم تا یک intent بسازه و startActivity کنه تا بره به اکتیویتی بعدی ! ، شما هم بسازید :)
- setPremiumState متدی بود که نوشته بودم ، تا مقدار boolean وضعیت کاربر رو بهش بدم ، و اون رو به عنوان وضعیت کاربر در preference ها ثبت کنم ! ، تا بعدا هم قابل استفاده باشه و یک متد به نام getPremiumState هم دارم !
- یک متغییر premiumState هم در کلاس G دارم که وضعیت فعلی کاربر هست ، مثلا میخوام بگم اگه ویژه بود یه دکمه ی پرداخت مخفی بشه
if(G.premiumState){
btnPay.setVisibility(View.GONE);
}
پاسخگویی و مشاهده پاسخ های این سوال تنها برای اعضای ویژه سایت امکان پذیر است .
چنانچه تمایل دارید به همه بخش ها دسترسی داشته باشید میتوانید از این بخش لایسنس این آموزش را خریداری نمایید .

