یک SDK با قابلیت زمان اجرا بسازید و مصرف کنید

1
مفاهیم کلیدی
2
محیط توسعه خود را تنظیم کنید
3
یک RE SDK بسازید
4
RE SDK را مصرف کنید
5
آزمایش و ساخت برای توزیع
،
1
مفاهیم کلیدی
2
محیط توسعه خود را تنظیم کنید
3
یک RE SDK بسازید
4
RE SDK را مصرف کنید
5
آزمایش و ساخت برای توزیع

یک SDK با قابلیت زمان اجرا بسازید

برای ساختن یک SDK با قابلیت زمان اجرا باید مراحل زیر را انجام دهید:

  1. ساختار پروژه خود را تنظیم کنید
  2. وابستگی های پروژه و ماژول خود را آماده کنید
  3. منطق کسب و کار SDK خود را اضافه کنید
  4. API های SDK را تعریف کنید
  5. یک نقطه ورودی برای SDK خود مشخص کنید

ساختار پروژه خود را تنظیم کنید

ما توصیه می کنیم که پروژه شما در ماژول های زیر سازماندهی شود:

  1. ماژول برنامه - برنامه آزمایشی که از آن برای آزمایش و توسعه SDK خود استفاده می‌کنید و نشان‌دهنده آن چیزی است که مشتریان برنامه واقعی شما دارند. برنامه شما باید به ماژول کتابخانه تبلیغات موجود ( SDK آگاه از زمان اجرا ) وابستگی داشته باشد.
  2. ماژول کتابخانه تبلیغات موجود (SDK آگاه از زمان اجرا) - یک ماژول کتابخانه Android که حاوی منطق SDK «غیر فعال در زمان اجرا» شما است، یک SDK به صورت ایستا پیوند خورده است.
    • برای شروع، می توان توانایی ها را تقسیم کرد. به عنوان مثال، برخی از کدها را می توان توسط SDK موجود شما مدیریت کرد، و برخی را می توان به SDK فعال در زمان اجرا هدایت کرد.
  3. ماژول کتابخانه تبلیغاتی با قابلیت زمان اجرا - شامل منطق تجاری SDK فعال با زمان اجرا شما است. این را می توان در Android Studio به عنوان یک ماژول کتابخانه اندروید ایجاد کرد.
  4. ماژول ASB فعال در زمان اجرا - داده های بسته را برای بسته بندی کد SDK فعال شده با زمان اجرا در یک ASB تعریف می کند.
    • باید به صورت دستی با استفاده از نوع com.android.privacy-sandbox-sdk ایجاد شود. می توانید این کار را با ایجاد یک دایرکتوری جدید انجام دهید.
    • این ماژول نباید حاوی هیچ کد و فقط یک فایل خالی build.gradle با وابستگی به ماژول کتابخانه تبلیغاتی فعال در زمان اجرا شما باشد. محتوای این فایل در Prepare your SDK تعریف شده است.
    • به یاد داشته باشید که این ماژول را در فایل settings.gradle و در ماژول کتابخانه تبلیغات موجود قرار دهید.

ساختار پروژه در این راهنما یک پیشنهاد است، می توانید ساختار متفاوتی را برای SDK خود انتخاب کنید و همان اصول فنی را اعمال کنید. همیشه می‌توانید ماژول‌های اضافی دیگری برای مدولار کردن کد در برنامه و ماژول‌های کتابخانه ایجاد کنید.

SDK خود را آماده کنید

برای آماده سازی پروژه خود برای توسعه SDK با قابلیت زمان اجرا، ابتدا باید چند وابستگی ابزار و کتابخانه را تعریف کنید:

  • کتابخانه‌های سازگاری SDK Runtime Backwards، که از دستگاه‌هایی پشتیبانی می‌کنند که دارای جعبه ایمنی حریم خصوصی (اندروید ۱۳ و پایین‌تر) نیستند ( androidx.privacysandbox.sdkruntime: )
  • کتابخانه های رابط کاربری برای پشتیبانی از ارائه تبلیغات ( androidx.privacysandbox.ui: )
  • ابزارهای توسعه دهنده SDK برای پشتیبانی از اعلان API SDK و تولید شیم ( androidx.privacysandbox.tools: )
  1. این پرچم را به فایل gradle.properties پروژه خود اضافه کنید تا قابلیت ایجاد SDK با قابلیت زمان اجرا فعال شود.

    # This enables the Privacy Sandbox for your project on Android Studio.
    android.experimental.privacysandboxsdk.enable=true
    android.experimental.privacysandboxsdk.requireServices=false
    
  2. build.gradle پروژه خود را تغییر دهید تا کتابخانه های Jetpack کمکی و وابستگی های دیگر را شامل شود:

    // Top-level build file where you can add configuration options common to all sub-projects/modules.
    buildscript {
        ext.kotlin_version = '1.9.10'
        ext.ksp_version = "$kotlin_version-1.0.13"
        ext.privacy_sandbox_activity_version = "1.0.0-alpha01"
        ext.privacy_sandbox_sdk_runtime_version = "1.0.0-alpha13"
        ext.privacy_sandbox_tools_version = "1.0.0-alpha09"
        ext.privacy_sandbox_ui_version = "1.0.0-alpha09"
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        }
    }
    
    plugins {
        id 'com.android.application' version '8.4.0-alpha13' apply false
        id 'com.android.library' version '8.4.0-alpha13' apply false
    
        // These two plugins do annotation processing and code generation for the sdk-implementation.
        id 'androidx.privacysandbox.library' version '1.0.0-alpha02' apply false
        id 'com.google.devtools.ksp' version "$ksp_version" apply false
    
        id 'org.jetbrains.kotlin.jvm' version '1.9.10' apply false
    }
    
    task clean(type: Delete) {
        delete rootProject.buildDir
    }
    
  3. فایل build.gradle را در ماژول کتابخانه تبلیغاتی با قابلیت اجرا (RE SDK) به‌روزرسانی کنید تا این وابستگی‌ها را شامل شود.

    dependencies {
        // This allows Android Studio to parse and validate your SDK APIs.
        ksp "androidx.privacysandbox.tools:tools-apicompiler:$privacy_sandbox_tools_version"
    
        // This contains the annotation classes to decorate your SDK APIs.
        implementation "androidx.privacysandbox.tools:tools:$privacy_sandbox_tools_version"
    
        // This is runtime dependency required by the generated server shim code for
        // backward compatibility.
        implementation "androidx.privacysandbox.sdkruntime:sdkruntime-provider:$privacy_sandbox_sdk_runtime_version"
    
        // These are runtime dependencies required by the generated server shim code as
        // they use Kotlin.
        implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1"
        implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1'
    
        // This is the core part of the UI library to help with UI notifications.
        implementation "androidx.privacysandbox.ui:ui-core:$privacy_sandbox_ui_version"
    
        // This helps the SDK open sessions for the ad.
        implementation "androidx.privacysandbox.ui:ui-provider:$privacy_sandbox_ui_version"
    
        // This is needed if your SDK implements mediation use cases
        implementation "androidx.privacysandbox.ui:ui-client:$privacy_sandbox_ui_version"
    }
    
  4. فایل build.gradle را در ماژول ASB فعال در زمان اجرا با موارد زیر جایگزین کنید:

    plugins {
        id 'com.android.privacy-sandbox-sdk'
    }
    
    android {
        compileSdk 34
        minSdk 21
    
        bundle {
            // This is the package name of the SDK that you want to publish.
            // This is used as the public identifier of your SDK.
            // You use this later on to load the runtime-enabled SDK
            packageName = '<package name of your runtime-enabled SDK>'
    
            // This is the version of the SDK that you want to publish.
            // This is used as the public identifier of your SDK version.
            setVersion(1, 0, 0)
    
            // SDK provider defined in the SDK Runtime library.
            // This is an important part of the future backwards compatibility
            // support, most SDKs won't need to change it.
            sdkProviderClassName = "androidx.privacysandbox.sdkruntime.provider.SandboxedSdkProviderAdapter"
    
            // This is the class path of your implementation of the SandboxedSdkProviderCompat class.
            // It's the implementation of your runtime-enabled SDK's entry-point.
            // If you miss this step, your runtime-enabled SDK will fail to load at runtime:
            compatSdkProviderClassName = "<your-sandboxed-sdk-provider-compat-fully-qualified-class-name>"
        }
    }
    
    dependencies {
        // This declares the dependency on your runtime-enabled ad library module.
        include project(':<your-runtime-enabled-ad-library-here>')
    }
    
  5. فایل build.gradle را در ماژول کتابخانه تبلیغات موجود خود (RA SDK) به‌روزرسانی کنید تا وابستگی‌های زیر را شامل شود:

    dependencies {
        // This declares the client's dependency on the runtime-enabled ASB module.
        //  ⚠️ Important: We depend on the ASB module, not the runtime-enabled module.
        implementation project(':<your-runtime-enabled-asb-module-here>')
    
        // Required for backwards compatibility on devices where SDK Runtime is unavailable.
        implementation "androidx.privacysandbox.sdkruntime:sdkruntime-client:$privacy_sandbox_sdk_runtime_version"
    
        // This is required to display banner ads using the SandboxedUiAdapter interface.
        implementation "androidx.privacysandbox.ui:ui-core:$privacy_sandbox_ui_version"
        implementation "androidx.privacysandbox.ui:ui-client:$privacy_sandbox_ui_version"
    
        // This is required to use SDK ActivityLaunchers.
        implementation "androidx.privacysandbox.activity:activity-core:$privacy_sandbox_activity_version"
        implementation "androidx.privacysandbox.activity:activity-client:$privacy_sandbox_activity_version"
    }
    

منطق کسب و کار SDK را اضافه کنید

منطق کسب و کار SDK خود را همانطور که به طور منظم در ماژول کتابخانه تبلیغاتی فعال با زمان اجرا انجام می دهید، پیاده سازی کنید.

اگر یک SDK موجود دارید که در حال انتقال آن هستید، در این مرحله به اندازه منطق کسب و کار، رابط، و عملکردهای رو به رو سیستم خود را جابه جا کنید، اما در آینده انتقال کامل را در نظر بگیرید.

اگر نیاز به دسترسی به فضای ذخیره‌سازی، شناسه تبلیغات Google Play، یا شناسه مجموعه برنامه دارید، بخش‌های زیر را بخوانید:

از API های ذخیره سازی در SDK خود استفاده کنید

SDK های موجود در SDK Runtime دیگر نمی توانند به حافظه داخلی برنامه دسترسی داشته باشند، بخوانند یا بنویسند و برعکس.

SDK Runtime فضای ذخیره سازی داخلی خود را جدا از برنامه اختصاص داده است.

SDKها می‌توانند با استفاده از APIهای ذخیره‌سازی فایل روی شی Context که توسط SandboxedSdkProvider#getContext() بازگردانده شده است، به این حافظه داخلی جداگانه دسترسی پیدا کنند.

SDK ها فقط می توانند از حافظه داخلی استفاده کنند، بنابراین فقط API های ذخیره سازی داخلی، مانند Context.getFilesDir() یا Context.getCacheDir() کار می کنند. نمونه‌های بیشتری را در دسترسی از حافظه داخلی مشاهده کنید.

دسترسی به حافظه خارجی از SDK Runtime پشتیبانی نمی شود. فراخوانی APIها برای دسترسی به حافظه خارجی یا یک استثنا ایجاد می کند یا null را برمی گرداند. لیست زیر شامل چند نمونه است:

شما باید از Context برگردانده شده توسط SandboxedSdkProvider.getContext() برای ذخیره سازی استفاده کنید. استفاده از API ذخیره‌سازی فایل در هر نمونه دیگری از شی Context ، مانند زمینه برنامه، تضمین نمی‌شود که در همه موقعیت‌ها همانطور که انتظار می‌رود کار کند.

قطعه کد زیر نحوه استفاده از فضای ذخیره سازی در SDK Runtime را نشان می دهد:

class SdkServiceImpl(private val context: Context) : SdkService {
    override suspend fun getMessage(): String = "Hello from Privacy Sandbox!"

    override suspend fun createFile(sizeInMb: Int): String {
        val path = Paths.get(
            context.dataDir.path, "file.txt"
        )

        withContext(Dispatchers.IO) {
            Files.deleteIfExists(path)
            Files.createFile(path)
            val buffer = ByteArray(sizeInMb * 1024 * 1024)
            Files.write(path, buffer)
        }

        val file = File(path.toString())
        val actualFileSize: Long = file.length() / (1024 * 1024)
        return "Created $actualFileSize MB file successfully"
    }
}

در حافظه داخلی جداگانه برای هر زمان اجرا SDK، هر SDK فهرست ذخیره سازی مخصوص به خود را دارد. فضای ذخیره سازی برای هر SDK یک تفکیک منطقی از حافظه داخلی SDK Runtime است که به محاسبه مقدار فضای ذخیره سازی هر SDK کمک می کند.

همه APIهای ذخیره سازی داخلی در شی Context یک مسیر ذخیره سازی برای هر SDK برمی گردانند.

به شناسه تبلیغاتی ارائه شده توسط خدمات Google Play دسترسی داشته باشید

اگر SDK شما نیاز به دسترسی به شناسه تبلیغاتی ارائه شده توسط خدمات Google Play دارد، از AdIdManager#getAdId() برای بازیابی مقدار به صورت ناهمزمان استفاده کنید.

به شناسه مجموعه برنامه ارائه شده توسط خدمات Google Play دسترسی داشته باشید

اگر SDK شما نیاز به دسترسی به شناسه مجموعه برنامه ارائه شده توسط خدمات Google Play دارد، از AppSetIdManager#getAppSetId() برای بازیابی مقدار به صورت ناهمزمان استفاده کنید.

API های SDK را اعلام کنید

برای اینکه SDK فعال در زمان اجرا شما خارج از زمان اجرا قابل دسترسی باشد، باید API هایی را تعریف کنید که کلاینت ها (RA SDK یا برنامه مشتری) می توانند مصرف کنند.

از حاشیه نویسی برای اعلام این رابط ها استفاده کنید.

حاشیه نویسی ها

API های SDK باید در Kotlin به عنوان رابط ها و کلاس های داده با استفاده از حاشیه نویسی های زیر اعلان شوند:

حاشیه نویسی ها
@PrivacySandboxService
  • نقطه ورود به RE SDK شما را تعریف می کند
  • باید منحصر به فرد باشد
@PrivacySandboxInterface
  • ماژولارسازی بیشتر و افشای رابط ها را فعال می کند
  • می تواند چندین نمونه داشته باشد
@PrivacySandboxValue
  • ارسال داده ها را در سراسر فرآیندها فعال می کند
  • مشابه ساختارهای تغییرناپذیر، که می توانند مقادیر متعددی از انواع مختلف را برگردانند
@PrivacySandboxCallback
  • API ها را با یک callback اعلام می کند
  • یک کانال پشتیبان برای فراخوانی کد مشتری ارائه می دهد

شما باید این رابط‌ها و کلاس‌ها را در هر جایی از ماژول کتابخانه تبلیغاتی فعال‌شده با زمان اجرا تعریف کنید.

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

@PrivacySandboxService

@PrivacySandboxService
interface SdkService {
    suspend fun getMessage(): String

    suspend fun createFile(sizeInMb: Int): String

    suspend fun getBanner(request: SdkBannerRequest, requestMediatedAd: Boolean): SdkSandboxedUiAdapter?

    suspend fun getFullscreenAd(): FullscreenAd
}

@PrivacySandboxInterface

@PrivacySandboxInterface
interface SdkSandboxedUiAdapter : SandboxedUiAdapter

@PrivacySandboxValue

@PrivacySandboxValue
data class SdkBannerRequest(
    /** The package name of the app. */
    val appPackageName: String,
    /**
     *  An [SdkActivityLauncher] used to launch an activity when the banner is clicked.
     */
    val activityLauncher: SdkActivityLauncher,
    /**
     * Denotes if a WebView banner ad needs to be loaded.
     */
    val isWebViewBannerAd: Boolean
)

@PrivacySandboxCallback

@PrivacySandboxCallback
interface InAppMediateeSdkInterface {
    suspend fun show()
}

انواع پشتیبانی شده

API های SDK فعال شده در زمان اجرا از انواع زیر پشتیبانی می کنند:

  • همه انواع اولیه در زبان برنامه نویسی جاوا (مانند int، long، char، boolean و غیره)
  • رشته
  • رابط های Kotlin حاشیه نویسی شده با @PrivacySandboxInterface یا @PrivacySandboxCallback
  • کلاس های داده Kotlin با @PrivacySandboxValue حاشیه نویسی شده اند
  • java.lang.List - همه عناصر موجود در لیست باید یکی از انواع داده های پشتیبانی شده باشند

چند اخطار اضافی وجود دارد:

  • کلاس های داده حاشیه نویسی شده با @PrivacySandboxValue نمی توانند دارای فیلدهایی از نوع @PrivacySandboxCallback باشند
  • انواع برگشتی نمی توانند حاوی انواع حاشیه نویسی شده با @PrivacySandboxCallback باشند
  • فهرست نمی تواند حاوی عناصری از انواع حاشیه نویسی شده با @PrivacySandboxInterface یا @PrivacySandboxCallback باشد

API های ناهمزمان

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

برای دستیابی به این هدف، همه روش‌ها در رابط‌های حاشیه‌نویسی شده با @PrivacySandboxService ، @PrivacySandboxInterface و @PrivacySandboxCallback باید به‌صراحت به‌عنوان APIهای ناهمزمان اعلام شوند.

API های ناهمزمان را می توان به دو روش در Kotlin پیاده سازی کرد:

  1. از توابع تعلیق استفاده کنید.
  2. تماس‌هایی را بپذیرید که پس از اتمام عملیات یا سایر رویدادها در حین پیشرفت عملیات مطلع می‌شوند. نوع برگشتی تابع باید یک واحد باشد.

استثنائات

APIهای SDK هیچ شکلی از استثناهای بررسی شده را پشتیبانی نمی کنند.

کد شیم تولید شده هرگونه استثنا در زمان اجرا را که توسط SDK پرتاب می شود را می گیرد و آنها را به عنوان PrivacySandboxException با اطلاعاتی در مورد علت در داخل آن به مشتری می فرستد.

کتابخانه UI

اگر واسط‌هایی دارید که تبلیغات را نشان می‌دهند، مانند یک بنر، باید رابط SandboxedUiAdapter را نیز برای فعال کردن جلسات باز کردن آگهی بارگذاری شده پیاده‌سازی کنید.

این جلسات یک کانال جانبی بین مشتری و SDK تشکیل می دهند و دو هدف اصلی را برآورده می کنند:

  • هر زمان که تغییر رابط کاربری رخ می دهد، اعلان ها را دریافت کنید.
  • مشتری را از هرگونه تغییر در ارائه رابط کاربری مطلع کنید.

از آنجایی که مشتری می تواند از رابط مشروح شده با @PrivacySandboxService برای ارتباط با SDK شما استفاده کند، هر API برای بارگیری تبلیغات می تواند به این رابط اضافه شود.

هنگامی که مشتری برای بارگیری تبلیغ درخواست می کند، آگهی را بارگیری کرده و نمونه ای از رابط پیاده سازی SandboxedUiAdapter را برگردانید. این به مشتری اجازه می دهد تا جلسات بازگشایی آن تبلیغ را درخواست کند.

وقتی مشتری برای باز کردن جلسه درخواست می‌کند، SDK فعال با زمان اجرا شما می‌تواند با استفاده از پاسخ آگهی و زمینه ارائه شده، یک نمای تبلیغاتی ایجاد کند.

برای رسیدن به این هدف، کلاسی ایجاد کنید که رابط SandboxedUiAdapter.Session را پیاده سازی کند و هنگامی که SandboxedUiAdapter.openSession() فراخوانی می شود، مطمئن شوید که client.onSessionOpened() را فراخوانی می کنید و نمونه ای از کلاس Session را به عنوان پارامتر ارسال می کنید.

class SdkSandboxedUiAdapterImpl(
   private val sdkContext: Context,
   private val request: SdkBannerRequest,
) : SdkSandboxedUiAdapter {
   override fun openSession(
       context: Context,
       windowInputToken: IBinder,
       initialWidth: Int,
       initialHeight: Int,
       isZOrderOnTop: Boolean,
       clientExecutor: Executor,
       client: SandboxedUiAdapter.SessionClient
   ) {
       val session = SdkUiSession(clientExecutor, sdkContext, request)
       clientExecutor.execute {
           client.onSessionOpened(session)
       }
   }
}

این کلاس همچنین هر زمان که تغییر رابط کاربری ایجاد شود اعلان‌هایی دریافت می‌کند. می‌توانید از این کلاس برای تغییر اندازه آگهی استفاده کنید، یا بدانید که چه زمانی پیکربندی تغییر کرده است.

درباره APIهای ارائه رابط کاربری در زمان اجرا بیشتر بیاموزید.

پشتیبانی از فعالیت

برای شروع فعالیت‌های متعلق به SDK از جعبه ایمنی حریم خصوصی، باید API SDK را تغییر دهید تا یک شی SdkActivityLauncher را که همچنین توسط کتابخانه UI ارائه شده است، دریافت کنید.

به عنوان مثال، API SDK زیر باید فعالیت‌ها را راه‌اندازی کند، بنابراین انتظار پارامتر SdkActivityLauncher را دارد:

@PrivacySandboxInterface
interface FullscreenAd {
    suspend fun show(activityLauncher: SdkActivityLauncher)
}

نقطه ورود SDK

کلاس انتزاعی SandboxedSdkProvider API را کپسوله می کند که SDK Runtime از آن برای تعامل با SDK های بارگذاری شده در آن استفاده می کند.

یک SDK فعال با زمان اجرا باید این کلاس انتزاعی را پیاده سازی کند تا یک نقطه ورودی برای زمان اجرا SDK ایجاد کند تا بتواند با آن ارتباط برقرار کند.

برای پشتیبانی از سازگاری با عقب، ما کلاس های زیر را معرفی کرده ایم:

درباره سازگاری به عقب برای زمان اجرا SDK بیشتر بیاموزید.

ابزارهای تولید شیم لایه دیگری از انتزاع اضافه می کنند: آنها یک کلاس انتزاعی به نام AbstractSandboxedSdkProvider را با استفاده از رابطی که با @PrivacySandboxService حاشیه نویسی کردید ایجاد می کنند.

این کلاس SandboxedSdkProviderCompat را گسترش می دهد و تحت همان بسته رابط حاشیه نویسی شما قرار دارد.

// Auto-generated code.
abstract class AbstractSandboxedSdkProvider : SandboxedSdkProviderCompat {
    abstract fun createMySdk(context: Context): MySdk
}

این کلاس تولید شده یک روش کارخانه انتزاعی واحد را نشان می دهد که یک Context را می گیرد و انتظار دارد رابط مشروح نقطه ورودی شما برگردانده شود.

نام این روش از رابط کاربری @PrivacySandboxService شما گرفته create است. به عنوان مثال، اگر رابط شما MySdk نام دارد، ابزارها createMySdk ایجاد می کنند.

برای اتصال کامل نقطه ورودی خود، باید یک پیاده سازی از واسط حاشیه نویسی @PrivacySandboxService خود را در SDK فعال در زمان اجرا به AbstractSandboxedSdkProvider ایجاد شده ارائه دهید.

class MySdkSandboxedSdkProvider : AbstractSandboxedSdkProvider() {
    override fun createMySdk(context: Context): MySdk = MySdkImpl(context)
}

تغییرات در ماژول ASB

شما باید نام کلاس کاملاً واجد شرایط پیاده سازی SandboxedSdkProviderCompat را در فیلد compatSdkProviderClassName build.gradle ماژول ASB خود اعلام کنید.

این کلاسی است که در مرحله قبل پیاده سازی کردید و build.gradle را در ماژول ASB خود به صورت زیر تغییر می دهید:

bundle {
    packageName = '<package name of your runtime-enabled SDK>'
    setVersion(1, 0, 0)

    // SDK provider defined in the SDK Runtime library.
    sdkProviderClassName = "androidx.privacysandbox.sdkruntime.provider.SandboxedSdkProviderAdapter"
    // This is the class that extends AbstractSandboxedSdkProvider,
    // MySdkSandboxProvider as per the example provided.
    compatSdkProviderClassName = "com.example.mysdk.MySdkSandboxProvider"
}

مرحله 2 : محیط توسعه خود را تنظیم کنید مرحله 4 : از SDK فعال با زمان اجرا استفاده کنید