Skip to content

iOS IntegrationIOS SDK

HeheBid iOS SDK (HeheSDK) is a client SDK for commercial ad monetization. The current release supports:

Ad format Description
Banner Fixed-size banner with optional auto-refresh
Interstitial Full-screen interstitial; the app chooses when to show after a successful load
Native Direct integration is self-rendered; mediation follows each platform’s native conventions (Adapter handles creative display)
Rewarded Full-screen rewarded ad; reward info is delivered via callback after completion

The SDK is distributed as an XCFramework, compatible with devices (arm64) and simulators (arm64 / x86_64), and can be used from both Objective-C and Swift projects. SDK / Adapter packages are distributed as XCFramework, support device and simulator, and can be used in Objective-C / Swift projects.

Distribution channels:

Channel URL
CocoaPods Spec Repo https://github.com/hehesdk/ios-sdk-specs.git
SPM https://github.com/hehesdk/ios-sdk-release
CDN binary https://res.wooymoon.com/sdk/release/ios/

Before integrating the iOS SDK, complete the following on the HeheBid platform:

  1. Register and complete account verification
  2. Create an app and obtain your App Key
  3. Create ad placements and obtain Placement IDs

Item Minimum
iOS 13.0+
Xcode 15.0+
Language Objective-C / Swift 5.0+
Package manager (optional) CocoaPods 1.12+ / Swift Package Manager

Choose one of the following integration methods.

Use the private Spec Repo with the standalone HeheSDK pod (Core only):

platform :ios, '13.0'
use_frameworks! :linkage => :static
source 'https://cdn.cocoapods.org/'
source 'https://github.com/hehesdk/ios-sdk-specs.git'
target 'YourApp' do
pod 'HeheSDK', '0.2.10'
end
Terminal window
pod install --repo-update

In Target → Frameworks, Libraries, and Embedded Content, add HeheSDK.xcframework

  • Set Embed & Sign

Open the project with .xcworkspace.
The legacy pod 'HeheAdSDK' is a full-package compatibility path; new integrations should use HeheSDK or the standalone Adapter pods in Section 13.

  1. Xcode: File → Add Package Dependencies…
  2. Repository URL:
https://github.com/hehesdk/ios-sdk-release
  1. Version recommendation: Exact Version 0.2.10 (or Up to Next Minor per your team policy)
  2. Add the HeheSDK product to your app target (for direct integration, select this product only)

Package.swift example:

dependencies: [
.package(url: "https://github.com/hehesdk/ios-sdk-release", exact: "0.2.10")
],
targets: [
.target(
name: "YourApp",
dependencies: [
.product(name: "HeheSDK", package: "ios-sdk-release")
]
)
]
  1. Download:
    HeheSDK-0.2.10.xcframework.zip
  2. Unzip to get HeheSDK.xcframework, then drag it into your project (check Copy items if needed)
  3. In Target → Frameworks, Libraries, and Embedded Content, add HeheSDK.xcframework
    • Set Embed & Sign

Then continue with Section 5: Xcode Project Configuration.


Complete these steps regardless of integration method.

  1. Select app Target → General
  2. Under Frameworks, Libraries, and Embedded Content, confirm HeheSDK.xcframework (or HeheSDK) is present
  3. Set Embed to Embed & Sign

Under Target → Build Settings → Other Linker Flags, add:

-ObjC

Objective-C

#import <HeheSDK/HeheSDK.h>

Swift

After adding HeheSDK to the target:

import HeheSDK

If Swift cannot resolve the module, add to your bridging header or Build Settings → Import Paths:

YourApp-Bridging-Header.h
#import <HeheSDK/HeheSDK.h>
#import <HeheSDK/HHRewardedAd.h>
#import <HeheSDK/HHNativeAd.h>

Apply these settings before initSDK as required by your compliance policy (required for direct integration; also applicable on mediation paths when the app calls initSDK early):

Method Description
setConsentStatus: GDPR consent status
setIsAgeRestrictedUser: COPPA age-restricted user flag
setDoNotSell: CCPA Do Not Sell setting

SKAdNetwork identifiers, Privacy Manifest, and related items must be configured by the host app based on your ad stack and store requirements.


Call initialization in application:didFinishLaunchingWithOptions: after privacy settings when applicable.
Load ads only after initialization succeeds. Check status with isInitialized.

#import <HeheSDK/HeheSDK.h>
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 1. Privacy (as needed)
[[HeheAds shareSDK] setConsentStatus:YES];
[[HeheAds shareSDK] setIsAgeRestrictedUser:NO];
[[HeheAds shareSDK] setDoNotSell:NO];
// 2. Enable logs during integration testing (see Section 12)
// [[HeheAds shareSDK] setLogEnabled:YES];
// 3. Initialize
[[HeheAds shareSDK] initSDK:@"YOUR_APP_KEY"
onSuccess:^{
NSLog(@"HeheSDK initialized");
}
onError:^(NSError *error) {
NSLog(@"HeheSDK init failed: %@", error.localizedDescription);
}];
return YES;
}
import UIKit
import HeheSDK
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
HeheAds.shareSDK().setConsentStatus(true)
HeheAds.shareSDK().setIsAgeRestrictedUser(false)
HeheAds.shareSDK().setDoNotSell(false)
// HeheAds.shareSDK().setLogEnabled(true)
HeheAds.shareSDK().initSDK("YOUR_APP_KEY", onSuccess: {
print("HeheSDK initialized")
}, onError: { error in
print("HeheSDK init failed: \(error.localizedDescription)")
})
return true
}

The following is the direct API. For mediation, use AdMob / TopOn official Banner APIs (see Section 13).

Enum Size
HHBannerAdSize320x50 / .size320x50 320 × 50
HHBannerAdSize320x100 / .size320x100 320 × 100
HHBannerAdSize300x250 / .size300x250 300 × 250
  1. Create HHBannerAd (Placement ID + size)
  2. Set delegate, and optionally refreshInterval (seconds; 0 means no auto-refresh)
  3. Call loadAd
  4. In bannerAdDidLoad:, addSubview: to your container (no need to set frame manually; the SDK centers by size in the parent view)
  5. Call destroy when the page is dismissed or the ad is no longer needed (after destroy you cannot loadAd again; create a new instance)
@interface BannerViewController () <HHBannerAdDelegate>
@property (nonatomic, strong) HHBannerAd *bannerAd;
@end
@implementation BannerViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.bannerAd = [[HHBannerAd alloc] initWithPlacementID:@"YOUR_PLACEMENT_ID"
bannerSize:HHBannerAdSize320x50];
self.bannerAd.delegate = self;
self.bannerAd.refreshInterval = 30;
[self.bannerAd loadAd];
}
- (void)bannerAdDidLoad:(HHBannerAd *)bannerAd {
[self.view addSubview:bannerAd];
}
- (void)bannerAd:(HHBannerAd *)bannerAd didFailWithError:(NSError *)error {
NSLog(@"Banner load failed: %@", error.localizedDescription);
}
- (void)bannerAdDidImpression:(HHBannerAd *)bannerAd {
NSLog(@"Banner impression");
}
- (void)bannerAdDidClick:(HHBannerAd *)bannerAd {
NSLog(@"Banner click");
}
- (void)bannerAdDidClose:(HHBannerAd *)bannerAd {
NSLog(@"Banner closed");
}
- (void)dealloc {
[self.bannerAd destroy];
}
@end
class BannerViewController: UIViewController, HHBannerAdDelegate {
private var bannerAd: HHBannerAd?
override func viewDidLoad() {
super.viewDidLoad()
let banner = HHBannerAd(placementID: "YOUR_PLACEMENT_ID", bannerSize: .size320x50)
banner.delegate = self
banner.refreshInterval = 30
banner.loadAd()
bannerAd = banner
}
func bannerAdDidLoad(_ bannerAd: HHBannerAd) {
view.addSubview(bannerAd)
}
func bannerAd(_ bannerAd: HHBannerAd, didFailWithError error: Error) {
print("Banner load failed: \(error.localizedDescription)")
}
deinit {
bannerAd?.destroy()
}
}

The following is the direct API. For mediation, use AdMob / TopOn official interstitial APIs.

Create HHInterstitialAd → loadAd → isReady == true → showAdFromViewController:

To show again after close, call loadAd again. On page exit you may call destroy: to clear the corresponding placement cache.

@interface InterstitialViewController () <HHInterstitialAdDelegate>
@property (nonatomic, strong) HHInterstitialAd *interstitialAd;
@end
@implementation InterstitialViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.interstitialAd = [[HHInterstitialAd alloc] initWithPlacementID:@"YOUR_PLACEMENT_ID"];
self.interstitialAd.delegate = self;
[self.interstitialAd loadAd];
}
- (IBAction)showInterstitial:(id)sender {
if (self.interstitialAd.isReady) {
[self.interstitialAd showAdFromViewController:self];
}
}
- (void)interstitialAdDidLoad:(HHInterstitialAd *)interstitialAd {
NSLog(@"Interstitial loaded");
}
- (void)interstitialAd:(HHInterstitialAd *)interstitialAd didFailWithError:(NSError *)error {
NSLog(@"Interstitial load failed: %@", error.localizedDescription);
}
- (void)interstitialAdDidClose:(HHInterstitialAd *)interstitialAd {
[self.interstitialAd loadAd]; // Preload next
}
- (void)dealloc {
[self.interstitialAd destroy:@[@"YOUR_PLACEMENT_ID"]];
}
@end
class InterstitialViewController: UIViewController, HHInterstitialAdDelegate {
private var interstitialAd: HHInterstitialAd?
override func viewDidLoad() {
super.viewDidLoad()
let ad = HHInterstitialAd(placementID: "YOUR_PLACEMENT_ID")
ad.delegate = self
ad.loadAd()
interstitialAd = ad
}
@IBAction func showInterstitial(_ sender: Any) {
guard let ad = interstitialAd, ad.isReady else { return }
ad.showAdFromViewController(self)
}
func interstitialAdDidClose(_ interstitialAd: HHInterstitialAd) {
interstitialAd.loadAd()
}
deinit {
interstitialAd?.destroy(["YOUR_PLACEMENT_ID"])
}
}

You can also call showAdFromRootViewController to present from an appropriate window root view controller.


The following is the direct API. For mediation, use each platform’s official native API (see Section 13). Adapters download and assemble main image / icon; the app should not call HHNativeAdView directly on mediation paths.

  1. Create HHNativeAdView and set delegate
  2. First addSubview to your page container, then loadAd
  3. In nativeAdViewDidLoad:, read adMaterial and build subviews inside that View
  4. Impression and click navigation are handled automatically by the SDK on the container—no extra click-view registration
  5. Call destroy when the page is dismissed
Property Description
title Title
desc Description (optional)
iconURL Icon URL (app downloads and displays)
imageURL Main image URL (optional; app downloads and displays)
ctaText Call-to-action text
rating Rating 0–5; 0 means no rating
- (void)loadNativeAd {
HHNativeAdView *adView = [[HHNativeAdView alloc] initWithPlacementID:@"YOUR_NATIVE_PLACEMENT_ID"];
adView.delegate = self;
adView.frame = self.nativeContainer.bounds;
adView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.nativeContainer addSubview:adView];
self.nativeAdView = adView;
[adView loadAd];
}
- (void)nativeAdViewDidLoad:(HHNativeAdView *)nativeAdView {
HHNativeAdMaterial *material = nativeAdView.adMaterial;
if (material == nil) { return; }
// Build title / icon / main image / CTA inside nativeAdView
[self buildNativeContentInAdView:nativeAdView material:material];
}
- (void)nativeAdView:(HHNativeAdView *)nativeAdView didFailWithError:(NSError *)error {
NSLog(@"Native ad load failed: %@", error.localizedDescription);
}
- (void)dealloc {
[self.nativeAdView destroy];
}
func loadNativeAd() {
let adView = HHNativeAdView(placementID: "YOUR_NATIVE_PLACEMENT_ID")
adView.delegate = self
adView.frame = nativeContainer.bounds
adView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
nativeContainer.addSubview(adView)
nativeAdView = adView
adView.loadAd()
}
func nativeAdViewDidLoad(_ nativeAdView: HHNativeAdView) {
guard let material = nativeAdView.adMaterial else { return }
buildNativeContent(in: nativeAdView, material: material)
}
deinit {
nativeAdView?.destroy()
}

The following is the direct API. For mediation, use AdMob / TopOn official rewarded APIs.

Create HHRewardedAd (placementID + userID + customData?)
→ loadAd → isReady → showAdFromViewController:
→ didRewardWithInfo: / didFailToRewardWithError:
  • userID is required; empty userID causes loadAd to fail
  • customData is optional and is passed through to the reward result
  • Confirm isReady == true before showing
  • After the user meets reward criteria, didRewardWithInfo: is called; otherwise didFailToRewardWithError:
Property Description
userID User ID passed at creation
userCustomData Custom data passed at creation (nil if not provided)
name Reward name
amount Reward amount
serverSideVerify Whether reward is verified server-side; when YES, prefer server notification for granting
canEarnReward Whether the reward can be granted (typically YES on success callback)
- (void)loadRewardedAd {
self.rewardedAd = [[HHRewardedAd alloc] initWithPlacementID:@"YOUR_REWARDED_PLACEMENT_ID"
userID:@"YOUR_USER_ID"
customData:nil];
self.rewardedAd.delegate = self;
[self.rewardedAd loadAd];
}
- (IBAction)showRewarded:(id)sender {
if (self.rewardedAd.isReady) {
[self.rewardedAd showAdFromViewController:self];
}
}
- (void)rewardedAd:(HHRewardedAd *)rewardedAd didRewardWithInfo:(HHAdRewardInfo *)rewardInfo {
if (rewardInfo.canEarnReward) {
// Grant reward; when serverSideVerify is YES, prefer server-side granting
NSLog(@"Reward %@ x %ld", rewardInfo.name, (long)rewardInfo.amount);
}
}
- (void)rewardedAd:(HHRewardedAd *)rewardedAd didFailToRewardWithError:(NSError *)error {
NSLog(@"Reward not earned: %@", error.localizedDescription);
}
- (void)rewardedAdDidClose:(HHRewardedAd *)rewardedAd {
[self.rewardedAd loadAd];
}
- (void)dealloc {
[self.rewardedAd destroy:@[@"YOUR_REWARDED_PLACEMENT_ID"]];
}
func loadRewardedAd() {
let ad = HHRewardedAd(placementID: "YOUR_REWARDED_PLACEMENT_ID",
userID: "YOUR_USER_ID",
customData: nil)
ad.delegate = self
ad.loadAd()
rewardedAd = ad
}
@IBAction func showRewarded(_ sender: Any) {
guard let ad = rewardedAd, ad.isReady else { return }
ad.showAdFromViewController(self)
}
func rewardedAd(_ rewardedAd: HHRewardedAd, didRewardWithInfo rewardInfo: HHAdRewardInfo) {
guard rewardInfo.canEarnReward else { return }
print("Reward \(rewardInfo.name) x \(rewardInfo.amount)")
}
deinit {
rewardedAd?.destroy(["YOUR_REWARDED_PLACEMENT_ID"])
}

Set before initSDK, and register the same IDFA as a test device on the HEHE developer platform:

[[HeheAds shareSDK] setTestDeviceIDFA:@"YOUR_DEVICE_IDFA"];
HeheAds.shareSDK().setTestDeviceIDFA("YOUR_DEVICE_IDFA")

Pass nil or an empty string to clear.

Enable during integration; disable for production builds:

[[HeheAds shareSDK] setLogEnabled:YES];
HeheAds.shareSDK().setLogEnabled(true)

Before release, confirm:

  • App Key and Placement IDs obtained
  • HeheSDK integrated (CocoaPods / SPM / manual), version 0.2.10+
  • -ObjC added to Other Linker Flags
  • Privacy APIs set before initSDK as needed
  • loadAd called only after successful initialization
  • isReady checked before showing interstitial / rewarded
  • destroy called when Banner / Native pages are dismissed; call destroy: for interstitial / rewarded as needed
  • Non-empty userID passed for rewarded ads
  • Native ads self-rendered inside HHNativeAdView and added to the view hierarchy
  • Full load → display → click flow verified on a real device

Callback When
bannerAdDidLoad: Ad loaded successfully
bannerAd:didFailWithError: Ad load failed
bannerAdDidImpression: Ad impression logged
bannerAdDidClick: User clicked the ad
bannerAdDidLeaveApp: User left the app after click
bannerAdDidClose: User closed the banner
Callback When
interstitialAdDidLoad: Ad loaded successfully
interstitialAd:didFailWithError: Ad load failed
interstitialAd:displayFailWithError: Ad display failed
interstitialAdWillLogImpression: Ad impression logged
interstitialAdDidClick: User clicked the ad
interstitialAdWillClose: Ad about to close
interstitialAdDidClose: Ad closed
Callback When
nativeAdDidLoad: Ad loaded successfully; adMaterial is available
nativeAd:didFailWithError: Ad load failed
nativeAdDidImpression: Ad impression logged
nativeAdDidClick: User clicked the ad
nativeAdDidLeaveApp: User left the app after click
Callback When
rewardedAdDidLoad: Ad loaded successfully
rewardedAd:didFailWithError: Ad load failed
rewardedAd:displayFailWithError: Ad display failed
rewardedAdWillLogImpression: Ad impression logged
rewardedAdDidClick: User clicked the ad
rewardedAdWillClose: Ad about to close
rewardedAdDidClose: Ad closed
rewardedAd:didRewardWithInfo: User earned the reward
rewardedAd:didFailToRewardWithError: Reward not earned
Class Description
HeheAds SDK global entry (initialization, privacy settings)
HHBannerAd Banner ad
HHInterstitialAd Interstitial ad
HHRewardedAd Rewarded ad
HHNativeAd Native ad (self-rendered)
HHNativeAdMaterial Native self-rendered creative
HHAdRewardInfo Reward result info

Support: For integration issues, contact HeheBid technical support or your account manager.