<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های Majid Sadeghi</title>
        <link>https://virgool.io/feed/@majid.sadeghi</link>
        <description>برنامه نویس اندروید</description>
        <language>fa</language>
        <pubDate>2026-06-16 05:37:33</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/62888/avatar/RQ80jv.jpeg?height=120&amp;width=120</url>
            <title>Majid Sadeghi</title>
            <link>https://virgool.io/@majid.sadeghi</link>
        </image>

                    <item>
                <title>پیاده سازی همزمان پرداخت درون برنامه ای بازار و مایکت</title>
                <link>https://virgool.io/@majid.sadeghi/%D9%BE%DB%8C%D8%A7%D8%AF%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-%D9%87%D9%85%D8%B2%D9%85%D8%A7%D9%86-%D9%BE%D8%B1%D8%AF%D8%A7%D8%AE%D8%AA-%D8%AF%D8%B1%D9%88%D9%86-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D8%A7%DB%8C-%D8%A8%D8%A7%D8%B2%D8%A7%D8%B1-%D9%88-%D9%85%D8%A7%DB%8C%DA%A9%D8%AA-cl2rtdexaqq7</link>
                <description>سلام؛تو این مقاله میخوام روشی رو برای پیاده سازی همزمان پرداخت درون برنامه ای بازار و مایکت معرفی کنم که به کمک flavor بتونیم تنها با انتخاب نوع flavor، تمام فرآیند های انتخاب نوع پرداخت هم تغییر کنه.نکته مهمی که این مقاله دربرگیرنده اون هستش نحوه استفاده از flavor ها هستش و پیاده سازی پرداخت درون برنامه صرفا مثالی برای این پیاده سازی هستش. یکی دیگه از بهترین مثال های پیاده سازی این روش، داشتن همزمان کدهای مربوط به GMS و HMS ( سرویس های موبایلی گوگل و هواوی) هستش که درصورت بارگذاری اپ داخل استور هواوی، میبایست کتابخونه های گوگل حذف شوند.نکته: برای آشنایی به مبحث flavor در اندروید میتونید به مقالات مرتبط مراجعه کنید.نکته: اگه حال خوندن مطلب رو ندارید من سورس نمونه این برنامه رو تو گیت خودم گذاشتم که از لینک زیر در دسترس هستش و میتونید کانفیگ هاش رو ببینید.https://github.com/majidsa70/inAppPurchaseدر واقع شما اگه یه برنامه یا بازی داشته باشی که داخلش محصولی برای فروش داشته باشی و شامل قوانین پرداخت درون برنامه ای بشه، باید برای هر استور، SDK پرداخت اون استور رو هم داشته باشی. (واقعا رو مخه !) این مقاله از اون جایی شکل میگیره که خودم با این مساله مواجه بودم و مجبور شدم هر دو رو پیاده کنم. نکته ای که وجود داره اینه که وقتی بیلد بازار رو میخواد بذارید داخل بازار، نباید اثری از مایکت و یا سایر استور ها داخل بیلد کافه بازار باشه، و خب البته برعکس این هم صادقه، یعنی مایکت هم همین ایراد رو میگیره و البته بقیه استورها؛ پس باید یه راهی پیدا کنیم برای این موضوع که خب ممکنه راههای زیادی هم داشته باشه و هر کسی راه خودش رو بره و خب منم اینجا راه خودم رو معرفی میکنم. پس سعی میکنم گام به گام این پیاده سازی رو جلو ببریم. 1 - تعریف flavor های لازم در فایل build.gradle در ماژول اصلی به فایل نمونه توجه کنید :build.gradle(app)در این بخش من flavor های لازم رو اضافه کردم که میتونید تو عکس ببینید. بعد از اضافه کردن این بخش ها و rebuild کردن پروژه، در بخش Build Variants میتویند این flavor ها رو ببینید. مطابق تصویر زیر :2 - اضافه کردن dependency های پرداخت براساس نوع flavorدر بخش dependency در فایل build.gradle ماژول، ما باید کتابخونه SDK رو براساس نوع flavor اضافه کنیم. با این روش وقتی برای یک استور مشخص بیلد بگیریم، dependency استور دیگه داخل بیلد و manifest قرار نمیگیره و این عالیه !همونطور که در عکس بالا میبینید، من dependency رو براساس نوع flavor انتخاب کردم. به طور مثال برای flavor از نوع myket که در مرحله یک توضیح دادم، از دستور myKetImplementation استفاده کردم.3 - حالا بیاید یکم کار جدی و تمیز انجام بدیم. از اونجایی که ما برای پیاده سازی پرداخت درون برنامه ای به طور یکسان با هر استور رفتار میکنیم (البته تقریبا)، یعنی فرقی نداره تو چه استوری هستیم، پس میتونیم به روش abstract یک دستورالعمل یکسان برای همه ی مراحل پرداخت بنویسیم و بعدش به کمک strategy pattern ، برای هر استور پیاده سازی (implementation) متفاوتی داشته باشیم. پس بیاید شروع کنیم :سلکتور بخش پکیج بندی کد ها رو از حالت Android به Project تغییر بدید تا مشابه تصویر زیر بشهحالا روی src کلیک راست کنید و بعد New -&gt; Directory . حالا یک اسم کاملا مشابه اسم flavor براش انتخاب کنید. مثلا myket . سپس روی پوشه تازه ساخته شده دوباره مراحل قبل رو تکرار کنید و اینبار بجای تایپ کردن اسم، گزینه java رو از منوی نمایش داده شده انتخاب کنید:حالا شما یک پوشه به اسم myket دارید که مشابه پوشه main هستش. حالا باید پوشه های داخلی myket رو هم مشابه main ایجاد کنید. (در واقع پوشه ها همون package ها هستن که موقع ساخت پروژه جدید، براساس اسمی که از شما میپرسه خودش ایجادشون میکنه ). در نهایت میشه مثل عکس زیر :حالا مراحل بالا رو باید برای همه ی flavor هایی که قبلا ساختید هم انجام بدید.4 - تو این مرحله من یه package جدید برای همه ی flavor ها به نام payment ایجاد میکنم. توجه داشته باشید که چون من میخوام فارغ از نوع flavor دستورات abstract رو  بنویسم، پس payment رو تو همه ایجاد میکنم و بعدش کلاس abstract رو که از این به بعد بهش PaymentRepository میگم رو توی پوشه main میذارم که در واقع directory اصلی هستش. و بعد از اون سایر پوشه ها (flavor) کلاس پیاده سازی (implementation) خودشون رو خواهند داشت. PaymentRepository  : interface PaymentRepository {
    fun initService( result: (Result&lt;String&gt;) -&gt; Unit)
    fun stopConnection()
    fun launchPurchase(
        SKU: String,payload:String,
        activityResultRegistry: ActivityResultRegistry,
        result: (Result&lt;MyPurchaseInfo&gt;) -&gt; Unit
    )

    fun getPurchasedList(result: (Result&lt;List&lt;MyPurchaseInfo&gt;&gt;) -&gt; Unit)

    fun consumePurchase(purchaseInfo: MyPurchaseInfo, result: (Result&lt;MyPurchaseInfo&gt;) -&gt; Unit)
}
همونطور که قبلا گفتم این فقط یک نمونه اس و شما میتونید مدل کاملتری از این پرداخت رو داشته باشید.کلاس های نمونه پیاده سازی این interface رو میتونید توی سورس کامل github که ابتدای این مقاله گذاشتم ببینید.موفق باشید.</description>
                <category>Majid Sadeghi</category>
                <author>Majid Sadeghi</author>
                <pubDate>Tue, 20 Jun 2023 14:57:17 +0330</pubDate>
            </item>
                    <item>
                <title>kotlin extension function کاتلین اکستنشن</title>
                <link>https://virgool.io/@majid.sadeghi/kotlin-extension-function-ihl6ufhrthsn</link>
                <description>اکستنشن ها (Extensions) برای دسترسی به ویژگی های بیشتر یک شی (object) بسیار کاربردی هستن. در واقع به کمک اون ها می‌تونید ویژگی‌های بیشتری برای اشیا در کاتلین داشته باشید. در بعضی مواقع حتی اون ها رو می‌تونید جایگزین کلاس های ثابت (Object or Static class) کنید.فرض کنید می‌خواهید در داخل فرگمنت‌ها یک پیغام از نوع Toast نمایش دهید. در حالت عادی کدی مشابه زیر در هر فرگمنت خواهید داشت.fun showToast(message:String){
    activity?.let {  // 1
        Toast.makeText(it,message,Toast.LENGTH_SHORT).show()
    }
} 1 - در فرگمنت ها باید حتما وضعیت  نال (null) بودن activity رو چک کنید و سعی کنید از ()requireActivity استفاده نکنید چرا که در صورت نال بودن اکتیویتی، exception دریافت می‌کنید. حالا بیاید با کمک اکستنشن، یک ویژگی جدید به فرگمنت‌ها اضافه کنیم که دیگه نیازی نباشه تو هر فرگمنت متد showToast رو بنویسیم. fun Fragment.showToast(message: String) {
    this.activity?.let { // 1
        Toast.makeText(it, message, Toast.LENGTH_SHORT).show()
    }
}همونطور که می‌بینید قبل از اسم متد (showToast) ما باید شی‌ای که می‌خواهیم به آن ویژگی اضافه کنیم رو مشخص کنیم. در واقع با کمک کد بالا، ما یک ویژگی جدید به‌نام showToast به فرگمنت اضافه کردیم که این ویژگی در تمام فرگمنت ها دردسترس خواهد بود و دیگه نیازی نیست تو همه فرگمنت‌ها کد اولی رو داشته باشیم. در مورد نکته یک هم باید بگم که کلمه کلیدی this داره به Fragment اشاره میکنه.( this = کلاسی که داریم بهش ویژگی اضافه می‌کنیم)حالا بیاید یه مثال دیگه رو ببینیم تا مفهوم واضح تر بشه.اگه یادتون باشه بالاتر گفتم که میتونیم اکستنشن‌ها رو جایگزین بعضی از کلاس‌های ثابت کنیم. مثلا فرض کنید یه کلاس ثابت دارید که براتون چک میکنه به اینترنت وصل هستید یا نه (connection check).object ConnectionCheck {
    fun isConnected(context: Context): Boolean {
        return (context.getSystemService(Context.CONNECTIVITY_SERVICE) as 
                   ConnectivityManager).activeNetworkInfo?.isConnected == true
    }
}همونطور که می‌بینید من یه کلاس ثابت دارم که از همه جا تو پروژه در دسترس هستش و وضعیت اتصال رو بهم میگه. حالا بیاید با اکستنشن از دستش خلاص بشیم.val Context.isConnected: Boolean
    get() {
        return (getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager)
            .activeNetworkInfo?.isConnected == true
    }و تمام ! حالا فقط کافیه از هر کلاسی که به Context دسترسی داره، ویژگی isConnected رو ازش صدا کنم. مثلا الان میخوام از داخل یه فرگمنت وضعیت اتصال رو چک کنم :context?.isConnectedباید بگم فوق‌العاده است !اینجا من فقط سعی کردم دو تا مثال ساده رو بیان کنم. اما این مطلب پایانی نداره و تا دلتون بخواد می‌تونید اکستنشن به کلاس‌هاتون اضافه کنید. اینم بگم که شما به همه نوع کلاسی می‌تونید اکستنشن اضافه کنید . حتی به کلاس‌هایی که خودتون نوشتید و نه فقط به کلاس‌های خود اندروید.</description>
                <category>Majid Sadeghi</category>
                <author>Majid Sadeghi</author>
                <pubDate>Mon, 18 Jul 2022 16:53:19 +0430</pubDate>
            </item>
            </channel>
</rss>