BAKit-iOS
基于位置的参与度
增强您的应用。赋予您的营销力量。
这不只是关于广告... 这是关于《个性化》
BoardActive 的平台连接品牌和消费者,使用基于位置的服务。我们的国际专利申请中的 Visualmatic™ 软件是一个强大的营销工具,允许品牌在任意位置设置虚拟界限,测量人流量,并在用户进入地理位置时通过个性化消息与他们互动……并且通过观察印象后用户去了哪里,有效地归因于广告活动的效率!
使用您的 BoardActive 账户创建地点(地理围栏区域)和消息(通知),向您的应用用户发送定制的消息。
一旦客户端建立了一个或多个地理围栏,BAKit SDK就会利用任何智能设备本地的位置监控功能,确定用户何时进入该地理围栏,并派发一份关于客户端组成的个性化通知。
配置所需
- 您已添加应用的Firebase项目。
- 一个BoardActive账户
创建Firebase项目
将Firebase核心和Firebase Messaging添加到您的应用中
要使用Firebase Cloud Messaging,您必须创建一个Firebase项目。
- Firebase iOS 快速入门 - 创建和了解Firebase项目的指南。
- 在iOS上设置Firebase Cloud Messaging客户端应用 - 如何处理Firebase Cloud Messaging(BoardActive发送推送通知的方式)。
- 请参考以下关于APNS的两篇文章,因为Firebase的文档有些过时。我们还将介绍如何在安装SDK的同时将推送通知添加到您的账户。
- 点击这里进入Firebase控制台
创建相关Firebase项目后,您可以下载GoogleService-Info.plist
文件,并在“CocoaPods”部分使用该文件。
接收您的BoardActive AppKey
- 请将Firebase项目中“服务账户”->“Firebase Admin SDK”下的Firebase服务账户中的Firebase密钥发送电子邮件至[email protected],他将回复您的BoardActive AppKey。
安装 BAKit SDK
- BoardActive for iOS 使用 Swift 4.0,并支持 iOS 10+。
- 需要 Xcode 9+ 进行构建,以支持 iPhone X 和 iOS 11。
- 当前,SDK 可通过 CocoaPods 或下载仓库并手动将 SDK 的源代码链接到您的项目中获得。
使用 CocoaPods
- 配置 CocoaPods
- 关闭/退出 Xcode。
- 在项目目录中的终端运行
$ pod init
。 - 打开您刚创建的
Podfile
文件,并添加以下 pods(参阅本节末尾的示例 Podfile)。pod 'BAKit-iOS'
pod 'Firebase/Core', '~> 5.0'
pod 'Firebase/Messaging'
- 在主项目目录中的终端运行
$ pod repo update
。 - 在主项目目录中的终端运行
$ pod install
,CocoaPods 创建工作区后,打开 .workspace 文件。 - 将之前在 创建 Firebase 项目 部分中提到的
GoogleService-Info.plist
文件导入您的项目中。
示例 Podfile
platform :ios, '10.0'
use_frameworks!
target :YourTargetName do
pod 'BAKit-iOS'
pod 'Firebase/Core', '~> 5.0'
pod 'Firebase/Messaging'
end
更新 Info.plist - 定位权限
请求位置权限需要在您的 Info.plist
文件中包含以下条目。每个条目都需要一个说明用户地理位置数据如何使用的 String
格式的关键词。
NSLocationAndWhenInUseUsageDescription
隐私 - 总是和在使用时位置的使用描述
NSLocationWhenInUseUsageDescription
隐私 - 在使用时使用描述
NSLocationAlwaysUsageDescription
隐私 - 总是位置使用描述
更新应用功能
在您的应用程序的主要目标中,您需要按照以下方式编辑它的 功能:
- 启用 后台模式。苹果提供文档解释了各种 后台模式,请参阅此处
- 勾选复选框 位置更新
- 勾选复选框 远程通知
- 启用 推送通知
使用 BAKit
AppDelegate
按照 将 Firebase Core 和 Firebase Messaging 添加到您的 App 部分中提供的苹果说明,请在您的 AppDelegate.swift
顶部添加以下代码
import BAKit
import Firebase
import UIKit
import UserNotifications
import Messages
import CoreLocation
import os.log
在声明 AppDelegate
类之前,会声明一个协议。符合该协议的类在示例应用中会收到通知
protocol NotificationDelegate: NSObject {
func appReceivedRemoteNotification(notification: [AnyHashable: Any])
func appReceivedRemoteNotificationInForeground(notification: [AnyHashable: Any])
}
在 AppDelegate
类声明的开始部分,声明以下变量和常量
public weak var notificationDelegate: NotificationDelegate?
private let authOptions = UNAuthorizationOptions(arrayLiteral: [.alert, .badge, .sound])
//Flags use to manage notification behaviour in various states
var isNotificationStatusActive = false
var isApplicationInBackground = false
var isAppActive = false
var isReceviedEventUpdated = false
在配置 Firebase 并声明 AppDelegate
对 Firebase 的 MessagingDelegate
的遵从性之后,将 BoardActive AppId 和 AppKey 存储到 BoardActive.client.userDefaults
,如下所示
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
Messaging.messaging().delegate = self
UNUserNotificationCenter.current().delegate = self
// AppId is of type Int
BoardActive.client.userDefaults?.set(<#AppId#>, forKey: "AppId")
// AppKey is of type String
BoardActive.client.userDefaults?.set(<#AppKey#>, forKey: "AppKey")
return true
}
/**
Update the flag values when application enters in background
*/
func applicationDidEnterBackground(_ application: UIApplication) {
isApplicationInBackground = true
isAppActive = false
}
将以下内容添加到您的 AppDelegate
类的结束花括号下方。
extension AppDelegate {
/**
Call this function after having received your FCM and APNS tokens.
Additionally, you must have set your AppId and AppKey using the
BoardActive class's userDefaults.
*/
func setupSDK() {
let operationQueue = OperationQueue()
let registerDeviceOperation = BlockOperation.init {
BoardActive.client.registerDevice { (parsedJSON, err) in
guard err == nil, let parsedJSON = parsedJSON else {
fatalError()
}
BoardActive.client.userDefaults?.set(true, forKey: String.ConfigKeys.DeviceRegistered)
BoardActive.client.userDefaults?.synchronize()
}
}
let requestNotificationsOperation = BlockOperation.init {
self.requestNotifications()
}
let monitorLocationOperation = BlockOperation.init {
DispatchQueue.main.async {
BoardActive.client.monitorLocation()
}
}
monitorLocationOperation.addDependency(requestNotificationsOperation)
requestNotificationsOperation.addDependency(registerDeviceOperation)
operationQueue.addOperation(registerDeviceOperation)
operationQueue.addOperation(requestNotificationsOperation)
operationQueue.addOperation(monitorLocationOperation)
}
public func requestNotifications() {
UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { granted, error in
if BoardActive.client.userDefaults?.object(forKey: "dateNotificationRequested") == nil {
BoardActive.client.userDefaults?.set(Date().iso8601, forKey: "dateNotificationRequested")
BoardActive.client.userDefaults?.synchronize()
}
BoardActive.client.updatePermissionStates()
guard error == nil, granted else {
// Handle error and possibility of user not granting permission
return
}
}
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
在遵循 Firebase 的 MessagingDelegate
且接收 FCM Token 的扩展中,将此 Token 存储在 BAKit 的 userDefaults
中。
// MARK: - MessagingDelegate
extension AppDelegate: MessagingDelegate {
/**
This function will be called once a token is available, or has been refreshed. Typically it will be called once per app start, but may be called more often, if a token is invalidated or updated. In this method, you should perform operations such as:
* Uploading the FCM token to your application server, so targeted notifications can be sent.
* Subscribing to any topics.
*/
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
BoardActive.client.userDefaults?.set(fcmToken, forKey: "deviceToken")
BoardActive.client.userDefaults?.synchronize()
}
}
为了确保您已实现必要的 UNUserNotificationCenterDelegate
函数,提供以下代码片段作为参考。
// MARK: - UNUserNotificationCenterDelegate
extension AppDelegate: UNUserNotificationCenterDelegate {
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let deviceTokenString = deviceToken.reduce("", { $0 + String(format: "%02X", $1) })
os_log("\n[AppDelegate] didRegisterForRemoteNotificationsWithDeviceToken :: APNs TOKEN: %s \n", deviceTokenString)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
// Handle APNS token registration error
os_log("\n[AppDelegate] didFailToRegisterForRemoteNotificationsWithError :: APNs TOKEN FAIL :: %s \n", error.localizedDescription)
}
/**
Called when app in foreground or background as opposed to `application(_:didReceiveRemoteNotification:)` which is only called in the foreground.
(Source: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application)
*/
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
handleNotification(application: application, userInfo: userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo as! [String: Any]
if userInfo["notificationId"] as? String == "0000001" {
handleNotification(application: UIApplication.shared, userInfo: userInfo)
}
NotificationCenter.default.post(name: NSNotification.Name("Refresh HomeViewController Tableview"), object: nil, userInfo: userInfo)
completionHandler(UNNotificationPresentationOptions.init(arrayLiteral: [.badge, .sound, .alert]))
}
/**
This delegate method will call when user opens the notification from the notification center.
*/
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
guard (response.actionIdentifier == UNNotificationDefaultActionIdentifier) || (response.actionIdentifier == UNNotificationDismissActionIdentifier) else {
return
}
let userInfo = response.notification.request.content.userInfo as! [String: Any]
if isApplicationInBackground && !isNotificationStatusActive {
isNotificationStatusActive = false
isApplicationInBackground = false
if let _ = userInfo["aps"] as? [String: Any], let messageId = userInfo["baMessageId"] as? String, let firebaseNotificationId = userInfo["gcm.message_id"] as? String, let notificationId = userInfo["baNotificationId"] as? String {
if (isReceviedEventUpdated) {
self.notificationDelegate?.appReceivedRemoteNotificationInForeground(notification: userInfo)
} else {
self.notificationDelegate?.appReceivedRemoteNotification(notification: userInfo)
}
}
} else if isAppActive && !isNotificationStatusActive {
if (isReceviedEventUpdated) {
self.notificationDelegate?.appReceivedRemoteNotificationInForeground(notification: userInfo)
} else {
self.notificationDelegate?.appReceivedRemoteNotification(notification: userInfo)
}
} else {
isNotificationStatusActive = true
isApplicationInBackground = false
NotificationCenter.default.post(name: Notification.Name("display"), object: nil)
}
completionHandler()
}
/**
Use `userInfo` for validating said instance, and calls `createEvent`, capturing the current application state.
- Parameter userInfo: A dictionary that contains information related to the remote notification, potentially including a badge number for the app icon, an alert sound, an alert message to display to the user, a notification identifier, and custom data. The provider originates it as a JSON-defined dictionary that iOS converts to an `NSDictionary` object; the dictionary may contain only property-list objects plus `NSNull`. For more information about the contents of the remote notification dictionary, see Generating a Remote Notification.
*/
public func handleNotification(application: UIApplication, userInfo: [AnyHashable: Any]) {
NotificationCenter.default.post(name: NSNotification.Name("Refresh HomeViewController Tableview"), object: nil, userInfo: userInfo)
if let _ = userInfo["aps"] as? [String: Any], let messageId = userInfo["baMessageId"] as? String, let firebaseNotificationId = userInfo["gcm.message_id"] as? String, let notificationId = userInfo["baNotificationId"] as? String {
switch application.applicationState {
case .active:
BoardActive.client.postEvent(name: String.Received, messageId: messageId, firebaseNotificationId: firebaseNotificationId, notificationId: notificationId)
break
case .background:
BoardActive.client.postEvent(name: String.Received, messageId: messageId, firebaseNotificationId: firebaseNotificationId, notificationId: notificationId)
break
case .inactive:
BoardActive.client.postEvent(name: String.Opened, messageId: messageId, firebaseNotificationId: firebaseNotificationId, notificationId: notificationId)
break
default:
break
}
}
}
}
添加以下代码以在应用终止时监测重要位置更新。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
if launchOptions?[UIApplicationLaunchOptionsKey.location] != nil {
let locationManager = CLLocationManager()
if CLLocationManager.locationServicesEnabled() {
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.delegate = self
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.allowsBackgroundLocationUpdates = true
locationManager.startMonitoringSignificantLocationChanges()
}
}
NotificationCenter.default.addObserver(BoardActive.client, selector: #selector(BoardActive.client.updatePermissionStates), name: Notification.Name("Update user permission states"), object: nil)
return true
}
func applicationDidBecomeActive(_ application: UIApplication) {
application.applicationIconBadgeNumber = 0
if (isApplicationInBackground) {
NotificationCenter.default.post(name: Notification.Name("Update user permission states"), object: nil)
}
isAppActive = true
}
extension AppDelegate: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let locValue: CLLocationCoordinate2D = manager.location?.coordinate else { return }
BoardActive.client.postLocation(location: manager.location!)
}
}
在您想启动位置和通知服务的控制器中,添加以下方法。
(UIApplication.shared.delegate! as! AppDelegate).setupSDK()
下载示例应用源代码
在代码仓库的 "Example" 目录下包含了一个示例应用。
寻求帮助
我们的团队愿意提供帮助。请联系我们
- 电话:(678) 383-2200
- 电子邮件我们 [email protected]
- 在线支持 网站