iOS全埋點解決方案-應用退出和啟動

来源:https://www.cnblogs.com/r360/archive/2022/03/29/16072093.html
-Advertisement-
Play Games

前言 ​ 通過應用程式退出事件,可以分析應用程式的平均使用時長;通過應用程式的啟動事件,可以分析日活和新增。我們可以通過全埋點方式 SDK 實現應用程式的退出和啟動事件。 一、全埋點的簡介 ​ 目前、全埋點採集可以採集一下4個事件。 1、$AppEnd 事件:應用程式退出事件 2、$AppStart ...


前言

​ 通過應用程式退出事件,可以分析應用程式的平均使用時長;通過應用程式的啟動事件,可以分析日活和新增。我們可以通過全埋點方式 SDK 實現應用程式的退出和啟動事件。

一、全埋點的簡介

​ 目前、全埋點採集可以採集一下4個事件。

1、$AppEnd 事件:應用程式退出事件

image-20220328114940691

2、$AppStart 事件:應用程式啟動事件

image-20220328115007985

3、$AppViewScreen 事件: 應用程式內界面預覽事件,對於 iOS 來說就是切換不同的 UIViewController。

4、$AppClick 事件: 控制項的點擊事件,比如點擊 UIButton 、UITableView 等。

預置事件:在 SDK 中自動採集的事件稱為預置事件。

二、應用程式退出

2.1 應用程式狀態:

​ 一個標準的 iOS 程式在不同的時期會有不同的運行狀態,在 iOS 程式中常見的狀態有5中。如圖所示:

image-20220328115753785

1、Not running:非運行狀態,指應用程式還沒有被啟動,或者已經被系統終止。

2、Inactive: 前臺非活躍狀態,指應用程式即將進入前臺狀態。

3、Active: 前臺活躍狀態,指應用程式正在前臺運行,可接受事件併進行處理。

4、Background: 進入後臺狀態,指應用程式進入後臺並可執行代碼。

5、Suspended: 掛起狀態,指應用程式進入後臺並沒有執行代碼,系統會自動將應用程式轉移到該狀態。掛起時,應用程式會保留在記憶體中,但不執行任何代碼,當系統出現記憶體不足情況時,系統會清除被掛起的應用程式。

​ 在應用程式的狀態轉換過程中,系統會調用實現 UIApplicationDelegate 協議類的一些方法,併發送相應的本地通知(先調用方法,待回調方法執行後,再發相應的通知),回調方法和本地通知的對應關係如下表

回調方法 本地通知
- application:didFinishI aunchingWithOptions: UIApplicationDidFinishLaunchingNotification
- applicationDidBecomeActive: UIApplicationDidBecomeActiveNotification
- applicationWillResignActive: UIApplicationWillResignActiveNotification
- applicationDidEnterBack ground:· UIApplicationDidEnterBackgroundNotification
- applicationWillEnterForeground: UIApplicationWillEnterForegroundNotificatio
- applicationWillTerminate: UIApplicationWillTerminateNotification

2.2 實現步驟

​ 通過上面介紹的內容可知,當一個 iOS 應用程式退出時,就意味著該應用程式進入了“後臺”,即處於 Background 狀態。因此,對於實現 $AppEnd 事件的全埋點,我們只需要註冊監聽 UIApplicationDidEnterBackgroundNotification 通知,然後在收到通知時觸發 $AppEnd 事件,即可達到 $AppEnd 事件全埋點的效果。

第一步:註冊監聽 UIApplicationDidEnterBackgroundNotification 本地通知。

在 SensorsAnalyticsSDK.m 文件中實現 - setupListeners 方法,用來監聽 UIApplicationDidEnterBackgroundNotification 本地通知,然後再相應的回調方法中觸發 $AppEnd 事件。

- (void)setupListeners {
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    // 註冊監聽 UIApplicationDidEnterBackgroundNotification 本地通知
    // 當應用程式進入後臺,調用通知方法
    [center addObserver:self
               selector:@selector(applicationDidEnterBackground:)
                   name:UIApplicationDidEnterBackgroundNotification
                 object:nil];
}

- (void)applicationDidEnterBackground:(NSNotification *)notification {
    NSLog(@"Application did enter background.");
    
    // 觸發 AppEnd 事件
    [self track:@"$AppEnd" properties:nil];
}

第二步:在 SensorsAnalyticsSDK.m 文件中初始化 - init 方法中調用 - setupListeners,併在 - dealloc 方法中移除監聽。

- (instancetype)init {
    self = [super init];
    if (self) {
        _automaticProperties = [self collectAutomaticProperties];
        
        // 添加應用程式狀態監聽
        [self setupListeners];
    }
    return self;
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

第三步:測試驗證

我們可以在 Xcode 中列印控制臺中查看如下的列印信息。

{
  "event" : "$AppEnd",
  "time" : 1648520301691,
  "propeerties" : {
    "$model" : "x86_64",
    "$manufacturer" : "Apple",
    "$lib_version" : "1.0.0",
    "$os" : "iOS",
    "$app_version" : "1.0",
    "$os_version" : "15.2",
    "$lib" : "iOS"
  }
}

三、應用程式啟動

應用程式的啟動,一般情況下,大致可以分為兩類場景:

• 冷啟動

• 熱啟動(從後臺恢復)

​ 不管是冷啟動還是熱啟動,觸發 $AppStart 事件的時機,都可以理解成是當“應用程式開始進入前臺並處於活動狀態”,也即前文介紹的 Active 狀態。因此,為了實現 $AppStart 事件的全埋點,我們可以註冊監聽 UIApplicationDidBecomeActiveNotification 本地通知,然後在其相應的回調方法里觸發 $AppStart 事件。

3.1 實現步驟

第一步:在 SensorsAnalyticsSDK.m 文件 - setupListeners 方法中,添加 UIApplicationDidBecomeActiveNotification 本地通知,然後再相應的回調方法中觸發 $AppStart 事件。

- (void)setupListeners {
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    // 註冊監聽 UIApplicationDidBecomeActiveNotification 本地通知
    // 當應用程式進入前臺台,調用通知方法
    [center addObserver:self
               selector:@selector(applicationDidBecomeActive:)
                   name:UIApplicationDidBecomeActiveNotification
                 object:nil];
}

- (void)applicationDidBecomeActive:(NSNotification *)notification {
    NSLog(@"Application did enter active.");
    
    // 觸發 AppEnd 事件
    [self track:@"$AppStart" properties:nil];
}

第二步: 測試驗證

​ 可以在 Xcode 列印控制臺中查看下麵的列印信息。

{
  "event" : "$AppStart",
  "time" : 1648520708355,
  "propeerties" : {
    "$model" : "x86_64",
    "$manufacturer" : "Apple",
    "$lib_version" : "1.0.0",
    "$os" : "iOS",
    "$app_version" : "1.0",
    "$os_version" : "15.2",
    "$lib" : "iOS"
  }
}

3.2 優化

問題:

通過測試可以發現,仍有以下幾個特殊場景存在問題:

• 下拉通知欄並上滑,會觸發 $AppStart 事件

• 上滑控制中心並下拉,會觸發 $AppStart 事件

• 雙擊 Home 鍵進入切換應用程式頁面,最後又選擇當前應用程式,會觸發 $AppStart 事件

以上幾個場景均會觸發 $AppStart 事件,明顯與實際情況有所不符。

那這些現象是什麼原因導致的呢?

我們繼續分析可以發現以下幾個現象:

• 下拉通知欄時,系統會發送 UIApplicationWillResignActiveNotification 通知;上滑通知欄時,系統會發送 UIApplicationDidBecomeActiveNotification 通知

• 上滑控制中心時,系統會發送 UIApplicationWillResignActiveNotification 通知;下拉控制中心時,系統會發送 UIApplicationDidBecomeActiveNotification 通知

• 雙擊 Home 鍵進入切換應用程式頁面時,系統會發送 UIApplicationWillResignActiveNotification 通知,然後選擇當前應用程式,系統會再發送 UIApplicationDidBecomeActiveNotification 通知

很容易總結出規律:在以上幾個場景下,系統均是先發送UIApplicationWillResignActiveNotification 通知,然後再發送 UIApplicationDidBecomeActiveNotification 通知。而我們又是通過註冊監聽 UIApplicationDidBecomeActiveNotification 通知來實現 $AppStart 事件全埋點,因此均會觸發 $AppStart 事件。

那如何解決這個問題呢?

在解決這個問題之前,我們先看另一個現象:不管是冷啟動還是熱啟動,系統均沒有發送 UIApplicationWillResignActiveNotification 通知。

因此,只要在收到 UIApplicationDidBecomeActiveNotification 通知時,判斷之前是否收到過 UIApplicationWillResignActiveNotification 通知,若沒有收到,則觸發 $AppStart 事件;若已收到,則不觸發 $AppStart 事件。這樣即可解決上面的問題。

優化方案:

第一步:在 SensorsAnalyticsSDK.m 文件中添加 applicationWillResignActive 標記位。

/// 標記應用程式是否收到 UIApplicationWillResignActiveNotification 本地通知
@property (nonatomic, assign) BOOL applicationWillResignActive;

第二步:在 - setupListeners 方法中新增註冊監聽 UIApplicationWillResignActiveNotification 的本地通知。

- (void)setupListeners {
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    // 註冊監聽 UIApplicationDidEnterBackgroundNotification 本地通知
    // 當應用程式進入後臺,調用通知方法
    [center addObserver:self
               selector:@selector(applicationDidEnterBackground:)
                   name:UIApplicationDidEnterBackgroundNotification
                 object:nil];
    
    // 註冊監聽 UIApplicationDidBecomeActiveNotification 本地通知
    // 當應用程式進入前臺台,調用通知方法
    [center addObserver:self
               selector:@selector(applicationDidBecomeActive:)
                   name:UIApplicationDidBecomeActiveNotification
                 object:nil];
    
    // 註冊監聽 UIApplicationWillResignActiveNotification 本地通知
    // 當應用程式進入前臺台,調用通知方法
    [center addObserver:self
               selector:@selector(applicationWillResignActive:)
                   name:UIApplicationWillResignActiveNotification
                 object:nil];
}

- (void)applicationWillResignActive:(NSNotification *)notification {
    
    // 設置標記位
    self.applicationWillResignActive = YES;
}

第三步:在UIApplicationDidBecomeActiveNotification 的回調方法中還原 applicationWillResignActive 的標記位

- (void)applicationDidBecomeActive:(NSNotification *)notification {
    NSLog(@"Application did enter active.");
    
    // 還原標記位
    if (self.applicationWillResignActive) {
        self.applicationWillResignActive = NO;
        return;
    }
    
    // 觸發 AppStart 事件
    [self track:@"$AppStart" properties:nil];
}

第四步:在 UIApplicationDidEnterBackgroundNotification 回調方法中還原 applicationWillResignActive 的標記位

- (void)applicationDidEnterBackground:(NSNotification *)notification {
    NSLog(@"Application did enter background.");
    
    // 還原標記位
    self.applicationWillResignActive = NO;
    
    // 觸發 AppEnd 事件
    [self track:@"$AppEnd" properties:nil];
}

第五步:測試驗證

{
  "event" : "$AppStart",
  "time" : 1648533646735,
  "propeerties" : {
    "$model" : "x86_64",
    "$manufacturer" : "Apple",
    "$lib_version" : "1.0.0",
    "$os" : "iOS",
    "$app_version" : "1.0",
    "$os_version" : "15.2",
    "$lib" : "iOS"
  }
}

四、應用程式被動啟動

​ 被動啟動:我們把由 iOS 系統觸發的應用程式自動進入後臺運行的啟動稱之為(應用程式的)被動啟動,使用 $AppStartPassively 事件來表示。

4.1、Background modes

​ 使用 Xcode 創建新的應用程式,預設情況下後臺刷新功能是關閉的,我們可以在 Capabilities 標簽中開啟 Background Modes,然後就可以勾選所需要的功能了,如下圖所示:

image-20220329140937136

通過上圖可知,有如下幾種後臺運行模式,它們都會觸發被動啟動($AppStartPassively 事件)。

1、Audio,AirPlay,and Picture in Picture : 音頻的播放,錄音,AirPlay及畫中畫的視頻播放

2、Location updates:此模式下,會由於地理位置變化而觸發應用程式啟動

3、Voice over IP : IP網路電話,通過對語音信號進行編碼數字化,然後轉換成IP數據包在TCP/IP網路上進行傳輸,從而達到在網路上進行語音通信的目的

4、External Accessory communication:此模式下,一些 MFi 外設通過藍牙或者 Lightning 接頭等方式與 iOS 設備連接,從而可在外設給應用程式發送消息時,觸發對應的應用程式啟動

5、Uses Bluetooth LE accessories:此模式與 External Accessory communication 類似,只是無需限制 MFi 外設,而需要的是 Bluetooth LE 設備

6、Acts as a Bluetooth LE accessory:此模式下,iPhone 作為一個藍牙外設連接,可以觸發應用程式啟動

7、Background fetch:此模式下,iOS 系統會在一定的時間間隔內觸發應用程式啟動,去獲取應用程式數據

8、Remote notifications:此模式是支持靜默推送,當應用程式收到這種推送後,不會有任何界面提示,但會觸發應用程式啟動

9、Background processing: 後端處理

4.2 實現步驟

​ 後臺用程式刷新拉起應用程式後,首先會回調 AppDelegate 中的 -application:didFinishLaunchingWithOptions: 方法。因此,我們可以通過註冊監聽 UIApplicationgDidFinishLaunchingNotification 本地通知來採集被動啟動事件信息。

第一步:在 - setupListeners 方法中添加 UIApplicationgDidFinishLaunchingNotification 本地通知,在回調方法中上報數據。

- (void)setupListeners {
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    // 註冊監聽 UIApplicationDidFinishLaunchingNotification 本地通知
    // 當應用程式被動,調用通知方法
    [center addObserver:self
               selector:@selector(applicationDidFinishLaunching:)
                   name:UIApplicationDidFinishLaunchingNotification
                 object:nil];
}
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
    
    // 觸發 AppStartPassively 事件
    [self track:@"$AppStartPassively" properties:nil];
}

第二步:新增一個私有屬性 launchedPassively,標記應用程式是否處於被動啟動

/// 標記應用程式是否是被動啟動
@property (nonatomic, assign, getter=isLaunchedPassively) BOOL launchedPassively;

第三步:在 - init 初始化方法中,通過 backgroundTimeRemaining 屬性是否等於 UIApplicationBackgroundFetchIntervalNever 來設置

- (instancetype)init {
    self = [super init];
    if (self) {
        _automaticProperties = [self collectAutomaticProperties];

        // 設置是否需是被動啟動標記
        _launchedPassively = UIApplication.sharedApplication.backgroundTimeRemaining != UIApplicationBackgroundFetchIntervalNever;
        
        // 添加應用程式狀態監聽
        [self setupListeners];
    }
    return self;
}

第四步:在 - applicationDidFinishLaunching 回調方法中,如果 isLaunchedPassively 為 YES,再觸發 $AppStartPassively 事件

- (void)applicationDidFinishLaunching:(NSNotification *)notification {
    NSLog(@"Application did finish launching.");
    // 當應用程式後臺運行時,觸發被動啟動事件
    if (self.isLaunchedPassively) {
        // 觸發 AppStartPassively 事件
        [self track:@"$AppStartPassively" properties:nil];
    }
}

第五步:測試驗證

1、開啟 Background modes 中的 Background fetch 覆選框

2、選擇 Demo Scheme , 一次單擊 Xcode 菜單欄中的 Product -> Scheme -> Edit -> Scheme -> Run -> Options

3、勾選 Background Fetch 選項,然後點擊 Close 按鈕。運行 Demo

{
  "event" : "$AppStartPassively",
  "time" : 1648537321216,
  "propeerties" : {
    "$model" : "x86_64",
    "$manufacturer" : "Apple",
    "$lib_version" : "1.0.0",
    "$os" : "iOS",
    "$app_version" : "1.0",
    "$os_version" : "15.2",
    "$lib" : "iOS"
  }


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 轉自:https://www.nerdfonts.com/https://www.nerdfonts.com/ 明確出處,如有侵權請及時聯繫刪除。 最近把開發環境換成了Windows 11,各個方面的使用還有點不習慣,不過經過了一天的配置,基本環境已經OK了。比較難受適應的是還是Terminal,在 ...
  • Linux 0.11源碼閱讀筆記-中斷過程 是什麼中斷 中斷發生時,電腦會停止當前運行的程式,轉而執行中斷處理程式,然後再返回原被中斷的程式繼續運行。中斷包括硬體中斷和軟體中斷,硬中斷是由外設自動產生的,軟中斷是程式通過int指令主動調用。中斷產生時,會有一個中斷號,根據中斷號可在中斷向量表中選擇 ...
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 一、介紹背景: VirtualBox : 由德國 InnoTek 軟體公司出品 Open Source Software, OSS(開源軟體) 的⼀種 Hypervisor ,現在則由 Oracle 公司進⾏開發(2008年02⽉ SUN 收購 ...
  • 之前小編為大家分享過一些Win10徹底關閉Windows Update自動更新的方法,主要是通過一些如設置流量計費或藉助一些專門的小工具來實現,但往往會發現,Win10自動更新就像打不死的小強,不管怎麼關閉,之後還是會自動更新,讓不少小伙伴頗為不爽。今天小編帶來了這篇改進型教程,通過全方位設置,徹底 ...
  • MySQL中的select for update大家應該都有所接觸,但什麼時候該去使用,以及有哪些需要註意的地方會有很多不清楚的地方,我把我如何使用和查詢到的文檔在此記錄。 作用 select本身是一個查詢語句,查詢語句是不會產生衝突的一種行為,一般情況下是沒有鎖的,用select for upda ...
  • 資料庫讀寫分離的目的是什麼;讀寫分離會帶來什麼問題?如何解決;MySQL主從複製的原理清楚嗎;讀寫分離具體怎麼實施呢 ...
  • Redis最新超詳細版教程通俗易懂 一、Nosql概述 為什麼使用Nosql 1、單機Mysql時代 90年代,一個網站的訪問量一般不會太大,單個資料庫完全夠用。隨著用戶增多,網站出現以下問題 數據量增加到一定程度,單機資料庫就放不下了 數據的索引(B+ Tree),一個機器記憶體也存放不下 訪問量變 ...
  • 協程是一個併發方案。也是一種思想。 傳統意義上的協程是單線程的,面對io密集型任務他的記憶體消耗更少,進而效率高。但是面對計算密集型的任務不如多線程並行運算效率高。 不同的語言對於協程都有不同的實現,甚至同一種語言對於不同平臺的操作系統都有對應的實現。 我們kotlin語言的協程是 corout... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...