用途
为什么要收集位置数据?
移动应用程序只有在用户体验依赖于或因位置感知而得到改善的情况下才应收集用户的位置信息。一个根据用户位置提供特定零售商优惠券或优惠的应用程序有正当理由请求用户授予位置权限。
保护用户隐私和维护信任至关重要。OpenLocate 的目的是标准化并简化具有隐私合规性和以用户为中心的理由的移动应用程序收集位置数据的过程。
OpenLocate 不应仅用于收集位置数据以实现货币化目的。
以下是一些关于如何在请求移动应用程序用户权限时遵循最佳实践和注意事项的博客文章
- https://medium.com/product-breakdown/5-ways-to-ask-users-for-ios-permissions-a8e199cc83ad
- https://uxplanet.org/mobile-ux-design-the-right-ways-to-ask-users-for-permissions-6cdd9ab25c27
为什么这个项目有用?
OpenLocate 受到开发人员、非营利组织、行业团体和行业的支持,以下是一些原因
- 以一种不会对移动应用程序性能产生不利影响的节能方式收集位置数据并非易事。OpenLocate 使社区中的每个人都能从关于如何做好这件事的共享知识中受益。
- 创建位置收集的标准和最佳实践。
- 开发者可以完全了解 OpenLocate 位置采集的工作原理。
- 通过 OpenLocate 采集的位置数据完全由开发者控制。
我可以用位置数据做什么?
移动应用开发者可以使用通过 OpenLocate 采集的位置数据
- 利用用户位置的相关信息来增强他们的移动应用。
- 通过启用与第三方 API(如 Google Places 或 Foursquare 场所)的集成,接收设备访问过的兴趣点(POI)的数据
- 通过此处列出的集成将位置数据发送到 OpenLocate 的合作伙伴。
谁支持 OpenLocate?
OpenLocate 获得了移动应用开发者、非营利性商业组织、学术界和地理信息系统(GIS)、物流、营销等领域领先公司的支持。
要求
- XCode 9.0+
- iOS 8.0+
OpenLocate 的工作原理
OpenLocate 利用 iOS CoreLocation API 中的多项服务,提供及时和相关的位置更新。
访问监控
API 用于通过记录访问的进入和退出来确定用户频繁访问的位置。位置变化
API 用于记录用户位置中的重大变化。- 当应用变为活动状态时,会缓存位置更新。如果缓存的修复比 15 分钟旧,则在后台时获取新的位置更新。
- 最后,使用
后台检索
定期检索用户的当前位置。
考虑到位置更新是分散的,记录了位置更新发生的环境中的上下文.
为了最小化电池使用和网络流量,位置更新不会立即传输,而是将它们批量本地传输,在定义的时间间隔内传输。默认传输间隔为六小时,但这可以配置。成功传输后,设备不再存储位置更新。
安装
CocoaPods
如果您使用CocoaPods,请在Podfile中添加以下行并运行pod install
pod 'OpenLocate'
使用
初始化跟踪
- 将适当的位置使用描述添加到应用程序的
Info.plist
中。务必在适当的位置填写您的应用程序名称(或根据需要修改字符串)
Xcode 9:
<key>NSLocationAlwaysUsageDescription</key>
<string>[App_name] would like to access location.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>[App_name] would like to access location.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>[App_name] would like to access location.</string>
- 通过构建具有适当URL和头部的配置来配置SDK应发送数据的位置。将配置提供给
initialize
方法。确保您的UIApplicationDelegate
中的application:didFinishLaunchingWithOptions:
方法调用了initialize方法
Swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? ) -> Bool {
let uuid = UUID(uuidString: "<YOUR_UUID>")!
let token = "YOUR_TOKEN"
let url = URL(string: "https://your_endpoint_here.com")!
let headers = ["Authorization": "Bearer \(token)"]
let configuration = Configuration(url: url, headers: headers)
do {
try OpenLocate.shared.initialize(with: configuration)
} catch {
print(error)
}
return true
}
Objective-C
#import <OpenLocate/OpenLocate-Swift.h>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
Endpoint *endpoint = [[Endpoint alloc] initWithUrl:[NSURL URLWithString:@"<YOUR_URL>"]
headers:@{@"Authorization": @"Bearer <YOUR_TOKEN"}];
Configuration *config = [[Configuration alloc] initWithEndpoints:@[endpoint]];
[OpenLocate.shared initializeWith:config error:nil];
return YES;
}
配置多个端点
如果您想将数据发送到多个终端,可以通过创建多个Configuration.Endpoint
对象并将它们传递给Configuration
对象来实现。如果数据无法发送到任何特定的终端,数据将保存在本地并在后续传输中重新尝试。最多保留10天的数据。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? ) -> Bool {
let url1 = URL(string: "https://example-url.com/endpoint1")!
let headers1 = ["Authorization": "Bearer example_auth_token"]
let endpoint1 = Configuration.Endpoint(url: url1, headers: headers1)
let url2 = URL(string: "https://example-url2.com/endpoint2")!
let headers2 = ["Authorization": "Bearer example_auth_token]
let endpoint2 = Configuration.Endpoint(url: url2, headers: headers2)
let configuration = Configuration(endpoints: [endpoint1, endpoint2])
do {
try OpenLocate.shared.initialize(with: configuration)
} catch {
print(error)
}
}
配置“正在使用时”位置授权
默认情况下,OpenLocate将使用并提示CLLocationManager
的.authorizedAlways
授权状态。如果您想使用.authorizedWhenInUse
状态,可以在调用initialize
之前指定。请注意,与默认设置相比,您将接收显著较少的位置更新。示例
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? ) -> Bool {
let uuid = UUID(uuidString: "<YOUR_UUID>")!
let token = "YOUR_TOKEN"
let url = URL(string: "https://your_endpoint_here.com")!
let headers = ["Authorization": "Bearer \(token)"]
let configuration = Configuration(url: url, headers: headers, authorizationStatus: .authorizedWhenInUse)
do {
try OpenLocate.shared.initialize(with: configuration)
} catch {
print(error)
}
}
开始位置跟踪
要开始位置跟踪,请调用OpenLocate
上的startTracking
方法。通过调用shared
获取实例。
Swift
OpenLocate.shared.startTracking()
Objective-C
[OpenLocate.shared startTracking];
停止位置跟踪
要停止跟踪,请调用OpenLocate
上的stopTracking
方法。通过调用shared
获取实例。
Swift
OpenLocate.shared.stopTracking()
C 语言基础
[OpenLocate.shared stopTracking];
检查位置跟踪的当前状态
在 OpenLocate
上调用 isTrackingEnabled
方法。通过调用 shared
获取实例。
Swift
OpenLocate.shared.isTrackingEnabled()
C 语言基础
[OpenLocate.shared isTrackingEnabled];
配置位置数据传输间隔
默认情况下,位置数据传输间隔为六小时。如果您想更改此设置,只需在构建您的 Configuration
对象时传入不同的值。
Swift
let configuration = Configuration(endpoints: [endpoint], transmissionInterval: 3 * 60.0 * 60.0) // 3 Hours
C 语言基础
Configuration *config = [[Configuration alloc] initWithEndpoints:@[endpoint]
collectingFieldsConfiguration:[CollectingFieldsConfiguration default]
transmissionInterval:3 * 60.0 * 60.0 // 3 Hours
authorizationStatus:kCLAuthorizationStatusAuthorizedAlways];
通过后台获取获取额外位置更新
如果您想要更多的周期性位置更新,您可以启用后台获取,以允许应用程序周期性地轮询位置更新。
确保在您的项目中启用后台获取
模式。
此外,在您的AppDelegate
中实现以下方法。
Swift
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
OpenLocate.shared.performFetchWithCompletionHandler(completionHandler)
}
Objective-C
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
{
[OpenLocate.shared performFetchWithCompletionHandler:completionHandler];
}
使用用户位置查询第三方地点API
为了使用用户的当前位置,通过在OpenLocate上调用fetchCurrentLocation
方法来获取位置。通过调用shared
获取实例。使用SDK收集的字段发送到第三方API。
例如,获取用户位置
try OpenLocate.shared.fetchCurrentLocation { location, error in
if let location = location {
fetchNearbyPlaces(location: location)
} else {
debugPrint(error.localizedDescription)
}
}
例如,使用位置查询Google地点API
Google 地图 API: https://developers.google.com/places/web-service/search
func fetchNearbyPlaces(location: OpenLocateLocation, completion: @escaping GooglePlacesCompletionHandler) {
guard let coordinates = location.locationFields.coordinates else {
completion(nil, GooglePlacesError.locationNotFound)
return
}
let queryParams = [
"location": "\(coordinates.latitude),\(coordinates.longitude)",
"radius": "500",
"type": "restaurant",
"keyword": "south",
"key": "<YOUR GOOGLE PLACES API KEY>"
] as [String : Any]
Alamofire.request(
"https://maps.googleapis.com/maps/api/place/nearbysearch/json",
parameters: queryParams
)
.responseJSON { response in
debugPrint(response)
guard let json = response.result.value as? [String: Any],
let placesJson = json["places"] as? [Any], !placesJson.isEmpty else {
completion(nil, GooglePlacesError.placesNotFound)
return
}
var places = [GooglePlace]()
for placeJson in placesJson {
let place = (placeJson as? [String: Any])!
places.append(GooglePlace(json: place))
}
completion(places, nil)
}
}
同样,可以使用 OpenLocate SDK 来查询其他 API,如 Facebook 地点图或任何其他第三方地点 API。
- Facebook 地点 API - https://developers.facebook.com/docs/places/
Wolfram Data Drop 将用户位置数据连接到 Wolfram 云进行数据分析
使用Data Drop 是来自 Wolfram Research 的一项服务,它通过为计算、可视化、分析或其他数据处理操作设置数据的收集方式而简化了收集数据的过程。 数据存储 存储并附加数据的语义,同时使它能够通过 Wolfram 云和系统轻松访问。
进入数据存储后,您可以使用 Wolfram 语言创建以下类型的可视化,这些可视化是使用来自 Wolfram 数据存储库 的 UFO 目击位置数据生成的
有关更多信息,请参阅 数据存储快速参考
通过 Data Drop Web API 将用户位置数据发送到数据存储
func pushLocationToDataDrop(location: OpenLocateLocation) {
Alamofire.request(
"https://datadrop.wolframcloud.com/api/v1.0/Add?bin=<YOUR BIN ID>",
method: .post,
parameters: location.locationFields,
encoding: JSONEncoding.default
)
.responseJSON { response in
debugPrint(response)
}
}
请求收集的字段
字段 | 类型 | 描述 | 启用标志 |
---|---|---|---|
ad_id | 字符串 | 一个唯一的数字字母字符串,每个设备只有一个,仅用于广告。更多信息 请此处。 | CollectingFieldsConfiguration.shouldLogAdId |
ad_opt_out | 布尔值 | 一个布尔值,表示用户是否限制了广告跟踪。更多信息 请此处。 | CollectingFieldsConfiguration.shouldLogAdId |
id_type | 字符串 | 一个表示操作系统广告信息所属的字符串值。'idfa' 用于 iOS 设备 | CollectingFieldsConfiguration.shouldLogAdId |
latitude | 十进制 | 纬度,以度为单位。 | CollectingFieldsConfiguration.shouldLogLocation |
longitude | 十进制 | 经度,以度为单位。 | CollectingFieldsConfiguration.shouldLogLocation |
utc_timestamp | 长 | 确定此位置的时。 | CollectingFieldsConfiguration.shouldLogTimestamp |
utc_timestamp_received | 长 | 将此位置更新传递给客户端的时间。位置更新可能比确认时间晚得多。 | |
horizontal_accuracy | 浮点数 | 不确定半径,以米为单位,测量位置。 | CollectingFieldsConfiguration.shouldLogHorizontalAccuracy |
垂直精度 | 浮点数 | 高度值的准确性,以米为单位。 | CollectingFieldsConfiguration.shouldLogHorizontalAccuracy |
altitude | 浮点数 | 以米为单位的高度。 | CollectingFieldsConfiguration.shouldLogAltitude |
carrier_name | 字符串 | 表示运营商名称的字符串值 | CollectingFieldsConfiguration.shouldLogNetworkInfo |
location_context | 字符串 | 表示收集时位置状态的字符串值。可能的值 - unknown 、passive 、regular 、visit_entry 、visit_exit |
CollectingFieldsConfiguration.shouldLogLocation |
课程 | 浮点数 | 设备移动的方向。 | CollectingFieldsConfiguration.shouldLogDeviceCourse |
速度 | 浮点数 | 设备瞬间速度,单位为米/秒。 | CollectingFieldsConfiguration.shouldLogDeviceSpeed |
is_charging | 布尔值 | 一个布尔值,用来确定当确定位置时手机是否在充电。 | CollectingFieldsConfiguration.shouldLogDeviceCharging |
device_model | 字符串 | 表示设备型号的字符串值。 | CollectingFieldsConfiguration.shouldLogDeviceModel |
os_version | 字符串 | 表示操作系统版本的字符串值。 | CollectingFieldsConfiguration.shouldLogDeviceOsVersion |
location_permission | 字符串 | 表示用户接受的位置权限的字符串值。 | CollectingFieldsConfiguration.shouldLocationPermission |
示例请求体
这是一个由SDK发送的示例请求体。
{
"locations":
[
{
"ad_id": "12a451dd-3539-4092-b134-8cb0ef62ab8a",
"ad_opt_out": true,
"id_type": "idfa",
"latitude": "37.773972",
"longitude": "-122.431297",
"utc_timestamp": "1508356559",
"utc_timestamp_received": "1508356559",
"horizontal_accuracy": 12.323,
"vertical_accuracy": 5.3,
"altitude": 0.456,
"carrier_name": "T Mobile",
"location_context": "regular",
"course": 175.0,
"speed": 11.032,
"is_charging": true,
"device_model": "iPhone 7",
"os_version": "iOS 11.0.3"
},
{
"ad_id": "12a451dd-3539-4092-b134-8cb0ef62ab8a",
"ad_opt_out": true,
"id_type": "idfa",
"latitude": "37.773972",
"longitude": "-122.431297",
"utc_timestamp": "1508356559",
"utc_timestamp_received": "1508356581",
"horizontal_accuracy": 12.323,
"vertical_accuracy": 5.3,
"altitude": 0.456,
"carrier_name": "T Mobile",
"location_context": "regular",
"course": 175.0,
"speed": 11.032,
"is_charging": true,
"device_model": "iPhone 7",
"os_version": "iOS 11.0.3"
}
]
}
如果您希望SDK将数据发送到您的AWS s3环境,例如,请查看根据上述SDK请求设置Kinesis Firehose。
位置权限最佳实践
startTracking()
方法时,OpenLocate将为您处理请求位置权限。OpenLocate还负责在应用启动之间记住这个启动状态,因此您只需要调用一次startTracking()
。然而,您必须决定在应用中调用startTracking()
的最佳时间。以下是一些解释了可以采取的不同方法的文章。请确保选择适合您的应用需求的一种。
- https://medium.com/product-breakdown/5-ways-to-ask-users-for-ios-permissions-a8e199cc83ad
- https://uxplanet.org/mobile-ux-design-the-right-ways-to-ask-users-for-permissions-6cdd9ab25c27
使用OpenLocate提交应用
OpenLocate默认收集广告ID。如果保持原样,在应用程序提交过程中,请确保您披露正在收集广告ID及其原因。这需要在应用程序商店提交表单中的“广告标识符”部分下检查某些复选框;我们建议至少检查以下选项,但您可能想根据应用程序对广告ID的特定使用情况检查其他选项。
- 将此应用程序安装归因于以前投放的广告
- 将此应用程序中采取的操作归因于以前投放的广告
- 限制广告跟踪承诺:即将适当尊重限制广告跟踪设置(有关更多详细信息,请参阅应用程序提交表单)
通讯
- 如果您需要帮助,请在该 论坛上发帖,或在 Stack Overflow 上用“OpenLocate”标签一个问题。
- 如果您发现了一个错误,请打开一个问题。
- 如果您有功能请求,请打开一个问题。
- 如果您想贡献,请提交一个拉取请求。
许可
本项目的许可协议为MIT许可 - 详细信息请参阅LICENSE.md文件。