KeenClient 3.7.0

KeenClient 3.7.0

测试已测试
语言语言 CC
许可协议 MIT
发布上次发布2017年6月

Terry HornerDaniel KadorHeitor Tashiro SergentBrian Baumhover维护。



  • Daniel Kador、Terry Horner、Claire Young、Heitor Sergent和Brian Baumhover编写

Keen IO iOS SDK


重要:从3.5.0版本开始,变量 maxAttempts 更名为 maxEventUploadAttempts,以避免与用于限制失败的查询功能相混淆。

重要:从3.3.0版本开始,您需要将 SystemConfiguration 框架添加到项目中。有关更多信息,请参阅 “构建设置” 部分。


Keen IO iOS客户端旨在易于开发,但又非常灵活。我们的目标是让您选择对您重要的事件,使用自己的词汇描述它们,并决定何时将它们发送到Keen IO。

虽然该存储库的名称暗示这个SDK仅适用于iOS,但也可以通过以下概述使用Cocoa版本在Mac OS应用程序中使用。代码库是相同的,但构建目标是不同的。 :)

安装

客户端安装应该非常简单,有三种不同的方式可以进行:Carthage、CocoaPods和二进制。如果您遇到任何问题,请在我们的仓库中创建一个问题,或者通过发送电子邮件至[email protected]与我们联系!

通用二进制文件

您可以在我们的发布页面这里检查最新的二进制版本。

虽然我们认为通用二进制文件使事情变得非常简单,但我们喜欢保持透明。我们喜欢反馈,尤其是以拉取请求的形式:)

下载
解压缩并添加到Xcode

解压缩您所使用的平台的ZIP文件,并将文件夹拖动到您的Xcode项目中。(KeenClient-Cocoa用于Cocoa,KeenClient用于iOS)。

Swift

如果您的Swift项目为使用CocoaPods的KeenClient静态库版本链接(即,未在Podfile中添加`use_frameworks!`),则需要添加一个桥接头文件,例如“ProjectName-Bridging-Header.h”。在桥接头文件中添加

// If you're linking to a static library versin of KeenClient (CocoaPods without use_frameworks!)
#import “KeenClient.h”

在您的项目目标的构建设置中,将“安装Objective-C兼容性头文件”设置为“是”,并将“Objective-C桥接头”设置为新建的桥接头文件“ProjectName-Bridging-Header.h”。

如果您使用CocoaPods并设置了use_frameworks!,或者使用Carthage,只需在Swift中像平常一样导入框架即可

import KeenClient

用法

要使用此客户端与Keen IO API,您必须配置Keen IO项目ID及其访问密钥(如果您需要账号,请在此处注册 - 这是免费的)。

注册您的项目ID和访问密钥

使用项目ID和访问密钥注册KeenClient共享客户端。推荐的做法是将此操作放在应用程序代理之一中,如下所示

Objective C

#import <KeenClient/KeenClient.h> // This import works for a framework version of KeenClient (CocoaPods with use_frameworks! or Carthage).
// or
#import "KeenClient.h" // If linking against a static library version (CocoaPods without use_frameworks!)
// ...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
	[KeenClient sharedClientWithProjectID:@"your_project_id" andWriteKey:@"your_write_key" andReadKey:@"your_read_key"];
	return YES;
}

Swift

import KeenClient // Import only required if linking to a framework version of KeenClient. Otherwise the bridging header takes care of this.
// ...
func application(_ application: UIApplication,
			didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
{
	let client: KeenClient
	client = KeenClient.sharedClient(withProjectID: "your_project_id", andWriteKey: "your_write_key", andReadKey: "your_read_key");
	return true
}

写入密钥用于向Keen IO发送事件。读取密钥用于在Keen IO进行分析。

[KeenClient sharedClientWithProjectID: andWriteKey: andReadKey:]执行注册。从现在起,在您的代码中,您可以通过调用objc [KeenClient sharedClient]来引用共享客户端。

添加事件

添加事件以进行跟踪。以下是一个包括两个标签页的应用的基本示例。我们要跟踪标签页何时被切换。

Objective C

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

  	NSDictionary *event = [NSDictionary dictionaryWithObjectsAndKeys:@"first view", @"view_name", @"going to", @"action", nil];
  	[[KeenClient sharedClient] addEvent:event toEventCollection:@"tab_views" error:nil];
}

Swift

override func viewWillAppear(_ animated: Bool)
{
	super.viewWillAppear(animated)
	let event = ["view_name": "first view Swift", "action": "going to"]
	do {
		try KeenClient.shared().addEvent(event, toEventCollection: "tab_views")
	} catch _ {
	};
}

首先创建一个任意的JSON序列化值的字典。我们支持

NSString, NSNumber, NSDate, NSDictionary, NSArray, and BOOL

JSON规范不包括关于日期值的内容。在Keen,我们知道日期对于跟踪来说很重要。Keen通过其API以ISO-8601格式来回发送日期。`KeenClient`为您处理这一点。

键必须是字母数字的,但是下划线字符(_)除外,它可以在字符串中的任何位置出现,但不能在开头。例如,“view_name”是允许的,但“_view_name”是不允许的。

您可以添加任意数量的活动。 KeenClient 将在您准备好发送它们之前将它们缓存在磁盘上。

KeenClient 将自动在每个跟踪的活动上打上时间戳。如果您想用自己的值覆盖系统值,请参考以下示例。请注意,“时间戳”键在标题属性字典中设置。

Objective C

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

   	NSDictionary *event = [NSDictionary dictionaryWithObjectsAndKeys:@"first view", @"view_name", @"going to", @"action", nil];
    NSDate *myDate = [NSDate date];
    KeenProperties *keenProperties = [[KeenProperties alloc] init];
   	keenProperties.timestamp = myDate;
    [[KeenClient sharedClient] addEvent:event
           	         withKeenProperties:keenProperties
       	              toEventCollection:@"tab_views"
   	                              error:nil];
}

Swift

override func viewWillAppear(animated: Bool)
{
	super.viewWillAppear(animated)

	let event = ["view_name": "first view Swift", "action": "going to"]
	let keenProps: KeenProperties = KeenProperties()
	keenProps.timestamp = NSDate() as Date!;
	do {
		try KeenClient.shared().addEvent(event, with: keenProps, toEventCollection: "tab_views")
	} catch _ {
	}
}
全局属性

现在您可能正在想,“看起来很简单。但如果我想在特定集合的 每个 事件上发送相同的属性呢?或者,只是 每个 事件?”我们通过称为全局属性的功能来覆盖这一需求。

全局属性是指在每次发送事件时都会发送的属性。例如,您可能希望始终捕获设备信息,如操作系统版本、手机类型、方向等。

处理全局属性有两种方式——一种较为简单但功能有限,另一种比较复杂但功能更强大。对于每一种,在您注册客户端之后,您需要设置在您使用的 KeenClient 实例上的 Objective-C 属性。

基于字典的全局属性

对于这种情况,Objective-C 属性名为 globalPropertiesDictionary。属性值将是一个您定义的 NSDictionary。每次添加事件时,客户端都会查看该属性的值,并将所有内容添加到用户定义的事件中。如果您有一系列静态属性要添加到每个事件中,请使用此方法。

以下是一个使用字典的示例

Objective C

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    KeenClient *client = [KeenClient sharedClient];
   	client.globalPropertiesDictionary = @{@"some_standard_key": @"some_standard_value"};
}

Swift

func applicationDidBecomeActive(application: UIApplication)
{
	KeenClient.shared().globalPropertiesDictionary =
					        ["some_standard_key" : "some_standard_value"]
}

如果用户定义的事件和全局属性中指定了两个同名属性,则用户定义事件的属性将被使用。

基于块的全球属性

对于这种情况,Objective-C 属性名为 globalPropertiesBlock。属性值将是一个您定义的块。每次添加事件时,该块都会被调用。客户端期望该块返回一个包含该事件集合全局属性的 NSDictionary。如果您有一系列动态属性要添加到每个事件中,请使用此方法。

以下是一个使用块的示例

Objective C

- (void)applicationDidBecomeActive:(UIApplication *)application
{
   	KeenClient *client = [KeenClient sharedClient];
    client.globalPropertiesBlock = ^NSDictionary *(NSString *eventCollection) {
   	    if ([eventCollection isEqualToString:@"apples"]) {
       	    return @{ @"color": @"red" };
        } else if ([eventCollection isEqualToString:@"pears"]) {
   	        return @{ @"color": @"green" };
        } else {
   	        return nil;
        }
   	};
}

Swift

- (void)applicationDidBecomeActive:(UIApplication *)application
{
		KeenClient.shared().globalPropertiesBlock =
			{(eventCollection : String?) -> [AnyHashable: Any]? in
					if (eventCollection!.compare("apples") ==
							ComparisonResult.orderedSame)
					{
							return ["color" : "red"]
					} else if (eventCollection!.compare("pears") ==
							ComparisonResult.orderedSame)
					{
							return ["color" : "green"]
					}
					return nil
		};
}

该块接受一个与特定事件名称相对应的单个字符串参数。我们希望它返回一个您构造的 NSDictionary。此示例没有使用该参数,但您的可以!

因为我们在这里支持块,所以您可以创建 动态 全局属性。例如,您可能想捕获设备的方向,这显然可能在运行时改变。使用块,每次添加事件时,您可以使用函数式编程询问操作系统当前的方向。非常有用,对吧?

另一个注意点——您可以使用 两个 字典属性和块属性。如果定义的属性之间存在冲突,优先顺序如下:用户定义的事件 > 块定义的事件 > 字典定义的事件。这意味着单个事件中添加的属性将 总是 显示,即使在全局定义中定义了相同的属性。

地理定位

类似于任何优秀的以移动为先的服务,Keen 支持地理定位,因此您可以跟踪事件发生的地点。这是默认启用的。只需像通常一样使用客户端,您的用户将被要求允许地理定位服务。所有事件将自动标记为当前位置。

如果您想控制何时请求位置服务的身份验证,您可以告诉Keen不要自动请求权限。您可以通过调用以下方法来实现:

Objective C

[KeenClient disableGeoLocationDefaultRequest];

Swift

KeenClient.disableGeoLocationDefaultRequest()
刷新当前位置

每次应用程序重新加载时,客户端都会自动向设备请求当前位置。为了节省电池电量,它不会再请求。您可以指示客户端再次向设备请求位置。只需要调用以下方法:

Objective C

[[KeenClient sharedClient] refreshCurrentLocation];

Swift

KeenClient.shared().refreshCurrentLocation()
手动设置位置

您还可以手动设置位置。以下是一个示例

Objective C

NSDictionary *event = [NSDictionary dictionaryWithObjectsAndKeys:@"first view", @"view_name", @"going to", @"action", nil];

KeenProperties *keenProperties = [[KeenProperties alloc] init];
CLLocation *location = [[CLLocation alloc] initWithLatitude:37.73 longitude:-122.47];
keenProperties.location = location;

[[KeenClient sharedClient] addEvent:event withKeenProperties:keenProperties toEventCollection:@"tab_views" error:nil];

Swift

let event = ["view_name": "first view Swift", "action": "going to"]
let keenProps: KeenProperties = KeenProperties()
let location: CLLocation = CLLocation(latitude: 37.73, longitude: -122.47)
keenProps.location = location

do {
    try KeenClient.shared().addEvent(event, with: keenProps, toEventCollection: "tab_views")
} catch _ {
}
在iOS 8+中请求位置授权

iOS 8引入了一种新的请求授权方法,在将位置自动附加到您的活动之前需要执行一些额外的步骤。

  1. 将以下一个或两个键添加到您的Info.plist文件中:NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription
  2. 调用适当的授权方法,以授权您的应用程序使用位置服务。自3.2.16版SDK以来,已添加了authorizeGeoLocationWhenInUseauthorizeGeoLocationAlways两个方法。authorizeGeoLocationWhenInUse默认启用,只要在Info.plist文件中指定了NSLocationWhenInUseUsageDescription,因此如果您选择使用“使用中”路径,则不需要调用它。authorizeGeoLocationAlways则必须显式调用。

示例

Objective C

[KeenClient authorizeGeoLocationAlways];
[KeenClient sharedClientWithProjectID:@"your_project_id" andWriteKey:@"your_write_key" andReadKey:@"your_read_key"];

Swift

KeenClient.authorizeGeoLocationAlways()
KeenClient.sharedClient(withProjectID: "your_project_id", andWriteKey: "your_write_key", andReadKey: "your_read_key");
将事件上传到Keen IO

将捕获的事件上传到Keen服务。这必须显式执行。我们建议在应用程序发送到后台时进行上传,但您可以选择任何您想要的时间(例如,如果应用程序的典型用户会话非常长)。上传器会生成自己的后台线程,这样主UI线程就不会被阻塞。

Objective C

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    UIBackgroundTaskIdentifier taskId = [application beginBackgroundTaskWithExpirationHandler:^(void) {
        NSLog(@"Background task is being expired.");
    }];

    [[KeenClient sharedClient] uploadWithFinishedBlock:^(void) {
        [application endBackgroundTask:taskId];
    }];
}

Swift

- (void)applicationDidEnterBackground:(UIApplication *)application
{
		let taskId : UIBackgroundTaskIdentifier = application.beginBackgroundTask(expirationHandler: {() -> Void in
				NSLog("Background task is being expired.")
		});
		KeenClient.shared().upload(finishedBlock: {() -> Void in
				application.endBackgroundTask(taskId)});
}

在此示例中,上传是在后台任务中完成的,以便即使在用户将您的应用程序发送到后台后,上传也可以继续。这里我们首先开始后台任务,开始上传,然后在上传完成后结束后台任务。

如果您想在应用程序执行期间定期调用上传,您可以通过在任何时间点在您的KeenClient实例上调用uploadWithFinishedBlock方法来实现。

Objective C

[[KeenClient sharedClient] uploadWithFinishedBlock:nil];

Swift

KeenClient.shared().upload(finishedBlock: nil)

重要提示:最好一次只发出一次上传。我们尽力减少在后台生成的上传线程数量,但如果您在一个紧密循环中多次调用上传,那么您将给自己带来问题。

限制上传重试次数

默认情况下,客户端将尝试上传给定事件3次 —— 之后它将是从本地队列中删除。您可以通过设置client.maxEventUploadAttempts值来更改此数字。

Objective C

// Set the max upload attempts to 10
[KeenClient sharedClient].maxEventUploadAttempts = 10;

Swift

// Set the max upload attempts to 10
KeenClient.shared().maxEventUploadAttempts = 10
附加组件

Keen IO可以通过解析数据或将它与其他数据集联合来丰富您发送的数据。这是通过“附加组件”的概念来完成的。

要激活插件,只需在事件中添加 "keen" 命名空间下的几个新属性即可。有关我们插件配置的详细文档,请参阅此处

例如,假设我们想启用IP到地域插件

Objective C

KeenClient *client = [KeenClient sharedClient];
client.globalPropertiesDictionary = @{@"keen":
                                         @{
                                           @"addons":@[
                                                       @{
                                                           @"name":@"keen:ip_to_geo",
                                                           @"input":@{
                                                                   @"ip":@"ip_address"
                                                           },
                                                           @"output":@"ip_geo_info"
                                                       }
                                                   ]
                                               },
                                           @"ip_address":[self getIPAddress:YES]
                                         };

Swift

KeenClient.shared().globalPropertiesDictionary = [
	"keen": [
		"addons": [
			[
				"name": "keen:ip_to_geo",
				"input": ["ip" : "ip_address"],
				"output": "ip_geo_info"
			]
		]
	],
	"ip_address": self.getIPAddress(true)
]

在这个例子中,我们添加了一个用于IP到地域信息的全局属性,该属性允许我们通过使用[self getIPAddress:YES]方法将设备的当前IP地址转换为设备的地域位置。

注意:[self getIPAddress:YES]是一个自定义方法,您需要自行实现,因为目前还没有内置的获取设备IP地址的方法。我们曾在这篇文章中提到的几个解决方案中有所成功。

查询

在您的应用程序内部收集事件数据后,您可能想要通过运行某些查询来分析它。您可以使用类KIOQueryKeenClient.runAsyncQueryKeenClient.runAsyncMultiAnalysisWithQueries方法来完成此操作。

根据要解决的问题的不同,您可以运行不同的查询。有关更详细的信息,请参阅我们的文档此处,但分析类型列表如下:

  • 计数 - 返回给定集合中找到的事件的总数。
  • 唯一计数 - 返回给定属性的唯一值的数量。
  • 最小值 - 返回给定属性的所有数值中的最小值。
  • 最大值 - 返回给定属性的所有数值中的最大值。
  • 求和 - 计算给定属性的所有数值的总和。
  • 平均值 - 计算给定属性的所有数值的平均值。
  • 中位数 - 计算给定属性的所有数值的中位数。
  • 百分位数 - 计算给定属性的所有数值的给定百分位数。
  • 选择唯一 - 返回给定属性找到的所有唯一值列表。

除此之外,您还可以运行

  • 多分析 - 在单个请求中运行多个分析。
  • 漏斗 - 跟踪一系列事件的完成情况。
限制查询尝试次数

Keen IO对查询有限制(更多信息请参阅此处。因此,考虑到应用程序的漫长的审批流程,一个查询语句中的小错误或更改事件属性集合可能会使您的应用程序达到查询限制,从而影响用户体验。

默认情况下,客户端只会尝试运行失败的查询10次。之后,它将在3600秒(1小时)后再次尝试。您可以设置client.maxQueryAttemptsclient.queryTTL的值来更改这些数字。

Objective C

[KeenClient sharedClient].maxQueryAttempts = 10;

// Change the default value to 10 minutes
[KeenClient sharedClient].queryTTL = 600;

Swift

KeenClient.shared().maxQueryAttempts = 10

// Change the default value to 10 minutes
KeenClient.shared().queryTTL = 600
示例

创建一个查询就像实例化一个KIOQuery对象那样简单

Objective-C

KIOQuery *countQuery = [[KIOQuery alloc] initWithQuery:@"count" andPropertiesDictionary:@{@"event_collection": @"collection", @"timeframe": @"this_14_days"}];

Swift

let countQuery: KIOQuery = KIOQuery(query:"count", andPropertiesDictionary:["event_collection": "collection", "timeframe": "this_14_days"])

让我们展示几个运行不同查询的例子。这两个函数KeenClient.runAsyncQueryKeenClient.runAsyncMultiAnalysisWithQueries的最后一个参数都是一个代码块。为了避免复制粘贴,我们将为所有查询使用相同的内容块。它将在查询成功时打印结果,或在查询失败时打印错误。

Objective-C

// Create block to run after query completes
void (^countQueryCompleted)(NSData *, NSURLResponse *, NSError *) = ^(NSData *responseData, NSURLResponse *returningResponse, NSError *error) {
    NSDictionary *responseDictionary = [NSJSONSerialization
                                        JSONObjectWithData:responseData
                                        options:kNilOptions
                                        error:nil];

    NSNumber *result = [responseDictionary objectForKey:@"result"];

    if(error || [responseDictionary objectForKey:@"error_code"]) {
        NSLog(@"Failure! 😞 \n\n error: %@\n\n response: %@", [error localizedDescription], [responseDictionary description]);
    } else {
        NSLog(@"Success! 😄 \n\n response: %@", [responseDictionary description]);
    }
};

Swift

// Create block to run after query completes
let countQueryCompleted = { (responseData: Data?, returningResponse: URLResponse?, error: Error?) -> Void in
    do {
        let responseDictionary: NSDictionary? = try JSONSerialization.jsonObject(with: responseData!, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary;

        if error != nil {
            self.resultTextView.text = "Error! 😞 \n\n error: \(error.localizedDescription)"
        } else if let errorCode = responseDictionary!.object(forKey: "error_code"),
            let errorMessage = responseDictionary!.object(forKey: "message") as? String {
            self.resultTextView.text = "Failure! 😞 \n\n error code: \(errorCode)\n\n message: \(errorMessage)"
        } else {
            let result: NSNumber = responseDictionary!.object(forKey: "result") as! NSNumber

            self.resultTextView.text = "Success! 😄 \n\n result: \(result) \n\n response: \(responseDictionary!.description)"
        }
    } catch let error as NSError {
        print("Error: \(error.localizedDescription)")
    }
}
计数示例

Objective-C

KIOQuery *countQuery = [[KIOQuery alloc] initWithQuery:@"count" andPropertiesDictionary:@{@"event_collection": @"collection", @"timeframe": @"this_14_days"}];

[[KeenClient sharedClient] runAsyncQuery:countQuery block:countQueryCompleted];

Swift

// KIOQuery object containing the query type and properties
let countQuery: KIOQuery = KIOQuery(query:"count", andPropertiesDictionary:["event_collection": "collection", "timeframe": "this_14_days"])

// Run the query
KeenClient.shared().runAsyncQuery(countQuery, block: countQueryCompleted)
计唯一示例

Objective-C

KIOQuery *countUniqueQuery = [[KIOQuery alloc] initWithQuery:@"count_unique" andPropertiesDictionary:@{@"event_collection": @"collection", @"target_property": @"key", @"timeframe": @"this_14_days"}];

[[KeenClient sharedClient] runAsyncQuery:countUniqueQuery block:countQueryCompleted];

Swift

let countUniqueQuery: KIOQuery = KIOQuery(query:"count_unique", andPropertiesDictionary:["event_collection": "collection", "target_property": "key", "timeframe": "this_14_days"])

KeenClient.shared().runAsyncQuery(countUniqueQuery, block: countQueryCompleted)
多分析示例

Objective-C

KIOQuery *countQuery = [[KIOQuery alloc] initWithQuery:@"count" andPropertiesDictionary:@{@"event_collection": @"collection", @"timeframe": @"this_14_days"}];
KIOQuery *countUniqueQuery = [[KIOQuery alloc] initWithQuery:@"count_unique" andPropertiesDictionary:@{@"event_collection": @"collection", @"target_property": @"key", @"timeframe": @"this_14_days"}];

// Optionally set a name for your queries, so it's easier to check the results
[countQuery setQueryName:@"count_query"];
[countUniqueQuery setQueryName:@"count_unique_query"];

[[KeenClient sharedClient] runAsyncMultiAnalysisWithQueries:@[countQuery, countUniqueQuery] block:countQueryCompleted];

Swift

let countQuery: KIOQuery = KIOQuery(query:"count", andPropertiesDictionary:["event_collection": "collection", "timeframe": "this_14_days"])
let countUniqueQuery: KIOQuery = KIOQuery(query:"count_unique", andPropertiesDictionary:["event_collection": "collection", "target_property": "key", "timeframe": "this_14_days"])

// Optionally set a name for your queries, so it's easier to check the results
countQuery.queryName = "count_query"
countUniqueQuery.queryName = "count_unique_query"

KeenClient.shared().runAsyncMultiAnalysis(withQueries: [countQuery, countUniqueQuery], block: countQueryCompleted);
漏斗示例

Objective-C

KIOQuery *funnelQuery = [[KIOQuery alloc] initWithQuery:@"funnel" andPropertiesDictionary:@{@"timeframe": @"this_14_days", @"steps": @[@{@"event_collection": @"user_signed_up",
            @"actor_property": @"user.id"},
          @{@"event_collection": @"user_completed_profile",
            @"actor_property": @"user.id"}]}];

[[KeenClient sharedClient] runAsyncQuery:funnelQuery block:countQueryCompleted];

Swift

let funnelQuery: KIOQuery = KIOQuery(query:"funnel", andPropertiesDictionary:["timeframe": "this_14_days", "steps": [["event_collection": "user_signed_up", "actor_property": "user.id"], ["event_collection": "user_completed_profile", "actor_property": "user.id"]]])

KeenClient.shared().runAsyncQuery(funnelQuery, block: countQueryCompleted)
调试

KeenClient执行大量日志记录,但默认情况下是关闭的。如果您想查看客户端使用产生的日志行,您可以通过简单的步骤启用日志记录。

Objective C

[KeenClient enableLogging];

Swift

KeenClient.enableLogging()

只需在您使用KeenClient之前将其放置在任何位置。一个很好的地方是在您的应用代理中。

要禁用日志记录,只需调用

Objective C

[KeenClient disableLogging];

Swift

KeenClient.disableLogging()

默认情况下,KeenClient将使用NSLog进行日志记录,并且只记录错误类别的消息。要显示更多消息,请使用setLogLevel:(KeenLogLevel)level启用更高的日志级别。

Objective C

// Enable verbose-level logging, which will display messages categorized
// as KeenLogLevelVerbose, KeenLogLevelInfo, KeenLogLevelWarning, and KeenLogLevelError
[KeenClient setLogLevel:KeenLogLevelVerbose];

Swift

// Enable verbose-level logging, which will display messages categorized
// as KeenLogLevelVerbose, KeenLogLevelInfo, KeenLogLevelWarning, and KeenLogLevelError
KeenClient.setLogLevel(.verbose)

在生产环境中调试问题常常需要远程收集日志,单纯的NSLog日志是不够的。KeenClient允许通过KeenLogSink协议和addLogSink:(id<KeenLogSink>)logSink与自定义日志收集器集成。只需实现KeenLogSink协议,在启用日志记录之前添加您的日志记录器。

Objective C

@interface ExampleLogger : NSObject  <KeenLogSink>
@end

@implementation ExampleLogger
- (void)logMessageWithLevel:(KeenLogLevel)msgLevel andMessage:(NSString*)message {
	WriteToMyCustomLogger(@"Logger: %@", message);
}

// Even after calling KeenClient removeLogSink, a sink will
// receive messages that had already been queued before the call
// to removeLogSink. This callback gives the logger an opportunity
// to do any processing or flushing it needs to do once it
// has actually been removed from the list of loggers.
- (void)onRemoved {
	NSLog(@"Logger removed.");
}
@end

...

// Add custom logger
[KeenClient addLogSink:[[ExampleLogger alloc] init]];
// Optionally, disable logging to NSLog
[KeenClient setIsNSLogEnabled:NO];
// Set desired log level. Only messages at or below
// this log level are sent to the logger
[KeenClient setLogLevel:KeenLogLevelInfo];
// Enable logging
[KeenClient enableLogging];

...

Swift

class ExampleLogger: KeenLogSink {
	public func logMessage(with msgLevel: KeenLogLevel, andMessage message: String!) {
		WriteToMyCustomLogger("Logger: %@", message)
	}

	// Even after calling KeenClient removeLogSink, a sink will
	// receive messages that had already been queued before the call
	// to removeLogSink. This callback gives the logger an opportunity
	// to do any processing or flushing it needs to do once it
	// has actually been removed from the list of loggers.
	func onRemoved() {
		NSLog("Logger removed.")
	}
}

...

// Add custom logger
KeenClient.addLogSink(ExampleLogger())
// Optionally, disable logging to NSLog
KeenClient.setIsNSLogEnabled(false);
// Set desired log level. Only messages at or below
// this log level are sent to the logger
KeenClient.setLogLevel(.verbose)
// Enable logging
KeenClient.enableLogging()

代理支持

KeenClient支持通过以下方法使用HTTP代理

- (void)setProxy:(NSString *)host port:(NSString *)port;

您可以轻松使用如下方式

Objective-C

[[KeenClient sharedClient] setProxy:@"secureproxy.example.com" port:@"2570"];

Swift

KeenClient.sharedClient().setProxy("secureproxy.example.com", port: "2570")

// Swift 3.0
KeenClient.shared().setProxy("secureproxy.example.com", port: "2570")

常见问题

问:当设备离线时会发生什么?当设备再次连接到Wi-Fi时会自动发送事件吗?

回答:我们的SDK处理离线数据收集,有内置的限制以防止数据堆积过多。我们也处理事件的重新提交,这样您就不必为此担心。

以下是它的操作方式。您指定事件应该在什么时候上传到Keen(例如,当应用处于后台时)。

如果发生这种情况时您的玩家离线,他们的数据将在设备上收集,并不会发送到Keen IO。但是,在下次他们触发发送事件的代码(例如,再次将应用置于后台)时,之前会话的所有数据也将发送(时间戳将反映事件实际发生的时刻)。

变更日志

您可以在这里找到变更日志。

待办事项

  • 原生iOS可视化。

问题 & 支持

如果您有任何问题、错误或建议,请通过GitHub问题报告。或者,随时在slack.keen.io与我们聊天。我们非常愿意听取您的反馈和想法!

参与

这是一个开源项目,我们热切欢迎社区的参与!请向我们提交pull请求和报告问题。