Objective-C 入門指南

本開發人員指南說明如何在 行動應用程式

簡介

Google 代碼管理工具可讓開發人員變更設定 透過 Google 代碼管理工具 在行動應用程式中放送 不必重新建立應用程式二進位檔並重新提交至應用程式介面 市集。

這很適合用來管理任何設定值 日後可能需要變更 包括:

  • 各種 UI 設定和顯示字串
  • 在應用程式中放送的廣告大小、位置或類型
  • 遊戲設定

您也能在執行階段使用規則,評估設定值 可啟用動態設定,例如:

  • 使用螢幕大小決定廣告橫幅大小
  • 使用語言和位置設定 UI 元素

Google 代碼管理工具也能以動態方式導入追蹤代碼 模型和像素的應用方式開發人員可以將重要事件推送至資料 ,並決定要觸發哪些追蹤代碼或像素。 代碼管理工具目前支援下列代碼:

  • Google 行動應用程式分析
  • 自訂函式呼叫代碼

事前準備

使用這份入門指南之前,您必須符合以下條件:

如果您是 Google 代碼管理工具新手,建議您 請先進一步瞭解容器、巨集和規則 (說明中心),再繼續閱讀本指南。

開始使用

本節將引導開發人員完成一般的代碼管理工具工作流程:

  1. 將 Google 代碼管理工具 SDK 加進專案
  2. 設定預設容器值
  3. 開啟容器
  4. 從容器取得設定值
  5. 將事件推送至資料層
  6. 預覽和發布容器

1. 將 Google 代碼管理工具 SDK 加進專案

使用 Google 代碼管理工具 SDK 前 libGoogleAnalyticsServices.a 以及 Library 的 Google 代碼管理工具 (GTM) 標頭檔案 新增至專案中 SDK 套件的目錄

接著,將下列內容加入應用程式目標的連結程式庫 (如果這些程式庫中) 尚未存在:

  • CoreData.framework
  • SystemConfiguration.framework
  • libz.dylib
  • libsqlite3.dylib
  • libGoogleAnalyticsServices.a

如果您希望應用程式存取 廣告客戶 (IDFA) 和追蹤標幟 Google 代碼管理工具 SDK 巨集,您也必須連結下列額外程式庫:

  • libAdIdAccess.a
  • AdSupport.framework
,瞭解如何調查及移除這項存取權。

2. 在專案中新增預設容器檔案

Google 代碼管理工具會在應用程式第一次執行時使用預設容器。預設 並持續使用直到應用程式能透過 更是如此

如要下載及新增預設容器二進位檔至應用程式,請按照下列步驟操作:

  1. 登入 Google 代碼管理工具網頁介面。
  2. 選取要下載的容器「版本」
  3. 點選「下載」按鈕,擷取容器二進位檔。
  4. 將二進位檔案加入 專案的根目錄和「支援檔案」資料夾

預設檔案名稱應為容器 ID (例如 GTM-1234)。 已下載二進位檔案,請務必移除檔案名稱中的版本後置字串 以確保遵循正確的命名慣例

雖然我們建議您使用二進位檔案,但如果容器不含規則或標記, 可以選用一個簡單的 屬性清單或 JSON 檔案。 檔案應位於主要套件中,且應如下所示 這個命名慣例:<Container_ID>.<plist|json>。 舉例來說,如果容器 ID 是 GTM-1234,則可指定 預設容器值,名為 GTM-1234.plist

3. 開啟容器

從容器擷取值之前,應用程式必須先開啟 開啟容器時,系統會從磁碟載入容器 (如果有的話)。 (如有需要),則會向網路發出要求。

如要在 iOS 開啟容器,最簡單的方法是使用 openContainerWithId:tagManager:openType:timeout:notifier:,如以下範例所示:

// MyAppDelegate.h
// This example assumes this file is using ARC.
#import <UIKit/UIKit.h>

@class TAGManager;
@class TAGContainer;

@interface MyAppDelegate : UIResponder <UIApplicationDelegate>

@property (nonatomic, strong) TAGManager *tagManager;
@property (nonatomic, strong) TAGContainer *container;

@end


// MyAppDelegate.m
// This example assumes this file is using ARC.
#import "MyAppDelegate.h"
#import "TAGContainer.h"
#import "TAGContainerOpener.h"
#import "TAGManager.h"

@interface MyAppDelegate ()<TAGContainerOpenerNotifier>
@end

@implementation MyAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  self.tagManager = [TAGManager instance];

  // Optional: Change the LogLevel to Verbose to enable logging at VERBOSE and higher levels.
  [self.tagManager.logger setLogLevel:kTAGLoggerLogLevelVerbose];

  /*
   * Opens a container.
   *
   * @param containerId The ID of the container to load.
   * @param tagManager The TAGManager instance for getting the container.
   * @param openType The choice of how to open the container.
   * @param timeout The timeout period (default is 2.0 seconds).
   * @param notifier The notifier to inform on container load events.
   */
  [TAGContainerOpener openContainerWithId:@"GTM-XXXX"   // Update with your Container ID.
                               tagManager:self.tagManager
                                 openType:kTAGOpenTypePreferFresh
                                  timeout:nil
                                 notifier:self];

  // Method calls that don't need the container.

  return YES;
}

// TAGContainerOpenerNotifier callback.
- (void)containerAvailable:(TAGContainer *)container {
  // Note that containerAvailable may be called on any thread, so you may need to dispatch back to
  // your main thread.
  dispatch_async(dispatch_get_main_queue(), ^{
    self.container = container;
  });
}

// The rest of your app delegate implementation.
敬上

4. 從容器取得設定值

容器開啟後,即可使用 這個 <type>ForKey: 方法:

// Retrieving a configuration value from a Tag Manager Container.

MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
TAGContainer *container = appDelegate.container;

// Get the configuration value by key.
NSString *title = [container stringForKey:@"title_string"];

以不存在的金鑰發出的要求,會傳回適當的預設值 改為要求類型:

// Empty keys will return a default value depending on the type requested.

// Key does not exist. An empty string is returned.
NSString subtitle = [container stringForKey:@"Non-existent-key"];
[subtitle isEqualToString:@""]; // Evaluates to true.

5. 將值推送到 DataLayer

DataLayer 是一種地圖,可用來啟用應用程式的執行階段資訊,例如觸控功能 才能供代碼管理工具巨集和畫面瀏覽 都會在 Docker 容器中執行

例如,將畫面瀏覽的相關資訊推送到 DataLayer 地圖。 在代碼管理工具的網頁介面中設定代碼來觸發轉換像素 及追蹤來電以回應這些畫面瀏覽, 加入應用程式中

使用 push: 將事件推送至資料層

//
//  ViewController.m
//  Pushing an openScreen event with a screen name into the data layer.
//

#import "MyAppDelegate.h"
#import "TAGDataLayer.h"
#import "ViewController.h"

@implementation ViewController

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    // The container should have already been opened, otherwise events pushed to
    // the data layer will not fire tags in that container.
    TAGDataLayer *dataLayer = [TAGManager instance].dataLayer;

    [dataLayer push:@{@"event": @"openScreen", @"screenName": @"Home Screen"}];
}

// Rest of the ViewController implementation

@end

您現在可以在網頁介面中建立代碼 (例如 Google Analytics 代碼) 即可為每個畫面瀏覽觸發一個事件 等於「openScreen」。如何傳遞畫面名稱 加入其中一個標記,請建立參照「screenName」的資料層巨集 索引鍵的值您也可以建立 (例如 Google Ads 轉換像素) 只針對特定畫面瀏覽觸發,計算方式為 建立一個規則,其中 等於「openScreen」 (&&) 等於「ConfirmationScreen」。

6. 預覽與發布容器

巨集值一律會與目前發布的版本對應。 發布最新版本的容器前,您可以先預覽 儲存容器

若要預覽容器,請在 Google 選擇容器版本來設定代碼管理工具網頁介面 ,然後選取「Preview」。持續追蹤 因為後續步驟會用到這個預覽網址。

可在代碼的預覽視窗中查看預覽網址
           管理工具網頁介面
圖 1: 從 代碼管理工具網頁介面。

如要啟用容器預覽,請在應用程式中加入程式碼 委派導入檔案,並定義 Google 代碼管理工具預覽網址 。

首先,請將下列以粗體顯示的程式碼片段新增至應用程式委派檔案:

@implementation MyAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

  self.tagManager = [TAGManager instance];
  
  // Add the code in bold below to preview a Google Tag Manager container.
  // IMPORTANT: This code must be called before the container is opened.
  NSURL *url = [launchOptions valueForKey:UIApplicationLaunchOptionsURLKey];
  if (url != nil) {
    [self.tagManager previewWithUrl:url];
  }
  
  id<TAGContainerFuture> future =
      [TAGContainerOpener openContainerWithId:@"GTM-XXXX"    // Placeholder Container ID.
                                   tagManager:self.tagManager
                                     openType:kTAGOpenTypePreferNonDefault
                                      timeout:nil];

  // The rest of your method implementation.

  self.container = [future get];

  return YES;
}


// Add the code in bold below preview a Google Tag Manager container.
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {

  if ([self.tagManager previewWithUrl:url]) {
    return YES;
  }

  // Code to handle other urls.
  return NO;
}

接著,在 應用程式屬性清單檔案的網址類型鍵:

URL identifier: your.package_name
URL scheme: tagmanager.c.your.package.name
敬上
在應用程式的
                屬性清單檔案。
圖 3: 新增代碼管理工具預覽網址配置 加入應用程式的屬性清單檔案中。
,瞭解如何調查及移除這項存取權。

在模擬器或實體裝置上開啟連結,即可執行以下操作: 在應用程式中預覽草稿容器

當您準備好將草稿設定值提供給 應用程式, 發布容器

進階設定

行動版 Google 代碼管理工具有多項進階設定 這些選項可讓您根據執行階段條件選取值 手動重新整理容器,並取得開啟的其他選項 容器以下各節將概述一些最常見的 儲存空間設定

開啟容器的進階選項

Google 代碼管理工具 SDK 提供多種開啟方式 可讓您進一步掌控載入程序的容器:

openContainerById:callback:

openContainerById:callback: 是最高級別且最具彈性的 API,用於開啟 都會在 Docker 容器中執行此函式會立即傳回包含預設容器 如果未儲存任何檔案 則能以非同步方式從磁碟或網路載入容器 或儲存的容器還不是最新狀態 (超過 12 小時)。

@interface ContainerCallback : NSObject<TAGContainerCallback>

@end

@implementation ContainerCallback

/**
 * Called before the refresh is about to begin.
 *
 * @param container The container being refreshed.
 * @param refreshType The type of refresh which is starting.
 */
- (void)containerRefreshBegin:(TAGContainer *)container
                  refreshType:(TAGContainerCallbackRefreshType)refreshType {
  // Notify UI that container refresh is beginning.
}

/**
 * Called when a refresh has successfully completed for the given refresh type.
 *
 * @param container The container being refreshed.
 * @param refreshType The type of refresh which completed successfully.
 */
- (void)containerRefreshSuccess:(TAGContainer *)container
                    refreshType:(TAGContainerCallbackRefreshType)refreshType {
  // Notify UI that container is available.
}

/**
 * Called when a refresh has failed to complete for the given refresh type.
 *
 * @param container The container being refreshed.
 * @param failure The reason for the refresh failure.
 * @param refreshType The type of refresh which failed.
 */
- (void)containerRefreshFailure:(TAGContainer *)container
                        failure:(TAGContainerCallbackRefreshFailure)failure
                    refreshType:(TAGContainerCallbackRefreshType)refreshType {
  // Notify UI that container request has failed.
}
@end

在載入過程中,有 openContainerById:callback: 個問題 多個生命週期回呼,您的程式碼就可瞭解 是否開始載入要求、要求失敗或成功的原因,以及 容器則是從磁碟或網路載入

除非應用程式可接受使用預設值,否則 您需要使用這些回呼來知道儲存或網路 容器載入完畢。請注意,您將無法載入已儲存的或 如果這是第一次執行應用程式,而且沒有網路容器 網路連線。

openContainerById:callback: 通過下列enum 做為這些回呼的引數:

RefreshType

說明
kTAGContainerCallbackRefreshTypeSaved 重新整理要求會載入儲存在本機的容器。
kTAGContainerCallbackRefreshTypeNetwork 重新整理要求會透過網路載入容器。

RefreshFailure

說明
kTAGContainerCallbackRefreshFailureNoSavedContainer 沒有可用的已儲存容器。
kTAGContainerCallbackRefreshFailureIoError 無法重新整理容器的 I/O 錯誤。
kTAGContainerCallbackRefreshFailureNoNetwork 沒有可用的網路連線。
kTAGContainerCallbackRefreshFailureNetworkError 發生網路錯誤。
kTAGContainerCallbackRefreshFailureServerError 伺服器發生錯誤,
kTAGContainerCallbackRefreshFailureUnknownError 發生無法分類的錯誤。

開啟非預設與最新容器的方法

TAGContainerOpener 結束openContainerById:callback: 並提供兩種開啟容器的簡便方法: openContainerWithId:tagManager:openType:timeout:notifier:openContainerWithId:tagManager:openType:timeout:

這些方法都會接受列舉,要求使用非預設或 更新容器

建議大多數應用程式使用 kTAGOpenTypePreferNonDefault, 會在指定內 逾時期限,即使容器較大 超過 12 小時。如果傳回過時的已儲存容器,也會 非同步網路要求 使用 kTAGOpenTypePreferNonDefault 時,這是預設值 如果沒有其他可用容器,或逾時期限 。

kTAGOpenTypePreferFresh 嘗試從以下時間傳回新容器: 在指定逾時期限內排除磁碟或網路 如果網路包含已儲存的容器 連線無法使用且/或超過逾時期限。

不建議使用 kTAGOpenTypePreferFresh 對使用者體驗產生明顯影響 例如 UI 旗標或顯示字串您也可以使用 隨時TAGContainer::refresh 強制執行網路容器要求

這兩種方便的方法都是非阻塞。 openContainerWithId:tagManager:openType:timeout: 會傳回 TAGContainerFuture 物件,其 get 方法會傳回 TAGContainer 載入後立即執行 (但 仍會封鎖)。 openContainerWithId:tagManager:openType:timeout:notifier: 方法會採用單一回呼 會在有容器可用時呼叫 這兩種方法的預設逾時期限為 2.0 秒。

使用規則評估執行階段的巨集

容器可以在執行階段透過規則評估值。可根據規則進行設定 例如裝置語言、平台或任何其他巨集值適用對象 例如,您可以運用規則根據 以及裝置在執行階段的語言使用 GCP 控制台 規則:

您可以使用規則,根據以下位置的裝置語言選取顯示字串:
            runtime:程式語言等於 es。這項規則使用預先定義的語言
            巨集和兩個字元的 ISO 639-1 語言代碼。
圖 1:新增規則以僅針對裝置啟用值組合巨集 設為使用西班牙文

接著,您就可以為每個語言建立值收集巨集,並將 規則,並插入適當的語言代碼。當這個容器 發布後,您的應用程式就會顯示本地化的螢幕 字串,視使用者裝置在執行階段的語言而定。

請注意,如果預設容器需要規則,您必須使用 二進位容器檔案做為預設選項 都會在 Docker 容器中執行

進一步瞭解如何設定規則 (說明中心)。

二進位檔預設容器檔案

需要規則的預設容器應使用二進位容器檔案 而不是屬性清單檔案或 JSON file 設為預設容器,二進位檔容器支援判定 巨集值在執行階段套用 Google 代碼管理工具規則時, 屬性清單或 JSON 檔案不會

您可以從 Google 代碼管理工具網站下載二進位容器檔案 介面和 API 應按照以下命名慣例新增至主要應用程式套件: GTM-XXXX,其中檔案名稱代表 容器 ID。

屬性清單檔案和/或 JSON 檔案 以及二進位容器檔案,SDK 會使用二進位容器 檔案設為預設容器

使用函式呼叫巨集

函式呼叫巨集是設為 您在應用程式中指定的函式即可函式呼叫巨集可用於 結合執行階段值與您的 Google 代碼管理工具規則,例如 根據設定在執行階段中向使用者顯示何種價格 裝置的語言和貨幣。

如何設定函式呼叫巨集:

  1. 在 Google 代碼管理工具網頁介面中定義函式呼叫巨集。 您可以選擇將引數設為鍵/值組合。
  2. 定義實作 TAGFunctionCallMacroHandler 的處理常式 通訊協定:
    // MyFunctionCallMacroHandler.h
    #import "TAGContainer.h"
    
    // The function name field of the macro, as defined in the Google Tag Manager
    // web interface.
    extern NSString *const kMyMacroFunctionName;
    
    @interface MyFunctionCallMacroHandler : NSObject<TAGFunctionCallMacroHandler>
    
    @end
    
    
    // MyFunctionCallMacroHandler.m
    #import "MyFunctionCallMacroHandler.h"
    
    // Corresponds to the function name field in the Google Tag Manager interface.
    NSString *const kMyMacroFunctionName = @"myConfiguredFunctionName";
    
    @implementation MacroHandler
    
    - (id)valueForMacro:(NSString *)functionName parameters:(NSDictionary *)parameters {
    
      if ([functionName isEqualToString:kMyMacroFunctionName]) {
        // Process and return the calculated value of this macro accordingly.
        return macro_value;
      }
      return nil;
    }
    
    @end
  3. 使用 TAGContainer::registerFunctionCallMacroHandler:forMacro: 和函式名稱來註冊處理常式: 找到以下幾點
  4. //
    // MyAppDelegate.h
    //
    #import <UIKit/UIKit.h>
    
    @interface MyAppDelegate : UIResponder <UIApplicationDelegate>
    
    @end
    
    
    //
    // MyAppDelegate.m
    //
    #import "MyAppDelegate.h"
    #import "MyFunctionCallMacroHandler.h"
    #import "TAGContainer.h"
    #import "TAGContainerOpener.h"
    #import "TAGManager.h"
    
    @implementation MyAppDelegate
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
      // Open the container.
      id<TAGContainerFuture> future =
          [TAGContainerOpener openContainerWithId:@"GTM-XXXX"    // Placeholder Container ID.
                                       tagManager:[TAGManager instance]
                                         openType:kTAGOpenTypePreferNonDefault
                                          timeout:nil];
    
      // Method calls that don't need the container.
    
      self.container = [future get];
    
      // Register a function call macro handler using the macro name defined
      // in the Google Tag Manager web interface.
      [self.container registerFunctionCallMacroHandler:[[MyFunctionCallMacroHandler alloc] init]
                                              forMacro:kMyMacroFunctionName];
    }
    
    @end

使用函式呼叫標記

函式呼叫代碼可讓預先註冊的函式在每次發生時執行 系統會將事件推送至資料層,而代碼規則 得出的值為 true

如何設定函式呼叫代碼:

  1. 在 Google 代碼管理工具網頁介面中定義函式呼叫代碼。 您可以選擇將引數設為鍵/值組合。
  2. 實作 TAGFunctionCallTagHandler 通訊協定:
    //
    // MyFunctionCallTagHandler.h
    //
    
    #import "TAGContainer.h"
    
    extern NSString *const kMyTagFunctionName;
    
    @interface MyFunctionCallTagHandler : NSObject<TAGFunctionCallTagHandler>
    
    @end
    
    
    //
    // MyFunctionCallTagHandler.m
    //
    
    // Corresponds to the function name field in the Google Tag Manager interface.
    NSString *const kMyTagFunctionName = @"myConfiguredFunctionName";
    
    @implementation MyFunctionCallTagHandler
    
    /**
     * This method will be called when any custom tag's rule(s) evaluate to true and
     * should check the functionName and process accordingly.
     *
     * @param functionName corresponds to the function name field, not tag
     *     name field, defined in the Google Tag Manager web interface.
     * @param parameters An optional map of parameters as defined in the Google
     *     Tag Manager web interface.
     */
    - (void)execute:(NSString *)functionName parameters:(NSDictionary *)parameters {
    
      if ([functionName isEqualToString:kMyTagFunctionName]) {
        // Process accordingly.
      }
    }
    @end
  3. 使用 Google 代碼管理工具網頁介面:
  4. //
    // MyAppDelegate.h
    //
    #import <UIKit/UIKit.h>
    
    @interface MyAppDelegate : UIResponder <UIApplicationDelegate>
    
    @end
    
    
    //
    // MyAppDelegate.m
    //
    #import "MyAppDelegate.h"
    #import "MyFunctionCallTagHandler.h"
    #import "TAGContainer.h"
    #import "TAGContainerOpener.h"
    #import "TAGManager.h"
    
    @implementation MyAppDelegate
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
      // Open the container.
      id<TAGContainerFuture> future =
          [TAGContainerOpener openContainerWithId:@"GTM-XXXX"    // Placeholder Container ID.
                                       tagManager:[TAGManager instance]
                                         openType:kTAGOpenTypePreferNonDefault
                                          timeout:nil];
    
      // Method calls that don't need the container.
    
      self.container = [future get];
    
      // Register a function call tag handler using the function name of the tag as
      // defined in the Google Tag Manager web interface.
      [self.container registerFunctionCallTagHandler:[[MyFunctionCallTagHandler alloc] init]
                                              forTag:kMyTagFunctionName];
    }
    @end

設定自訂重新整理週期

Google 代碼管理工具 SDK 會嘗試擷取 如果目前容器存在時間超過 12 小時,就會看見新的容器。如要設定 自訂容器重新整理期間,請使用 NSTimer,如 範例:

- (void)refreshContainer:(NSTimer *)timer {
  [self.container refresh];
}

self.refreshTimer = [NSTimer scheduledTimerWithTimeInterval:<refresh_interval>
                                                     target:self
                                                   selector:@selector(refreshContainer:)
                                                   userInfo:nil
                                                    repeats:YES];

使用 Logger 進行偵錯

根據預設,Google 代碼管理工具 SDK 會在記錄中列印錯誤和警告。 啟用更詳細的記錄對於偵錯會很有幫助,而且 實作您自己的 Logger,如以下範例所示:

// MyAppDelegate.h
// This example assumes this file is using ARC.
// This Logger class will print out not just errors and warnings (as the default
// logger does), but also info, debug, and verbose messages.
@interface MyLogger: NSObject<TAGLogger>
@end

@implementation MyLogger
- (void)error:(NSString *)message {
  NSLog(@"Error: %@", message);
}

- (void)warning:(NSString *)message {
  NSLog(@"Warning: %@", message);
}

- (void)info:(NSString *)message {
  NSLog(@"Info: %@", message);
}

- (void)debug:(NSString *)message {
  NSLog(@"Debug: %@", message);
}

- (void)verbose:(NSString *)message {
  NSLog(@"Verbose: %@", message);
}
@end

// MyAppDelegate.m
// This example assumes this file is using ARC.
@implementation MyAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  self.tagManager = [TAGManager instance];
  
  self.tagManager.logger = [[MyLogger alloc] init];
  
  // Rest of Tag Manager and method implementation.
  return YES;
}
// Rest of app delegate implementation.
@end

或者,您也可以使用以下方法設定現有 Logger 的 LogLevel: TagManager::logger::setLogLevel, 如下所示:

// Change the LogLevel to INFO to enable logging at INFO and higher levels.
self.tagManager = [TAGManager instance];
[self.tagManager.logger setLogLevel:kTAGLoggerLogLevelInfo];