التوثيق · التكامل مع iOS

5. استدعاء تنسيقات الإعلانات

لا يزال كل استدعاء يتلقى سلسلة نصية تمثّل معرّف موضع الإعلان (placeholder) مُعدّة في بوابة AKS — ويحوّلها AKS وقت التشغيل إلى شبكة إعلانات وقائمة شبكات بديلة تُستخدم عند الفشل.

5.1 نمط الربط

أنواع ردود نداء الإعلانات في AKS ‏(AdsCallback وBannerCallback وNativeCallback وRewardedAdCallbacks وAppOpenAdCallbacks) هي أصناف ترث منها وتعيد تعريف أساليبها باستخدام override — وليست إغلاقات برمجية (closures). النمط المتعارف عليه (والمستخدم في الشيفرات التي تستدعي AppsKitSDKAdsManagerIOS) هو إنشاء صنف مُكيّف خاص صغير لكل تنسيق، يقوم بما يلي:

  1. يرث من نوع رد النداء في AKS ويستدعي super.init().
  2. يمرّر كل حدث من أحداث دورة الحياة إلى ما تحتاجه طبقة واجهة المستخدم لديك.
  3. في إعلانات البانر والإعلانات المدمجة مع المحتوى والإعلانات بمكافأة، يربط التحميل بالعرض تلقائيًا — أي إن إعادة تعريف onBannerLoaded()/onNativeLoaded()/onRewardedLoaded() في المُكيّف هي التي تُطلق استدعاء show... المقابل، مع إعادة استخدام self بوصفه رد النداء لخطوة العرض أيضًا.
swift
private class BannerCallbackAdapter: BannerCallback {
    private let onLoaded: () -> Void
    private let onFailed: (String) -> Void
    private weak var container: UIView?
    private let placeholder: String

    init(container: UIView, placeholder: String, onLoaded: @escaping () -> Void, onFailed: @escaping (String) -> Void) {
        self.container = container
        self.placeholder = placeholder
        self.onLoaded = onLoaded
        self.onFailed = onFailed
        super.init()
    }

    override func onBannerLoaded() {
        onLoaded()
        guard let vc = UIApplication.topViewController(), let view = container else {
            onFailed("No active view controller found")
            return
        }
        AppsKitSDKAdsManagerIOS.instance.showBanner(from: vc, placeholder: placeholder, container: view, callback: self)
    }
    override func onBannerFailedToLoad() { onFailed("") }
    override func onBannerClicked() {}
    override func onBannerShown() {}
    override func onBannerSizeChanged(bannerSizes: BannerSizes) {}
    override func setBannerSize(width: Double, height: Double) {}
}

ينطلق UIApplication.topViewController() (الذي توفره AppsKit.xcframework بوصفه امتدادًا لـ UIApplication) من متحكم العرض الجذري للنافذة الرئيسية، ويتتبّع أي متحكم معروض أو متحكم تنقّل أو علامات تبويب للوصول إلى الشاشة الموجودة فعليًا في المقدمة — وتحتاج إليه كلما تطلّب الاستدعاء متحكم عرض ولم يكن لديك سوى UIView، أو لم يتوفر لديك أي سياق لواجهة المستخدم.

الإعلانات البينية

swift
// Load only
AppsKitSDKAdsManagerIOS.instance.loadInterstitial(from: viewController, placeholder: placeholder, callback: adapter)

// Show a previously loaded interstitial
AppsKitSDKAdsManagerIOS.instance.showInterstitial(from: viewController, placeholder: placeholder, callback: adapter)

يرث adapter من AdsCallback:

swift
private class InterstitialCallbackAdapter: AdsCallback {
    private let onAdLoaded: () -> Void
    private let onAdFailed: () -> Void

    init(onAdLoaded: @escaping () -> Void, onAdFailed: @escaping () -> Void) {
        self.onAdLoaded = onAdLoaded
        self.onAdFailed = onAdFailed
        super.init()
    }

    override func onLoaded()         { onAdLoaded() }
    override func onFailedToLoad()   { onAdFailed() }
    override func onAdShown()        {}
    override func onAdDismissed()    {}
    override func onAdFailedToShow() {}
}

الإعلانات بمكافأة

swift
// Separate load/show — chain load→show in your adapter's onRewardedLoaded(), same pattern as banner/native
AppsKitSDKAdsManagerIOS.instance.loadRewarded(from: viewController, placeholder: placeholder, callback: adapter)

AppsKitSDKAdsManagerIOS.instance.showRewarded(from: viewController, placeholder: placeholder, callback: adapter)

يرث adapter من RewardedAdCallbacks ويربط onRewardedLoaded() مباشرةً بـ showRewarded، مع إعادة استخدام self بوصفه رد النداء لخطوة العرض:

swift
private class RewardedAdCallbackAdapter: RewardedAdCallbacks {
    private let placeholder: String
    private let onUserEarnedReward: () -> Void
    private let onFailed: (String) -> Void

    init(placeholder: String, onUserEarnedReward: @escaping () -> Void, onFailed: @escaping (String) -> Void) {
        self.placeholder = placeholder
        self.onUserEarnedReward = onUserEarnedReward
        self.onFailed = onFailed
        super.init()
    }

    override func onRewardedLoaded() {
        guard let vc = UIApplication.topViewController() else {
            onFailed("No active view controller found")
            return
        }
        AppsKitSDKAdsManagerIOS.instance.showRewarded(from: vc, placeholder: placeholder, callback: self)
    }
    override func onAdRewarded()            { onUserEarnedReward() }
    override func onRewardedCompleted()     { onUserEarnedReward() }
    override func onAdRewardedAdDismissed() {}
    override func onRewardedAdLoadFailure() { onFailed("Failed to load rewarded ad") }
    override func onRewardedFailedToShow()  { onFailed("Failed to show rewarded ad") }
}

يوفّر AKS أيضًا loadAndShowRewarded(from:placeholder:callback:) في AppsKitSDKAdsManagerIOS للتحميل والعرض باستدعاء واحد، ويتلقى RewardedLoadAndShowCallback — وهو بروتوكول لا يتضمن سوى onRewardedAdSuccess()/onRewardedAdFailed() (ولا يتطلب super.init() لأنه بروتوكول، وليس صنفًا مجرّدًا). استخدم استدعاءَي loadRewarded/showRewarded المنفصلين أعلاه عندما تحتاج إلى التحميل مسبقًا والعرض لاحقًا؛ واستخدم loadAndShowRewarded عندما تريد دائمًا العرض فور اكتمال التحميل.

إعلانات فتح التطبيق

swift
AppsKitSDKAdsManagerIOS.instance.loadAppOpen(placeholder: placeholder, callback: adapter)

AppsKitSDKAdsManagerIOS.instance.showAppOpen(from: viewController, placeholder: placeholder, callback: adapter)

يرث adapter من AppOpenAdCallbacks:

swift
private class AppOpenCallbackAdapter: AppOpenAdCallbacks {
    private let onAdLoaded: () -> Void
    private let onAdFailed: () -> Void

    init(onAdLoaded: @escaping () -> Void, onAdFailed: @escaping () -> Void) {
        self.onAdLoaded = onAdLoaded
        self.onAdFailed = onAdFailed
        super.init()
    }

    override func onLoaded()       { onAdLoaded() }
    override func onFailedToLoad() { onAdFailed() }
    override func onAdShown()      {}
    override func onDismiss()      {}
    override func onAdFailToShow() {}
}

هذا هو المسار اليدوي لإعلانات فتح التطبيق — لاستخدام معالجة AKS التلقائية على مستوى التطبيق، التي تتحكم فيها الإعدادات عن بُعد، استخدم بدلًا منه مسار العمل المدمج في AKSBaseAppDelegate (§4.6).

إعلانات البانر

swift
AppsKitSDKAdsManagerIOS.instance.loadBanner(from: viewController, placeholder: placeholder, callback: adapter)

AppsKitSDKAdsManagerIOS.instance.showBanner(from: viewController, placeholder: placeholder, container: bannerContainerView, callback: adapter)

يرث adapter من BannerCallback — راجع التعريف الكامل لـ BannerCallbackAdapter في §5.1 أعلاه، والذي يربط onBannerLoaded() مباشرةً بـ showBanner.

BannerSizes: ‏BANNER (320×50)، ‏LARGE_BANNER (320×100)، ‏MEDIUM_RECTANGLE (300×250)، ‏FULL_BANNER (468×60).

الإعلانات المدمجة مع المحتوى

swift
AppsKitSDKAdsManagerIOS.instance.loadNative(from: viewController, placeholder: placeholder, isShowInScrollView: true, callback: adapter)

AppsKitSDKAdsManagerIOS.instance.showNative(
    from: viewController, container: nativeContainerView, placeholder: placeholder,
    res: nil, isShowInScrollView: true, callback: adapter
)

// Show the native ad using the design you created for this placeholder in the
// AKS portal, instead of an XIB — see below.
AppsKitSDKAdsManagerIOS.instance.showTemplatedNative(
    from: viewController, container: nativeContainerView, placeholder: placeholder,
    isShowInScrollView: true, callback: adapter
)

يُستخدم showTemplatedNative لمواضع الإعلانات التي صُمّم مظهر إعلانها المدمج مع المحتوى وأُسنِد إليها على بوابة AKS بدلًا من داخل تطبيقك — ولا توجد فيه معلمة res أصلًا، لأنك لست مسؤولًا عن توفير التخطيط. يحدّد AKS قالب البوابة المناسب لموضع الإعلان هذا، ويجلبه (ويخزّنه مؤقتًا بعد أول عملية جلب)، ثم يعرض الإعلان المدمج مع المحتوى باستخدامه عبر مسار التحميل والعرض نفسه الذي يستخدمه showNative. إذا لم يُسنَد قالب إلى موضع الإعلان، أو تعذّر جلبه، يعود AKS إلى تصميمه الافتراضي المدمج للإعلانات المدمجة مع المحتوى بدلًا من أن يفشل الإعلان — لذا يمكن استدعاؤه بأمان دائمًا، حتى قبل إعداد قالب على البوابة.

يرث adapter من NativeCallback ويربط onNativeLoaded() مباشرةً بـ showNative، وفق النمط نفسه المستخدم في BannerCallbackAdapter:

swift
private class NativeCallbackAdapter: NativeCallback {
    private weak var container: UIView?
    private let placeholder: String
    private let onAdLoaded: () -> Void
    private let onAdFailed: (String) -> Void

    init(container: UIView, placeholder: String, onAdLoaded: @escaping () -> Void, onAdFailed: @escaping (String) -> Void) {
        self.container = container
        self.placeholder = placeholder
        self.onAdLoaded = onAdLoaded
        self.onAdFailed = onAdFailed
        super.init()
    }

    override func onNativeLoaded() {
        onAdLoaded()
        guard let vc = UIApplication.topViewController(), let view = container else {
            onAdFailed("No active view controller found")
            return
        }
        AppsKitSDKAdsManagerIOS.instance.showNative(
            from: vc, container: view, placeholder: placeholder,
            res: nil, isShowInScrollView: true, callback: self
        )
    }
    override func onNativeFailedToLoad() { onAdFailed("") }
    override func onNativeClicked()      {}
    override func onNativeShown()        {}
}

الترويج للميزات

يوفّر AppsKitSDKAdsManagerIOS واجهة للترويج للميزات، كما هو الحال مع التنسيقات الأخرى:

swift
// Optional — exclude features the user already has unlocked from being promoted
AppsKitSDKAdsManagerIOS.instance.setFeaturesAvailable(availableFeatures: ["premium_theme", "no_ads"])

AppsKitSDKAdsManagerIOS.instance.showFeaturePromotion(
    from: viewController,
    placeholder: placeholder,
    callback: adapter
)

يتوافق adapter مع OnFeaturePromotionClicked — وهو بروتوكول، وليس صنفًا مجرّدًا، لذا لا حاجة إلى super.init():

swift
private class FeaturePromotionAdapter: NSObject, OnFeaturePromotionClicked {
    private let onClicked: (String) -> Void
    private let onFailed: (String) -> Void

    init(onClicked: @escaping (String) -> Void, onFailed: @escaping (String) -> Void) {
        self.onClicked = onClicked
        self.onFailed = onFailed
    }

    func onFeaturePromotionClicked(targetScreen: String)    { onClicked(targetScreen) }
    func onFailToShowFeaturePromotion(errorMessage: String) { onFailed(errorMessage) }
}