Mobile Development 22 min read

Implementing Event Tracking (埋点) in iOS Clients: Concepts, Approaches, and Code Samples

This article explains the fundamentals of event tracking in iOS apps, compares server‑side and client‑side tracking, details three implementation strategies (code‑based, non‑intrusive, and visual), introduces a data classification scheme, and provides Swift code examples—including enums, protocols, a chain‑based data‑passing mechanism, and runtime method‑hooking techniques—while also discussing practical challenges and best‑practice recommendations.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Implementing Event Tracking (埋点) in iOS Clients: Concepts, Approaches, and Code Samples

The article introduces event tracking (埋点) for iOS client development, outlining its definition as event tracking, its classification into server‑side and client‑side tracking, and the advantages and drawbacks of each.

Three main implementation approaches are described:

Code‑based tracking: inserting tracking calls directly in business code.

Non‑intrusive (full) tracking: using runtime hooks to add tracking without modifying business code.

Visual tracking: a UI‑driven solution that generates tracking rules which are sent from a server to the client.

For client‑side tracking, the article defines a data classification model consisting of three event types:

PageView : page exposure events.

ViewElement : exposure of specific UI elements.

ClickPosition : button or view click events.

Each type has a set of properties (e.g., pageId , contentId , sourcePage , etc.) illustrated with example payload structures.

Swift implementations are provided to model these events. An enum Events groups the three cases, each with its own key enum and associated property enum:

public enum Events {
    /// 页面曝光埋点
    case pageView(key: PageKey, properties: [PageKey.Property])
    /// 页面元素曝光埋点
    case viewElement(key: ViewElementKey, properties: [ViewElementKey.Property])
    /// 按钮点击事件曝光埋点
    case clickPosition(key: ClickPositionKey, properties: [ClickPositionKey.Property])
}

Supporting enums ( PageKey , ViewElementKey , ClickPositionKey ) define concrete identifiers and nested Property enums for each event type. A protocol EventsProtocol supplies default track and trackEvent methods that forward events to a private processTrack implementation, which pattern‑matches the event and would invoke the appropriate reporting logic.

To pass data between view controllers without tightly coupling code, a singly‑linked Chain class is introduced. It stores a dictionary of properties and a reference to a parent chain, enabling hierarchical data retrieval:

class Chain: NSObject {
    var property: [AnyHashable: Any]?
    var parent: Chain?
    init(property: [AnyHashable: Any]? = nil, parent: Chain? = nil) {
        self.property = property
        self.parent = parent
    }
    func add(property: [AnyHashable: Any]) { /* merge logic */ }
}

A Trackable protocol extends any class with a unique identifier and provides methods to create, update, retrieve, and clean chain entries, ensuring that data such as sourcePage can be passed from a list controller to a detail controller and later used in a pageView report.

Non‑intrusive tracking is achieved by runtime method swizzling. A helper class MyHook swaps implementations of target selectors:

#import "MyHook.h"
#import
@implementation MyHook
+ (void)hookClass:(Class)classObject fromSelector:(SEL)fromSelector toSelector:(SEL)toSelector {
    Method fromMethod = class_getInstanceMethod(classObject, fromSelector);
    Method toMethod   = class_getInstanceMethod(classObject, toSelector);
    if (class_addMethod(classObject, fromSelector, method_getImplementation(toMethod), method_getTypeEncoding(toMethod))) {
        class_replaceMethod(classObject, toSelector, method_getImplementation(fromMethod), method_getTypeEncoding(fromMethod));
    } else {
        method_exchangeImplementations(fromMethod, toMethod);
    }
}
@end

Using this utility, UIViewController and UIControl methods such as viewWillAppear: and sendAction:to:forEvent: are hooked to inject reporting logic before the original implementation runs.

The article also discusses practical challenges encountered with non‑intrusive tracking, including controller identification, view identification, parameter extraction, method‑name changes, team coordination, and the limits of a fully non‑intrusive solution, concluding that a hybrid approach is often necessary.

Finally, the author summarizes the key take‑aways: understand tracking concepts, choose an implementation that fits the product’s complexity, and apply the appropriate technique at the right place.

iOSSwiftevent trackingmobile analyticsMethod Swizzlingdata-passingnon‑intrusive tracking
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.