En

فصل ۷: پیاده‌سازی خرید درون‌برنامه‌ای

خرید درون‌برنامه‌ای مایکت API ساده‌ای برای شما فراهم کرده تا به راحتی بتوانید امور خرید را مدیریت کنید. در ادامه نحوه ارسال درخواست از برنامه شما به سرویس خرید درون‌برنامه‌ای نشان داده شده.

توجه: برای دیدن یک پیاده‌سازی کامل و نحوه اجرای درست، فصل ۲ را ببینید. در آن بخش یک مثال کامل برای نحوه پیاده‌سازی خرید درون‌برنامه‌ای شرح داده شده، که حاوی کلاس‌های کمکی برای انجام وظایف کلیدی است، مانند راه‌اندازی اولیه، ارسال درخواست‌ها، بررسی پاسخ‌های مایکت، و مدیریت threadهای پس‌زمینه تا بتوانید خرید درون‌برنامه‌ای را از activity اصلی خود صدا بزنید.

قبل از شروع، توصیه می‌شود که فصل ۵ را برای آشنایی با مفاهیم اصلی بخوانید تا پیاده‌سازی برای شما راحت‌تر شود.

برای پیاده‌سازی خرید درون‌برنامه‌ای در برنامه‌تان شما باید موارد زیر را انجام دهید:

  1. کتابخانه خرید درون‌برنامه‌ای را به برنامه خود اضافه کنید.
  2. فایل AndroidManifest.xml را بروزرسانی کنید.
  3. یک ServiceConnection بسازید و آن را به IInAppBillingService متصل کنید.
  4. درخواست‌های خرید درون برنامه را از برنامه خود به IInAppBillingService بفرستید.
  5. پاسخ‌های دریافتی از مایکت را بررسی کنید.

اضافه کردن فایل AIDL به برنامه

IInAppBillingService.aidl یک فایل AIDL است که رابطی برای سرویس خرید درون‌برنامه‌ای مایکت تعریف می‌کند. شما از این رابط برای برقراری ارتباط با مایکت استفاده می‌کنید.

دریافت فایل AIDL:

  1. برنامه نمونه TrivialDrive را از اینجا و یا در Github مشاهده نمایید.

    فایل را در آدرس /src/com/android/vending/billing/IInAppBillingService.aidl پیدا می‌کنید.

اضافه کردن فایل AIDL به پروژه:

  1. فایل IInAppBillingService.aidl را در پروژه خود کپی کنید.
  2. اگر از محیط Eclipse استفاده می‌کنید:

    1. اگر قبلا پروژه خود را ساخته‌اید آن را در Eclipse باز کنید، در غیر این صورت یک Android Application Project جدید بسازید.
    2. در پوشه /src روی File > New > Package کلیک کنید تا یک package جدید ایجاد کنید و نام آن را com.android.vending.billing قرار دهید.
    3. فایل IInAppBillingService.aidl را که در مرحله قبل گرفته‌اید در بسته src/com.android.vending.billing/ کپی کنید.
  • اگر از محیطی غیر از Eclipse استفاده می‌کنید: پوشه /src/com/android/vending/billing را در پروژه خود بسازید و فایل IInAppBillingService.aidl را که گرفته‌اید در این پوشه کپی نمایید. فایل AIDL در پروژه خود قرار دهید و به وسیله ابزار Ant پروژه خود را build تا فایل IInAppBillingService.java ساخته شود.
  • برنامه خود را build کنید. حال باید فایلی با نام IInAppBillingService.java در پوشه /gen خود داشته باشید. دقت کنید که شما این فایل را دستی نمی‌سازید بلکه بعد در طی build کردن ساخته می‌شود.
  • بروزرسانی Manifest برنامه

    خرید درون‌برنامه‌ای وابسته به برنامه مایکت است، که همه ارتباطات بین برنامه شما و سرور مایکت را مدیریت خواهد کرد. برای استفاده از برنامه مایکت برنامه شما باید مجوز مناسب را درخواست کند. شما می‌توانید این کار را با اضافه کردن مجوز ir.mservices.market.BILLING به فایل AndroidManifest.xml انجام دهید. در صورتی که برنامه شما مجوز خرید درون‌برنامه‌ای را درخواست نکرده باشد، درخواست‌اش برای ارتباط با مایکت پذیرفته نمی‌شود و برنامه شما با خطا مواجه می‌شود.

    شما می‌توانید برای برنامه خود اجازه‌های لازم را با قرار دادن کد زیر در فایل AndroidManifest.xml صادر کنید:


    <uses-permission android:name="ir.mservices.market.BILLING" />

    ساخت یک ServiceConnection

    برنامه شما برای ارتباط با مایکت باید یک ServiceConnection داشته باشد استفاده کند. برنامه شما حداقل باید موارد زیر را انجام دهد:

    • اتصال به IInAppBillingService.
    • ارسال درخواست‌ها به برنامه مایکت.
    • مدیریت پاسخ‌ها که برای هر درخواست بر‌می‌گردد.

    متصل شدن به IInAppBillingService

    برای برقراری ارتباط با سرویس خرید درون‌برنامه‌ای مایکت، یک ServiceConnection را برای متصل شدن activity خود به IInAppBillingService پیاده‌سازی کنید. متدهای onServiceDisconnected و onServiceConnected را override کنید تا یک نمونه از IInAppBillingService را بعد از ایجاد اتصال دریافت کنید.

    IInAppBillingService mService;
    ServiceConnection mServiceConn = new ServiceConnection() {
    @Override
    mService = null;
    public void onServiceDisconnected(ComponentName name){ }
    public void onServiceConnected(ComponentName name,IBinder service){
    @Override
    mService = IInAppBillingService.Stub.asInterface(service); }
    };

    در متد OnCreate از activity خود، اتصال را با فراخوانی متد bindService برقرار کنید. به ورودی آن یک Intent که به سرویس خرید درون‌برنامه‌ای اشاره می‌کند، و یک نمونه از ServiceConnection که ساخته‌اید را بدهید.

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);       
        bindService(new Intent("com.android.vending.billing.InAppBillingService.BIND"), mServiceConn, Context.BIND_AUTO_CREATE);
    }

    شما هم اکنون می‌توانید از mService برای برقراری ارتباط با مایکت استفاده کنید.

    مهم: یادتان باشد در انتهای کار اتصال با سرویس حتما قطع کنید. اگر این اتصال را قطع نکنید، اگر این اتصال باز بماند ممکن است باعث کاهش کارایی دستگاه کابر شود. مثال زیر نحوه قطع نمودن اتصال از یک ServiceConnection به نام mServiceConn را با overrid کردن متد OnDestroy در activity نشان می‌دهد.

    @Override
    public void onDestroy() {
    super.onDestroy();
    unbindService(mServiceConn);
    if (mService !=null){ }
    }

    برای پیاده‌سازی کامل یک ServiceConnection که به IInAppBillingService متصل می‌شود، فصل ۲ و مثال‌هایش را ببینید.

    فرستادن درخواست‌های خرید درون‌برنامه‌ای

    هنگامی که برنامه شما به مایکت متصل شد، شما می‌توانید برای محصولات درون برنامه درخواست خرید بفرستید. مایکت یک رابط کاربری برای روند پراخت کاربران فراهم می‌کند طوری که برنامه شما درگیر مدیریت ترانکش‌ها نخواهد شد و این عملیات‌ها بر عهده مایکت خواهد بود. وقتی یک محصول خریداری شد، مایکت کاربر را مالک آن می‌داند و تا زمانی که مصرف نشده، از خرید دوباره آن محصول (یعنی شناسه محصول‌ها یکی باشد) توسط کاربر جلوگیری می‌کند. شما باید نحوه مصرف محصولات در برنامه‌تان را کنترل کنید و مایکت را برای مصرف مطلع سازید تا محصول دوباره برای خرید مهیا شود. شما همچنین می‌توانید به راحتی فهرست محصولاتی که کاربر مالک آنهاست را از مایکت بخواهید. این زمانی مفید خواهد بود که مثلا بخواهید هنگام باز شدن برنامه‌تان بر اساس این محصولات به کاربر سرویس مناسبی دهید.

    کوئری محصولات موجود برای خرید:

    در برنامه‌تان، شما می‌توانید اطلاعات ریز محصول‌تان را از مایکت درخواست کنید. برای فرستادن چنین درخواستی، ابتدا یک Bundle بسازید که حاوی یک ArrayList از شناسه محصولات با کلید ITEM_ID_LIST است.

    ArrayList skuList = new ArrayList ();
    skuList.add("premiumUpgrade");
    Bundle querySkus =
    skuList.add("gas"); new Bundle();
    querySkus.putStringArrayList("ITEM_ID_LIST", skuList);
    Bundle skuDetails = mService.getSkuDetails(3, getPackageName(), "inapp", querySkus)

    برای دریافت این اطلاعات از مایکت، متد getSkuDetails را فراخوانی کنید و به عنوان نسخه خرید درون‌برنامه‌ای مقدار «3»، نام بسته برنامه (packange name)، نوع خرید ("inapp") و Bundleی که ساختید را بدهید.

    Bundle skuDetails = mService.getSkuDetails(3, getPackageName(), "inapp", querySkus);

    اگر درخواست موفقیت‌آمیز باشد، Bundleی که برگردانده می‌شود یک کد پاسخ BILLING_RESPONSE_RESULT_OK (0) خواهد داشت.

    هشدار: هشدار: متد getSkuDetails را در thread اصلی برنامه خود فراخوانی نکنید. اگر این متد را فراخوانی کنید باعث ایجاد درخواستی شبکه‌ای در برنامه شما می‌شود و برنامه مسدود می‌شود. در عوض یک thread جداگانه بسازید و متد getSkuDetails را از درون آن فراخوانی نمایید.

    برای دیدن *همه‌ی* کدهای پاسخ از مایکت، فصل ۸ را مطالعه نمایید.

    نتایج کوئری در یک ArrayList با کلید DETAILS_LIST و اطلاعات خرید در یک رشته دیگر با فرمت JSON ذخیره شده است. برای مشاهده جزئیات محصول که برگردانده می شود به فصل ۸ مراجعه کنید.

    در این مثال، شما قیمت محصولات خود را از skuDetails، همان Bundleی که در کد قبلی برگردانده شده است، بازیابی می‌کنید.

    int response = skuDetails.getInt("RESPONSE_CODE");
    if (response == 0) {
       ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");
       for (String thisResponse : responseList) {       JSONObject object = new JSONObject(thisResponse);
          if (sku.equals("premiumUpgrade")) mPremiumUpgradePrice = price;
          String sku = object.getString("productId");       String price = object.getString("price");       else if (sku.equals("gas")) mGasPrice = price;
       }
    }

    خرید یک محصول

    برای شروع یک درخواست خرید در برنامه‌تان، متد getBuyIntent در سرویس خرید درون‌برنامه‌ای را فراخوانی کنید. به این متد ورودی‌های، نسخه API خرید درون‌برنامه‌ای (3)، نام بسته برنامه‌تان (package name)، شناسه محصول، نوع خرید ("inapp") و یک رشته developerPayload، را بدهید. از رشته developerPayload برای مشخص کردن هر اطلاعات اضافی که مایلید مایکت به همراه اطلاعات خرید برای شما برگرداند، استفاده می‌شود.

    Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(),    sku, "inapp", "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");

    اگر درخواست موفقیت‌آمیز باشد، Bundleی که برگردانده می‌شود حاوی کد پاسخ BILLING_RESPONSE_RESULT_OK (0) و یک PendingIntent است که شما می‌توانید از آنها برای آغاز عملیات خرید استفاده نمایید. برای مشاهده تمامی کدهای پاسخی که ممکن است از مایکت دریافت کنید به فصل ۸ مراجعه نمایید. پس از آن یک 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 یک کد نتیجه Activity.RESULT_OK (1) یا Activity.RESULT_CANCELED (0) را خواهد داشت. برای مشاهده سایر اطلاعاتی که در Intent وجود دارد، فصل ۸ را ببینید.

    اطلاعات خرید برای سفارش یک رشته با فرمت JSON است که با کلید INAPP_PURCHASE_DATA در Intent پاسخ قرار دارد، به عنوان مثالی از چنین رشته JSONی:

    '{
    "orderId":"12999763169054705758.1371079406387615",
    "packageName":"com.example.app",
    "purchaseTime":1345678900000,
    "productId":"exampleSku", "purchaseState":0,
    "purchaseToken":"rojeslcdyyiapnqcynkjyyjh"
    "developerPayload":"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ", }'

    در ادامه مثال قبل، شما کد پاسخ، داده‌های خرید و امضای دیجیتالی را در Intent پاسخ دریافت می‌کنید.

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == 1001) {
    String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
    int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
    if (resultCode == RESULT_OK) {
    String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE"); try {
    alert("You have bought the " + sku + ". Excellent choice, adventurer!");
    JSONObject jo = new JSONObject(purchaseData); String sku = jo.getString("productId"); }
    }
    catch (JSONException e) { alert("Failed to parse purchase data."); e.printStackTrace(); } }
    }

    توصیه امنیتی: وقتی که شما یک درخواست خرید ارسال می‌کنید، یک رشته‌ی token بسازید که به طور منحصر به فرد این درخواست خرید را مشخص کند و آن را در developerPayload قراد دهید. شما می‌توانید از یک رشته‌ای که تصادفی تولید شده به عنوان token استفاده کنید. هنگامی که شما پاسخ خرید را از مایکت دریافت می‌کنید مطمئن شوید که امضای دیجیتالی، orderId، و رشته developerPayload داده‌های بازگشتی را بررسی می‌کنید. برای امنیت بیشتر، شما باید این کار را بر روی سرورهای امن خود انجام دهید. اطمینان حاصل کنید که orderId یک مقدار منحصر به فرد باشد و شما قبلا آن را پردازش نکرده‌اید و رشته developerPayload با tokenی که قبلاً با درخواست خرید فرستاده‌اید مطابقت داشته باشد.

    کوئری محصولات خریده شده

    برای بازیابی اطلاعات خریدهای کاربر از برنامه‌تان، متد getPurchases را فراخوانی کنید و به عنوان ورودی ، شماره نسخه‌ی API درون‌برنامه‌ای (3)، نام بسته برنامه‌تان (package name) و نوع خرید ("inapp") را بدهید.

    Bundle ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null);

    سرویس مایکت تنها برای کاربری که در حال حاضر در برنامه مایکت وارد شده کار می‌کند. اگر درخواست موفقیت آمیز باشد، Bundle برگشتی کد پاسخ 0 خواهد داشت. همچنین Bundle پاسخ حاوی یک لیست از شناسه محصول، یک لیست از جزئیات سفارش هر خرید و همچنین امضاهای دیجیتال هر خرید می‌باشد.

    به منظور بهبود عملکرد سرویس خرید درون‌برنامه‌ای، وقتی برای بار اول getPurchase را فراخوانی می‌کنید فقط تا سقف معینی محصول متعلق به کاربر را بر می‌گرداند (برای مثال ۷۰۰ تا). اگر کاربر تعداد محصولاتی که خریداری کرده بیشتر باشد، مایکت یک رشته token که بر روی کلید INAPP_CONTINUATION_TOKEN منطبق شده را در Bundle پاسخ قرار می‌دهد تا به شما نشان دهد کاربر محصولات بیشتری برای نمایش دارد و می‌توانید آنها را بازیابی کنید. سپس برنامه شما getPurchases را فرا می‌خواند و این token را به عنوان آرگومان ورودی به آن می‌دهد. مایکت بازگرداندن token های دنباله دار را تا زمانی که تمام محصولاتی که متعلق به کاربر است ارسال نشده ادامه می‌دهد.

    برای کسب اطلاعات بیشتر در مورد داده‌هایی که توسط getPurchases بازگردانده می‌شوند فصل ۸ را مطالعه نمایید. مثال زیر نشان می‌دهد که شما چگونه می‌توانید این اطلاعات را بازیابی کنید.

    int response = ownedItems.getInt("RESPONSE_CODE");
    if (response == 0) {
    ArrayList<String> ownedSkus = ownedItems.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
    ArrayList<String> purchaseDataList = ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
    String continuationToken = ownedItems.getString("INAPP_CONTINUATION_TOKEN");
    ArrayList<String> signatureList = ownedItems.getStringArrayList("INAPP_DATA_SIGNATURE"); for (int i = 0; i < purchaseDataList.size(); ++i) {
    // do something with this purchase information
    String purchaseData = purchaseDataList.get(i); String signature = signatureList.get(i); String sku = ownedSkus.get(i);

    // 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
    }

    مصرف نمودن یک خرید

    هنگامی که محصولی توسط کاربر خریداری می‌شود مالک آن تلقی می‌شود و امکان خرید دوباره آن را نخواهد داشت. شما باید یک درخواست مصرف به مایکت ارسال کنید تا مایکت اجازه خرید دوباره محصول را به کاربر بدهد.

    مهم: تنها محصولات «مصرف شدنی» را می‌توان مصرف کرد، درخواست مصرف برای محصولات «مصرف نشدنی» کد پاسخ خطا برمی‌گرداند.

    اینکه شما چگونه مصرف شدن محصول در برنامه خود را پیاده می‌کنید به عهده شماست. معمولا شما محصولاتی را مصرف می‌کنید که اثر موقت در برنامه دارند و کاربر ممکن است بخواهد چندین بار آنها را بخرد ( برای مثال خرید پول در یک بازی). اما محصولاتی که با یک بار خرید اثر دائمی دارند را مصرف نمی‌کنید (مانند ارتقای حساب کاربری در برنامه).

    برای ثبت مصرف یک خرید، متد consumePurchase را فراخوانی نمایید و مقدار رشته purchaseToken (که خریدی را مشخص می‌کند که قرار است مصرف شود) را به عنوان ورودی به آن بدهید. purchaseToken بخشی از داده‌ای است که در INAPP_PURCHASE_DATA به وسیله مایکت بعد از یک خرید موفق برگردانده می‌شود. در این مثال، شما مصرف محصولی را که با purchaseToken در متغیر token مشخص می‌شود، مصرف می‌کنید.

    int response = mService.consumePurchase(3, getPackageName(), token);

    هشدار: متد consumePurchase را در thread اصلی برنامه خود فراخوانی نکنید. اگر این کار را کنید باعث ایجاد درخواست شبکه‌ای (اینترنتی) در برنامه شما می‌شود و آن را مسدود کند. در عوض یک thread جداگانه بسازید و متد consumePurchase را درون آن فراخوانی نمایید.

    این مسئولیت شماست که مزایای هر محصول را به کاربر ارائه دهید. به عنوان مثال اگر یک کاربر در بازی شما پول یا سکه خریداری کند، شما باید مقدار پول یا تعداد سکه او را بروز رسانی نمایید.

    توصیه ایمنی: شما باید قبل از ارائه مزایای یک محصول مصرف شدنی، یک درخواست مصرف را به مایکت ارسال نمایید و مطمن شوید که مایکت درخواست مصرف را تایید کرده است.

    محصولات اشتراکی

    مایکت از اشتراک پشتیبانی می‌کند. در آینده نزدیک مستند این نوع خرید درون‌برنامه‌ای منتشر خواهد شد. برای اطلاعات بیشتر در این زمینه می‌توانید از تیم پشتیبانی مایکت به آدرس ایمیل developer@myket.irکمک بگیرید.

    برنامه خود را ایمن کنید

    برای امنیت اطلاعاتی که به برنامه شما ارسال می‌شود، مایکت رشته JSON پاسخ هر سفارش خرید را امضای دیجیتالی می‌کند. مایکت برای هر برنامه یک جفت کلید RSA می‌سازد که با استفاده از کلید اختصاصی امضای دیجیتال را انجام می‌دهد، و کلید عمومی را در پنل توسعه‌دهندگان در دسترس شما قرار می‌دهد تا برای تایید امضا از آن استفاده کنید. در برنامه مثال TrivialDrive کلاس‌هایی فراهم شده که عملیات تایید امضا را انجام می‌دهند، می‌توانید از آنها استفاده کنید.

    توجه: برای فهمیدن کلید عمومی برنامه خود، در پنل توسعه‌دهندگان مایکت اینجا را ببینید.

    زمانی که برنامه شما داده‌های امضا شده را دریافت می‌کند، می‌توانید از کلید عمومی مخصوص برنامه خود برای تایید امضای دیجیتال استفاده نمایید. با تایید کردن امضا می‌توانید مطمئن شوید که داده‌ها دستکاری نشده‌اند. شما می‌توانید این کار را در برنامه‌تان انجام دهید اما اگر برنامه شما به یک سرور امن وصل می‌شود، ما پیشنهاد می‌کنیم بررسی صحت امضا را در آن سرور انجام دهید.

    برا ی کسب اطلاعات بیشتر فصل ۹ را ببینید.


    مراجعه به فصل 8

    کلیه حقوق متعلق به مایکت می باشد.