بخش مقدماتی¶
این بخش شامل تعاریف و مفاهیم مقدماتی است که بهتر است پیش از مطالعهٔ سایر بخشها با آنها آشنا باشید.
پرداخت درونبرنامهای اول مارکت چیست؟¶
پرداخت درونبرنامهای، که به اختصار به آن IAB (واژه ی مختصر شده ی In-App Billing) نیز میگوییم، یکی از خدمات ارائه شده توسط اول مارکت است که به شما امکان میدهد یک فروشگاه در برنامهٔ خود راهاندازی کنید و در آن محتویات دیجیتال مورد نظرتان را بفروشید. برای مثال، میتوانید از پرداخت درونبرنامهای برای فروش محتویات قابل دانلود مانند فایلهای موسیقی، محتویات مجازی مانند سکهٔ داخل بازیها یا بهروزرسانی برخی از بخشهای برنامه که باعث ایجاد تجربهٔ بهتری برای کاربر میشود استفاده کنید. از آنجایی که اول مارکت ازسه روش پرداخت (قبض ، اعتباراول مارکت، درگاه بانک) استفاده میکند، کاربران میتوانند به راحتی خرید خود را انجام دهند. و اول مارکت تمام مراحل خرید را مدیریت میکند و شما نیازی به مدیریت تراکنش ها ندارید و اول مارکت پس از اتمام فرآیند پرداخت، جزئیات پرداخت را به برنامهٔ شما باز میگرداند. پرداخت درونبرنامهای فقط در برنامههایی که دراول مارکت منتشر میکنید قابل پیادهسازی است. به غیر از داشتن حساب توسعهدهنده که برای انتشار برنامهها ساختهاید، نیازی به ساخت هیچ حساب دیگری نیست. برای کمک به پیادهسازی پرداخت درونبرنامهای از مستندات مربوط به پرداخت درونبرنامهای که برایتان آماده کردهایم، استفاده نمایید.
هشدار
پرداخت درونبرنامهای اول مارکت برروی کلیه دستگاه های اندرویدی نسخه 2.3.3 به بالا قابل اجرا میباشد.
تعاریف و مفاهیم پایه¶
در این بخش مفاهیم پایهای شرح داده میشوند که برای اضافه کردن پرداخت درونبرنامهای بایستی با آنها آشنا باشید.
API پرداخت درونبرنامهای¶
API پرداخت درونبرنامهای اول مارکت، ارائه ی پرداخت درونبرنامهای در برنامهتان را ساده میکند. با استفاده از API پرداخت درونبرنامهای اول مارکت میتوانید جزئیات محصول را از اول مارکت بپرسید، سفارش خرید محصول درونبرنامهای را بدهید، و فهرست محصولاتی که کاربر صاحب آنها است را از اول مارکت بپرسید. برنامهٔ اول مارکت درخواستها و پاسخهای پرداخت، بین برنامهٔ شما و سِرور اول مارکت را مدیریت میکند. در عمل برنامهٔ شما هیچگاه با سِروِراول مارکت به طور مستقیم در ارتباط نیست و هیچ ارتباط شبکهای بین خودش و سِروِر اول مارکت را مدیریت نمیکند. در عوض برنامهٔ شما درخواستهای پرداخت را (توسط ارتباطات بین پردازشی IPC) به برنامه اول مارکت میفرستد و پاسخها را از آن دریافت میکند. برنامهٔ اول مارکت برای تکمیل درخواستهای پرداخت درونبرنامهای باید بتواند از طریق اینترنت به سِروِر اول مارکت دسترسی پیدا کند.
محصولات درونبرنامهای¶
محصولات درونبرنامهای، کالاها یا خدمات دیجیتالی هستند که از درون برنامهٔ خود برای فروش به کاربر عرضه میکنید. مثالهایی از کالاهای دیجیتال عبارتند از: سکهٔ درون بازی، بهروزرسانی برخی از بخشهای برنامه که باعث ایجاد تجربهٔ بهتری برای کاربر میشود، محتوای جدید برای برنامه. پرداخت درونبرنامهای فقط برای فروش محتوای دیجیتالی است. در حال حاضر نمیتوانید از پرداخت درونبرنامهای برای فروش خدمات شخصی، محصولات فیزیکی یا هر چیزی که نیاز به تحویل فیزیکی داشته باشد، استفاده کنید. شما مسئول تحویل محتوای دیجیتالی هستید که در برنامهٔ خود به فروش میرسانید. اول مارکت هیچ مسئولیتی در قبال تحویل محتوا به کاربر برنامهٔ شما ندارد. محصولات درونبرنامهای همیشه تنها در یک برنامه قابل فروش هستند؛ یعنی، یک برنامه نمیتواند محصول درونبرنامهای برنامهٔ دیگری را بفروشد، حتی اگر آن محصول متعلق به توسعهدهندهای واحد باشد.
انواع محصولات درونبرنامهای¶
اول مارکت از انواع مختلف محصولات درونبرنامهای پشتیبانی میکند تا شما دستِ بازی در طرحریزی مالی برنامهٔ خود داشته باشید. تمام این محصولات را در پنل پرداخت اول مارکت(بخش محصولات/خدمات) تعریف میکنید. برای هر یک از محصولات میتوانید اطلاعاتی مانند شناسهٔ منحصر به فرد (SKU)، قیمت، عنوان و توضیح و ... را تعریف کنید. محصولات درونبرنامهای در حالت کلی در دستههای «فروشی» و «اشتراک» قابل تعریف هستند.
محصولات فروشی¶
محصولات فروشی، محصولاتی هستند که هنگام خرید یک مرتبه پرداخت برای آنها صورت میگیرد و به صورت مفهومی به دو دستهٔ محصولات «مصرفی» و «غیرمصرفی» تقسیم میشوند.شما میتوانید محصولات خود را به دو صورت مصرفی و غیرمصرفی به کاربر عرضه کنید.
محصولات مصرفی¶
محصولات مصرفی، کاربر میتواند چندین مرتبه این محصولات را خریداری کند (مانند سکهٔ داخل بازی، سوخت یا طلسم جادویی). لازم است پس از اتمام فرآیند خرید این نوع محصول توسط کاربر، خرید را اصطلاحاً مصرف کنید. در صورتی که پس از اتمام خرید این نوع محصول، خرید انجام شده را در برنامهٔ خود مصرف نکنید، اول مارکت اجازه نمیدهد کاربر مجدداً محصول مورد نظر را خریداری کند. برای یادگیری بیشتر دربارهٔ مصرف کردن خرید محصولات درون برنامهای، مصرف کردن خرید را مشاهده کنید.
محصولات غیرمصرفی¶
محصولات غیر مصرفی، هستند که کاربر یک مرتبه آنها را خریداری میکند اما تأثیر این خرید همیشگی است. مثل حذف تبلیغات از برنامه یا ارتقاء برنامه از نسخهٔ آزمایشی به نسخهٔ کامل است. این محصولات را نباید مصرف کنید تا برای همیشه دراول مارکت در حساب کاربر بمانند. بدین صورت اثر خرید این نوع محصولات دائمی خواهد بود و با حذف و نصب مجدد برنامهٔ شما از بین نخواهد رفت.
اشتراک (ماهانه|سالانه)¶
اشتراک محصولی است که به شما امکان میدهد محتوا، خدمات، یا ویژگیهایی را به کاربران برنامهتان با صورتحسابهای دورهای ماهانه یا سالانه بفروشید. میتوانید اشتراکها را تقریباً برای تمام انواع محتوای دیجیتال در بازی یا برنامهٔ خود تعریف کنید و بفروشید. برای اطلاع از روش انجام کار، بخش راهنمای اشتراکها را ببینید. شما میتوانید از جریان پرداخت مشابهی که برای محصولات درونبرنامهای فروشی استفاده میشود برای خرید اشتراکها و بازیابی اطلاعات اشتراک استفاده کنید. مثالی از کد پیادهسازی اشتراک را در اینجا ببینید.
هشدار
برخلاف محصولات درونبرنامهای مصرفی، اشتراکها قابل مصرف نیستند. برای کسب اطلاعات بیشتر در مورد انواع محصولات، شکل ۱ را ببینید.
شکل 1. انواع محصولات و نحوه خرید و مصرف محصولات مصرفشدنی
مصرف کردن خرید¶
زمانی که کاربر محصول درون برنامه ای خرید میکند، بلافاصله پس از خرید باید مصرف شود در غیر این صورت اول مارکت مانع از خرید مجدد آن میشود. درخواست مصرف را فقط برای محصولات مصرفی برنامهتان بفرستید.
توجه
برای کسب اطلاعات بیشتر در مورد انواع محصولات، شکل ۱ را ببینید.
پنل پرداخت اول مارکت¶
پنل پرداخت اول مارکت محلیست که از طریق آن میتوانید محصولات درونبرنامهای که برای فروش در نظر دارید را مدیریت کنید. برای کسب اطلاعات بیشتر مستندات مربوط به تعریف محصولات درونبرنامهای دراول مارکت را مشاهده کنید.
شناسهٔ محصول (SKU)¶
شناسهٔ یکتایی است که در زمان تعریف محصولات درونبرنامهای خود در پنل پرداخت، به آنها اختصاص میدهید. شناسهٔ محصول در تشخیص یکتای یک محصول هنگام ایجاد درخواست و ارسال پاسخهای مربوط به پرداخت درونبرنامهای کاربرد دارد. این شناسه متفاوت از نام محصول است و کاربر برنامه هنگام فرآیند پرداخت آن را نخواهد دید. دقت داشته باشید که شناسهها پس از تعریف قابل تغییر نیستند.
توکن خرید (purchaseToken)¶
رشتهای است که توسط اول مارکت برای شناسایی یکتای یک تراکنش پرداخت ساخته میشود.
اطلاعات اضافی توسعهدهنده (Developer Payload)¶
رشتهٔ دلخواهی است که حاوی اطلاعات تکمیلی مربوط به سفارش خرید است. به طور معمول این رشته به عنوان یک نشانه است که منحصراً این درخواست خرید را شناسایی میکند. توسعهدهنده هنگام ارسال درخواست خرید میتواند علاوه بر پارامترهای دیگر این رشته را نیز به اول مارکت بفرستد. در صورتی که این رشته مقداردهی شده باشد، اول مارکت به همراه پاسخ پرداخت این رشته را نیز برمیگرداند.
کلید عمومی پرداخت¶
زمانی که برای اولین بار پیشنویس برنامهٔ خود را در اول مارکت قرار میدهید، اول مارکت به صورت خودکار یک کلید گواهی عمومی (Public license key) برای آن تولید میکند. برای برقراری یک ارتباط امن بین برنامهٔ خود و سِروِرهای اول مارکت به این کلید نیاز دارید. این کلید برای هر برنامه یک مرتبه تولید میشود و زمانی که فایل APK برنامه را بهروز میکنید این کلید تغییر نخواهد کرد.
خرید محصولات¶
در این بخش به ترتیب: روند خرید، روند مصرف کردن خرید، و مراحل مدیریت خریدهای محصولات مصرفی شرح داده میشوند.
روند خرید¶
شکل ۲. مراحل پایهای برای درخواست خرید
- در اولین گام روند خرید، برنامهٔ شما بایستی به گونهای بفهمد که آیا نسخهٔ API پرداخت درونبرنامهای که استفاده میکند توسط اول مارکت پشتیبانی میشود یا خیر. برای این منظور یک درخواست
isBillingSupported
به اول مارکت میفرستد. - وقتی برنامهٔ شما شروع میشود یا کاربر وارد برنامه میشود (لاگین میکند)، فرصت مناسبی است که فهرست محصولاتی که کاربر صاحب آنها است را از اول مارکت بپرسید. برای این منظور یک درخواست
getPurchases
بفرستید. در صورتی که درخواست موفقیتآمیز باشد، اول مارکت یکBundle
حاوی فهرستی از شناسهٔ محصولات خریداری شده، فهرستی از جزئیات یک خرید و فهرستی از امضاهای خریدها را به برنامهٔ شما برمیگرداند. - معمولاً میخواهید کاربر را از محصولاتی که میتواند بخرد مطلع سازید. برنامهٔ شما میتواند یک درخواست
getSkuDetails
برای گرفتن جزئیات محصولات درونبرنامهای که در اول مارکت تعریف کردهاید بفرستد. برای این منظور بایستی فهرستی از شناسهٔ کالاهایی که میخواهید جزئیاتشان را بدانید را در درخواست خود مشخص کنید. در صورتی که درخواست موفقیتآمیز باشد، اول مارکت یکBundle
شامل جزئیات محصول (از قبیل قیمت، عنوان، توضیحات و نوع محصول) را برمیگرداند. - در صورتی که کاربر صاحب یک محصول درونبرنامهای نباشد (یعنی قبلاً آن را خریداری نکرده یا در صورت خرید محصولی از نوع مصرفی، خرید مورد نظر در برنامه مصرف شده باشد)، میتواند آن را خریداری کند. برای این منظور برنامهٔ شما یک درخواست
getBuyIntent
که در آن شناسهٔ محصول و سایر پارمترها مشخص شده است را به اول مارکت میفرستد. - اول مارکت
Bundle
ای که حاوی یکPendingIntent
است را برمیگرداند. برنامهٔ شما برای آغاز عملیات پرداخت از این Bundle استفاده میکند. - برنامهٔ شما با فراخوانی متد
startIntentSenderForResult
، اینتنت ارسال شده از اول مارکتPendingIntent
را اجرا میکند. - وقتی روند پرداخت پایان یافت (یعنی زمانی که کاربر محصول را خرید یا از خرید آن صرفنظر کرد) اول مارکت پاسخ را در قالب یک
Intent
به متدonActivityResult
برنامهٔ شما میفرستد. کد نتیجهٔonActivityResult
کدی است که بیانگر خرید موفق محصول یا لغو عملیات است. پاسخIntent
شامل اطلاعاتی دربارهٔ محصول خریداری شده، از جمله رشتهٔpurchaseToken
است که توسط اول مارکت برای شناسایی یکتای این تراکنش خرید ساخته شده است. اینIntent
همچنین شامل امضای خرید است که توسط کلید خصوصی توسعهدهنده امضا شده است.
توجه
برای یادگیری بیشتر در مورد فراخوانیهای API و پاسخهای سرور، بخش API Reference را مشاهده کنید.
روند مصرف کردن خرید¶
میتوانید از مکانیزم مصرف ارائه شده در API پرداخت درون برنامهای اول مارکت برای پیگیری مالکیت کاربر بر محصولات درونبرنامهای استفاده کنید. پس از اتمام یک خرید موفق توسط کاربر، خرید مورد نظر در اول مارکت ذخیره میشود. زمانی که کاربرِ برنامهٔ شما یک محصول درونبرنامهای را خریداری میکند از دید اول مارکت «صاحب آن» خواهد بود. کاربر نمیتواند محصولاتی که هماکنون صاحب آنها میباشد را مجدداً خریداری کند. برای این که امکان خرید مجدد این محصول توسط کاربری که هماکنون صاحب آن است فراهم شود، باید در برنامهتان یک درخواست مصرف برای آن محصول درونبرنامهای بدهید.
توجه
مصرف کردن محصول درونبرنامهای سبب میشود که اول مارکت دیگر کاربر را مالک آن محسوب نکند و اطلاعات خرید آن را دور بریزد.
هشدار
از بین انواع محصولات درونبرنامهای، فقط محصولات درون برنامهای مصرفی را مصرف کنید. اشتراک و محصولات درونبرنامهای غیرمصرفی را نباید مصرف کنید.
برای واضحتر شدن این مفهوم دیدن اینفوگرافیک تهیه شده در شکل ۱ میتواند مفید باشد.
برنامهٔ شما برای گرفتن فهرست محصولاتی که کاربر صاحب آنها است، یک درخواست getPurchases
به اول مارکت میفرستد. همچنین برنامهٔ شما میتواند برای مصرف محصولاتی که کاربر صاحب آنها است، یک درخواست مصرف توسط فراخوانی consumePurchase
به اول مارکت بفرستد. در آرگومان درخواست مصرف، بایستی توکن خرید (purchaseToken
) آن (رشتهٔ یکتایی که هنگام خرید آن محصول از اول مارکت دریافت کردهاید) را مشخص کنید. در نهایت، اول مارکت کد وضعیتی که مشخص میکند آیا مصرف با موفقیت ذخیره شده است یا خیر را بازمیگرداند.
شکل ۳. مراحل پایه برای درخواست مصرف
شما تصمیم میگیرید که محصولات درونبرنامهای خریداری شده را به چه شکلی در برنامهتان برای کاربر فراهم کنید (به این امر به اصطلاح «تأمین کردن محصول» میگوییم) و خود مسئول کنترل و پیگیری آن هستید. برای مثال، در صورتی که کاربر سکهی داخل بازی را خریداری کرده، بایستی مقدار دارایی سکهٔ کاربر در بازیتان را به میزان سکهای که خریداری کرده افزایش دهید.
هشدار
قبل از تأمین محصولات مصرفی در برنامهتان، شما باید درخواست مصرف را به اول مارکت فرستاده و پاسخی موفق از اینکه مصرف ذخیره شده است، دریافت کرده باشید.
مراحل مدیریت خریدهای محصولات مصرفی¶
در ادامه، روند پایه برای خرید یک محصول درونبرنامهای از نوع مصرفی را مرور میکنیم:
- روند خرید را با فراخوانی
getBuyIntent
آغاز کنید. - پاسخ
Bundle
را از اول مارکت دریافت کنید. این پاسخ شامل اطلاعاتی مبنی بر موفقیتآمیز بودن یا نبودن فرآیند خرید است. - اگر خرید موفقیتآمیز بود، خرید را با دستور
consumePurchase
مصرف کنید. - کد پاسخی که مشخص میکند مصرف موفقیتآمیز بوده است یا خیر را ازاول مارکت دریافت کنید.
- اگر مصرف موفقیتآمیز بود، محصول را در برنامهٔ خود تأمین کنید (عملیاتی که قرار بود با خرید محصول اتفاق بیفتد را انجام دهید).
متعاقباً، هنگامی که کاربر برنامه را اجرا میکند یا به برنامه وارد میشود (لاگین میکند)، باید وضعیت داراییهای کاربر را بررسی نمایید، اینکه چه محصولات مصرفی و یا غیرمصرفی دارد و آنها را چگونه باید تأمین کنید. روند پیشنهادی شروع برنامه برای زمانی که محصول مصرفی در برنامهتان دارید را در زیر مشاهده میکنید:
- برای دریافت محصولاتی که کاربر صاحب آنها است، درخواست
getPurchases
را به اول مارکت ارسال کنید. - اگر محصول قابل مصرفی وجود داشت، محصول را با دستور
consumePurchase
مصرف کنید. به این دلیل لازم است این کار را بکنید که ممکن است خرید محصول کامل شده باشد، اما قبل از ارسال درخواست مصرف آن، ارتباط قطع شده باشد. - کد پاسخی که مشخص میکند مصرف محصول موفقیت آمیز بود یا خیر را از اول مارکت دریافت کنید.
- اگر مصرف موفقیت آمیز بود، محصول را در برنامهٔ خود تأمین کنید.
کار با پنل مدیریت پرداخت¶
ایجاد لیست محصولات¶
پنل پرداخت اول مارکت به شما این امکان را میدهد که به ازای هر یک از برنامههایتان یک لیست جدا از محصولات داشته باشید. شما تنها وقتی میتوانید یک محصول را در برنامهتان به فروش برسانید که آن را در پنل پرداخت ثبت کرده باشید. توجه داشته باشید که هر برنامه لیست محصولات مربوط به خود را دارد و امکان فروش محصولات دیگر برنامهها در برنامهٔ شما وجود ندارد.
لیست محصولات مربوط به برنامهٔ خود را میتوانید با ورود به بخش برنامههای فروشنده مشاهده کنید.
در لیست محصولات برای هر محصول اطلاعاتی از قبیل شناسه محصول، توضیحات محصول و قیمت آن محصول وجود دارد. این لیست فقط شامل اطلاعات کلی دربارهٔ محصول شماست و به هیچ وجه محتوای محصول شما را شامل نمیشود. یعنی اینکه شما خودتان باید محصولی (محتوا) را که در برنامهتان میفروشید، به دست کاربر برسانید.
شکل 4. برای اضافه کردن محصول در پنل مدیریت پرداخت درون برنامهای دو راه دارید. یا اینکه محصولات را تک تک وارد کنید و یا اینکه از گزینهٔ ورود توسط CSV استفاده کنید.
اضافه کردن محصولات به صورت تک تک¶
برای اضافه کردن محصولات به صورت تک به تک از طریق پنل مدیریت پرداخت درون برنامهای باید مراحل زیر را طی کنید:
- به حساب کاربری خود وارد شوید.
- در پنل مدیریت پرداخت درون برنامهای وارد بخش برنامههای فروشنده شوید.
- بر روی گزینهٔ افزودن محصول کلیک کنید و اطلاعات مورد نیاز برای هر محصول را وارد کنید.
شکل 5
برای هر محصول موارد زیر را باید وارد کنید:
شناسهٔ کالا
- شناسهٔ کالای هر محصول در هر برنامه باید منحصر به فرد باشد. این شناسه باید با حروف کوچک لاتین یا یک عدد شروع شود و همگی کاراکترهای استفاده شده در آن باید فقط از حروف کوچک لاتین، اعداد لاتین، _ و نقطه باشند.
- شما به هیچ عنوان مجاز به ویرایش شناسهٔ یک محصول بعد از ایجاد آن نیستید و امکان استفادهٔ مجدد از این شناسهها نیز وجود ندارد.
- عنوان
- یک توضیح بسیار کوچک از محصول است که به ازای هر برنامهٔ شما باید منحصر به فرد باشد. ارائهٔ عنوان برای هر محصول ضروری است و پیشنهاد میشود برای نمایش بهتر طول عنوان بیش از ۲۵ کاراکتر نباشد.
- توضیحات
- یک توضیح مفصل برای محصولی که میخواهید بفروشید باید ارائه کنید. این توضیح در صفحهٔ پرداخت اول مارکت به کاربر نشان داده میشود. البته امکان استفاده از این توضیح در برنامهٔ خودتان نیز وجود دارد.
- قیمت
- برای هر محصول باید یک قیمت به ریال وارد کنید. حداقل و حداکثر این قیمت در قرارداد شما با اول مارکت مشخص شده است. قیمت محصول نمیتواند از مقداری که در قرارداد شما مشخص شده است، کمتر یا بیشتر باشد.
- برنامه
- در زمان اضافه کردن محصولات باید مشخص کنید محصولی که قصد اضافه کردن آن را دارید برای فروش در کدام یک از برنامههای شما ارائه میشود.
اضافه کردن محصولات به صورت دستهای¶
برای اضافه کردن محصولات به صورت دستهای میتوانید آنها را با فرمت مشخص از طریق یک فایل CSV
به لیست محصولات وارد کنید.
هشدار
قبل از ورود لیست محصولات یکبار از صحت شناسهٔ محصولات مطمئن شوید، زیرا بعد از وارد کردن امکان تغییر آنها وجود ندارد.
شکل 6
درون فایل CSV اطلاعات هر محصول را در سطری جداگانه با قالب زیر وارد کنید: (توجه کنید که از ویرگول(,) برای جدا کردن آیتمهای اصلی و از نقطه ویرگول (;) برای جدا کردن زیر آیتمها استفاده میشود).
“product_id”,”publish_state”,”purchase_type”,”autotranslate ”,”locale; title; description”,”autofill”,”country; price”
- “product_id”: شناسهی کالا یا همان SKU
- “publish_state”: وضعیت محصول که میتواند “published” به معنی فعال یا “unpublished” به منظور غیر فعال باشد.
- “purchase_type”: این فیلد هنوز پشتیبانی نمیشود و لازم است خالی وارد شود. یعنی به صورت “”.
- “autotranslate”: این امکان هنوز پشتیبانی نمیشود و لازم است “false” وارد شود.
- “locale; title; description”: عنوان و توضیحات محصول برای زبانهای فارسی و انگلیسی که به صورت زیر میبایست وارد شوند:
- “fa_IR; farsi-title; farsi-description; en_US; english-title; english-description”
- “autofill”: این امکان هنوز پشتیبانی نمیشود و لازم است “false” وارد شود.
- “country; price”: در این بخش قیمت محصول در کنار نام کشور درج میشود. واحد قیمت ریال است و کشور لازم است به صورت IR وارد شود.
توجه
امکان وارد کردن دستهای محصولات اشتراکی به صورت CSV وجود ندارد و میبایست به صورت دستی وارد شوند.
کار کردن با شمارهٔ سفارشها¶
- بعد از این که کاربر یک محصول درونبرنامهای شما را خرید،اول مارکت برای این خرید یک شمارهٔ منحصر به فرد و دائمی در نظر میگیرد. اول مارکت این شماره را بعد از پایان کامل جریان خرید در اختیار شما قرار میدهد. از طریق مقدار
orderId
در فیلدPURCHASE_STATE_CHANGED
که در intent بازگشتی وجود دارد میتوانید به شمارهٔ سفارش دسترسی داشته باشید. - از این کد میتوانید در برنامهٔ خود برای پیگیری خرید کاربر و یا برای ایجاد گزارشها استفاده کنید.
- شمارهٔ سفارش یک رشته اَسکی است که با یک فرمت مشخص از طریق اول مارکت در اختیار شما قرار داده میشود.
- “orderId” : “keXQZxQmY74kNU_J”
دریافت کلید عمومی¶
- پنل پرداخت اول مارکت یک کلید عمومی در اختیار شما قرار میدهد که باید در برنامهٔ خود از آن استفاده کنید. این کلید برای هر برنامه منحصر به فرد است. برای دریافت این کلید از بخش برنامههای فروشنده بر روی کلید RSA برنامهٔ خود کلیک کرده و آن را دریافت کنید.
شکل 7
پیادهسازی¶
پیادهسازی سریع پرداخت درونبرنامهای با کلاسهای کمکی¶
این راهنما در نه گام حداقل کارهای لازم برای پیادهسازی و راهاندازی پرداخت درونبرنامهای در برنامهتان را توضیح میدهد.
پیادهسازی این بخش به کمک کلاسهای کمکی انجام شده است که در پوشهٔ util
مربوط به پروژهٔ مثال TrivialDrive قرار دارند. این کلاسها کار شما را برای راهاندازی سریع پرداخت درونبرنامهای، مدیریت درخواستهای پرداخت درونبرنامهای از thread اصلی برنامه و…راحتتر میکنند. برای پیادهسازی کامل پرداخت درونبرنامهای با کمک کلاسهای کمکی، کلاس آموزشی فروش محصولات درونبرنامهای را ببینید.
برای کارهای پیچیدهتر لازم است مستندات دیگر را مطالعه کنید و از پیچ و خم اتفاقات از لحظهٔ پیشنهاد دادن کالاهایتان برای فروش تا زمان تحویل کالای دیجیتالتان به کاربر و ثبت این تحویل مطلع شوید.
1. برنامهای ساده برای پرداخت درون برنامهای¶
خوب است که همیشه با مثالی شروع کنیم و با بازی با اجزای آن کار را جلو ببریم. این مثال که از سوی گوگل ارائه شده است TrivialDrive نام دارد و نمونهٔ مناسبی برای درک مفاهیم پایهای پرداخت درونبرنامهای و دسترسی به فایلهای لازم برای کپی کردن در محیط توسعه است (گام 2 را ببینید). ما سه خط از این مثال را تغییر دادهایم تا برای خرید به جای گوگل به سراغ اول مارکت بیاید.
سورس کد کامل این برنامه را میتوانید در قالب یک فایل زیپ شده از اینجا و یا در قالب یک git repository از اینجا دریافت کنید. سه خط تغییر ما نیز در خطهای ۲۸۸ و ۲۸۹ کلاس IabHelper و خط ۲۱ از فایل AndroidManifest.xml قرار دارند.
2. کتابخانه¶
فایل IInAppBillingService.aidl
و پوشهٔ util
از کد مثال را به پروژهٔ خود اضافه کنید. حواستان باشد که نام بستهٔ فایلهای درون پوشهٔ util
را با توجه به محل جدیدشان چنانچه لازم است ویرایش و بهروز کنید. در انتهای این کار ساختار پوشهبندی پروژهٔ شما در Android Studio باید شبیه تصویر زیر باشد. در مورد جزئیات اضافه کردن این فایل بخش افزودن کتابخانهٔ پرداخت درونبرنامهای در کلاس آموزشی فروش محصولات درونبرنامهای را ببینید.
شکل 8
3. مجوز دسترسی¶
این کد را به فایل AndroidManifest.xml
برنامهٔ خود اضافه کنید:
<uses-permission android:name="com.hrm.android.market.permission.PAY_THROUGH_MARKET" />
4. محصول¶
به پنل توسعهدهندگان اول مارکت مراجعه کنید و apk برنامهٔ خود را آپلود کنید ولی درخواست بررسی آن را ندهید. در پنل پرداخت اول مارکت در بخش «محصولات/خدمات»، محصولی جدید با شناسهٔ محصول مشخص، اضافه کنید و این شناسه را برای مرحلهٔ پنج به یاد بسپارید. مقادیر مناسب کوتاهی در بخش عنوان و توضیحات بنویسید و دکمهٔ ارسال را بزنید.
5. متغیرها¶
پیش از صدا زدن متد onCreate
مربوط به activity
ای که فروش محصول درونبرنامهای را انجام میدهد، متغیرهای زیر را تعریف کنید و مقادیر پیشفرض مناسبی برای آنها تعیین کنید:
// Debug tag, for logging
static final String TAG = "";
// SKUs for our products: the premium upgrade (non-consumable)
static final String SKU_PREMIUM = "";
// Does the user have the premium upgrade
boolean mIsPremium = false;
// (arbitrary) request code for the purchase flow
static final int RC_REQUEST = ;
// The helper object
IabHelper mHelper;
6. onCreate¶
به متد onCreate
مربوط به activity
ای که فروش محصول درونبرنامهای را انجام میدهد، کدهای زیر را اضافه کنید:
String base64EncodedPublicKey = "";
// You can find it in your Avval market console.
// It is recommended to add more security than just pasting it in your source code;
mHelper = new IabHelper(this, base64EncodedPublicKey);
Log.d(TAG, "Starting setup.");
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
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);
}
});
7. کدهای مثال مربوط به listenerها¶
کدهای داخل پوشهٔ util
کارهای مشترک بین برنامههایی که از طریق پرداخت درونبرنامهای کالا میفروشند را انجام میدهند. برای زمانی که این کدها چکهای لازم را انجام دادهاند و دیگر نوبت اقدامی توسط برنامهنویس است، لازم است که listener
هایی بنویسید تا به موقع وارد عمل شوند. در کد زیر listener
اول زمانی استفاده میشود که اول مارکت فهرست خریدهای مصرف نشدهٔ کاربر را باز میگرداند و listener
دوم زمانی که یک خرید به اتمام میرسد فراخوانی خواهد شد.
// Listener that's called when we finish querying the items and subscriptions we own
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
Log.d(TAG, "Query inventory finished.");
// Have we been disposed of in the meantime If so, quit.
if (mHelper == null) return;
// Is it a failure
if (result.isFailure()) {
complain("Failed to query inventory: " + result);
return;
}
Log.d(TAG, "Query inventory was successful.");
/*
* Check for items we own. Notice that for each purchase, we check
* the developer payload to see if it's correct! See
* verifyDeveloperPayload().
*/
// Do we have the premium upgrade
Purchase premiumPurchase = inventory.getPurchase(SKU_PREMIUM);
mIsPremium = (premiumPurchase != null && verifyDeveloperPayload(premiumPurchase));
Log.d(TAG, "User is " + (mIsPremium "PREMIUM" : "NOT PREMIUM"));
updateUi();
setWaitScreen(false);
Log.d(TAG, "Initial inventory query finished; enabling main UI.");
}
};
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase);
// if we were disposed of in the meantime, quit.
if (mHelper == null) return;
if (result.isFailure()) {
complain("Error purchasing: " + result);
setWaitScreen(false);
return;
}
if (!verifyDeveloperPayload(purchase)) {
complain("Error purchasing. Authenticity verification failed.");
setWaitScreen(false);
return;
}
Log.d(TAG, "Purchase successful.");
updateUi();
setWaitScreen(false);
}
};
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
if (mHelper == null) return;
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
}
else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
8. کد مثال فرستادن کاربر برای خرید یک کالا¶
این کد کاربر را به صفحهٔ خرید «ارتقا» در اول میفرستد. وقتی کاربر از اول مارکت برگردد، برنامهٔ شما به کمک کد mPurchaseFinishedListener
خبردار میشود.
mHelper.launchPurchaseFlow(this, SKU_PREMIUM, RC_REQUEST,
mPurchaseFinishedListener, "payload-string");
9. onDestroy¶
در زمان اتمام عمر activity
، اتصال خود را از سرویس قطع کنید:
// We're being destroyed. It's important to dispose of the helper here!
@Override
public void onDestroy() {
super.onDestroy();
// very important:
Log.d(TAG, "Destroying helper.");
if (mHelper != null) {
mHelper.dispose();
mHelper = null;
}
}
کار شما در این مرحله تمام است. فقط منتظر بمانید که اول مارکت آخرین نسخهٔ apk شما را بر روی سِرورهایش قرار دهد.
کلاس آموزشی فروش محصولات درونبرنامهای¶
در این کلاس آموزشی یاد میگیرید که چگونه عملیات معمول پرداخت درونبرنامهای را در برنامهتان با استفاده از کلاسهای کمکی موجود در پوشهٔutil
از پروژهٔ مثال TrivialDrive پیادهسازی کنید. در صورت نیاز به کسب اطلاعات بیشتر در مورد جزئیات کلاسهای پوشهٔ util
، لطفاً به کدهای مربوطهشان مراجعه کنید.
این کلاس آموزشی مبتنی بر نسخهٔ ۳ از API پرداخت درونبرنامهای اول مارکت است. بهتر است قبل از شروع این کلاس، بخش مقدماتی را برای آشنایی با مفاهیم پایه استفاده شده مطالعه کنید.
آمادهسازی برنامه برای پرداخت درونبرنامهای¶
پیش از اینکه بتوانید از سرویس پرداخت درونبرنامهای استفاده کنید، باید کتابخانهٔ پرداخت درونبرنامهای و مجوزهای لازم برای برقراری ارتباط با اول مارکت را به برنامهتان اضافه کنید. به علاوه باید ارتباطی بین برنامهٔ خود و برنامهٔ اول مارکت برقرار کنید. همچنین باید بررسی کنید که اول مارکت از نسخهٔ پرداخت درونبرنامهای که در برنامهتان استفاده میکنید، پشتیبانی میکند یا خیر.
دانلود برنامهٔ نمونه¶
در این کلاس آموزشی از پیادهسازی API پرداخت درونبرنامهای اول مارکت در برنامهٔ نمونه (که TrivialDrive نام دارد) استفاده میشود. برنامهٔ نمونه شامل کلاسهای کمکی برای پیادهسازی سریع پرداخت درونبرنامهای است و نمونهٔ مناسبی برای درک مفاهیم پایهای پرداخت درونبرنامهای است. ما سه خط از این مثال را تغییر دادهایم تا برای خرید به جای گوگل به سراغ اول مارکت بیاید.
سورس کد کامل این برنامه را میتوانید در قالب یک فایل زیپ شده از اینجا و یا در قالب یک git repository از اینجا دریافت کنید. سه خط تغییر ما نیز در خطهای ۲۸۸ و ۲۸۹ کلاس IabHelper و خط ۲۱ از فایل AndroidManifest.xml قرار دارند.
برنامهتان را در پنل توسعهدهندگان اول مارکت بارگذاری کنید¶
پنل توسعهدهندگان اول مارکت جایی است که برنامهٔ خود را در آن منتشر میکنید. زمانی که برنامهٔ جدیدی را در پنل توسعهدهندگان اضافه میکنید، اول مارکت به صورت خودکار یک کلید عمومی برای برنامهٔ شما تولید میکند. برای ایجاد ارتباطی امن بین برنامهٔ خود و سِرورهای اول مارکت به این کلید نیاز دارید. این کلید تنها یک مرتبه برای برنامهٔ شما ساخته میشود و با بهروزرسانی برنامهٔ خود و بارگذاری APK جدید تغییر نخواهد کرد. برای اضافه کردن برنامهٔ خود به پنل توسعهدهندگان اول مارکت مراجعه کنید. در صورت نیاز به کسب اطلاعات بیشتر به مستندات پنل رجوع کنید.
افزودن کتابخانهٔ پرداخت درونبرنامهای¶
برای استفاده از قابلیتهای پرداخت درونبرنامهای اول، باید فایل IInAppBillingService.aidl
را به پروژهٔ خود اضافه کنید. این فایل رابط (interface
) سرویس اول مارکت را تعریف میکند.
میتوانید فایل IInAppBillingService.aidl
را در برنامهٔ نمونه TrivialDrive بیابید. بسته به اینکه برنامهٔ جدیدی ایجاد میکنید یا برنامهٔ قبلی خود را میخواهید تغییر دهید، گامهای زیر را برای اضافه کردن کتابخانهٔ پرداخت درونبرنامهای به پروژهتان دنبال کنید.
پروژه ی جدید:¶
برای اضافه کردن کتابخانهٔ پرداخت درونبرنامهای به پروژهٔ جدید خود:
- فایلهای برنامهٔ نمونهٔ TrivialDrive را در پروژهٔ اندروید خود کپی کنید.
- نام بستهٔ (package name) فایلهایی که کپی کردهاید را به نام بستهٔ پروژهٔ خود تغییر دهید.
- فایل
AndroidManifest.xml
را باز کنید و نام بسته را به نام بستهٔ پروژهٔ خود تغییر دهید. - عبارات import را تصحیح کنید تا پروژهتان به درستی کامپایل شود.
- کدهای برنامهٔ نمونه را تغییر دهید تا برنامهٔ خود را بسازید. یادتان باشد کلید عمومی برنامهٔ خود را از پنل پرداخت در
MainActivity.java
کپی کنید.
پروژه ی موجود:¶
برای اضافه کردن کتابخانهٔ پرداخت درونبرنامهای اول مارکت به پروژهٔ موجود:
- فایل
IInAppBillingService.aidl
را در پروژهٔ اندروید خود کپی کنید.
- در Android Studio: پوشهای به نام
aidl
در زیر پوشهٔsrc/main
ایجاد کنید. بستهٔ جدیدcom.android.vending.billing
را در این پوشه اضافه کنید و فایلIInAppBillingService.aidl
را در این بسته import کنید. - در Eclipse: فایل
IInAppBillingService.aidl
را در پوشهٔsrc/
پروژهٔ خود import کنید. - در دیگر محیطهای توسعه: پوشهٔ
/src/com/android/vending/billing
را بسازید و فایلIInAppBillingService.aidl
را در این پوشه کپی کنید.
- برنامهٔ خود را build کنید. پس از build موفقیتآمیز باید فایل
IInAppBillingService.java
تولید شده را در پوشهٔgen/
در Eclipse و در Android Studio در مسیر ذیل ببینید: app/build/generated/source/aidl/debug/com/android/vending/billing - کلاسهای کمکی درون پوشهٔ
util/
برنامهٔ نمونهٔ TrivialDrive را به پروژهتان اضافه کنید. به یاد داشته باشید که نام بستهٔ این فایلها را نیز متناسب با پروژهٔ خود تغییر دهید تا پروژهتان به درستی کامپایل شود. پروژهٔ شما هماکنون شامل کتابخانهٔ پرداخت درونبرنامهای اول مارکت است.
تنظیم مجوز پرداخت¶
برنامهٔ شما برای رد و بدل کردن پیغامهای درخواست و پاسخ با سرویس پرداخت درونبرنامهای اول مارکت نیاز به مجوز دارد. برای دادن مجوز لازم به برنامهتان خط زیر را به فایل AndroidManifest.xml
خود اضافه کنید:
<uses-permission android:name="com.hrm.android.market.permission.PAY_THROUGH_MARKET" />
برقراری ارتباط با اول مارکت¶
برای اینکه بتوانید درخواستهای پرداخت درونبرنامهای را از برنامهتان به اول مارکت بفرستید، باید به سرویس پرداخت درونبرنامهای اول مارکت متصل شوید. کلاسهای کمکی موجود در برنامهٔ نمونه، اتصال به سرویس پرداخت درونبرنامهای را مدیریت میکنند. لذا نیازی نیست که خودتان مستقیماً ارتباط را مدیریت کنید.
برای راهاندازی ارتباط با اول مارکت، در متد onCreate
مربوط به activity
، نمونهای از کلاس IabHelper
بسازید. پارامترهای متد سازندهٔ (constructor
) این کلاس عبارتند از: Context
مربوط به activity
و رشتهای که حاوی کلید عمومی برنامهی شما است.
IabHelper mHelper;
@Override
public void onCreate(Bundle savedInstanceState) {
// ...
String base64EncodedPublicKey;
// Create the helper, passing it our context and the public key to verify signatures with
Log.d(TAG, "Creating IAB helper.");
mHelper = new IabHelper(this, base64EncodedPublicKey);
}
هشدار
توصیهٔ امنیتی: برای ایمن نگه داشتن کلید عمومی از گزند کاربران مخرب یا هکرها، سعی کنید آن را به صورت رشتهای ثابت درون کد قرار ندهید. در عوض برای پنهان کردن کلید اصلی، رشته را به طریقی در زمان اجرا بسازید یا از دستکاری بیتها (مانند XOR با چند رشتهٔ دیگر) استفاده کنید یا آن را از یک مخزن رمزشده بگیرید. کلید به خودی خود دادهٔ محرمانهای نیست، امامطمئناً نمیخواهید کار را برای هکرها جهت جایگزینی کلید عمومی برنامهٔ شما با کلیدی دیگر آسان کنید.
در ادامه با فراخوانی متد startSetup
از IabHelper
ای که پیشتر ساختید، عمل اتصال به سرویس را انجام دهید. به این متد نمونهای از OnIabSetupFinishedListener
بدهید. زمانی که IabHelper
عملیات راهاندازی را تمام میکند OnIabSetupFinishedListener
را فراخوانی میکند. همچنین در خلال فرآیند راهاندازی، IabHelper
بررسی میکند که آیا اول مارکت از نسخهٔ ۳ پرداخت درونبرنامهای پشتیبانی میکند یا خیر. در صورتی که نسخهٔ API پشتیبانی نشود یا خطای دیگری در هنگام برقراری اتصال به سرویس رخ دهد، OnIabSetupFinishedListener
مطلع میشود و یک شیء IabResult
با پیغام خطای مربوطه به آن ارسال میشود.
// Start setup. This is asynchronous and the specified listener
// will be called once setup completes.
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
Log.d(TAG, "Setup finished.");
if (!result.isSuccess()) {
// Oh noes, there was a problem.
complain("Problem setting up in-app billing: " + result);
return;
}
// Have we been disposed of in the meantime If so, quit.
if (mHelper == null) return;
// IAB is fully set up. Now, let's get an inventory of stuff we own.
...
}
});
در صورتی که برقراری ارتباط با موفقیت انجام شود، میتوانید از mHelper
برای ردو بدل کردن پیغامهای درخواست و پاسخ بین برنامهتان و اول مارکت استفاده کنید. وقتی کاربر، برنامهتان را باز میکند زمان خوبی است که فهرست برنامههایی که صاحب آنها است را از اول مارکت بپرسید. این موضوع بیشتر در بخش درخواست محصولات خریداری شده توضیح داده شده است.
هشدار
به یاد داشته باشید که اتصال از سرویس پرداخت درونبرنامهای را زمانی که activity`تان را میبندید، قطع کنید. اگر اتصال را قطع نکنید، اتصال باز به سرویس باعث تنزل کارایی دستگاه کاربر میشود. برای قطع اتصال و آزاد کردن منابع سیستم، متد `dispose از نمونهٔ کلاس IabHelper را زمانی که `activity`تان از بین میرود، فراخوانی کنید.
@Override
public void onDestroy() {
super.onDestroy();
// very important:
Log.d(TAG, "Destroying helper.");
if (mHelper != null) {
mHelper.dispose();
mHelper = null;
}
}
محصولات درونبرنامهای¶
پیش از انتشار برنامهٔ خود، باید فهرست محصولاتی که میخواهید در برنامهتان بفروشید را در پنل پرداخت اول مارکت تعریف کنید. برای کسب اطلاعات بیشتر در این مورد میتوانید به مستندات مربوطه مراجعه کنید.
درخواست فهرست محصولات قابل فروش¶
برای دریافت جزئیات محصولات درونبرنامهای (برای مثال قیمت، عنوان، نوع و توضیحات محصول) که پیشتر دراول مارکت برای برنامهتان تعریف کردهاید، میتوانید به اول مارکت کوئری بزنید. این کار برای مثال زمانی مفید است که میخواهید فهرست محصولاتی که کاربر در حال حاضر صاحب آنها نیست و میتواند آنها را بخرد را به وی نشان دهید.
توجه
وقتی کوئری میزنید، بایستی شناسهی محصولات را صریحاً مشخص کنید. شناسهٔ محصولی (که به آن SKU نیز گفته میشود) که برای هر محصول تعریف کردهاید را میتوانید درپنل پرداخت، بخش محصولات/خدمات، زیر ستون «شناسهٔ محصول» ببینید.
برای دریافت جزئیات محصول، متد:
queryInventoryAsync(boolean
, List
, QueryInventoryFinishedListener)
را از نمونهٔ IabHelper
ای که قبلاً ساختهاید، فراخوانی کنید:
اولین پارامتر ورودی این متد نشاندهندهٔ این است که آیا جزئیات محصول هم باید برگردانده شود (که در این صورت باید مقدار آن را true
بگذارید).
- پارامتر دوم این متد،
List
ای است شامل یک یا چندین شناسهٔ محصولِ مربوط به محصولاتی که برای آنها کوئری میزنید. - پارامتر آخر این متد،
QueryInventoryFinishedListener
، یکlistener
را مشخص میکند که پس از پایان عملیات کوئری فراخوانی میشود و پاسخ کوئری را بررسی میکند.
اگر از کلاسهای کمکی برنامهٔ نمونهٔ TrivialDrive استفاده کنید، این کلاسها مدیریت thread
های پسزمینه برای درخواستهای پرداخت درونبرنامهای را انجام میدهند و شما میتوانید به راحتی از thread
اصلی برنامهتان کوئری بزنید.
نمونه کد زیر نشان میدهد که چگونه میتوانید جزئیات مربوط به دو محصول با شناسههای SKU_GAS
و SKU_PREMIUM
که قبلاً در پنل توسعهدهندگان تعریفشان کردهاید را دریافت کنید.
ArrayList<String skus = new ArrayList<();
skus.add(SKU_GAS);
skus.add(SKU_PREMIUM);
mHelper.queryInventoryAsync(true, skus, mGotInventoryListener);
اگر کوئری موفقیتآمیز باشد، نتایج کوئری در شیء Inventory
ای ذخیره میشود که به listener
برگردانده میشود.
نمونه کد زیر نشان میدهد که چگونه میتوانید قیمت محصولات را از نتایج برگردانده شده بازیابی کنید.
// Listener that's called when we finish querying the items and subscriptions we own
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
Log.d(TAG, "Query inventory finished.");
// Have we been disposed of in the meantime If so, quit.
if (mHelper == null) return;
// Is it a failure
if (result.isFailure()) {
complain("Failed to query inventory: " + result);
return;
}
Log.d(TAG, "Query inventory was successful.");
String gasPrice =
inventory.getSkuDetails(SKU_GAS).getPrice();
String premiumPrice =
inventory.getSkuDetails(SKU_PREMIUM).getPrice();
// update the UI
}
}
خرید محصولات درونبرنامهای¶
پس از اینکه برنامهٔ شما به اول مارکت متصل شد، میتوانید درخواستهای خرید محصولات درونبرنامهای را آغاز کنید. اول مارکت رابط کاربری لازم برای فرآیند خرید کاربرانتان را فراهم میکند. بنابراین نیازی ندارید که تراکنشهای پرداخت را مستقیماً در برنامهتان بررسی و مدیریت کنید.
زمانی که محصولی خریداری میشود، کاربر مالک محصول محسوب میشود. تا زمانی که کاربر مالک محصولی باشد نمیتواند دوباره آن را خریداری کند مگر اینکه آن را مصرف کند (با مصرف کردن محصول، کاربر دیگر صاحب آن محصول نخواهد بود). شما میتوانید چگونگی مصرف محصول در برنامهتان را کنترل کنید و اول مارکت را از مصرف محصول در برنامهتان مطلع سازید تا کاربر بتواند دوباره آن را خریداری کنید. برای کسب اطلاعات بیشتر مصرف کردن خرید را ببینید.
همچنین میتوانید به اول مارکت کوئری بزنید تا فهرست خریدهایی که کاربر انجام داده را بگیرید. برای مثال این کار زمانی مفید است که بخواهید هنگامی که کاربر برنامهتان را باز میکند، اثر خریدهایش را در برنامهتان منعکس کنید و محتویات یا ویژگیهایی را در اختیار وی قرار دهید.
خرید محصول¶
برای شروع درخواست خرید از برنامهتان متد:
launchPurchaseFlow(Activity act, String sku, int requestCode,
OnIabPurchaseFinishedListener listener, String extraData)
را از نمونهٔ IabHelper
ای که قبلاً ساختهاید فراخوانی کنید. این فراخوانی باید از thread
اصلی برنامه انجام شود. در ادامه پارامترهای این متد توضیح داده شدهاند:
اولین پارامتر، activity
است که فراخوانی را انجام داده.
- پارمتر دوم، شناسهٔ محصول (یا
SKU
) آیتم مورد خریداری است. باید قبلاً محصول را در پنل پرداخت تعریف کرده باشید و وضعیت آن در حالت فعال باشد. دقت کنید که شناسهٔ محصول را بدهید نه نام آن را. در غیر این صورت قابل شناسایی نخواهد بود. - پارامتر سوم، مقدار کد درخواست است. این مقدار میتواند هر عدد صحیح مثبتی باشد. اول مارکت این کد درخواست را به همراه پاسخ خرید به متد
onActivityResult
مربوط بهactivity
درخواست دهنده، برمیگرداند. - پارامتر چهارم،
listener
ای است که هنگام پایان یافتن عملیات خرید فراخوانی میشود و پاسخ خرید اول مارکت را بررسی و مدیریت میکند. - پارامتر پنجم حاوی رشتهٔ
developer payload
است. که شما میتوانید در آن اطلاعات تکمیلی مربوط به سفارش خود را بفرستید (میتواند یک رشتهٔ خالی نیز باشد). معمولاً این رشته توکنی است که منحصراً این درخواست خرید را مشخص میکند. اگر این رشته را مقداردهی کنید، اول مارکت آن را به همراه پاسخ خرید برمیگرداند. متعاقباً زمانی که در مورد این خرید کوئری میزنید، اول مارکت این رشته را به همراه سایر جزئیات خرید برمیگرداند.
هشدار
توصیهٔ امنیتی: بهتر است رشتهای بفرستید که به برنامهٔ شما کمک کند تا کاربری که خرید را انجام داده را شناسایی کنید؛ بدین ترتیب بعداً میتوانید تشخیص دهید که خرید مورد نظر توسط آن کاربر معتبر است یا خیر. برای محصولات درونبرنامهای مصرفی میتوانید از رشتهای که به صورت تصادفی تولید شده استفاده کنید، اما برای محصولات درونبرنامهای غیرمصرفی باید از رشتهای استفاده کنید که کاربر را به صورت منحصر به فرد شناسایی میکند. در اینجا منظور کاربر برنامهٔ خودتان است، زیرا برنامهٔ شما به اطلاعات حساب کاربر در اول مارکت دسترسی ندارد (البته در صورتی که در برنامهتان امکان ایجاد حساب کاربری وجود داشته باشد).
مثالی که در ادامه آمده است نشان میدهد که چگونه میتوانید درخواست خرید برای محصولی با شناسهٔ SKU_GAS
را بدهید. در این مثال مقدار دلخواه کد درخواست، 10001 است و رشتهٔ developer payload
آن رمز شده است.
mHelper.launchPurchaseFlow(this, SKU_GAS, 10001,
mPurchaseFinishedListener, "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
در صورتی که سفارش خرید موفقیتآمیز باشد، پاسخ اول مارکت در شیء Purchase
ای ذخیره میشود که به listener
برگردانده میشود.
مثال زیر نشان میدهد که چگونه میتوانید پاسخ خرید را در listener
بررسی و مدیریت کنید (برحسب اینکه سفارش خرید با موفقیت پایان یافته یا خیر، و اینکه کاربر بنزین خریداری کرده یا ارتقاء به نسخهٔ پولی را). در این مثال بنزین (gas) محصول درونبرنامهای است که میتواند چندین مرتبه خریداری شود، بنابراین باید پس از خرید، آن را مصرف کنید تا کاربر بتواند آن را دوباره خریداری کند. برای کسب اطلاعات بیشتر در مورد مصرف محصول، بخش مصرف کردن خرید را ببینید. ارتقاء به نسخهٔ پولی (premium upgrade) تنها یک مرتبه قابل خرید است، بنابراین نیازی نیست که آن را مصرف کنید. بهتر است پس از خرید موفقیتآمیزِ محصول توسط کاربر، رابط کاربری (UI) برنامهتان را فوراً به نحوی تغییر دهید که کاربر بتواند محصول جدید خریداری شدهٔ خود را ببیند.
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase);
// if we were disposed of in the meantime, quit.
if (mHelper == null) return;
if (result.isFailure()) {
complain("Error purchasing: " + result);
setWaitScreen(false);
return;
}
if (!verifyDeveloperPayload(purchase)) {
complain("Error purchasing. Authenticity verification failed.");
setWaitScreen(false);
return;
}
Log.d(TAG, "Purchase successful.");
if (purchase.getSku().equals(SKU_GAS)) {
// consume the gas and update the UI
}
else if (purchase.getSku().equals(SKU_PREMIUM)) {
// give user access to premium content and update the UI
}
else if (purchase.getSku().equals(SKU_INFINITE_GAS_MONTHLY)
|| purchase.getSku().equals(SKU_INFINITE_GAS_YEARLY)) {
// give user access to subscription content and update the UI
}
}
};
هشدار
توصیهٔ امنیتی: زمانی که پاسخ خرید را ازاول مارکت دریافت میکنید، حتماً صحت امضای دادهٔ بازگشتی، orderId، و رشتهٔ developerPayload در شیء Purchase را بررسی کنید (جهت اطمینان از اینکه مقادیر مورد انتظار را دریافت میکنید). باید بررسی کنید که مقدار orderId مقدار یکتایی است و قبلاً آن را پردازش نکردهاید. همچنین بررسی کنید که مقدار رشتهٔ developerPayload همان مقداری باشد که قبلاً با درخواست خرید ارسال کرده بودید. برای امنیت بیشتر باید این بررسیها را سمت سِرور خودتان انجام دهید.
کوئری محصولات خریداری شده¶
پس از یک خرید موفق، اول مارکت اطلاعات خرید را ذخیره میکند. بهتر است هر از چند گاه، برای دریافت فهرست خریدهای کاربر به سرویس پرداخت درونبرنامهای کوئری بزنید (برای مثال هر موقع که کاربر برنامه را باز میکند). به این ترتیب میتوانید بهروزترین اطلاعات مالکیت کاربر بر محصولات درونبرنامهای را در برنامهتان منعکس کنید.
برای دریافت فهرست خریدهای کاربر از برنامهتان متد:
queryInventoryAsync(QueryInventoryFinishedListener)
را از نمونهٔ IabHelper
ای که پیشتر ساختهاید فراخوانی کنید. پارامتر QueryInventoryFinishedListener
، یک listener
است که در پایان انجام عملیات کوئری، فراخوانی میشود و پاسخ کوئری را بررسی و مدیریت میکند. فراخوانی این متد از thread
اصلی برنامه مشکلی ایجاد نمیکند.
mHelper.queryInventoryAsync(mGotInventoryListener);
در صورتی که کوئری موفقیتآمیز باشد، نتایج کوئری در شیء Inventory
ای که به listener
فرستاده میشود، ذخیره میشود. سرویس پرداخت درونبرنامهای فقط خریدهای کاربری که هماکنون در اول مارکت لاگین است را برمیگرداند.
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
Log.d(TAG, "Query inventory finished.");
// Have we been disposed of in the meantime If so, quit.
if (mHelper == null) return;
// Is it a failure
if (result.isFailure()) {
complain("Failed to query inventory: " + result);
return;
}
Log.d(TAG, "Query inventory was successful.");
/*
* Check for items we own. Notice that for each purchase, we check
* the developer payload to see if it's correct! See
* verifyDeveloperPayload().
*/
// Do we have the premium upgrade
}
};
مصرف کردن خرید¶
شما میتوانید از API پرداخت درونبرنامهای اول مارکت برای پیگیری مالکیت کاربر بر محصولات خرید شدهاش استفاده کنید. زمانی که یک محصول درون برنامهای خریداری میشود، اول مارکت متوجه میشود که کاربر صاحب آن است و تا زمانی که کاربر آن را مصرف نکرده باشد مانع خرید مجدد همان محصول میشود. شما میتوانید نحوهٔ مصرف محصول در برنامهی خود را کنترل کنید و پس از مصرف به اول مارکت اطلاع دهید تا دیگر مانع خرید مجدد آن توسط کاربر نشود.
توجه
یادآوری: از بین انواع محصولات درونبرنامهای، محصولاتی که از نوع محصولات مصرفی در منطق برنامهتان تعریف کردهاید را مصرف کنید. زیرا این دسته از محصولات هستد که تأثیر موقتی دارند و کاربر میخواهد چندین مرتبه آنها را خریداری کند (مانند سکهٔ درون بازی). مسلماً کاربر نمیخواهد محصولات درونبرنامهای غیرمصرفی که یک مرتبه آنها را خریداری کرده اما تأثیرشان همیشگی است را دوباره خریداری کند (برای مثال ارتقاء برنامه به نسخهٔ پولی)؛ لذا درخواست مصرف را فقط برای محصولات مصرفی برنامهتان بفرستید. برای محصولات درونبرنامهای از نوع اشتراک نیز نباید درخواست مصرف بدهید. جهت کسب اطلاعات بیشتر بخش مفاهیم پایه را ببینید.
مسئولیت کنترل و پیگیریِ چگونگی ارائهٔ محصولات درونبرنامهای که کاربر در برنامهتان میخرد به عهدهٔ شما است. برای مثال اگر کاربر سکهٔ درون بازی را بخرد، شما باید دارایی کاربر را به مقدار سکهای که خریداری کرده افزایش دهید.
هشدار
توصیهٔ امنیتی: باید پیش از منعکس کردن اثر خرید کاربر در برنامهتان (در صورتی که محصول خریداری شده از نوع مصرفی باشد)، برای آن درخواست مصرف بفرستید. پیش از فراهم کردن محصول خریداری شده در برنامهتان، مطمئن شوید که پاسخ مصرف موفق از اول مارکت دریافت کردهاید.
برای مصرف یک محصول، متد:
consumeAsync(Purchase, OnConsumeFinishedListener)
را ازنمونهٔ IabHelper
ای که قبلاً ساختهاید فراخوانی کنید. اولین پارامتر این متد، یک شیء Purchase
است که بیانگر محصولی است که قرار است مصرف شود. پارامتر دوم این متد، OnConsumeFinishedListener
، زمانی که عملیات مصرف پایان مییابد فراخوانی میشود که در ادامه پاسخ مصرف را بررسی و مدیریت خواهد کرد. فراخوانی این متد از thread
اصلی مانعی ندارد.
در این مثال، میخواهید محصول بنزین (gas) که کاربر پیشتر در برنامهتان خریداری کرده است را مصرف کنید:
mHelper.consumeAsync(inventory.getPurchase(SKU_GAS),
mConsumeFinishedListener);
مثال زیر نحوهٔ پیادهسازی OnConsumeFinishedListener
را نشان میدهد:
// Called when consumption is complete
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase, IabResult result) {
Log.d(TAG, "Consumption finished. Purchase: " + purchase + ", result: " + result);
// if we were disposed of in the meantime, quit.
if (mHelper == null) return;
// We know this is the "gas" sku because it's the only one we consume,
// so we don't check which sku was consumed. If you have more than one
// sku, you probably should check...
if (result.isSuccess()) {
// successfully consumed, so we apply the effects Log.d(TAG, "Consumption successful. Provisioning.");
mTank = mTank == TANK_MAX TANK_MAX : mTank + 1;
saveData();
alert("You filled 1/4 tank. Your tank is now " + String.valueOf(mTank) + "/4 full!");
}
else {
complain("Error while consuming: " + result);
}
updateUi();
setWaitScreen(false);
Log.d(TAG, "End consumption flow.");
}
};
چک کردن آیتمهای قابل مصرف در آغاز برنامه¶
چک کردن آیتمهای قابل مصرف، زمانی که کاربر برنامهٔ شما را باز میکند، کار مهمی است. معمولاً ابتدا محصولات خریداری شدهٔ کاربر را از سرویس خرید درونبرنامهای میپرسید (توسط queryInventoryAsync
).سپس اشیاء Purchase
قابل مصرف را از Inventory
بگیرید. در صورتی که برنامهٔ شما تشخیص دهد که کاربر صاحب محصولاتی از نوع قابل مصرف است، باید بلافاصله درخواست مصرف آن را به اول مارکت بفرستد و در برنامهاش محصول را برای کاربر فراهم کند. برای کسب اطلاعات بیشتر در مورد پیادهسازی این بررسی در آغاز برنامه، برنامهٔ نمونهٔ TrivialDrive را ببینید.
پیادهسازی پرداخت درونبرنامهای توسط API پرداخت¶
برنامهٔ اول مارکت واسط ساده و کارایی برای مدیریت تراکنشهای پرداخت درونبرنامهای ارائه میدهد. اطلاعات زیر نحوهٔ ارسال درخواست از برنامهٔ شما به سرویس پرداخت درونبرنامهای توسط API را نشان میدهد.
توجه: برای پیادهسازی کامل به کلاس آموزشی فروش محصولات درونبرنامهای و پروژهٔ TrivialDrive مراجعه کنید. این کلاس آموزشی، مثال کاملی از پیادهسازی پرداخت درونبرنامهای ارائه میکند که شامل کلاسهایی برای انجام وظایف کلیدی مربوط به برقراری اتصالات، فرستادن درخواست پرداخت، پردازش پاسخ اول مارکت و مدیریت موازی کارهای پسزمینهای است تا شما بتوانید فراخوانی متدهای پرداخت درونبرنامهای را از activity
اصلی خود انجام دهید.
قبل از شروع توصیه میشود بخش مقدماتی را به دقت بخوانید تا با مفاهیم کلی پرداخت درونبرنامهای آشنا شوید و پیادهسازی آن برایتان آسانتر شود.
در ادامهٔ این بخش، پنج گام اصلی زیر برای پیادهسازی پرداخت درونبرنامهای شرح داده میشوند:
- کتابخانهٔ پرداخت درونبرنامهای (فایل AIDL) را به پروژهٔ خود اضافه کنید.
- فایل
AndroidManifest.xml
را بهروزرسانی کنید. - یک
ServiceConnection
ایجاد کنید و آن را بهIInAppBillingService
متصل کنید. - درخواستهای پرداخت درونبرنامهای را از برنامهٔ خود به
IInAppBillingService
بفرستید. - پاسخهای پرداخت درونبرنامهای اول مارکت را مدیریت کنید.
اضافه کردن فایل AIDL به پروژه¶
فایل IInAppBillingService.aidl
، یک Android Interface Definition Language (AIDL) است که رابطی برای سرویس پرداخت درونبرنامهای اول مارکت است. از این رابط برای برقراری ارتباط با اول مارکت و ساختن درخواستهای پرداخت استفاده میکنید.
دریافت فایل AIDL:¶
- پروژهٔ مثال TrivialDrive را از اینجا دانلود کنید.
- فایل
IInAppBillingService.aidl
را میتوانید در آدرسsrc/main/aidl/com/android/vending/billing/IInAppBillingService.aidl
داخل پروژهٔ TrivialDrive پیدا کنید.
افزودن کتابخانهٔ پرداخت درونبرنامهای (فایل AIDL) به پروژه:¶
- فایل
IInAppBillingService.aidl
را در پروژهٔ اندروید خود کپی کنید.
- اگر از Eclipse استفاده میکنید:
- اگر قبلاً پروژهٔ خود را ساختهاید آن را در
Eclipse
باز کنید، در غیر این صورت یک پروژهٔ اندروید جدید بسازید. - در پوشهٔ
src/
رویFileNewPackage
کلیک کنید و بستهٔ جدیدی با نامcom.android.vending.billing
ایجاد کنید. - فایل IInAppBillingService.aidlای که در گام قبل گرفتید را در پوشهٔ
src/com.android.vending.billing/
کپی کنید. - در
Android Studio
: پوشهای به نامaidl
زیر پوشهٔsrc/main
ایجاد کنید. بستهٔ جدید com.android.vending.billing
را در این پوشه اضافه کنید و فایلIInAppBillingService.aidl
را در این بسته import کنید.- در دیگر محیطهای توسعه: پوشهٔ
/src/com/android/vending/billing
را بسازید و فایلIInAppBillingService.aidl
را در این پوشه کپی کنید.
- برنامه خود را build کنید. بعد از انجام این کار بایستی فایلی به نام
IInAppBillingService.java
در پوشهٔgen/
اگر ازEclipse
استفاده می کنید، و درAndroid Studio
در مسیر ذیل ببینید:app/build/generated/source/aidl/debug/com/android/vending/billing
دقت کنید که شما این فایل را نمیسازید بلکه هنگامbuild
کردن پروژهتان این فایل به صورت خودکار ساخته خواهد شد.
ویرایش فایل manifest برنامه¶
پرداختهای درونبرنامهای از طریق برنامهٔ اندرویدی اول مارکت که تمامی ارتباطات بین برنامهٔ شما و سِرور اول مارکت را مدیریت میکند، انجام میشوند. برای استفاده از برنامهٔ اول مارکت، برنامهٔ شما باید دسترسی زیر را درخواست کند. اگر برنامهٔ شما دسترسی پرداخت درونبرنامهای را درخواست نکرده باشد، اما اقدام به فرستادن درخواست کند، درخواستش رد شده و برنامهتان با خطا مواجه میشود.
برای اینکه دسترسیهای موردنیاز را به برنامهٔ خود بدهید، کد زیر را به فایل AndroidManifest.xml
برنامهتان اضافه کنید:
<uses-permission android:name="com.hrm.android.market.permission.PAY_THROUGH_MARKET" />
ساخت ServiceConnection¶
برنامهٔ شما باید از طریق یک ServiceConnection
با اول مارکت ارتباط برقرار کند. باید حداقل موارد زیر را در برنامهتان انجام دهید:
اتصال به IInAppBillingService
.
- فرستادن درخواست پرداخت به برنامه اول مارکت.
- مدیریت پیامهای پاسخی که برای درخواست پرداخت برمیگردد.
اتصال به IInAppBillingService¶
برای برقراری ارتباط با سرویس پرداخت درونبرنامهای اول مارکت، ServiceConnection
ای پیادهسازی کنید که activity
شما را به IInAppBillingService
متصل میکند.
متدهای onServiceDisconnected
و onServiceConnected
را override
کنید تا پس از برقراری اتصال نمونهای از IInAppBillingService
داشته باشید.
IInAppBillingService mService;
ServiceConnection mServiceConn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
@Override
public void onServiceConnected(ComponentName name,
IBinder service) {
mService = IInAppBillingService.Stub.asInterface(service);
}
};
در متد onCreate
مربوط به activity
خود، اتصال را با فراخوانی متد bindService
برقرار کنید. به عنوان پارامتر ورودی به این متد، Intent
ای که به سرویس پرداخت درونبرنامهای اشاره دارد و نمونهای از ServiceConnection
ای که ایجاد کردهاید را بدهید. برای مقدار نام بستهٔ مقصد Intent، نام بستهٔ اول مارکت (یعنی com.hrm.android.market
) را وارد کنید.
هشدار
همواره برای محافظت از تراکنشهای پرداخت، مطمئن شوید که نام بستهٔ مقصد Intent را با استفاده از متد setPackage (آنچنان که در مثال زیر آمده است)، به نام بستهٔ اول مارکت سِت کردهاید. این کار باعث میشود که تنها برنامهٔ اول مارکت بتواند درخواستهای پرداخت برنامهٔ شما را مدیریت کند و برنامههای دیگر نتوانند جلوی این درخواستها را بگیرند. همچنین در صورتی که از API اندروید با نسخهٔ بالاتر از ۲۱ استفاده میکنید، حتما میبایست نام بسته را برای Intent ست کنید، در غیر این صورت در اندروید ۵ به بالا، سیستم عامل از وصل شدن به سرویس جلوگیری میکند.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent serviceIntent = new Intent("com.hrm.android.market.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.hrm.android.market");
bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
شما اکنون میتوانید از mService
برای ارتباط با سرویس اول مارکت استفاده کنید.
به یاد داشته باشید زمانی که activity`تان از بین میرود اتصال از سرویس پرداخت درونبرنامهای را قطع کنید. اگر اتصال را قطع نکنید، اتصال باز به سرویس باعث تنزل کارایی دستگاه کاربر میشود. مثال زیر طریقهٔ قطع کردن اتصال در سرویس پرداخت درونبرنامهای با نام `mServiceConn را نشان میدهد که با override کردن متد onDestroy در activity انجام میشود.
@Override
public void onDestroy() {
super.onDestroy();
// very important:
if (mServiceConn != null) {
unbindService(mServiceConn);
}
}
برای دیدن پیادهسازی کامل ServiceConnection
ای که به IInAppBillingService
متصل میشود به کلاس آموزشی فروش محصولات درونبرنامهای و پروژهٔ مثال TrivialDrive مراجعه کنید.
ساخت درخواست پرداخت درونبرنامهای¶
وقتی برنامهٔ شما به اول مارکت متصل شد، میتوانید برای محصولات درونبرنامهای درخواست خرید بفرستید. اول مارکت با فراهم کردن رابط پرداخت برای کاربران، شما را از مدیریت مستقیم تراکنشهای پرداخت معاف میکند. وقتی محصولی خریداری شد، اول مارکت میفهمد که کاربر مالک آن محصول است و تا زمانی که آن خرید مصرف نشده، از خرید محصول دیگری با همان شناسهٔ کالا جلوگیری میکند. جهت کسب اطلاعات بیشتر در مورد مصرف کردن خرید، بخش مفاهیم پایه و مصرف کردن خرید را ببینید. میتوانید فهرست محصولاتی که کاربر صاحب آنها میباشد را ازاول مارکت بپرسید. برای مثال، این کار زمانی مفید است که بخواهید خریدهای مصرفنشدهٔ کاربر را بگیرید.
کوئری برای محصولات قابل خرید¶
میتوانید در برنامهتان جزئیات محصول را از اول مارکت بپرسید. برای این کار نخست Bundle
ای بسازید که شامل یک ArrayList
از شناسهٔ محصولات با کلید “ITEM_ID_LIST” است.
ArrayList skuList = new ArrayList();
skuList.add("premiumUpgrade");
skuList.add("gas");
Bundle querySkus = new Bundle();
querySkus.putStringArrayList(“ITEM_ID_LIST”, skuList);
برای بازیابی این اطلاعات از اول مارکت، متد getSkuDetails
را فراخوانی کنید. ورودیهای این متد عبارتند از: نسخهٔ API پرداخت درونبرنامهای (“3”)، نام بستهٔ برنامهٔ خود، نوع خرید (“inapp”) و Bundle
ای که پیشتر ساختید.
Bundle skuDetails = mService.getSkuDetails(3,
getPackageName(), "inapp", querySkus);
اگر درخواست موفقیتآمیز بود، Bundle
ای که برگردانده میشود کد پاسخ 0 یا BILLING_RESPONSE_RESULT_OK
دارد.
هشدار
متد getSkuDetails را در thread اصلی (thread رابط کاربری) برنامهتان فراخوانی نکنید. فراخوانی این متد باعث ایجاد درخواست شبکهای میشود که نباید در thread اصلی (thread رابط کاربری) برنامهٔ شما انجام شود و آن را بلوکه کند. در عوض یک thread جداگانه بسازید و متد getSkuDetail را از درون آن فراخوانی کنید.
برای دیدن تمامی کدهای پاسخ اول مارکت مرجع API را مشاهده کنید.
نتایج پرسوجو در یک ArrayList
رشتهای با کلید DETAILS_LIST
و اطلاعات خرید نیز در یک رشته با فرمت JSON ذخیره شدهاند. برای دیدن انواع اطلاعات برگردانده شده مربوط به جزئیات محصول بخش مرجع API را مشاهده کنید.
در این مثال، قیمت محصولات درونبرنامهای خود را از skuDetails
(همان Bundle
ای که در کد قبلی برگردانده شده است) بازیابی میکنید.
int response = skuDetails.getInt("RESPONSE_CODE");
if (response == 0) {
ArrayList responseList
= skuDetails.getStringArrayList("DETAILS_LIST");
for (String thisResponse : responseList) {
JSONObject object = new JSONObject(thisResponse);
String sku = object.getString("productId");
String price = object.getString("price");
if (sku.equals("premiumUpgrade")) mPremiumUpgradePrice = price;
else if (sku.equals("gas")) mGasPrice = price;
}
}
خرید محصول¶
برای شروع درخواست خرید، متد getBuyIntent
از سرویس پرداخت درونبرنامهای را فراخوانی کنید. ورودیهای این متد عبارتند از: نسخهٔ API پرداخت درونبرنامهای (“3”)، نام بستهٔ برنامهتان، شناسهٔ محصول، نوع خرید (“inapp” یا “subs”) و رشتهٔ developerPayload
. از رشتهٔ developerPayload
برای مشخص کردن هرگونه اطلاعات تکمیلی که میخواهید اول مارکت به همراه اطلاعات خرید برای شما برگرداند، استفاده میشود.
Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(),
sku, "inapp", "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
اگر درخواست موفقیت آمیز بود، Bundle
برگشتی کد پاسخ BILLING_RESPONSE_RESULT_OK
(یا 0) و PendingIntent
ای که برای شروع عملیات خرید میتوانید از آن استفاده کنید را به همراه دارد. برای دیدن تمامی کدهای پاسخ اول مارکت، بخش مرجع API را مشاهده کنید. در ادامه یک PendingIntent
از Bundle
برگردانده شده با کلید BUY_INTENT
استخراج کنید.
PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
برای تکمیل تراکنش خرید، متد startIntentSenderForResult
را فراخوانی کنید و از PendingIntent
ای که خودتان ساختهاید، استفاده کنید. در این مثال شما برای کد درخواست از مقدار دلخواه 1001 استفاده میکنید.
startIntentSenderForResult(pendingIntent.getIntentSender(),
1001, new Intent(), Integer.valueOf(0), Integer.valueOf(0),
Integer.valueOf(0));
اول مارکت پاسخ PendingIntent
را به متد onActivityResult
برنامهٔ شما میفرستد. متد onActivityResult
کد نتیجهٔ (1) Activity.RESULT_OK
یا (0) Activity.RESULT_CANCELED
را خواهد داشت. برای مشاهدهٔ اطلاعات دیگر سفارش که در Intent برگردانده شده وجود دارد، بخش مرجع API را ببینید.
به همراه این کد، Intent
ی خواهد بود که نقش حوالهٔ دیجیتالی خرید شما را خواهد داشت. این حواله در فرمت JSON است و با کلید INAPP_PURCHASE_DATA
در Intent
پاسخ قرار دارد. به عنوان مثال:
{
"orderId":"12999763169054705758.1371079406387615",
"packageName":"com.example.app",
"productId":"exampleSku",
"purchaseTime":1345678900000,
"purchaseState":0,
"developerPayload":"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ",
"purchaseToken":"opaque-token-up-to-1000-characters"
}
توجه
اول مارکت یک توکن برای خرید تولید میکند. این توکن دنبالهای از کاراکترهای مبهم است و حداکثر طول آن ۱۰۰۰ کاراکتر است. این توکن را به متدهای دیگر پاس کنید، برای مثال زمانی که خرید را مصرف میکنید (توضیحات مصرف کردن خرید را ببینید). این توکن را خلاصه و کوتاه نکنید؛ کل توکن را باید ذخیره کنید و برگردانید.
برای دیدن فهرست کامل کلیدهای موجود در پاسخ برگردانده شده مرجع API را مشاهده کنید.
در ادامهٔ مثال قبل، شما کد پاسخ، دادههای خرید و امضای دیجیتالی را از Intent
پاسخ دریافت میکنید.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1001) {
int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
if (resultCode == RESULT_OK) {
try {
JSONObject jo = new JSONObject(purchaseData);
String sku = jo.getString("productId");
alert("You have bought the " + sku + ". Excellent choice,
adventurer!");
}
catch (JSONException e) {
alert("Failed to parse purchase data.");
e.printStackTrace();
}
}
}
}
هشدار
پیشنهاد امنیتی: وقتی درخواست خرید را میفرستید، یک token رشتهای بسازید که به طور مشخص این درخواست خرید را مشخص میکند و آن را در developerPayload قرار دهید. میتوانید از رشتههایی که به طور تصادفی ساخته شدهاند به عنوان token استفاده کنید. وقتی پاسخ درخواست خرید را از اول مارکت دریافت کردید، حتماً امضای دادههای برگشتی، orderId و رشته developerPayload را بررسی کنید. برای امنیت بیشتر، باید این کار را در سِرور امن خود انجام دهید. مطمئن شوید که مقدار`orderId` منحصر به فرد است و قبلاً آن را پردازش نکردهاید و رشتهٔ developerPayload با token ای که قبلًا با درخواست خرید فرستاده بودید، مطابقت دارد.
توجه
برخی اوقات، ممکن است بعد از اینکه کاربر را به سیستم پرداخت درونبرنامهای منتقل نمودید، Activity برنامهٔ شما به صورت خودکار توسط اندروید بسته شود. با اینکه پس از اتمام کار کاربر با سیستم پرداخت، اندروید به صورت خودکار دوباره Activity برنامهٔ شما را میسازد، ولی تغییراتی که شما در Activity مورد نظر دادهاید از بین خواهد رفت. لذا این اتفاق باعث میشود که کاربر خرید را انجام دهد ولی برنامهٔ شما نتواند آن را ثبت کند. این اتفاق روی دستگاههای ضعیف اندرویدی به بسیار متداول است و در گوشیهای قوی هم گاهی اتفاق میافتد. برای جلوگیری از این کار، متد onSaveInstanceState را برای Activity`ای که کاربر را به سیستم پرداخت میفرستد پیاده کنید و هر چیزی که میخواهید پس از بسته شدن `Activity بازیابی کنید، در Bundle`ای که به عنوان آرگومان به متد گفته شده داده شده است، قرار دهید. پس از بسته شدن `Activity و باز شدن مجدد آن توسط اندروید، همین`Bundle`ای که در متد onSaveInstanceState تغییرش دادید، به عنوان آرگومان متد onCreate در Activity گفته شده داده خواهد شد، که میتوانید اطلاعات ذخیرهشدهتان را بازیابی کنید. برای اطلاعات بیشتر به [اینجا](http://developer.android.com/training/basics/activity-lifecycle/recreating.html) سر بزنید.
کوئری محصولات خریداری شده¶
برای بازیابی اطلاعات مربوط به خریدهای کاربر از برنامهی شما، متد getPurchases
را فراخوانی کنید. پارامترهای ورودی این متد عبارتند از: شمارهٔ نسخهٔ API پرداخت درون برنامهای (“3”)، نام بستهٔ برنامهتان و نوع خرید (“inapp” یا “subs”).
Bundle ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null);
اول مارکت صرفاً خریدهای مربوط به حساب کاربری که در حال حاضر دراول مارکت لاگین است را باز میگرداند. اگر درخواست موفقیتآمیز باشد، Bundle
برگشتی کد پاسخ 0 دارد. همچنین Bundle
پاسخ شامل لیستی از شناسهٔ محصولات، لیستی از جزئیات سفارش هر خرید و امضای هر خرید است.
سرویس پرداخت درون برنامهای برای افزایش کارایی، زمانی که برای اولین بار getPurchases
فراخوانی میشود حداکثر تا ۱۰۰ محصول که متعلق به کاربر است را باز میگرداند. اگر کاربر تعداد زیادی محصول خریداری شده داشته باشد، اول مارکت برای نشان دادن اینکه محصولات بیشتری میتوانند بازیابی شوند یک token
رشتهای که به کلید INAPP_CONTINUATION_TOKEN
نگاشته شده است را در Bundle
پاسخ قرار میدهد. سپس برنامهٔ شما میتواند مجدداً getPurchases
را فراخوانی کند و این token
را به عنوان آرگومان به آن بدهد. اول مارکت تا زمانی که تمام محصولاتی که متعلق به کاربر است به برنامهٔ شما فرستاده شود به برگرداندن token
های متوالی در Bundle
پاسخ ادامه خواهد داد.
مثال زیر نشان میدهد که چگونه شما میتوانید این دادهها را دریافت کنید.
int response = ownedItems.getInt("RESPONSE_CODE");
if (response == 0) {
ArrayList ownedSkus =
ownedItems.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
ArrayList purchaseDataList =
ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
ArrayList signatureList =
ownedItems.getStringArrayList("INAPP_DATA_SIGNATURE");
String continuationToken =
ownedItems.getString("INAPP_CONTINUATION_TOKEN");
for (int i = 0; i < purchaseDataList.size(); ++i) {
String purchaseData = purchaseDataList.get(i);
String signature = signatureList.get(i);
String sku = ownedSkus.get(i);
// do something with this purchase information
// e.g. display the updated list of products owned by user
}
// if continuationToken != null, call getPurchases again
// and pass in the token to retrieve more items
}
مصرف کردن یک خرید¶
شما میتوانید از API پرداخت درونبرنامهای اول مارکت برای پیگیری مالکیت کاربر بر محصولات درونبرنامهای خریداری شده توسط وی استفاده کنید. وقتی محصول درونبرنامهای خریداری میشود، به عنوان داراییِ «تحت تملک» آن کاربر تلقی شده و نمیتواند دوباره توسط آن کاربر خریداری شود. برای اینکه امکان خرید مجدد آن محصول فراهم شود، باید درخواست مصرف آن را به اول مارکت بفرستید.
تنها خرید مربوط به محصولات مصرفی را مصرف کنید. جهت کسب اطلاعات بیشتر، بخش مفاهیم پایه را ببینید.
چگونگی اجرای مکانیزم مصرف در برنامهتان بستگی به خودتان دارد. معمولاً محصولات درونبرنامهای را مصرف میکنید که اثرات موقت دارند و کاربر ممکن است چندین مرتبه آنها را خریداری کند (برای مثال خرید سکه یا ابزار درون بازی). اما محصولاتی که تنها یکبار فروخته میشوند و اثری دائمی دارند (مانند ارتقا دادن به نسخه کامل برنامه) را مصرف نکنید.
برای ثبت مصرف یک خرید، متد consumePurchase
را فراخوانی کنید و مقدار رشتهٔ purchaseToken
(که خریدی که قرار است مصرف کنید را مشخص میکند) را به عنوان ورودی به آن بدهید. purchaseToken
قسمتی از دادهای است که در رشتهٔ INAPP_PURCHASE_DATA
توسط اول مارکت در جواب یک خرید موفق برگردانده میشود. در مثال زیر مصرف محصولی که purchaseToken
آن در متغیر token
قراد دارد را ثبت میکنید.
int response = mService.consumePurchase(3, getPackageName(), token);
هشدار
متد consumePurchase را در thread اصلی (thread رابط کاربری) فراخوانی نکنید. فراخوانی این متد باعث ایجاد درخواستی شبکهای میشود که thread اصلی شما (thread رابط کاربری) را بلوکه میکند. به جای آن یک thread جداگانه بسازید و متد consumePurchase را از درون آن فراخوانی کنید.
شما تصمیم میگیرید که محصولات درونبرنامهای خریداری شده را به چه شکلی در برنامهتان برای کاربر فراهم کنید (به این امر به اصطلاح «تأمین کردن محصول» میگوییم) و خود مسئول کنترل و پیگیری آن هستید. برای مثال، در صورتی که کاربر سکهی داخل بازی را خریداری کرده، شما باید فهرست اموال بازیکن را با مقدار سکهای که خریده است بهروز کنید.
هشدار
پیشنهاد امنیتی: قبل از تأمین محصولات مصرفی در برنامهتان، شما باید درخواست مصرف را به اول مارکت فرستاده و پاسخی موفق از اینکه مصرف ثبت شده است، دریافت کرده باشید.
برای فهم بهتر موضوع اینفوگرافیک تهیه شده (شکل ۱) را ببینید.
پیادهسازی اشتراک¶
روند پیادهسازی اشتراک مانند روند پیادهسازی خرید محصول است با این تفاوت که نوع محصول باید برابر با”subs” باشد. پاسخ و نتیجهٔ خرید دقیقا همانند خرید محصولات درونبرنامهای، به متد onActivityResult
شما ارسال میشود.
Bundle bundle = mService.getBuyIntent(3, "com.example.myapp",
MY_SKU, "subs", developerPayload);
PendingIntent pendingIntent = bundle.getParcelable(RESPONSE_BUY_INTENT);
if (bundle.getInt(RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) {
// Start purchase flow (this brings up Market UI).
// Result will be delivered through onActivityResult().
startIntentSenderForResult(pendingIntent, RC_BUY, new Intent(),
Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));
}
برای بازیابی اشتراکهای فعال، بار دیگر از متد getPurchases
استفاده کنید با این تفاوت که پارامتر مربوط به نوع محصول را برابر با”subs” قرار دهید.
Bundle activeSubs = mService.getPurchases(3, "com.example.myapp",
"subs", continueToken);
این فراخوانی یک Bundle
به شما باز میگرداند که شامل تمامی اشتراکهای فعال کاربر است. به محض منقضی شدن اشتراک (در صورت انصراف و یا عدم موجودی کاربر) دیگر در این Bundle
برگردانده شده نخواهد آمد.
امن کردن برنامهتان¶
برای کسب اطمینان از بابت عدم دستکاری حوالهٔ خرید داده شده به برنامهتان، اول مارکت رشتهٔ JSON ارسالی حاوی جزئیات خرید را امضاء میکند. اول مارکت از رمزنگاری نامتقارن برای ساختن این امضاء استفاده میکند. به این ترتیب که با استفاده از کلید خصوصی تولید شده در سِرور پرداخت، رشتهٔ مربوطه امضاء میشود و این امضاء توسط کلید عمومیای که در بخش «برنامههای فروشنده» در پنل پرداخت در اختیار شما قرار گرفته، قابل بررسی است.
توجه
کلید عمومی برای هر برنامه منحصر به فرد است. برای دریافت این کلید در بخش برنامههای فروشنده بر روی کلید RSA برنامهٔ خود کلیک کرده و آن را دریافت کنید.
شما میتوانید بررسی امضای گفته شده را بر روی برنامه خود انجام دهید، آنطور که در پروژهٔ TrivalDrive انجام شده است. ولی چنانچه برنامهتان برای ارائهٔ امکاناتش به سِروری امن اتصال پیدا میکند، پیشنهاد ما انجام این بررسی بر روی آن سِرور امن است. برای کسب اطلاعات بیشتر درباره طراحیهای امنیتی به بخش ملاحظات امنیتی مراجعه کنید.
اشتراک¶
سرویس اشتراک به شما اجازه میدهد که هزینهٔ ارائهٔ محتوا یا خدمات خود را به صورت ماهانه یا سالانه از کاربران دریافت کنید. همچنین با استفاده از این سرویس می توانید اشتراک آزمایشی رایگان را به کاربران خود ارائه دهید.
قابلیت اشتراک در پنل توسعهدهندگان اول مارکت اضافه شده است و برای کلیه کاربران اول مارکت نسخهٔ 6 به بالا قابل استفاده است. یک برنامه میتواند محصولات اشتراک متعدد داشته باشد که هر کدام از آنها محصولات درونبرنامهای مجزا با ماهیت پرداخت دورهای هستند.
اگر کاربر در طی یک دوره سرویس اشتراک را لغو کند، مبلغ دریافت شده برای آن دوره به وی عودت داده نمیشود. در عوض، او قادر خواهد بود تا پایان دوره به سرویس خریداری شده دسترسی داشته باشد. لطفاً توجه داشته باشید که سرویس اشتراک باید تا زمانی که حتی یک کاربر فعال وجود دارد، از سوی توسعهدهنده پشتیبانی شود. عدم انجام این کار منجر به تعلیق حساب توسعهدهنده و کسر هزینههای تحمیل شده به کاربران سرویس اشتراک از حساب توسعهدهنده خواهد شد.
مروری بر اشتراکها¶
اشتراک محصولی است که در پرداخت درونبرنامهای ارائه میشود و به شما امکان میدهد محتوا، خدمات، یا ویژگیهایی را به کاربران برنامهتان با صورتحسابهای ماهانه یا سالانه بفروشید. میتوانید اشتراکها را برای تقریباً هر نوع محتوای دیجیتالی در هر نوع برنامه کاربردی یا بازی بفروشید.
همانند دیگر محصولات درونبرنامهای، اشتراکها را در پنل پرداخت اول مارکت تعریف میکنید و سپس آنها را از درون برنامههای نصب شده بر روی دستگاههای اندرویدی میفروشید. برای تعریف محصولی از نوع اشتراک در پنل پرداخت اول مارکت، نوع محصول را اشتراک (ماهانه یا سالانه) انتخاب کنید و برای آن یک قیمت و دوره آزمایشی (در صورت تمایل) تعیین کنید. جهت کسب اطلاعات بیشتر، مستندات مربوط به تعریف محصولات اشتراکی ببینید.
زمانی که کاربران محصولی از نوع اشتراک را در برنامهٔ شما خریداری میکنند، برنامهٔ اندرویدی اول مارکت تمامی جزئیات را مدیریت میکند و برنامههای شما هرگز نیازی به پردازش مستقیم تراکنشهای مالی نخواهند داشت.
کاربران میتوانند پس از خرید اشتراکها، آنها را پروفایل کاربریشان در برنامه اول مارکت روی گوشیشان مشاهده کنند و اگر بخواهند آنها را لغو کنند. جهت کسب اطلاعات بیشتر در این مورد، بخش لغو اشتراک را در ادامهٔ همین صفحه ببینید. در حالت کلی، اصطلاحات و قواعد پایهای که برای محصولات استاندارد درونبرنامهای (محصولات فروشی) استفاده میشود برای اشتراکها نیز به کار میرود.
هزینهٔ اشتراک¶
هر محصول اشتراکی باید قیمتی بیش از صفر داشته باشد. میتوانید چندین اشتراک برای یک محتوا داشته باشید. به عنوان مثال میتوانید برای اشتراک سالانه در مقایسه با اشتراک ماهانه تخفیف بیشتری در نظر بگیرید.
توجه
برای تغییر هزینهٔ یک اشتراک، میتوانید یک شناسهٔ محصول اشتراکی جدید با قیمت جدید منتشر کنید، سپس آن را در برنامهٔ خود به جای محصول اصلی ارائه دهید. کاربرانی که در حال حاضر آن را خریداری کردهاند با قیمت قبلی شارژ میشوند، اما کاربران جدید با قیمت جدید شارژ خواهند شد.
صورتحساب کاربر¶
در پنل پرداخت اول مارکت، میتوانید محصولات اشتراکی را با صورتحسابهای دورهای خودکار در یکی از فواصل زیر تعریف کنید:
- ماهانه: اول مارکت در زمان خرید یک بار کاربر را شارژ میکند (هزینهٔ اشتراک را از کاربر میگیرد) و پس از هر ماه شمسی، مجدداً مقدار تعیینشده را از حساب کاربر کسر و به حساب شما واریز میکند.
- سالانه: اول مارکت در زمان خرید و در همان تاریخ در سالهای بعدی حساب کاربر را شارژ میکند (هزینهٔ اشتراک را از حساب کاربر کم میکند).
پرداخت هزینهٔ اشتراک با قیمت و فاصلهٔ مشخص شده ادامه پیدا میکند. در هر بار تمدید اشتراک، اول مارکت حساب کاربر را به صورت خودکار شارژ و سپس کاربر را از طریق پیامک باخبر میکند.
دورههای پرداخت همواره با دورههای اشتراک، بر اساس تاریخ خرید مطابقت دارند.
زمانی که پرداخت اشتراک موفقیتآمیز باشد، اول مارکت از طریق API خرید درونبرنامهای یک توکن به برنامهی فروشنده برمیگرداند. برنامهٔ شما میتواند توکن را به صورت محلی (روی دستگاه کاربر) ذخیره کند و یا آن را برای نگهداری به سِرورتان (در صورت وجود) ارجاع دهد. از این توکن میتوانید برای تأیید و یا لغو اشتراک استفاده کنید.
اگر پرداخت دورهای موفقیتآمیز نباشد (برای مثال در صورتی که اعتبار مشتری کافی نباشد)، اشتراک تمدید نمیشود. در این صورت زمانی که متد getPurchases
فراخوانی میشود (برای گرفتن فهرست محصولاتی که کاربر صاحب آنها است)، اشتراکهای منقضی یا ناموفق برگردانده نمیشوند.
دورههای آزمایشی¶
در پنل پرداخت اول مارکت، میتوانید یک دورهٔ آزمایشی رایگان تعیین کنید که به کاربران امکان میدهد محتویات اشتراکی را قبل از خرید آن امتحان کنند. دورهٔ آزمایشی برای مدت زمانی که تعیین میکنید معتبر است و سپس به صورت خودکار به اشتراک کامل با زمان و هزینهٔ مشخص شده تبدیل میشود.
برای استفاده از دورهٔ آزمایشی، کاربر باید اشتراک کامل را از طریق پرداخت درونبرنامهای استاندارد خریداری کند. اما کاربر هیچ هزینهای پرداخت نمیکند، زیرا دورهٔ آغازین، دورهٔ آزمایشی است. در اینجا اول مارکت یک تراکنش با قیمت صفر ریال ثبت میکند و اشتراک در طول دورهٔ آزمایشی یا قبل از لغو آن خریدشده محسوب خواهد شد. زمانی که تراکنش به پایان میرسد، اول مارکت کاربر را از طریق ارسال پیامک از خریدی که شامل یک دورهٔ آزمایشی با هزینهٔ اولیهٔ صفر ریال است، مطلع میکند.
زمانی که دورهٔ آزمایشی به پایان میرسد، اول مارکت به صورت خودکار حساب کاربر را با مقدار هزینهٔ اشتراک کامل شارژ میکند. در صورت نیاز، کاربر میتواند اشتراک را در مدت زمان دورهٔ آزمایشی لغو کند. در این صورت، اول مارکت اشتراک را بلافاصله منقضی میکند (منتظر به اتمام رسیدن دورهٔ آزمایشی نمیماند). این امر به این دلیل است که کاربر برای دورهٔ آزمایشی پولی پرداخت نکرده است، لذا در صورت لغو آن مجاز به دستیابی به محتویاتش نخواهد بود.
شما میتوانید در پنل پرداخت اول مارکت بدون نیاز به تغییر یا به روزرسانی APK خود، یک دورهٔ آزمایشی برای اشتراک مورد نظر تعیین کنید. تنها کافی است این اشتراک را در فهرست محصولات خود یافته، آن را ویرایش کنید و روزهای دورهٔ آزمایشی را تعیین کنید. تعداد روزهای دورهٔ آزمایشی، در صورت وجود، باید هفت روز یا بیشتر باشد. میتوانید مدت زمان دورهی مورد نظر را هر زمانی که خواستید تغییر دهید، اما توجه داشته باشید که اول مارکت این تغییر را برای کاربرانی که پیشتر این دورهٔ آزمایشی را خرید کردهاند اعمال نمیکند. فقط خریدهای جدید اشتراک از دورهٔ آزمایشی بهروزشده استفاده خواهند کرد. میتوانید یک دورهٔ آزمایشی رایگان برای هر محصول اشتراکی تعیین کنید.
ایجاد اشتراک¶
در پنل پرداخت اول مارکت، میتوانید اشتراکها، محصولات درونبرنامهای یا هر دو را اضافه کنید. میتوانید چندین اشتراک که به محتواها یا خدمات متفاوت اجازه دسترسی میدهند را تعریف کنید، یا میتوانید چندین اشتراک را برای یک محتوا اما با فواصل یا قیمتهای متفاوت ایجاد کنید. برای مثال، یک مجله ممکن است بخواهد هم اشتراکهای ماهانه و هم اشتراکهای سالانه را برای یک محتوا در نظر بگیرد، که اشتراک سالانه آن شامل تخفیف میشود.
لغو اشتراک¶
کاربران میتوانند اشتراکهای خود را در پروفایل کاربری خود در برنامه اول مارکت خود مشاهده و در صورت تمایل آن را لغو کنند. در حال حاضر، API پرداخت درونبرنامهای، لغو اشتراکها از طریق برنامهنویسی در برنامهٔ فروشنده را پشتیبانی نمیکند.
زمانی که کاربر یک اشتراک را لغو میکند، وجه پرداخت شده برای دورهٔ جاری مسترد نمیگردد. در این صورت کاربر کماکان میتواند تا پایان دورهٔ صورتحساب جاری به اشتراک لغو شده دسترسی داشته باشد. برای مثال در صورتی که کاربر یک اشتراک ماهانه را بخرد و آن را در ۱۵امین روز دوره لغو کند، اشتراک تا پایان ۳۰امین روز (یا با یک روز کم تر یا بیشتر) معتبر خواهد بود.
توجه
در تمامی موارد، بایستی محتوایی که مشترکین شما خریداری کردهاند تا زمانی که مجاز به دستیابی به آن هستند، در اختیارشان قرار گیرد. این بدان معناست که نباید محتوای یک اشتراک را تا زمانی که کاربری عضو فعال آن است حذف کنید، حتی در صورتی که اشتراک آن در پایان دورهٔ جاری به اتمام میرسد. حذف محتوایی که مشترک حق دستیابی به آن را دارد منجر به جریمهٔ شما خواهد شد.
استرداد وجوه¶
اول مارکت از استرداد وجوه پس از خرید اشتراک پشتیبانی نمیکند، لذا کاربران برای استرداد وجوهشان بایستی مستیماً با شما تماس بگیرند. در صورتی که درخواست استرداد وجوه را دریافت کردید، میتوانید از API سمت سِرور برای لغو کردن یا دیدن اینکه اشتراک مورد نظر در حال حاضر لغو شده است، استفاده کنید. اما توجه داشته باشید که اول مارکت اشتراکهای لغو شده را تا پایان دورهٔ صورتحساب جاری معتبر در نظر میگیرد، بنابراین حتی در صورتی که وجه اشتراک را مسترد و اشتراک را لغو کنید، کاربر کماکان میتواند به محتویات آن دسترسی داشته باشد.
خط مشیها و پردازش پرداخت¶
برنامههای منتشر شده در اول مارکت که اشتراک میفروشند بایستی از پرداخت درونبرنامهای برای مدیریت تراکنشها استفاده کنند و نباید لینکهایی به خارج از برنامهٔ اول مارکت(مانند یک وبسایت) برای خرید ارائه کنند.
در صورتی که اشتراک یک محصول از جایی خارج از برنامه نیز قابل خرید باشد، همان اشتراک میبایست با قیمت مساوی و یا کمتر در داخل برنامه و از طریق اول مارکت قابل خرید باشد.
ملاحظات امنیتی¶
زمانی که تصمیم به استفاده از پرداخت درون برنامهای در برنامهی خود گرفتید، سعی کنید راهکارهای امنیت و طراحی که در این سند مورد بحث قرار گرفته است را دنبال کنید. این راهنما برای تمامی افرادی که از سرویس پرداخت درون برنامهای اول مارکت استفاده میکنند، پیشنهاد میشود.
عملیات تأیید امضا را روی سِرور انجام دهید¶
در عمل، باید تأیید امضا را روی یک سِرور انجام دهید نه روی دستگاه کاربر. پیاده سازی فرآیند تأیید روی سِرور، شکستن فرآیند تأیید توسط مهندسی معکوس کردن فایل apk را مشکل میکند. اگر پردازش امنیتی را به سِرور خود منتقل کردید، مطمئن شوید که ارتباط بین دستگاه و سِرور شما امن است.
از محتوای رمزنگاری نشدهٔ خود محافظت کنید¶
برای جلوگیری از انتشار غیر قانونی محتوای خود توسط کاربران سوءاستفادهگر، سعی کنید این محتوا را درون فایل apk برنامهٔ خود قرار ندهید، در عوض، یکی از این کارها را انجام دهید: از یک وبسرویس real-time برای انتقال محتوا به برنامهٔ خود استفاده کنید. این کار به شما اجازه میدهد محتوای خود را بهروز نگهدارید.
- از یک سِرور برای انتقال محتوا به برنامهٔ خود استفاده کنید.
وقتی محتوا را از سِرور یا یک سرویس real-time دریافت میکنید، میتوانید آن را در حافظهٔ موقت دستگاه یا حافظهٔ SD کارت ذخیره کنید. اگر محتوا را روی SD کارت ذخیره میکنید، حتماً آن را رمزگذاری کنید و از یک کلید رمزنگاری مختص همان دستگاه استفاده کنید.
کدهایتان را مبهم و به هم ریخته کنید¶
شما باید کد پرداخت درون برنامهای خود را مبهم و به هم ریخته (obfuscate) کنید تا کار را برای مهاجمینی که میخواهند از طریق مهندسی معکوس پروتکلهای امنیتی، به محتوا و سایر اجزای برنامهتان دسترسی پیدا کنند، سخت کنید. ما به شما پیشنهاد میکنیم حداقل ابزار مبهمسازی مثل Proguard را روی کدهایتان اعمال کنید.
همچنین برای مبهمسازی کد پرداخت درون برنامه ای تکنیکهای زیر را به شما پیشنهاد میکنیم:
متدها را درون متدهای دیگر قرار دهید (Inline methods).
- به جای اینکه رشتهها را به صورت ثابت تعریف کنید آنها را در زمان اجرا بسازید.
- از Java Reflection برای فراخوانی متدها استفاده کنید.
استفاده از این تکنیکها احتمال موفقیت مهاجمان در حمله به برنامهٔ شما را کاهش میدهد و به تبع باعث افزایش امنیت پیادهسازی پرداخت درون برنامهای میشود.
هشدار
اگر از Proguard برای مبهم کردن کد استفاده میکنید، بایستی خط زیر را به فایل تنظیمات Proguard اضافه کنید:
keep class com.android.vending.billing
تمام بخشهای برنامهٔ نمونه را تغییر دهید¶
اگر از کدهای برنامهٔ نمونهٔ پرداخت درون برنامهای (TrivialDrive) برای پیادهسازی پرداخت درونبرنامهای استفاده کردهاید لطفاً توجه داشته باشید که این برنامه در دسترس عموم است و میتواند توسط هر کسی دانلود شود. این امر به معنی این است که مهندسی معکوس برنامهٔ شما توسط مهاجمین آسانتر خواهد شد. اگر شما از کد نمونه دقیقاً به همان شکلی که منتشر شده است استفاده میکنید، سعی کنید قبل از انتشار برنامهٔ خود، آن را تغییر دهید. برای مثال میتوانید نام مِتدهای درون کلاسهای کمکی موجود در پوشهٔ util
را تغییر دهید.
همچنین از آنجایی که مهاجمین عموماً به دنبال نقاط شروع و پایان شناخته شدهٔ هر برنامه هستند، تغییر این بخش از کدها که همانند برنامهٔ نمونه هستند بسیار مهم است.
از nonce های تصادفی امن استفاده کنید¶
nonce هایی که استفاده میکنید نباید قابل حدس زدن باشند یا دوباره استفاده شوند. همیشه از یک الگوریتم رمزنگاری امن مانند SecureRandom برای تولید nonce ها استفاده کنید. با این کار میتوانید از حملات replay یا playback جلوگیری کنید. همچنین اگر صحت nonce ها را سمت سِرور بررسی میکنید، حتماً آنها را سمت سِرور ایجاد کنید.
توجه
یادآوری: nonce در بحث امنیت عدد اختیاری است که تنها یک مرتبه در یک ارتباط رمزنگاری شده استفاده میشود. اغلب یک عدد تصادفی یا شبهتصادفی است که در پروتکل احرازهویت میآید (برای اطمینان از این که ارتباطات قبلی نمیتوانند در حملات replay مجدداً استفاده شوند).
برای درخواست خرید حتماً از developer payload استفاده کنید¶
در API نسخهٔ ۳ پرداخت درون برنامهای میتوانید همراه هر درخواست خرید یک توکن رشتهای موسوم به developer payload هم به اول مارکت ارسال کنید. این رشته میتواند به عنوان یک شناسهٔ منحصر به فرد از سمت شما برای این خرید در نظر گرفته شود. اول مارکت بعد از اتمام مراحل خرید این رشته را همراه با جزئیات پرداخت به برنامهٔ شما بازمیگرداند. متعاقباً هنگامی که اطلاعات این خرید را ازاول مارکت میپرسید، اول مارکت این رشته را نیز همراه دیگر جزئیات خرید برمیگرداند.
شما باید توکن رشتهای استفاده کنید که به برنامهتان در تشخیص کاربری که خرید را انجام داده کمک کند. به این ترتیب بعداً میتوانید بفهمید که خرید مورد نظر برای کاربر معتبر است یا خیر. برای محصولات مصرفی این رشته میتواند کاملاً تصادفی باشد؛ اما برای محصولات غیرمصرفی، برای اطمینان از صحت خریده شدن محصول توسط کاربر باید از رشتهای استفاده کنید که منحصراً آن فرد را شناسایی میکند.
توجه
از آنجایی که برنامهٔ شما به اطلاعات حساب کاربر دراول مارکت دسترسی ندارد، در اینجا منظور کاربر برنامهٔ خودتان است (البته در صورتی که در برنامهتان امکان ایجاد حساب کاربری وجود داشته باشد).
وقتی که پاسخ را از اول مارکت دریافت کردید، مطمئن شوید رشتهٔ developer payload که اول مارکت همراه با جزئیات خرید به شما بازگردانده است، همانی است که شما برای شروع عملیات پرداخت به اول مارکت ارسال کرده بودید. برای اطمینان از امنیت بیشتر پیشنهاد میشود این عملیات اعتبارسنجی را بر روی سِرور خود انجام دهید.
اقدام علیه نقض کپی رایت و علامت تجاری¶
اگر میبینید محتوای شما در حال تکثیر و پخش در برنامههای دیگر است، خیلی سریع و قاطعانه این مورد را پیگیری کنید.
مجوز دسترسی کاربران به محتوای خریداری شده را همیشه بررسی کنید¶
اگر از یک سِرور برای فراهم کردن محتوای خریداری شده به کاربران خود استفاده میکنید، همیشه سعی کنید مجوز دسترسی کاربران به این محتوا را بررسی کنید. بدین ترتیب میتوانید هر موقع احساس کردید دزدی یا درخواست غیر مجازی صورت گرفته است، مجوز آن کاربر را لغو کرده و جلوی دسترسی او را بگیرید.
از کلید عمومی اول مارکت محافظت کنید¶
برای ایمن نگه داشتن کلید عمومی از گزند کاربران مخرب یا هکرها، سعی کنید آن را به صورت رشتهای ثابت درون کد قرار ندهید. در عوض برای پنهان کردن کلید اصلی، آن را به طریقی در زمان اجرا بسازید یا از دستکاری بیتها (مانند XOR با چند رشتهٔ دیگر) استفاده کنید یا آن را از یک مخزن رمزشده بگیرید. خود کلید دادهٔ محرمانهای نیست، امامطمئناً نمیخواهید کار را برای هکرها جهت جایگزینی کلید عمومی برنامهٔ شما با کلیدی دیگر آسان کنید.
مرجع پرداخت درونبرنامهای¶
این بخش شامل اطلاعات مرجع برای استفاده از API نسخهٔ ۳ پرداخت درون برنامهای است.
مرجع API¶
کدهای بازگشتی از سِرور¶
جدول زیر فهرست کاملی از پاسخهایی که سِرور اول مارکت به برنامهٔ شما باز میگرداند را ارائه میکند. کد پاسخ، عددی است که در کلید RESPONSE_CODE
در Bundle
بازگشتی از اول قرار دارد. باید تمام این کدهای پاسخ را در برنامهتان مدیریت کنید.
کد بازگشتی | مقدار | توضیحات |
---|---|---|
BILLING_RESPONSE_RESULT_OK | 0 | با موفقیت انجام شد. |
BILLING_RESPONSE_RESULT_USER_CANCELED | 1 | کاربر عملیات را لغو کرد. |
BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE | 3 | API برای درخواست ارسال شده پشتیبانی نمیشود. |
BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE | 4 | این محصول برای فروش موجود نیست. |
BILLING_RESPONSE_RESULT_DEVELOPER_ERROR | 5 | پارامترهای ارسالی به API معتبر نیستند. این خطا همچنین میتواند بیانگر این موارد باشد: برنامه به درستی امضا نشده است، تغییرات مورد نیاز در مانیفست ایجاد نشده است، برنامه در پنل پرداخت اول مارکت ثبت نشده یا مجوزهای لازم برای استفاده از پرداخت را کسب نکرده است. |
BILLING_RESPONSE_RESULT_ERROR | 6 | خطا در هنگام انجام عملیات پرداخت |
BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED | 7 | خطا در خرید به دلیل اینکه این محصول در حال حاضر در «مالکیت» کاربر است. |
BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED | 8 | خطا در مصرف، زیرا این محصول تحت «مالکیت» کاربر نیست. |
جدول ۱. کدهای بازگشتی در API نسخهٔ ۳ پرداخت
مرجع API¶
API پرداخت درون برنامهای در فایل IInAppBillingService.aidl
تعریف شده است. این فایل را میتوانید در برنامهٔ نمونه پیدا کنید.
متد getSkuDetails
¶
این متد جزئیات محصول هر یک از شناسههای محصول مشخص شده در لیست را برمیگرداند. در Bundle
بازگشتی از اول مارکت، نتایج کوئری در یک ArrayList
رشتهای که به کلید DETAILS_LIST
نگاشته شده است، قرار گرفتهاند. هر رشته در این آرایه حاوی اطلاعات محصول در فرمت JSON است. فیلدهای رشتهی JSON در جدول زیر توضیح داده شدهاند.
کلید | توضیحات |
---|---|
productId | شناسهٔ محصول (یا SKU) |
type | مقدار آن برای محصولات درون برنامهای فروشی “inapp” و برای اشتراکها “subs” است. |
price | قیمت فرمت شده همراه با علامت ﷼. توجه کنید که این قیمت همان قیمتی است که در پنل پرداخت وارید کردهاید. |
title | عنوان محصول |
description | توضیحاتی در مورد این محصول |
جدول ۲. توضیحات فیلدهای موجود در رشتهٔ JSON بازگشتی با فراخوانی متد getSkuDetails
متد getBuyIntent¶
این متد یک کد پاسخ (که در کلید RESPONSE_CODE
قرار دارد) و یک PendingIntent
برای راهاندازی خرید محصول (که در کلیدBUY_INTENT
قرار دارد) را باز میگرداند. اول مارکت پس از دریافت PendingIntent
، یک Intent
پاسخ حاوی دادههای مربوط به آن خرید را برمیگرداند. در جدول ۳ دادههای بازگشتی در Intent
پاسخ به صورت خلاصه توضیح داده شدهاند.
کلید | توضیحات |
---|---|
RESPONSE_CODE | اگر مقدار آن 0 باشد نشاندهنده یک خرید موفقیتآمیز است. هر مقدار دیگر نشاندهندهٔ بروز خطا است. |
INAPP_PURCHASE_DATA | یک رشته حاوی اطلاعات خرید در فرمت JSON است. توضیحات فیلدهای این رشته در جدول ۴ آمده است. |
INAPP_DATA_SIGNATURE | یک رشته حاوی امضای اطلاعات خرید میباشد که توسط کلید خصوصی توسعهدهنده امضا شده است. |
جدول ۳. دادههای بازگشتی بعد از درخواست خرید در API نسخهٔ ۳
کلید | توضیحات |
---|---|
autoRenewing | این فیلد بیانگر این است که آیا اشتراک به صورت خودکار تمدید میشود یا خیر. در صورتی که مقدار آن true باشد، اشتراک فعال است و به صورت خودکار با سررسیدن تاریخ پرداخت بعدی فعال میشود. در صورتی که مقدار آن false باشد، بیانگر این است که کاربر اشتراک را لغو کرده است. در این صورت کاربر تنها تا پایان دورهٔ فعلی اشتراکش به محتوای اشتراک دسترسی خواهد داشت و با اتمام دورهٔ فعلی اجازهٔ دسترسی به محتوای اشتراک را از دست خواهد داد (مگر اینکه دوباره قابلیت تمدید خودکار را فعال کند یا آن را به صورت دستی، آنگونه که در قسمت تمدید دستی توضیح داده شده است، تمدید کند). |
orderId | یک شناسهٔ منحصر به فرد برای هر سفارش. |
packageName | نام بستهٔ برنامهای که خرید از آن صورت گرفته. |
productId | شناسهٔ محصول یا SKU. که در هنگام اضافه کردن محصول در پنل پرداخت آن را تعریف میکنید. |
purchaseTime | زمان خرید محصول را بر حسب میلی ثانیه (از تاریخ ۱ ژانویه ۱۹۷۰) نشان میدهد. |
purchaseState | وضعیت این سفارش. مقادیر ممکن عبارتند از: 0 (خریداری شده)، 1 (لغو شده)، 2 (برگشت خورده). |
developerPayload | رشتهای است که توسعهدهنده آن را میسازد و حاوی اطلاعات تکمیلی در مورد سفارش خرید است. زمانی که درخواست getBuyIntent را میسازید میتوانید مقداری نیز برای این فیلد مشخص کنید. |
purchaseToken | رشتهای است که توسط اول مارکت برای شناسایی یکتای یک تراکنش پرداخت ساخته میشود. |
جدول ۴. توضیحات فیلدهای JSON در INAPP_PURCHASE_DATA
متد getPurchases¶
این متد محصولاتی که کاربر خریداری کرده ولی هنوز مصرف نشدهاند را باز میگرداند. در جدول ۵ دادههای بازگشتی در Bundle پاسخ آورده شده است.
کلید | توضیحات |
---|---|
RESPONSE_CODE | اگر درخواست موفقیتآمیز باشد مقدار آن 0 است. هر مقدار دیگر نشاندهندهٔ بروز خطا است. |
INAPP_PURCHASE_ITEM_LIST | یک ArrayList رشتهای حاوی لیستی از شناسهٔ محصولات است. |
INAPP_PURCHASE_DATA_LIST | یک ArrayList حاوی جزئیات خریدها است. برای آگاهی از جزئیات اطلاعات ذخیره شده در هر آیتم INAPP_PURCHASE_DATA از لیست، به جدول ۴ مراجعه کنید. |
INAPP_DATA_SIGNATURE_LIST | یک ArrayList رشتهای حاوی امضای خریدها است. |
INAPP_CONTINUATION_TOKEN | توکنی برای بازیابی دستهٔ بعدی محصولات درونبرنامهای که این کاربر مالک آنها است. اول مارکت در صورتی این فیلد را مقداردهی میکند که تعداد محصولاتی که کاربر صاحب آنها است، زیاد باشد. وقتی که این توکن در پاسخ موجود باشد، برای دریافت مابقی لیست خریدهای کاربر باید مجدداً getPurchases را فراخوانی کرده و این توکن را نیز به آن بدهید. پاسخ بازگشتی شامل ادامهٔ لیست خریدهای کاربر و احتمالاً توکنی دیگر خواهد بود. در صورت موجود بودن این توکن در پاسخ برگردانده شده، باید این روند را تا زمانی که لازم است ادامه دهید تا لیست همهٔ خریدهای کاربر را دریافت کنید. |
جدول ۵. پاسخ بازگشتی حاصل از فراخوانی متد getPurchases