├── help └── html │ ├── css │ ├── scss │ │ ├── style.scss │ │ ├── _index.scss │ │ ├── _variables.scss │ │ ├── _xcode.scss │ │ ├── _print.scss │ │ ├── _object.scss │ │ └── _layout.scss │ └── style.css │ ├── img │ ├── disclosure.png │ ├── disclosure_open.png │ ├── title_background.png │ ├── library_background.png │ └── button_bar_background.png │ ├── js │ └── script.js │ ├── index.html │ ├── hierarchy.html │ ├── Constants │ ├── BCLEventType.html │ └── BCLBeaconCtrlPushEnvironment.html │ └── Classes │ └── BCLConfiguration.html ├── .gitignore ├── Podfile ├── BeaconCtrl ├── BCLBeaconControl-Bridging-Header.h ├── CLBeacon+BeaconCtrl.h ├── Private │ ├── BCLUtils.h │ ├── BCLCouponActionHandler.h │ ├── BCLURLActionHandler.h │ ├── UIWindow+BCLVisibleViewController.h │ ├── NSObject+BCLAdditions.h │ ├── BCLActionHandler.h │ ├── BCLActionHandlerFactory.h │ ├── BCLCouponActionHandler.m │ ├── NSHTTPURLResponse+BCLHTTPCodes.h │ ├── BCLObservedBeaconsPicker.h │ ├── NSUserDefaults+BCLiCloud.h │ ├── BCLActionEventScheduler.h │ ├── BCLActionEvent.h │ ├── BCLUtils.m │ ├── NSHTTPURLResponse+BCLHTTPCodes.m │ ├── BCLBackend.h │ ├── BCLAbstractBackend.h │ ├── NSObject+BCLAdditions.m │ ├── UIWindow+BCLVisibleViewController.m │ ├── BCLActionHandlerFactory.m │ ├── BCLActionEvent.m │ ├── BCLAdminBackend.h │ ├── NSUserDefaults+BCLiCloud.m │ ├── BCLURLActionHandler.m │ ├── BCLActionEventScheduler.m │ ├── BCLAbstractBackend.m │ └── BCLObservedBeaconsPicker.m ├── BCLEncodableObject.h ├── BeaconCtrl-Prefix.pch ├── UIColor+Hex.h ├── Conditions │ ├── BCLConditionEvent.h │ └── BCLConditionEvent.m ├── BCLExtension.h ├── BCLTypes.h ├── SAMCache+BeaconCtrl.h ├── BCLLocation.h ├── BCLCondition.h ├── BCLTrigger.h ├── CLBeacon+BeaconCtrl.m ├── BCLBeaconRangingBatch.h ├── BCLAction.m ├── UIColor+Hex.m ├── BCLEncodableObject.m ├── BCLAction.h ├── BCLLocation.m ├── SAMCache+BeaconCtrl.m ├── BCLConfiguration.h ├── BCLKontaktIOBeaconConfigManager.h ├── BCLZone.h ├── BCLTrigger.m ├── BCLEventScheduler.h ├── BCLBeaconRangingBatch.m ├── BCLZone.m ├── BCLBeaconCtrlDelegate.h ├── BCLBeaconCtrlAdmin.m ├── BCLConfiguration.m ├── BCLBeacon.h ├── BCLBeaconCtrlAdmin.h ├── BCLBeaconCtrl.h ├── BCLEventScheduler.m └── BCLKontaktIOBeaconConfigManager.m ├── BeaconCtrl.podspec ├── LICENSE.txt └── README.md /help/html/css/scss/style.scss: -------------------------------------------------------------------------------- 1 | @import "variables", "normalize", "layout", "index", "object", "print", "xcode"; 2 | -------------------------------------------------------------------------------- /help/html/img/disclosure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upnext/BeaconControl_iOS_SDK/HEAD/help/html/img/disclosure.png -------------------------------------------------------------------------------- /help/html/img/disclosure_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upnext/BeaconControl_iOS_SDK/HEAD/help/html/img/disclosure_open.png -------------------------------------------------------------------------------- /help/html/img/title_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upnext/BeaconControl_iOS_SDK/HEAD/help/html/img/title_background.png -------------------------------------------------------------------------------- /help/html/img/library_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upnext/BeaconControl_iOS_SDK/HEAD/help/html/img/library_background.png -------------------------------------------------------------------------------- /help/html/img/button_bar_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upnext/BeaconControl_iOS_SDK/HEAD/help/html/img/button_bar_background.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | .idea 3 | 4 | *.xcuserstate 5 | xcuserdata/ 6 | *.xccheckout 7 | BeaconCtrl.xcodeproj/project.xcworkspace/ 8 | 9 | *.swp 10 | *~.nib 11 | -------------------------------------------------------------------------------- /help/html/css/scss/_index.scss: -------------------------------------------------------------------------------- 1 | .index-container { 2 | display: flex; 3 | flex-direction: row; 4 | flex-wrap: wrap; 5 | 6 | @media (max-width: $mobile-max-width) { 7 | flex-direction: column; 8 | } 9 | 10 | .index-column { 11 | flex: 1 1 33%; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | 3 | platform :ios, '7.0' 4 | 5 | xcodeproj 'BeaconCtrl.xcodeproj' 6 | 7 | target "BeaconCtrl", :exclusive => true do 8 | link_with "BeaconCtrl" 9 | pod "UNNetworking", :git => "https://github.com/upnext/UNNetworking.git", :branch => :master 10 | pod "KontaktSDK-OLD” 11 | pod "SAMCache" 12 | end 13 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLBeaconControl-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLBeaconControl-Bridging-Header.h 3 | // Pods 4 | // 5 | // Created by Adrian Chojnacki on 14/12/16. 6 | // 7 | // 8 | 9 | #ifndef BCLBeaconControl_Bridging_Header_h 10 | #define BCLBeaconControl_Bridging_Header_h 11 | 12 | #import "BCLBeaconCtrl.h" 13 | 14 | #endif /* BCLBeaconControl_Bridging_Header_h */ 15 | -------------------------------------------------------------------------------- /help/html/css/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | $body-font: -apple-system-font, "Helvetica Neue", Helvetica, sans-serif; 2 | $code-font: "Source Code Pro", Monaco, Menlo, Consolas, monospace; 3 | 4 | $body-background: #f2f2f2; 5 | $content-background: #fff; 6 | $content-border: #e9e9e9; 7 | $tint-color: #08c; 8 | $object-background: #f9f9f9; 9 | $object-border: #e9e9e9; 10 | 11 | $mobile-max-width: 650px; 12 | -------------------------------------------------------------------------------- /BeaconCtrl/CLBeacon+BeaconCtrl.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD 3-Clause License found in the 6 | // LICENSE.txt file in the root directory of this source tree. 7 | // 8 | 9 | #import 10 | 11 | @interface CLBeacon (BeaconCtrl) 12 | 13 | - (NSString *) bcl_identifier; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLUtils.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NSArray* AllocNotRetainedArray(); 15 | NSSet* AllocNotRetainedSet(); -------------------------------------------------------------------------------- /help/html/css/scss/_xcode.scss: -------------------------------------------------------------------------------- 1 | .xcode { 2 | header, aside { 3 | display: none; 4 | } 5 | 6 | .container { 7 | padding: 0; 8 | } 9 | 10 | article { 11 | margin-top: 0; 12 | 13 | #content { 14 | border: 0; 15 | margin: 0; 16 | } 17 | } 18 | 19 | .method-info { 20 | &, .section-method.hide & { 21 | max-height: auto; 22 | overflow: visible; 23 | 24 | &.hiding { 25 | display: block; 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLCouponActionHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLCouponActionHandler.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "BCLURLActionHandler.h" 13 | 14 | @interface BCLCouponActionHandler : BCLURLActionHandler 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLEncodableObject.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLEncodableObject.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import "UNCoding.h" 14 | 15 | @interface BCLEncodableObject : NSObject 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /BeaconCtrl/BeaconCtrl-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 7 | // All rights reserved. 8 | // 9 | // This source code is licensed under the BSD 3-Clause License found in the 10 | // LICENSE.txt file in the root directory of this source tree. 11 | // 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #endif 16 | -------------------------------------------------------------------------------- /BeaconCtrl/UIColor+Hex.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+Hex.h 3 | // Pods 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | @interface UIColor (Hex) 15 | 16 | + (UIColor *)colorFromHexString:(NSString *)hexString; 17 | - (NSString *)hexString; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLURLActionHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLURLActionHandler.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import "BCLActionHandler.h" 14 | 15 | @interface BCLURLActionHandler : NSObject 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/UIWindow+BCLVisibleViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIWindow+BCLVisibleViewController.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | @interface UIWindow (BCLVisibleViewController) 15 | 16 | - (UIViewController *)bcl_visibleViewController; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/NSObject+BCLAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+BCLAdditions.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | @interface NSObject (BCLAdditions) 15 | 16 | - (id) bcl_performSelector:(SEL)selector withParameters:(NSArray *)parameters; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLActionHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLActionHandler.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import "BCLAction.h" 14 | 15 | @protocol BCLActionHandler 16 | 17 | + (NSString *)handledActionTypeName; 18 | 19 | - (void)handleAction:(BCLAction *)action; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /BeaconCtrl/Conditions/BCLConditionEvent.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLConditionEvent.h 3 | // 4 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 5 | // All rights reserved. 6 | // 7 | // This source code is licensed under the BSD 3-Clause License found in the 8 | // LICENSE.txt file in the root directory of this source tree. 9 | // 10 | 11 | #import 12 | #import "BCLCondition.h" 13 | #import "UNCoding.h" 14 | 15 | @interface BCLConditionEvent : NSObject 16 | 17 | @property (nonatomic, strong) NSString *eventType; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLActionHandlerFactory.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLActionHandlerFactory.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import "BCLActionHandler.h" 14 | 15 | @interface BCLActionHandlerFactory : NSObject 16 | 17 | - (id)actionHandlerForActionTypeName:(NSString *)actionTypeName; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLCouponActionHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // BCLCouponActionHandler.m 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "BCLCouponActionHandler.h" 13 | 14 | @interface BCLCouponActionHandler () 15 | 16 | @end 17 | 18 | @implementation BCLCouponActionHandler 19 | 20 | + (NSString *)handledActionTypeName 21 | { 22 | return @"coupon"; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLExtension.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLExtension.h 3 | // 4 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 5 | // All rights reserved. 6 | // 7 | // This source code is licensed under the BSD 3-Clause License found in the 8 | // LICENSE.txt file in the root directory of this source tree. 9 | // 10 | 11 | #import 12 | #import "BCLTypes.h" 13 | 14 | @class BCLBeacon; 15 | 16 | @protocol BCLExtension 17 | @required 18 | 19 | + (NSString *) bcl_extensionName; 20 | - (instancetype) initWithParameters:(NSDictionary *)parameters; 21 | 22 | - (void) event:(BCLEventType)eventType forBeacon:(BCLBeacon *)beacon; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /help/html/css/scss/_print.scss: -------------------------------------------------------------------------------- 1 | @media print { 2 | body { 3 | background: #fff; 4 | padding: 8px; 5 | } 6 | 7 | header { 8 | position: static; 9 | background: #fff; 10 | color: #000; 11 | } 12 | 13 | aside { 14 | display: none; 15 | } 16 | 17 | .container { 18 | max-width: none; 19 | padding: 0; 20 | } 21 | 22 | article { 23 | margin-top: 0; 24 | 25 | #content { 26 | border: 0; 27 | background: #fff; 28 | padding: 15px 0 0 0; 29 | 30 | .title { 31 | margin-top: 0; 32 | padding-top: 0; 33 | } 34 | } 35 | } 36 | 37 | .method-info { 38 | &, & .pointy-thing { 39 | background: #fff; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLTypes.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLTypes.h 3 | // 4 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 5 | // All rights reserved. 6 | // 7 | // This source code is licensed under the BSD 3-Clause License found in the 8 | // LICENSE.txt file in the root directory of this source tree. 9 | // 10 | 11 | #import 12 | 13 | typedef NS_ENUM(NSInteger, BCLEventType) { 14 | BCLEventTypeUnknown = 0, 15 | BCLEventTypeEnter = 1, 16 | BCLEventTypeLeave = 2, 17 | BCLEventTypeRangeImmediate = 3, 18 | BCLEventTypeRangeNear = 4, 19 | BCLEventTypeRangeFar = 5, 20 | BCLEventTypeDwellTime = 6, 21 | BCLEventTypeTimer = 7 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /BeaconCtrl/SAMCache+BeaconCtrl.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD 3-Clause License found in the 6 | // LICENSE.txt file in the root directory of this source tree. 7 | // 8 | 9 | #import "SAMCache.h" 10 | 11 | #define BLECacheActionIdentifierFormat(action,beacon) \ 12 | [NSString stringWithFormat:@"beacon.%@.action.%@.type.%@", beacon.identifier, action.uniqueIdentifier, action.type] 13 | 14 | @interface SAMCache (BeaconCtrl) 15 | 16 | + (SAMCache *) bcl_monitoredProximityCache; 17 | + (SAMCache *) bcl_lastActionEventsCache; 18 | + (SAMCache *)bcl_actionEventsCache; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/NSHTTPURLResponse+BCLHTTPCodes.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSHTTPURLResponse+BCLHTTPCodes.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | @interface NSHTTPURLResponse (BCLHTTPCodes) 15 | 16 | @property (readonly) BOOL isInformational; 17 | @property (readonly) BOOL isSuccess; 18 | @property (readonly) BOOL isRedirect; 19 | @property (readonly) BOOL isClientError; 20 | @property (readonly) BOOL isServerError; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLLocation.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLLocation.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import 14 | 15 | #import 16 | 17 | @interface BCLLocation : NSObject 18 | 19 | @property (nonatomic, strong, readonly) CLLocation *location; 20 | @property (nonatomic, strong, readonly) NSNumber *floor; 21 | 22 | - (instancetype)initWithLocation:(CLLocation *)location floor:(NSNumber *)floor; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLObservedBeaconsPicker.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLObservedBeaconsPicker.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import "BCLLocation.h" 14 | #import "BCLEncodableObject.h" 15 | 16 | @interface BCLObservedBeaconsPicker : BCLEncodableObject 17 | 18 | - (instancetype)initWithBeacons:(NSSet *)beacons andZones:(NSSet *)zones; 19 | 20 | - (NSSet *)observedBeaconsWithLocation:(BCLLocation *)location beaconsDidChange:(BOOL *)didChange; 21 | - (NSSet *)observedZones:(BOOL *)didChange; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLCondition.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLCondition.h 3 | // SBB 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import "BCLTypes.h" 14 | 15 | @class BCLBeacon; 16 | @class BCLZone; 17 | 18 | @protocol BCLCondition 19 | 20 | @required 21 | 22 | + (NSString *) bcl_conditionType; 23 | - (instancetype) initWithParameters:(NSDictionary *)parameters; 24 | 25 | - (BOOL) evaluateCondition:(BCLEventType)eventType forBeacon:(BCLBeacon *)beacon; 26 | - (BOOL)evaluateCondition:(BCLEventType)eventType forZone:(BCLZone *)zone; 27 | 28 | @end -------------------------------------------------------------------------------- /BeaconCtrl/Private/NSUserDefaults+BCLiCloud.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSUserDefaults+BCLiCloud.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | @interface NSUserDefaults (BCLiCloud) 15 | 16 | -(void)setValue:(id)value forKey:(NSString *)key iCloudSync:(BOOL)sync; 17 | -(void)setObject:(id)value forKey:(NSString *)key iCloudSync:(BOOL)sync; 18 | 19 | -(id)valueForKey:(NSString *)key iCloudSync:(BOOL)sync; 20 | -(id)objectForKey:(NSString *)key iCloudSync:(BOOL)sync; 21 | 22 | -(BOOL)synchronizeWithiCloud; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLActionEventScheduler.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLActionEventScheduler.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import "BCLTypes.h" 14 | 15 | extern NSString * const BCLActionEventSchedulerBackgroundTaskIdentifier; 16 | 17 | @class BCLActionEvent, BCLBackend; 18 | 19 | @interface BCLActionEventScheduler : NSObject 20 | 21 | - (instancetype) initWithBackend:(BCLBackend *)backend; 22 | 23 | - (void)sendActionEvents:(void (^)(NSError *error))completion; 24 | 25 | - (void) storeEvent:(BCLActionEvent *)event; 26 | 27 | - (BCLActionEvent *) lastStoredEventWithType:(BCLEventType)type; 28 | 29 | + (void)clearCache; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLActionEvent.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLEvent.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import 14 | #import "BCLTypes.h" 15 | 16 | @interface BCLActionEvent : NSObject 17 | 18 | @property (readonly) NSString *identifier; 19 | @property (assign) NSTimeInterval timestamp; 20 | @property (strong) NSString *beaconIdentifier; 21 | @property (strong) NSString *zoneIdentifier; 22 | @property (strong) NSString *actionIdentifier; 23 | @property (strong) NSString *actionName; 24 | @property (nonatomic) BCLEventType eventType; 25 | 26 | - (NSString *) eventTypeName; 27 | 28 | @end 29 | 30 | 31 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLTrigger.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLTrigger.h 3 | // 4 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 5 | // All rights reserved. 6 | // 7 | // This source code is licensed under the BSD 3-Clause License found in the 8 | // LICENSE.txt file in the root directory of this source tree. 9 | // 10 | 11 | #import 12 | #import "BCLBeacon.h" 13 | #import "BCLZone.h" 14 | #import "BCLCondition.h" 15 | #import "BCLAction.h" 16 | #import "BCLEncodableObject.h" 17 | 18 | @protocol BCLBeaconCtrlDelegate; 19 | 20 | @interface BCLTrigger : BCLEncodableObject 21 | 22 | @property (strong, nonatomic) BCLBeacon *beacon; //FIXME: why strong ? 23 | @property (strong, nonatomic) BCLZone *zone; //FIXME: why strong ? 24 | @property (strong, nonatomic) NSArray *conditions; 25 | @property (strong, nonatomic) NSArray *actions; 26 | 27 | - (void)updatePropertiesFromDictionary:(NSDictionary *)dictionary; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /BeaconCtrl.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "BeaconCtrl" 3 | s.version = "0.0.1" 4 | s.summary = "Low Energy Bluetooth Framework" 5 | s.authors = { "Upnext Ltd." => "http://www.up-next.com"} 6 | s.homepage = "http://www.up-next.com/beacon" 7 | s.source = { :git => "ssh://git@stash.up-next.com:7999/bp/bp-ios-sdk.git", :tag => "v#{s.version}" } 8 | s.license = 'LICENSE*.*' 9 | 10 | s.platform = :ios, '7.0' 11 | s.ios.deployment_target = '7.0' 12 | 13 | s.source_files = "BeaconCtrl", "BeaconCtrl/**/*.{h,m}" 14 | s.private_header_files = "BeaconCtrl/Private/*.h" 15 | 16 | s.frameworks = 'Foundation', 'CoreFoundation', 'CoreLocation', 'SystemConfiguration', 'MobileCoreServices', 'UIKit' 17 | s.weak_frameworks = 'Twitter', 'Social', 'Accounts' 18 | 19 | s.dependency "SAMCache" 20 | s.dependency "UNNetworking" 21 | s.dependency "KontaktSDK-OLD" 22 | 23 | s.requires_arc = true 24 | end 25 | -------------------------------------------------------------------------------- /BeaconCtrl/CLBeacon+BeaconCtrl.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD 3-Clause License found in the 6 | // LICENSE.txt file in the root directory of this source tree. 7 | // 8 | 9 | #import "CLBeacon+BeaconCtrl.h" 10 | 11 | @implementation CLBeacon (BeaconCtrl) 12 | 13 | - (NSString *) bcl_identifier 14 | { 15 | @synchronized(self) { 16 | // Build identifier 17 | 18 | NSMutableArray *arr = [NSMutableArray arrayWithCapacity:3]; 19 | if (self.proximityUUID) { 20 | [arr addObject:self.proximityUUID.UUIDString]; 21 | } 22 | 23 | if (self.major) { 24 | [arr addObject:self.major]; 25 | } 26 | 27 | if (self.minor) { 28 | [arr addObject:self.minor]; 29 | } 30 | 31 | return [arr componentsJoinedByString:@"+"]; 32 | } 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLBeaconRangingBatch.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD 3-Clause License found in the 6 | // LICENSE.txt file in the root directory of this source tree. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @class BCLBeaconRangingBatch; 13 | 14 | @protocol BCLBeaconRangingBatchDelegate 15 | 16 | - (void) processBeaconBatch:(BCLBeaconRangingBatch *)batch beacons:(NSArray *)rangedBeacons; 17 | @end 18 | 19 | @interface BCLBeaconRangingBatch : NSObject 20 | 21 | @property (strong) NSMutableDictionary *batch; 22 | 23 | @property (strong, readonly) NSArray *regions; 24 | 25 | @property (weak) id delegate; 26 | 27 | - (instancetype) initWithDelegate:(id )delegate; 28 | 29 | - (void) add:(NSArray *)rangedBeacons forRegion:(CLBeaconRegion *)region; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLUtils.m: -------------------------------------------------------------------------------- 1 | // 2 | // BCLUtils.m 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "BCLUtils.h" 13 | 14 | NSArray* AllocNotRetainedArray() { 15 | CFArrayRef arrayRef = NULL; 16 | CFArrayCallBacks notRetainedCallbacks = kCFTypeArrayCallBacks; 17 | notRetainedCallbacks.retain = NULL; 18 | notRetainedCallbacks.release = NULL; 19 | arrayRef = CFArrayCreate(kCFAllocatorDefault, 0, 0, ¬RetainedCallbacks); 20 | return (__bridge NSArray *)arrayRef; 21 | } 22 | 23 | NSSet* AllocNotRetainedSet() { 24 | CFSetRef setRef = NULL; 25 | CFSetCallBacks notRetainedCallbacks = kCFTypeSetCallBacks; 26 | notRetainedCallbacks.retain = NULL; 27 | notRetainedCallbacks.release = NULL; 28 | setRef = CFSetCreate(kCFAllocatorDefault, 0, 0, ¬RetainedCallbacks); 29 | return (__bridge NSSet *)setRef; 30 | } 31 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/NSHTTPURLResponse+BCLHTTPCodes.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSHTTPURLResponse+BCLHTTPCodes.m 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "NSHTTPURLResponse+BCLHTTPCodes.h" 13 | 14 | @implementation NSHTTPURLResponse (BCLHTTPCodes) 15 | 16 | - (BOOL) isInformational 17 | { 18 | return (self.statusCode >= 100 && self.statusCode < 200); 19 | } 20 | 21 | - (BOOL) isSuccess 22 | { 23 | return (self.statusCode >= 200 && self.statusCode < 300) || [self isRedirect] || [self isInformational]; 24 | } 25 | 26 | - (BOOL) isRedirect 27 | { 28 | return (self.statusCode >= 300 && self.statusCode < 400); 29 | } 30 | 31 | - (BOOL) isClientError 32 | { 33 | return (self.statusCode >= 400 && self.statusCode < 500); 34 | } 35 | 36 | - (BOOL) isServerError 37 | { 38 | return (self.statusCode >= 500 && self.statusCode < 600); 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLAction.m: -------------------------------------------------------------------------------- 1 | // 2 | // BCLAction.m 3 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 4 | // All rights reserved. 5 | // 6 | // This source code is licensed under the BSD 3-Clause License found in the 7 | // LICENSE.txt file in the root directory of this source tree. 8 | // 9 | 10 | static NSString * const BCLActionCouponTypeName = @"coupon"; 11 | static NSString * const BCLActionURLTypeName = @"url"; 12 | static NSString * const BCLActionCouponURLAttrName = @"url"; 13 | 14 | #import "BCLAction.h" 15 | #import "UNCodingUtil.h" 16 | 17 | @implementation BCLAction 18 | 19 | - (NSString *)description 20 | { 21 | return [NSString stringWithFormat:@"%@ (%@)", self.name, self.type]; 22 | } 23 | 24 | - (BOOL)isCouponAction 25 | { 26 | return [self.type.lowercaseString isEqualToString:BCLActionCouponTypeName]; 27 | } 28 | 29 | - (BOOL)isUrlAction 30 | { 31 | return [self.type.lowercaseString isEqualToString:BCLActionURLTypeName]; 32 | } 33 | 34 | - (NSURL *)URL 35 | { 36 | if (!self.isCouponAction && !self.isUrlAction) { 37 | return nil; 38 | } 39 | 40 | return [NSURL URLWithString:self.payload[BCLActionCouponURLAttrName]]; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLBackend.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLBackend.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import "BCLAbstractBackend.h" 14 | 15 | @class BCLConfiguration, BCLActionEventScheduler, BCLBeacon; 16 | 17 | @interface BCLBackend : BCLAbstractBackend 18 | 19 | @property (copy, readonly) NSString *pushEnvironment; 20 | @property (copy, readonly) NSString *pushToken; 21 | @property (copy, readwrite, nonatomic) NSString *userId; 22 | 23 | - (instancetype) initWithClientId:(NSString *)clientId clientSecret:(NSString *)clientSecret pushEnvironment:(NSString *)pushEnvironment pushToken:(NSString *)pushToken; 24 | 25 | - (void) fetchConfiguration:(void(^)(BCLConfiguration *configuration, NSError *error))completion; 26 | - (void) sendEvents:(NSArray *)events completion:(void(^)(NSError *error))completion; 27 | - (void) fetchUsersInRangesOfBeacons:(NSSet *)beacons zones:(NSSet *)zones completion:(void (^)(NSDictionary *result, NSError *error))completion; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /BeaconCtrl/UIColor+Hex.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+Hex.m 3 | // Pods 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "UIColor+Hex.h" 13 | 14 | @implementation UIColor (Hex) 15 | 16 | + (UIColor *)colorFromHexString:(NSString *)hexString { 17 | unsigned rgbValue = 0; 18 | NSScanner *scanner = [NSScanner scannerWithString:hexString]; 19 | [scanner scanHexInt:&rgbValue]; 20 | return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0 blue:(rgbValue & 0xFF)/255.0 alpha:1.0]; 21 | } 22 | 23 | - (NSString *)hexString 24 | { 25 | const CGFloat *components = CGColorGetComponents(self.CGColor); 26 | 27 | CGFloat r = components[0]; 28 | CGFloat g = components[1]; 29 | CGFloat b = components[2]; 30 | 31 | NSString *result = [[NSString stringWithFormat:@"%02lX%02lX%02lX", 32 | lroundf(r * 255), 33 | lroundf(g * 255), 34 | lroundf(b * 255)] lowercaseString]; 35 | 36 | return result; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLAbstractBackend.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLAbstractBackend.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import "UNCoding.h" 14 | 15 | @interface BCLAbstractBackend : NSObject 16 | 17 | @property (nonatomic, copy) NSString *clientId; 18 | @property (nonatomic, copy) NSString *clientSecret; 19 | 20 | @property (copy, readonly) NSString *accessToken; 21 | 22 | - (instancetype) initWithClientId:(NSString *)clientId clientSecret:(NSString *)clientSecret; 23 | 24 | + (NSString *) baseURLString; 25 | + (NSString *) authenticationURLString; 26 | 27 | - (void) setupURLRequest:(NSMutableURLRequest *)mutableRequest; 28 | - (BOOL)shouldFurtherProcessResponse:(NSURLResponse *)response completion:(void(^)(NSError *error))completion; 29 | - (BOOL) retrySelector:(SEL)selector sender:(id)sender parameters:(NSArray *)parameters; 30 | - (void) refetchToken:(void(^)(NSString *token, NSError *error))completion; 31 | - (NSDictionary *)authenticationParameters; 32 | - (void) reset; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/NSObject+BCLAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+BCLAdditions.m 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "NSObject+BCLAdditions.h" 13 | 14 | @implementation NSObject (BCLAdditions) 15 | 16 | - (id) bcl_performSelector:(SEL)selector withParameters:(NSArray *)parameters 17 | { 18 | // perform selector 19 | NSMethodSignature *sig = [self methodSignatureForSelector:selector]; 20 | if (!sig) 21 | return nil; 22 | 23 | NSInvocation* invo = [NSInvocation invocationWithMethodSignature:sig]; 24 | [invo setSelector:selector]; 25 | [invo retainArguments]; 26 | 27 | for (NSInteger idx = 0; idx < parameters.count; idx++) { 28 | id parameter = parameters[idx]; 29 | if (parameter != [NSNull null]) { 30 | [invo setArgument:¶meter atIndex:idx + 2]; 31 | } 32 | } 33 | 34 | [invo invokeWithTarget:self]; 35 | if (sig.methodReturnLength) { 36 | id anObject; 37 | [invo getReturnValue:&anObject]; 38 | return anObject; 39 | } 40 | return nil; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/UIWindow+BCLVisibleViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIWindow+BCLVisibleViewController.m 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "UIWindow+BCLVisibleViewController.h" 13 | 14 | @implementation UIWindow (BCLVisibleViewController) 15 | 16 | - (UIViewController *)bcl_visibleViewController 17 | { 18 | return [self bcl_getVisibleViewControllerFrom:self.rootViewController]; 19 | } 20 | 21 | - (UIViewController *) bcl_getVisibleViewControllerFrom:(UIViewController *) vc { 22 | if ([vc isKindOfClass:[UINavigationController class]]) { 23 | return [self bcl_getVisibleViewControllerFrom:[((UINavigationController *) vc) visibleViewController]]; 24 | } else if ([vc isKindOfClass:[UITabBarController class]]) { 25 | return [self bcl_getVisibleViewControllerFrom:[((UITabBarController *) vc) selectedViewController]]; 26 | } else { 27 | if (vc.presentedViewController) { 28 | return [self bcl_getVisibleViewControllerFrom:vc.presentedViewController]; 29 | } else { 30 | return vc; 31 | } 32 | } 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLEncodableObject.m: -------------------------------------------------------------------------------- 1 | // 2 | // BCLEncodableObject.m 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "BCLEncodableObject.h" 13 | #import "UNCodingUtil.h" 14 | 15 | @implementation BCLEncodableObject 16 | 17 | #pragma mark - NSSecureCoding 18 | 19 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 20 | { 21 | if (!self) { 22 | return nil; 23 | } 24 | 25 | [UNCodingUtil decodeObject:self withCoder:aDecoder]; 26 | 27 | return self; 28 | } 29 | 30 | - (void)encodeWithCoder:(NSCoder *)aCoder 31 | { 32 | [UNCodingUtil encodeObject:self withCoder:aCoder]; 33 | } 34 | 35 | + (BOOL)supportsSecureCoding 36 | { 37 | return YES; 38 | } 39 | 40 | #pragma mark UNCoding 41 | 42 | - (instancetype) initWithDictionary:(NSDictionary *)dictionary 43 | { 44 | if (self = [super init]) { 45 | [[[UNCodingUtil alloc] initWithObject:self] loadDictionaryRepresentation:dictionary]; 46 | } 47 | return self; 48 | } 49 | 50 | - (NSDictionary *) dictionaryRepresentation 51 | { 52 | return [[[UNCodingUtil alloc] initWithObject:self] dictionaryRepresentation]; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Upnext Technologies Sp. z o.o. 2 | All rights reserved. 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 5 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 6 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 7 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /BeaconCtrl/BCLAction.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLAction.h 3 | // 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import "BCLEncodableObject.h" 14 | 15 | @class BCLTrigger; 16 | 17 | /*! 18 | * A class representing BeaconCtrl actions in the SDK 19 | */ 20 | @interface BCLAction : BCLEncodableObject 21 | 22 | /** @name Properties */ 23 | 24 | /// An identifier assigned by the backend 25 | @property (strong) NSNumber *identifier; 26 | 27 | /// Action's name 28 | @property (strong) NSString *name; 29 | 30 | /// Action's type 31 | @property (strong) NSString *type; 32 | 33 | /// Is this a test action (a special subtype of a custom action that can be created while adding a beacon in the admin interface) 34 | @property (nonatomic) BOOL isTestAction; 35 | 36 | /// An array with custom values assigned to an action in the admin interface 37 | @property (strong) NSArray *customValues; 38 | 39 | /// A dictionary with a custom payload of an action (e.g. an URL in case of URL actions) 40 | @property (strong) NSDictionary *payload; 41 | 42 | /// A trigger that calls an action 43 | @property (weak) BCLTrigger *trigger; 44 | 45 | /// A callback that is called when an action is performed 46 | @property (copy) void(^onActionCallback)(BCLAction *action); 47 | 48 | /** @name Methods */ 49 | 50 | /*! 51 | * @brief A shortcut method that returns an URL assigned to some types of actions 52 | * 53 | * @return An URL object assigned to an action 54 | */ 55 | - (NSURL *)URL; 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLActionHandlerFactory.m: -------------------------------------------------------------------------------- 1 | // 2 | // BCLActionHandlerFactory.m 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "BCLActionHandlerFactory.h" 13 | #import "BCLActionHandler.h" 14 | #import 15 | 16 | static NSDictionary *_actionHandlerMapping; 17 | 18 | @implementation BCLActionHandlerFactory 19 | 20 | - (id)init 21 | { 22 | if (self = [super init]) { 23 | if (!_actionHandlerMapping) { 24 | _actionHandlerMapping = [BCLActionHandlerFactory mappingDictionary]; 25 | } 26 | } 27 | 28 | return self; 29 | } 30 | 31 | - (id)actionHandlerForActionTypeName:(NSString *)actionTypeName 32 | { 33 | return _actionHandlerMapping[actionTypeName.lowercaseString]; 34 | } 35 | 36 | #pragma mark - Private 37 | 38 | + (NSDictionary *)mappingDictionary 39 | { 40 | int numberOfClasses = objc_getClassList(NULL, 0); 41 | Class classList[numberOfClasses]; 42 | numberOfClasses = objc_getClassList(classList, numberOfClasses); 43 | 44 | NSMutableDictionary *mapping = [NSMutableDictionary dictionary]; 45 | 46 | for (int i = 0; i < numberOfClasses; i++) { 47 | Class aClass = classList[i]; 48 | 49 | if (class_getClassMethod(aClass, @selector(conformsToProtocol:)) && [aClass conformsToProtocol:@protocol(BCLActionHandler)]) { 50 | mapping[[aClass handledActionTypeName]] = [[aClass alloc] init]; 51 | } 52 | } 53 | 54 | return [mapping copy]; 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /help/html/css/scss/_object.scss: -------------------------------------------------------------------------------- 1 | .section-specification { 2 | table { 3 | width: auto; 4 | 5 | th { 6 | text-align: left; 7 | } 8 | } 9 | } 10 | 11 | .method-title { 12 | margin-left: -15px; 13 | margin-bottom: 8px; 14 | transition: margin-left .3s ease-out; 15 | 16 | .section-method.hide & { 17 | margin-left: 0; 18 | } 19 | 20 | code { 21 | font-weight: 400; 22 | font-size: .85em; 23 | } 24 | } 25 | 26 | .method-info { 27 | background: $object-background; 28 | border-bottom: 1px solid $object-border; 29 | margin: 0 -25px; 30 | padding: 20px 25px 0 25px; 31 | transition: height .3s ease-out; 32 | 33 | position: relative; 34 | 35 | .pointy-thing { 36 | background: $content-background; 37 | height: 10px; 38 | border-bottom: 1px solid $object-border; 39 | margin: -20px -25px 16px -25px; 40 | 41 | &:before { 42 | display: inline-block; 43 | content: ""; 44 | 45 | background: $object-background; 46 | border: 1px solid $object-border; 47 | border-bottom: 0; 48 | border-right: 0; 49 | 50 | position: absolute; 51 | left: 21px; 52 | top: 3px; 53 | width: 12px; 54 | height: 12px; 55 | transform: rotate(45deg); 56 | } 57 | } 58 | 59 | .method-subsection { 60 | margin-bottom: 15px; 61 | 62 | .argument-name { 63 | width: 1px; 64 | text-align: right; 65 | 66 | code { 67 | color: #808080; 68 | font-style: italic; 69 | font-weight: 400; 70 | } 71 | } 72 | } 73 | } 74 | 75 | .section-method { 76 | &.hide .method-info { 77 | height: 0 !important; 78 | overflow: hidden; 79 | display: none; 80 | } 81 | 82 | &.hide.animating .method-info { 83 | display: block; 84 | } 85 | 86 | &.animating .method-info { 87 | overflow: hidden; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /help/html/js/script.js: -------------------------------------------------------------------------------- 1 | function $() { 2 | return document.querySelector.apply(document, arguments); 3 | } 4 | 5 | if (navigator.userAgent.indexOf("Xcode") != -1) { 6 | document.documentElement.classList.add("xcode"); 7 | } 8 | 9 | var jumpTo = $("#jump-to"); 10 | 11 | if (jumpTo) { 12 | jumpTo.addEventListener("change", function(e) { 13 | location.hash = this.options[this.selectedIndex].value; 14 | }); 15 | } 16 | 17 | function hashChanged() { 18 | if (/^#\/\/api\//.test(location.hash)) { 19 | var element = document.querySelector("a[name='" + location.hash.substring(1) + "']"); 20 | 21 | if (!element) { 22 | return; 23 | } 24 | 25 | element = element.parentNode; 26 | 27 | element.classList.remove("hide"); 28 | fixScrollPosition(element); 29 | } 30 | } 31 | 32 | function fixScrollPosition(element) { 33 | var scrollTop = element.offsetTop - 150; 34 | document.documentElement.scrollTop = scrollTop; 35 | document.body.scrollTop = scrollTop; 36 | } 37 | 38 | [].forEach.call(document.querySelectorAll(".section-method"), function(element) { 39 | element.classList.add("hide"); 40 | 41 | element.querySelector(".method-title a").addEventListener("click", function(e) { 42 | var info = element.querySelector(".method-info"), 43 | infoContainer = element.querySelector(".method-info-container"); 44 | 45 | element.classList.add("animating"); 46 | info.style.height = (infoContainer.clientHeight + 40) + "px"; 47 | fixScrollPosition(element); 48 | element.classList.toggle("hide"); 49 | if (element.classList.contains("hide")) { 50 | e.preventDefault(); 51 | } 52 | setTimeout(function() { 53 | element.classList.remove("animating"); 54 | }, 300); 55 | }); 56 | }); 57 | 58 | window.addEventListener("hashchange", hashChanged); 59 | hashChanged(); 60 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLLocation.m: -------------------------------------------------------------------------------- 1 | // 2 | // BCLLocation.m 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "BCLLocation.h" 13 | #import 14 | 15 | @interface BCLLocation () 16 | 17 | @property (nonatomic, strong, readwrite) CLLocation *location; 18 | @property (nonatomic, strong, readwrite) NSNumber *floor; 19 | 20 | @end 21 | 22 | @implementation BCLLocation 23 | 24 | - (instancetype)initWithLocation:(CLLocation *)location floor:(NSNumber *)floor 25 | { 26 | if (self = [super init]) { 27 | _location = location; 28 | _floor = floor; 29 | } 30 | 31 | return self; 32 | } 33 | 34 | #pragma mark - NSSecureCoding 35 | 36 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 37 | { 38 | self = [super init]; 39 | if (!self) { 40 | return nil; 41 | } 42 | [UNCodingUtil decodeObject:self withCoder:aDecoder]; 43 | 44 | return self; 45 | } 46 | 47 | - (void)encodeWithCoder:(NSCoder *)aCoder 48 | { 49 | [UNCodingUtil encodeObject:self withCoder:aCoder]; 50 | } 51 | 52 | + (BOOL)supportsSecureCoding 53 | { 54 | return YES; 55 | } 56 | 57 | #pragma mark UNCoding 58 | 59 | - (instancetype) initWithDictionary:(NSDictionary *)dictionary 60 | { 61 | if (self = [super init]) { 62 | [[[UNCodingUtil alloc] initWithObject:self] loadDictionaryRepresentation:dictionary]; 63 | } 64 | return self; 65 | } 66 | 67 | - (NSDictionary *) dictionaryRepresentation 68 | { 69 | return [[[UNCodingUtil alloc] initWithObject:self] dictionaryRepresentation]; 70 | } 71 | 72 | - (NSArray *)propertiesToExcludeFromEncoding 73 | { 74 | return @[]; 75 | } 76 | 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /BeaconCtrl/SAMCache+BeaconCtrl.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD 3-Clause License found in the 6 | // LICENSE.txt file in the root directory of this source tree. 7 | // 8 | 9 | #import "SAMCache+BeaconCtrl.h" 10 | 11 | static SAMCache *bcl_monitoredProximityCache; 12 | static SAMCache *bcl_lastActionEventsCache; 13 | static SAMCache *bcl_actionEventsCache; 14 | 15 | @implementation SAMCache (BeaconCtrl) 16 | 17 | + (SAMCache *) bcl_monitoredProximityCache 18 | { 19 | if (bcl_monitoredProximityCache != nil) { 20 | return bcl_monitoredProximityCache; 21 | } 22 | 23 | static dispatch_once_t onceToken; 24 | dispatch_once(&onceToken, ^{ 25 | bcl_monitoredProximityCache = [[SAMCache alloc] initWithName:[NSString stringWithFormat:@"com.up-next.BeaconCtrl.monitored"]]; 26 | }); 27 | 28 | return bcl_monitoredProximityCache; 29 | } 30 | 31 | + (SAMCache *)bcl_lastActionEventsCache 32 | { 33 | if (bcl_lastActionEventsCache != nil) { 34 | return bcl_lastActionEventsCache; 35 | } 36 | 37 | static dispatch_once_t onceToken; 38 | dispatch_once(&onceToken, ^{ 39 | bcl_lastActionEventsCache = [[SAMCache alloc] initWithName:[NSString stringWithFormat:@"com.up-next.BeaconCtrl.lastActionEventsCache"]]; 40 | }); 41 | 42 | return bcl_lastActionEventsCache; 43 | } 44 | 45 | + (SAMCache *)bcl_actionEventsCache 46 | { 47 | if (bcl_actionEventsCache != nil) { 48 | return bcl_actionEventsCache; 49 | } 50 | 51 | static dispatch_once_t onceToken; 52 | dispatch_once(&onceToken, ^{ 53 | bcl_actionEventsCache = [[SAMCache alloc] initWithName:[NSString stringWithFormat:@"com.up-next.BeaconCtrl.actionEventsCache"]]; 54 | }); 55 | 56 | return bcl_actionEventsCache; 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLConfiguration.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLConfiguration.h 3 | // 4 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 5 | // All rights reserved. 6 | // 7 | // This source code is licensed under the BSD 3-Clause License found in the 8 | // LICENSE.txt file in the root directory of this source tree. 9 | // 10 | 11 | #import 12 | #import "BCLExtension.h" 13 | #import "BCLEncodableObject.h" 14 | 15 | /*! 16 | * A BCLConfiguration object represents a beacon, zone, actions and extensions configuration relevant for a given BeaconCtrl Application, fetched from the BeaconCtrl Client API and is kept as a reference in 17 | * the BCLBeaconCtrl singleton 18 | */ 19 | @interface BCLConfiguration : BCLEncodableObject 20 | 21 | /** @name Properties */ 22 | 23 | /// Fetched extensions. Set of initialized instances of objects. 24 | @property (strong, nonatomic, readonly) NSSet *extensions; 25 | 26 | /// Fetched beacons. A set of CTLBeacon objects 27 | @property (strong, nonatomic, readonly) NSSet *beacons; 28 | 29 | /// Fetched zones. A set of CTLZone objects 30 | @property (strong, nonatomic, readonly) NSSet *zones; 31 | 32 | /// Kontakt.io API key or nil if the kontakt.io add-on is not switched on 33 | @property (nonatomic, copy, readonly) NSString *kontaktIOAPIKey; 34 | 35 | /** @name Methods */ 36 | 37 | /*! 38 | * @brief inits a BCLConfiguration object with jsonData fetched from the backend 39 | * @param jsonData An NSData object that contains json with a configuration representation fetched from the backend 40 | */ 41 | - (instancetype) initWithJSON:(NSData *)jsonData; 42 | 43 | /*! 44 | * @brief Finds a class with a given name (found by calling a given selector on a class) and protocol 45 | * @param name A name of the class to find 46 | * @param protocol A protocol that the class needs to conform to 47 | * @param nameSelector A selector that will be called on a class to get its name 48 | */ 49 | + (Class) classForName:(NSString *)name protocol:(Protocol *)protocol selector:(SEL)nameSelector; 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLKontaktIOBeaconConfigManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLKontaktIOBeaconConfigManager.h 3 | // Pods 4 | // 5 | // Created by Artur Wdowiarski on 18.09.2015. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @class BCLKontaktIOBeaconConfigManager; 12 | @class KTKBeacon; 13 | 14 | @protocol BCLKontaktIOBeaconConfigManagerDelegate 15 | 16 | - (void)kontaktIOBeaconManagerDidFetchKontaktIOBeacons:(BCLKontaktIOBeaconConfigManager *)manager; 17 | - (void)kontaktIOBeaconManager:(BCLKontaktIOBeaconConfigManager *)manager didMonitorBeaconDevices:(NSArray *)devices; 18 | - (void)kontaktIOBeaconManager:(BCLKontaktIOBeaconConfigManager *)manager didStartUpdatingBeaconWithUniqueId:(NSString *)uniqueId; 19 | - (void)kontaktIOBeaconManager:(BCLKontaktIOBeaconConfigManager *)manager didFinishUpdatingBeaconWithUniqueId:(NSString *)uniqueId newConfig:(KTKBeacon *)config success:(BOOL)success; 20 | - (void)kontaktIOBeaconManager:(BCLKontaktIOBeaconConfigManager *)manager didStartUpdatingFirmwareForBeaconWithUniqueId:(NSString *)uniqueId; 21 | - (void)kontaktIOBeaconManager:(BCLKontaktIOBeaconConfigManager *)manager isUpdatingFirmwareForBeaconWithUniqueId:(NSString *)uniqueId progress:(NSUInteger)progress; 22 | - (void)kontaktIOBeaconManager:(BCLKontaktIOBeaconConfigManager *)manager didFinishUpdatingFirmwareForBeaconWithUniqueId:(NSString *)uniqueId newFirwmareVersion:(NSString *)firmwareVersion success:(BOOL)success; 23 | 24 | @end 25 | 26 | @interface BCLKontaktIOBeaconConfigManager : NSObject 27 | 28 | @property (nonatomic, weak) id delegate; 29 | 30 | @property (nonatomic, copy) NSMutableDictionary *configsToUpdate; 31 | 32 | @property (nonatomic, copy) NSMutableDictionary *firmwaresToUpdate; 33 | 34 | @property (nonatomic, strong) NSMutableDictionary *kontaktBeaconsDictionary; 35 | 36 | - (instancetype)initWithApiKey:(NSString *)apiKey; 37 | 38 | - (void)fetchConfiguration:(void(^)(NSError *error))completion; 39 | 40 | - (void)startManagement; 41 | 42 | - (NSDictionary *)fieldsToUpdateForKontaktBeacon:(KTKBeacon *)beacon; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLZone.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLZone.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import 14 | #import 15 | 16 | /*! 17 | * A class representing zones of beacons in BeaconCtrl 18 | */ 19 | 20 | @interface BCLZone : NSObject 21 | 22 | /** @name Properties */ 23 | 24 | /// Zone identifier assigned by the backend 25 | @property (nonatomic, copy) NSString *zoneIdentifier; 26 | 27 | /// Name of a zone 28 | @property (nonatomic, copy) NSString *name; 29 | 30 | /// A custom color assigned to a zone on the backend 31 | @property (nonatomic, strong) UIColor *color; 32 | 33 | /// Beacons assigned to a zone. A hash table with weak references to BCLBeacon objects 34 | @property (nonatomic, strong) NSHashTable *beacons; // conveniency 35 | 36 | /// Triggers assigned to a zone 37 | @property (strong, nonatomic) NSArray *triggers; 38 | 39 | /// Callback called on enter zone event 40 | @property (copy) void(^onEnterCallback)(BCLZone *zone); 41 | 42 | /// Callback called on leave zone event 43 | @property (copy) void(^onExitCallback)(BCLZone *zone); 44 | 45 | /** @name Methods */ 46 | 47 | /*! 48 | * @brief Initialize a zone object with an identifier and a name 49 | * 50 | * @param zoneIdentifier A zone identifier 51 | * @param name A zone name 52 | * 53 | * @return An initialized zone object 54 | */ 55 | - (instancetype)initWithIdentifier:(NSString *)zoneIdentifier name:(NSString *)name; 56 | 57 | /*! 58 | * @brief Update a zone's properties with values from a dictionary and a set of beacons 59 | * 60 | * @param dictionary A dictionary with zone's properties 61 | * @param beaconsSet A set of BLCBeacon objects that will be assigned to a zone 62 | * 63 | * @return An updated zone object 64 | */ 65 | - (void)updatePropertiesFromDictionary:(NSDictionary *)dictionary beacons:(NSSet *)beaconsSet; 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLActionEvent.m: -------------------------------------------------------------------------------- 1 | // 2 | // BCLEvent.m 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "BCLActionEvent.h" 13 | #import "BCLActionEventScheduler.h" 14 | #import 15 | 16 | @implementation BCLActionEvent 17 | 18 | - (instancetype)init 19 | { 20 | if (self = [super init]) { 21 | _identifier = [[NSUUID UUID] UUIDString]; 22 | _timestamp = [[NSDate date] timeIntervalSince1970]; 23 | } 24 | return self; 25 | } 26 | 27 | - (id)copyWithZone:(NSZone *)zone 28 | { 29 | BCLActionEvent *copyEvent = [[BCLActionEvent alloc] init]; 30 | UNCodingUtil *codingHelper = [[UNCodingUtil alloc] initWithObject:self]; 31 | for (NSString *propertyKey in codingHelper.allProperties) { 32 | [self setValue:[self valueForKey:propertyKey] forKey:propertyKey]; 33 | } 34 | return copyEvent; 35 | } 36 | 37 | - (NSString *)eventTypeName 38 | { 39 | switch (self.eventType) { 40 | case BCLEventTypeEnter: 41 | return @"enter"; 42 | case BCLEventTypeLeave: 43 | return @"leave"; 44 | case BCLEventTypeRangeFar: 45 | return @"far"; 46 | case BCLEventTypeRangeNear: 47 | return @"near"; 48 | case BCLEventTypeRangeImmediate: 49 | return @"immediate"; 50 | case BCLEventTypeDwellTime: 51 | return @"dwell_time"; 52 | default: 53 | return nil; 54 | } 55 | } 56 | 57 | - (NSString *)description 58 | { 59 | return [NSString stringWithFormat:@"Action Event: type: %@ - beacon_id: %@ - zone_id: %@ - timestamp: %f ", self.eventTypeName, self.beaconIdentifier, self.zoneIdentifier, self.timestamp]; 60 | } 61 | 62 | #pragma mark - NSCoding 63 | 64 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 65 | { 66 | [UNCodingUtil decodeObject:self withCoder:aDecoder]; 67 | return self; 68 | } 69 | 70 | - (void)encodeWithCoder:(NSCoder *)aCoder 71 | { 72 | [UNCodingUtil encodeObject:self withCoder:aCoder]; 73 | } 74 | 75 | + (BOOL)supportsSecureCoding 76 | { 77 | return YES; 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLTrigger.m: -------------------------------------------------------------------------------- 1 | // 2 | // BCLTrigger.m 3 | // 4 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 5 | // All rights reserved. 6 | // 7 | // This source code is licensed under the BSD 3-Clause License found in the 8 | // LICENSE.txt file in the root directory of this source tree. 9 | // 10 | 11 | #import "BCLTrigger.h" 12 | #import "BCLCondition.h" 13 | #import "BCLConfiguration.h" 14 | #import "BCLActionEvent.h" 15 | #import "BCLBeaconCtrlDelegate.h" 16 | #import "UNCodingUtil.h" 17 | 18 | @implementation BCLTrigger 19 | 20 | - (instancetype) init 21 | { 22 | if (self = [super init]) { 23 | self.conditions = (NSArray *)[NSArray array]; 24 | self.actions = [NSArray array]; 25 | } 26 | return self; 27 | } 28 | 29 | - (void)updatePropertiesFromDictionary:(NSDictionary *)dictionary 30 | { 31 | // load conditions 32 | for (NSDictionary *conditionDictionary in dictionary[@"conditions"]) { 33 | // parameters without key "type" 34 | NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; 35 | NSArray *parameterKeys = [conditionDictionary.allKeys filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF != %@",@"type"]]; 36 | for (NSString *key in parameterKeys) { 37 | parameters[key] = conditionDictionary[key]; 38 | } 39 | 40 | Class conditionClass = [BCLConfiguration classForName:conditionDictionary[@"type"] protocol:@protocol(BCLCondition) selector:@selector(bcl_conditionType)]; 41 | if (conditionClass) { 42 | id conditionImpl = [[conditionClass alloc] initWithParameters:parameters]; 43 | self.conditions = (NSArray *)[self.conditions arrayByAddingObject:conditionImpl]; 44 | } 45 | } 46 | 47 | BCLAction *action = [[BCLAction alloc] init]; 48 | action.identifier = dictionary[@"action"][@"id"]; 49 | action.name = dictionary[@"action"][@"name"]; 50 | action.type = dictionary[@"action"][@"type"]; 51 | action.isTestAction = [dictionary[@"test"] boolValue]; 52 | 53 | action.customValues = dictionary[@"action"][@"custom_attributes"]; 54 | action.payload = dictionary[@"action"][@"payload"]; 55 | action.trigger = self; 56 | self.actions = [self.actions arrayByAddingObject:action]; 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLAdminBackend.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLAdminBackend.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "BCLAbstractBackend.h" 13 | #import "BCLTypes.h" 14 | 15 | @class BCLBeacon; 16 | @class BCLZone; 17 | 18 | @interface BCLAdminBackend : BCLAbstractBackend 19 | 20 | - (void)authenticateUserWithEmail:(NSString *)email password:(NSString *)password completion:(void(^)(BOOL success, NSError *error))completion; 21 | - (void)registerNewUserWithEmail:(NSString *)email password:(NSString *)password passwordConfirmation:(NSString *)passwordConfirmation completion:(void(^)(BOOL success, NSError *error))completion; 22 | 23 | - (void)fetchTestApplicationCredentials:(void (^)(NSString *applicationClientId, NSString *applicationClientSecret, NSError *error))completion; 24 | 25 | - (void)createBeacon:(BCLBeacon *)beacon testActionName:(NSString *)testActionName testActionTrigger:(BCLEventType)trigger testActionAttributes:(NSArray *)testActionAttributes completion:(void (^)(BCLBeacon *, NSError *))completion; 26 | - (void)updateBeacon:(BCLBeacon *)beacon testActionName:(NSString *)testActionName testActionTrigger:(BCLEventType)trigger testActionAttributes:(NSArray *)testActionAttributes completion:(void (^)(BOOL success, NSError *error))completion; 27 | - (void)deleteBeacon:(BCLBeacon *)beacon completion:(void (^)(BOOL success, NSError *error))completion; 28 | 29 | - (void)fetchVendors:(void (^)(NSArray *vendors, NSError *error))completion; 30 | 31 | - (void)fetchBeacons:(void (^)(NSSet *beacons, NSError *error))completion; 32 | 33 | - (void)syncBeacon:(BCLBeacon *)beacon completion:(void (^)(NSError *error))completion; 34 | 35 | - (void)fetchZones:(NSSet *)beacons completion:(void (^)(NSSet *zones, NSError *error))completion; 36 | 37 | - (void)fetchZoneColors:(void (^)(NSArray *zoneColors, NSError *error))completion; 38 | 39 | - (void)createZone:(BCLZone *)zone completion:(void (^)(BCLZone *newZone, NSError *error))completion; 40 | - (void)updateZone:(BCLZone *)zone completion:(void (^)(BOOL success, NSError *error))completion; 41 | - (void)deleteZone:(BCLZone *)zone completion:(void (^)(BOOL success, NSError *error))completion; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/NSUserDefaults+BCLiCloud.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSUserDefaults+BCLiCloud.m 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "NSUserDefaults+BCLiCloud.h" 13 | 14 | @implementation NSUserDefaults (BCLiCloud) 15 | 16 | -(void)setValue:(id)value forKey:(NSString *)key iCloudSync:(BOOL)sync 17 | { 18 | if (sync) 19 | [[NSUbiquitousKeyValueStore defaultStore] setValue:value forKey:key]; 20 | 21 | [self setValue:value forKey:key]; 22 | } 23 | 24 | -(id)valueForKey:(NSString *)key iCloudSync:(BOOL)sync 25 | { 26 | if (sync) 27 | { 28 | //Get value from iCloud 29 | id value = [[NSUbiquitousKeyValueStore defaultStore] valueForKey:key]; 30 | 31 | //Store locally and synchronize 32 | [self setValue:value forKey:key]; 33 | [self synchronize]; 34 | 35 | return value; 36 | } 37 | 38 | return [self valueForKey:key]; 39 | } 40 | 41 | - (void)removeValueForKey:(NSString *)key iCloudSync:(BOOL)sync 42 | { 43 | [self removeObjectForKey:key iCloudSync:sync]; 44 | } 45 | 46 | 47 | 48 | -(void)setObject:(id)value forKey:(NSString *)defaultName iCloudSync:(BOOL)sync 49 | { 50 | if (sync) 51 | [[NSUbiquitousKeyValueStore defaultStore] setObject:value forKey:defaultName]; 52 | 53 | [self setObject:value forKey:defaultName]; 54 | } 55 | 56 | -(id)objectForKey:(NSString *)key iCloudSync:(BOOL)sync 57 | { 58 | if (sync) 59 | { 60 | //Get value from iCloud 61 | id value = [[NSUbiquitousKeyValueStore defaultStore] objectForKey:key]; 62 | 63 | //Store to NSUserDefault and synchronize 64 | [self setObject:value forKey:key]; 65 | [self synchronize]; 66 | 67 | return value; 68 | } 69 | 70 | return [self objectForKey:key]; 71 | } 72 | 73 | - (void)removeObjectForKey:(NSString *)key iCloudSync:(BOOL)sync 74 | { 75 | if (sync) 76 | [[NSUbiquitousKeyValueStore defaultStore] removeObjectForKey:key]; 77 | 78 | //Remove from NSUserDefault 79 | return [self removeObjectForKey:key]; 80 | } 81 | 82 | 83 | 84 | -(BOOL)synchronizeWithiCloud 85 | { 86 | BOOL res = true; 87 | 88 | res &= [self synchronize]; 89 | res &= [[NSUbiquitousKeyValueStore defaultStore] synchronize]; 90 | 91 | return res; 92 | } 93 | 94 | @end 95 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLEventScheduler.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD 3-Clause License found in the 6 | // LICENSE.txt file in the root directory of this source tree. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @class BCLBeacon; 13 | @class BCLZone; 14 | 15 | /** 16 | * Schedules events for later execution. Used, e.g., to delay beacon 'leave' and zone 'enter' actions. 17 | */ 18 | @interface BCLEventScheduler : NSObject 19 | 20 | /** @name Properties */ 21 | 22 | /// A background task identifier used to schedule events for execution in background mode. 23 | @property (assign) UIBackgroundTaskIdentifier backgroundTaskIdentifier; 24 | 25 | /** @name Methods */ 26 | 27 | /** 28 | * @brief Schedule a beacon event for later. 29 | * @param beacon A beacon for which the event occured 30 | * @param delay Delay value in seconds 31 | * @param callback On time callback block 32 | */ 33 | - (void) scheduleEventForBeacon:(BCLBeacon *)beacon afterDelay:(NSTimeInterval)delay onTime:(void(^)(BCLBeacon *beacon))callback; 34 | 35 | /** 36 | * @biref Schedule a zone 'enter' event for later. 37 | * @param previousZone A zone whose range has been left 38 | * @param newZone A zone whose range has been entered 39 | * @param delay Delay value in seconds 40 | * @param callback On time callback block 41 | */ 42 | - (void) scheduleChangeZoneEventWithPreviousZone:(BCLZone *)previousZone newZone:(BCLZone *)newZone afterDelay:(NSTimeInterval)delay onTime:(void(^)(BCLZone *previousZone, BCLZone *newZone))callback; 43 | 44 | /** 45 | * @brief Cancel all events scheduled for a beacon 46 | * @param beacon A beacon beacon whose events will be cancelled 47 | * 48 | * @return YES if canelled. 49 | */ 50 | - (BOOL) cancelForBeacon:(BCLBeacon *)beacon; 51 | 52 | /*! 53 | * @brief Cancel any scheduled 'enter' zone events 54 | * @return YES is an event has been cancelled 55 | */ 56 | - (BOOL) cancelChangeZoneEvent; 57 | 58 | /** 59 | * @brief Check if a beacon has any scheduled events 60 | * @param beacon A beacon that will be checked for scheduled events 61 | * 62 | * @return YES if any event is scheduled for a beacon 63 | */ 64 | - (BOOL) isScheduledForBeacon:(BCLBeacon *)beacon; 65 | 66 | /*! 67 | * @brief Check if there's a scheduled 'enter' zone event 68 | * @return YES if there's any scheduled 'enter' zone event 69 | */ 70 | - (BOOL) isChangeZoneEventScheduled; 71 | 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /BeaconCtrl/Conditions/BCLConditionEvent.m: -------------------------------------------------------------------------------- 1 | // 2 | // BCLConditionEvent.m 3 | // 4 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 5 | // All rights reserved. 6 | // 7 | // This source code is licensed under the BSD 3-Clause License found in the 8 | // LICENSE.txt file in the root directory of this source tree. 9 | // 10 | 11 | #import "BCLConditionEvent.h" 12 | #import "UNCodingUtil.h" 13 | #import "BCLBeacon.h" 14 | 15 | @implementation BCLConditionEvent 16 | 17 | + (NSString *)bcl_conditionType 18 | { 19 | return @"event_type"; 20 | } 21 | 22 | - (instancetype)initWithParameters:(NSDictionary *)parameters 23 | { 24 | if (self = [self init]) { 25 | _eventType = parameters[@"event_type"]; 26 | } 27 | return self; 28 | } 29 | 30 | - (BOOL)evaluateCondition:(BCLEventType)eventType forBeacon:(BCLBeacon *)beacon 31 | { 32 | if ((eventType == BCLEventTypeEnter) && [self.eventType isEqualToString:@"enter"]) { 33 | return YES; 34 | } else if ((eventType == BCLEventTypeLeave) && [self.eventType isEqualToString:@"leave"]) { 35 | return YES; 36 | } else if ((eventType == BCLEventTypeRangeFar) && [self.eventType isEqualToString:@"far"]) { 37 | return YES; 38 | } else if ((eventType == BCLEventTypeRangeNear) && [self.eventType isEqualToString:@"near"]) { 39 | return YES; 40 | } else if ((eventType == BCLEventTypeRangeImmediate) && [self.eventType isEqualToString:@"immediate"]) { 41 | return YES; 42 | } 43 | return NO; 44 | } 45 | 46 | - (BOOL)evaluateCondition:(BCLEventType)eventType forZone:(BCLZone *)zone 47 | { 48 | if ((eventType == BCLEventTypeEnter) && [self.eventType isEqualToString:@"enter"]) { 49 | return YES; 50 | } else if ((eventType == BCLEventTypeLeave) && [self.eventType isEqualToString:@"leave"]) { 51 | return YES; 52 | } 53 | 54 | return NO; 55 | } 56 | 57 | #pragma mark - NSSecureCoding 58 | 59 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 60 | { 61 | if (!self) { 62 | return nil; 63 | } 64 | [UNCodingUtil decodeObject:self withCoder:aDecoder]; 65 | return self; 66 | } 67 | 68 | - (void)encodeWithCoder:(NSCoder *)aCoder 69 | { 70 | [UNCodingUtil encodeObject:self withCoder:aCoder]; 71 | } 72 | 73 | + (BOOL)supportsSecureCoding 74 | { 75 | return YES; 76 | } 77 | 78 | #pragma mark UNCoding 79 | 80 | - (instancetype) initWithDictionary:(NSDictionary *)dictionary 81 | { 82 | if (self = [super init]) { 83 | [[[UNCodingUtil alloc] initWithObject:self] loadDictionaryRepresentation:dictionary]; 84 | } 85 | return self; 86 | } 87 | 88 | - (NSDictionary *) dictionaryRepresentation 89 | { 90 | return [[[UNCodingUtil alloc] initWithObject:self] dictionaryRepresentation]; 91 | } 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /help/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | BeaconCtrl Reference 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 | 16 |

17 | BeaconCtrl 18 |

19 | 20 |

21 | UP-NEXT 22 |

23 | 24 |
25 |
26 | 27 | 36 | 37 |
38 |
39 |
40 |
41 |

BeaconCtrl Reference

42 | 43 | 44 | 45 |
46 | 47 | 48 | 49 |
50 |

Class References

51 | 68 |
69 | 70 | 71 | 72 |
73 | 74 |

Protocol References

75 | 80 | 81 | 82 | 83 |

Constant References

84 | 91 | 92 | 93 | 94 |
95 | 96 |
97 | 98 |
99 | 107 |
108 |
109 |
110 |
111 |
112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /help/html/hierarchy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | BeaconCtrl Hierarchy 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 | 16 |

17 | BeaconCtrl 18 |

19 | 20 |

21 | UP-NEXT 22 |

23 | 24 |
25 |
26 | 27 | 36 | 37 |
38 |
39 |
40 |
41 |

BeaconCtrl Hierarchy

42 | 43 | 44 |
45 |

Class Hierarchy

46 | 47 | 82 | 83 |
84 | 85 | 86 | 87 |
88 | 89 |

Protocol References

90 | 95 | 96 | 97 |

Constant References

98 | 105 | 106 | 107 |
108 | 109 | 110 |
111 | 119 |
120 |
121 |
122 |
123 |
124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLBeaconRangingBatch.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD 3-Clause License found in the 6 | // LICENSE.txt file in the root directory of this source tree. 7 | // 8 | 9 | #import "BCLBeaconRangingBatch.h" 10 | 11 | #define BCLRangingSecondsTimeFrame 1 12 | 13 | // timeout value since last read. After that amount of time batch is cheared out 14 | #define BCLRangingSecondsTimeout 120 15 | 16 | static NSDate *lastRanging; 17 | 18 | @implementation BCLBeaconRangingBatch 19 | 20 | - (instancetype) initWithDelegate:(id )delegate 21 | { 22 | if (self = [self init]) { 23 | self.delegate = delegate; 24 | } 25 | return self; 26 | } 27 | 28 | 29 | - (void) add:(NSArray *)rangedBeacons forRegion:(CLBeaconRegion *)region 30 | { 31 | @synchronized(self) { 32 | if (!self.batch) { 33 | self.batch = [NSMutableDictionary dictionary]; 34 | [self resetForRegion:region]; 35 | } 36 | 37 | NSTimeInterval timeIntervalSinceLastRanging = [[NSDate date] timeIntervalSinceDate:lastRanging ?: [NSDate dateWithTimeIntervalSinceReferenceDate:0]]; 38 | if (timeIntervalSinceLastRanging >= BCLRangingSecondsTimeout) { 39 | [self resetForRegion:region]; 40 | } 41 | 42 | lastRanging = [NSDate date]; 43 | 44 | NSArray *beaconsInBatch = self.batch[region.identifier][@"beacons"]; 45 | 46 | if (beaconsInBatch.count > 0) { 47 | // if time elapsed from the last read is significant I assume that there was 48 | // break and batch is processed as new 49 | NSDate *refDate = self.batch[region.identifier][@"refdate"]; 50 | NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceDate:refDate]; 51 | 52 | // reset batch after BCLRangingSecondsTimeout 53 | if (timeInterval >= BCLRangingSecondsTimeout) { 54 | [self resetForRegion:region]; 55 | beaconsInBatch = self.batch[region.identifier][@"beacons"]; 56 | } 57 | 58 | // expand 59 | beaconsInBatch = [beaconsInBatch arrayByAddingObjectsFromArray:rangedBeacons]; 60 | self.batch[region.identifier] = @{@"refdate": refDate, @"beacons": beaconsInBatch}; 61 | 62 | if (timeInterval >= BCLRangingSecondsTimeFrame) { 63 | id delegateStrong = self.delegate; 64 | if ([delegateStrong conformsToProtocol:@protocol(BCLBeaconRangingBatchDelegate)]) { 65 | [delegateStrong processBeaconBatch:self beacons:beaconsInBatch]; 66 | } 67 | [self resetForRegion:region]; 68 | } 69 | } else { 70 | // init with ranged beacons 71 | self.batch[region.identifier] = @{@"refdate": [NSDate date], @"beacons": rangedBeacons}; 72 | id delegateStrong = self.delegate; 73 | if ([delegateStrong conformsToProtocol:@protocol(BCLBeaconRangingBatchDelegate)]) { 74 | [delegateStrong processBeaconBatch:self beacons:rangedBeacons]; 75 | } 76 | [self resetForRegion:region]; 77 | } 78 | } 79 | } 80 | 81 | - (NSArray *) regions 82 | { 83 | @synchronized(self) { 84 | return [self.batch allKeys]; 85 | } 86 | } 87 | 88 | - (void) resetForRegion:(CLBeaconRegion *)region 89 | { 90 | self.batch[region.identifier] = @{@"refdate": [NSDate date], @"beacons": [NSArray array]}; 91 | } 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLZone.m: -------------------------------------------------------------------------------- 1 | // 2 | // BCLZone.m 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "BCLZone.h" 13 | #import "BCLBeacon.h" 14 | #import "BCLUtils.h" 15 | #import "UIColor+Hex.h" 16 | #import 17 | 18 | @implementation BCLZone 19 | 20 | - (instancetype)initWithIdentifier:(NSString *)zoneIdentifier name:(NSString *)name 21 | { 22 | if (self = [super init]) { 23 | _zoneIdentifier = zoneIdentifier; 24 | _name = name; 25 | } 26 | 27 | return self; 28 | } 29 | 30 | - (NSString *)description 31 | { 32 | return [NSString stringWithFormat:@"%@ id: %@", self.name, self.zoneIdentifier]; 33 | } 34 | 35 | - (void)updatePropertiesFromDictionary:(NSDictionary *)dictionary beacons:(NSSet *)beaconsSet 36 | { 37 | self->_name = dictionary[@"name"]; 38 | self->_zoneIdentifier = [dictionary[@"id"] description]; 39 | 40 | // convert number value to string 41 | NSMutableSet *beaconIds = [NSMutableSet set]; 42 | for (NSNumber *number in dictionary[@"beacon_ids"]) { 43 | NSAssert([number isKindOfClass:[NSNumber class]], @"Invalid data - beacon_ids"); 44 | [beaconIds addObject:number.description]; 45 | } 46 | 47 | if (dictionary[@"color"]) { 48 | self.color = [UIColor colorFromHexString:dictionary[@"color"]]; 49 | } 50 | 51 | // store found beacons 52 | NSHashTable *beacons = [NSHashTable weakObjectsHashTable]; 53 | for (BCLBeacon *beacon in [beaconsSet filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"beaconIdentifier IN %@",beaconIds]]) { 54 | [beacons addObject:beacon]; 55 | beacon.zone = self; 56 | } 57 | self->_beacons = beacons; 58 | } 59 | 60 | - (NSArray *)triggers 61 | { 62 | @synchronized(self) { 63 | if (!_triggers) { 64 | _triggers = [NSArray array]; 65 | } 66 | return _triggers; 67 | } 68 | } 69 | 70 | #pragma mark - NSCopying 71 | 72 | - (id)copyWithZone:(NSZone *)zone 73 | { 74 | BCLZone *copyZone = [[BCLZone alloc] init]; 75 | UNCodingUtil *codingHelper = [[UNCodingUtil alloc] initWithObject:self]; 76 | for (NSString *propertyKey in codingHelper.allProperties) { 77 | [copyZone setValue:[self valueForKey:propertyKey] forKey:propertyKey]; 78 | } 79 | 80 | return copyZone; 81 | } 82 | 83 | #pragma mark - NSSecureCoding 84 | 85 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 86 | { 87 | self = [super init]; 88 | if (!self) { 89 | return nil; 90 | } 91 | [UNCodingUtil decodeObject:self withCoder:aDecoder]; 92 | 93 | return self; 94 | } 95 | 96 | - (void)encodeWithCoder:(NSCoder *)aCoder 97 | { 98 | [UNCodingUtil encodeObject:self withCoder:aCoder]; 99 | } 100 | 101 | + (BOOL)supportsSecureCoding 102 | { 103 | return YES; 104 | } 105 | 106 | #pragma mark UNCoding 107 | 108 | - (instancetype) initWithDictionary:(NSDictionary *)dictionary 109 | { 110 | if (self = [super init]) { 111 | [[[UNCodingUtil alloc] initWithObject:self] loadDictionaryRepresentation:dictionary]; 112 | } 113 | return self; 114 | } 115 | 116 | - (NSDictionary *) dictionaryRepresentation 117 | { 118 | return [[[UNCodingUtil alloc] initWithObject:self] dictionaryRepresentation]; 119 | } 120 | 121 | - (NSArray *)propertiesToExcludeFromEncoding 122 | { 123 | return @[]; 124 | } 125 | 126 | @end 127 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLURLActionHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // BCLURLActionHandler.m 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "BCLURLActionHandler.h" 13 | #import "UIWindow+BCLVisibleViewController.h" 14 | 15 | @interface BCLURLActionHandler () 16 | 17 | @property (nonatomic, weak, readonly) UIWebView *webView; 18 | @property (nonatomic) BOOL isPresenting; 19 | @property (nonatomic) BOOL isDismissing; 20 | @property (nonatomic, strong) NSMutableArray *navigationControllers; 21 | 22 | @end 23 | 24 | @implementation BCLURLActionHandler 25 | 26 | - (instancetype)init 27 | { 28 | if (self = [super init]) { 29 | _navigationControllers = [@[] mutableCopy]; 30 | } 31 | 32 | return self; 33 | } 34 | 35 | + (NSString *)handledActionTypeName 36 | { 37 | return @"url"; 38 | } 39 | 40 | - (void)handleAction:(BCLAction *)action 41 | { 42 | NSLog(@"Is going to explicitly perform coupon action: %@", action); 43 | 44 | if (self.isPresenting || self.isDismissing) { 45 | [self performSelector:@selector(handleAction:) withObject:action afterDelay:0.3]; 46 | return; 47 | } 48 | 49 | UIViewController *visibleViewController = [[UIApplication sharedApplication].keyWindow bcl_visibleViewController]; 50 | 51 | if (![self canPresentURLOnViewController:visibleViewController]) { 52 | [self performSelector:@selector(handleAction:) withObject:action afterDelay:5]; 53 | return; 54 | } 55 | 56 | UIViewController *webViewController = [[UIViewController alloc] init]; 57 | webViewController.view.frame = visibleViewController.view.frame; 58 | UIWebView *webView = [[UIWebView alloc] initWithFrame:webViewController.view.frame]; 59 | webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 60 | [webViewController.view addSubview:webView]; 61 | 62 | UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:webViewController]; 63 | [self.navigationControllers addObject:navigationController]; 64 | 65 | UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismissCoupon:)]; 66 | webViewController.navigationItem.rightBarButtonItem = barButtonItem; 67 | 68 | self.isPresenting = YES; 69 | dispatch_async(dispatch_get_main_queue(), ^() { 70 | [visibleViewController presentViewController:navigationController animated:YES completion:^() { 71 | self.isPresenting = NO; 72 | [webView loadRequest:[NSURLRequest requestWithURL:action.URL]]; 73 | }]; 74 | }); 75 | } 76 | 77 | - (void)dismissCoupon:(id)sender 78 | { 79 | UINavigationController *navigationController = (UINavigationController *)[[[sender nextResponder] nextResponder] nextResponder]; 80 | 81 | if ([navigationController.visibleViewController.navigationItem.rightBarButtonItem isEqual:sender]) { 82 | self.isDismissing = YES; 83 | [navigationController dismissViewControllerAnimated:YES completion:^() { 84 | self.isDismissing = NO; 85 | }]; 86 | } 87 | 88 | if ([self.navigationControllers containsObject:navigationController]) { 89 | [self.navigationControllers removeObject:navigationController]; 90 | } 91 | } 92 | 93 | - (BOOL)canPresentURLOnViewController:(UIViewController *)viewController 94 | { 95 | return ![viewController isKindOfClass:[UIAlertController class]]; 96 | } 97 | 98 | @end 99 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLBeaconCtrlDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLBeaconCtrlDelegate.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | @class BCLZone; 15 | @class BCLBeacon; 16 | 17 | /*! 18 | * BCLBeaconCtrl delegate. Gets notified about BeaconCtrl SDK actions 19 | */ 20 | @protocol BCLBeaconCtrlDelegate 21 | 22 | @optional 23 | 24 | /** @name Methods */ 25 | 26 | /*! 27 | * @brief Called when a beacon or zone action is performed in background-mode 28 | * 29 | * @param action An action that will be called 30 | */ 31 | - (void) notifyAction:(BCLAction *)action; 32 | 33 | /*! 34 | * @brief Called to ask a delegate if a local notificiation for the BeaconCtrl action should be presented automatically by the SDK 35 | * 36 | * @discussion When a BeaconCtrl action is performed in background-mode, a local notification is created automatically using the action's name. You can use this method to prevent this default behavior. 37 | * 38 | * @param action An action that would normally be notified in case of background-mode by default by the SDK 39 | * 40 | * @return YES, if the action should be notified automatically 41 | */ 42 | - (BOOL) shouldAutomaticallyNotifyAction:(BCLAction *)action; 43 | 44 | /*! 45 | * @brief Called just before a beacon or zone action is performed 46 | * 47 | * @param action An action that will be called 48 | */ 49 | - (void) willPerformAction:(BCLAction *)action; 50 | 51 | /*! 52 | * @brief Called just after a beacon or zone action was performed 53 | * 54 | * @param action An action that was called 55 | */ 56 | - (void) didPerformAction:(BCLAction *)action; 57 | 58 | /*! 59 | * @brief Called to ask a delegate if a BeaconCtrl action should be handled automatically by the SDK 60 | * 61 | * @discussion Some BeaconCtrl actions, e.g. URL actions, are handled automatically by the SDK by default (in case of URL actions a modal web view is shown). You can use this method to prevent this default behavior. 62 | * 63 | * @param action An action that would normally be handled by default by the SDK 64 | * 65 | * @return YES, if the action should be handled automatically 66 | */ 67 | - (BOOL) shouldAutomaticallyPerformAction:(BCLAction *)action; 68 | 69 | 70 | /*! 71 | * @brief Called each time a set of beacons currently monitored by the SDK has changed 72 | * 73 | * @discussion The SDK monitors a limited set of beacons at any given time and changes this set basing on the device's position and beacons currently in range. This way, the SDK gets through the iOS limitation for 20 monitored beacons at a time. 74 | * 75 | * @param newObservedBeacons A set of new monitored beacons. 76 | */ 77 | - (void) didChangeObservedBeacons:(NSSet *)newObservedBeacons; 78 | 79 | /*! 80 | * @brief Called each time the closest beacon has changed. 81 | * 82 | * @param closestBeacon A beacons that is currently the closest to the device 83 | */ 84 | - (void) closestObservedBeaconDidChange:(BCLBeacon *)closestBeacon; 85 | 86 | /*! 87 | * @brief Called each time the current zone has changed 88 | * 89 | * @param currentZone The beacon zone in which the device is at a given time. It's calculated by looking at beacons in range and their estimated distances from the device 90 | */ 91 | - (void) currentZoneDidChange:(BCLZone *)currentZone; 92 | 93 | - (void) beaconsPropertiesUpdateDidStart:(BCLBeacon *)beacon; 94 | 95 | - (void) beaconsPropertiesUpdateDidFinish:(BCLBeacon *)beacon success:(BOOL)success; 96 | 97 | - (void) beaconsFirmwareUpdateDidStart:(BCLBeacon *)beacon; 98 | 99 | - (void) beaconsFirmwareUpdateDidProgress:(BCLBeacon *)beacon progress:(NSUInteger)progress; 100 | 101 | - (void) beaconsFirmwareUpdateDidFinish:(BCLBeacon *)beacon success:(BOOL)success; 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLBeaconCtrlAdmin.m: -------------------------------------------------------------------------------- 1 | // 2 | // BCLBeaconCtrlAdmin.m 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "BCLBeaconCtrlAdmin.h" 13 | #import "BCLAdminBackend.h" 14 | 15 | @interface BCLBeaconCtrlAdmin () 16 | 17 | @property (nonatomic, copy) NSString *clientId; 18 | @property (nonatomic, copy) NSString *clientSecret; 19 | 20 | @property (nonatomic, strong) BCLAdminBackend *backend; 21 | 22 | @end 23 | 24 | @implementation BCLBeaconCtrlAdmin 25 | 26 | + (instancetype)beaconCtrlAdminWithCliendId:(NSString *)clientId clientSecret:(NSString *)clientSecret 27 | { 28 | BCLBeaconCtrlAdmin *beaconCtrlAdmin = [self new]; 29 | 30 | beaconCtrlAdmin.clientId = clientId; 31 | beaconCtrlAdmin.clientSecret = clientSecret; 32 | 33 | beaconCtrlAdmin.backend = [[BCLAdminBackend alloc] initWithClientId:clientId clientSecret:clientSecret]; 34 | 35 | return beaconCtrlAdmin; 36 | } 37 | 38 | - (void)fetchZonesAndBeacons:(void(^)(NSError *error))completion 39 | { 40 | __weak BCLBeaconCtrlAdmin *weakSelf = self; 41 | [self.backend fetchBeacons:^(NSSet *beacons, NSError *error) { 42 | if (!error) { 43 | weakSelf.beacons = beacons; 44 | [weakSelf.backend fetchZones:beacons completion:^(NSSet *zones, NSError *error) { 45 | if (!error) { 46 | weakSelf.zones = zones; 47 | } 48 | if (completion) completion(error); 49 | }]; 50 | } else { 51 | if (completion) completion(error); 52 | } 53 | }]; 54 | } 55 | 56 | - (void)syncBeacon:(BCLBeacon *)beacon completion:(void (^)(NSError *))completion 57 | { 58 | [self.backend syncBeacon:beacon completion:completion]; 59 | } 60 | 61 | - (void)fetchZoneColors:(void (^)(NSError *))completion 62 | { 63 | __weak BCLBeaconCtrlAdmin *weakSelf = self; 64 | 65 | [self.backend fetchZoneColors:^(NSArray *zoneColors, NSError *error) { 66 | if (!error) { 67 | weakSelf.zoneColors = zoneColors; 68 | if (completion) completion(error); 69 | } else { 70 | if (completion) completion(error); 71 | } 72 | }]; 73 | } 74 | 75 | - (void)fetchVendors:(void (^)(NSArray *vendors, NSError *error))completion 76 | { 77 | [self.backend fetchVendors:completion]; 78 | } 79 | 80 | - (void)loginAdminUserWithEmail:(NSString *)email password:(NSString *)password completion:(void (^)(BOOL, NSError *))completion 81 | { 82 | [self.backend authenticateUserWithEmail:email password:password completion:completion]; 83 | } 84 | 85 | - (void)registerAdminUserWithEmail:(NSString *)email password:(NSString *)password passwordConfirmation:(NSString *)passwordConfirmation completion:(void (^)(BOOL, NSError *))completion 86 | { 87 | [self.backend registerNewUserWithEmail:email password:password passwordConfirmation:passwordConfirmation completion:completion]; 88 | } 89 | 90 | - (void)fetchTestApplicationCredentials:(void (^)(NSString *, NSString *, NSError *))completion 91 | { 92 | [self.backend fetchTestApplicationCredentials:completion]; 93 | } 94 | 95 | - (void)createBeacon:(BCLBeacon *)beacon testActionName:(NSString *)testActionName testActionTrigger:(BCLEventType)trigger testActionAttributes:(NSArray *)testActionAttributes completion:(void (^)(BCLBeacon *, NSError *))completion 96 | { 97 | [self.backend createBeacon:beacon testActionName:testActionName testActionTrigger:trigger testActionAttributes:testActionAttributes completion:completion]; 98 | } 99 | 100 | - (void)updateBeacon:(BCLBeacon *)beacon testActionName:(NSString *)testActionName testActionTrigger:(BCLEventType)trigger testActionAttributes:(NSArray *)testActionAttributes completion:(void (^)(BOOL, NSError *))completion 101 | { 102 | [self.backend updateBeacon:beacon testActionName:testActionName testActionTrigger:trigger testActionAttributes:testActionAttributes completion:completion]; 103 | } 104 | 105 | - (void)deleteBeacon:(BCLBeacon *)beacon completion:(void (^)(BOOL, NSError *))completion 106 | { 107 | [self.backend deleteBeacon:beacon completion:completion]; 108 | } 109 | 110 | - (void)createZone:(BCLZone *)zone completion:(void (^)(BCLZone *, NSError *))completion 111 | { 112 | [self.backend createZone:zone completion:completion]; 113 | } 114 | 115 | - (void)updateZone:(BCLZone *)zone completion:(void (^)(BOOL, NSError *))completion 116 | { 117 | [self.backend updateZone:zone completion:completion]; 118 | } 119 | 120 | - (void)deleteZone:(BCLZone *)zone completion:(void (^)(BOOL, NSError *))completion 121 | { 122 | [self.backend deleteZone:zone completion:completion]; 123 | } 124 | 125 | - (void)logout 126 | { 127 | [self.backend reset]; 128 | } 129 | 130 | @end 131 | -------------------------------------------------------------------------------- /help/html/css/scss/_layout.scss: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | .clear { 6 | clear: both; 7 | } 8 | 9 | .clearfix { 10 | &:before, &:after { 11 | clear: both; 12 | display: table; 13 | content: ""; 14 | } 15 | } 16 | 17 | .xcode .hide-in-xcode { 18 | display: none; 19 | } 20 | 21 | body { 22 | font: 62.5% $body-font; 23 | background: $body-background; 24 | } 25 | 26 | h1, h2, h3 { 27 | font-weight: 300; 28 | color: #808080; 29 | } 30 | 31 | h1 { 32 | font-size: 2em; 33 | color: #000; 34 | } 35 | 36 | h4 { 37 | font-size: 13px; 38 | line-height: 1.5; 39 | margin: 21px 0 0 0; 40 | } 41 | 42 | a { 43 | color: $tint-color; 44 | text-decoration: none; 45 | } 46 | 47 | pre, code { 48 | font-family: $code-font; 49 | word-wrap: break-word; 50 | } 51 | 52 | pre > code, .method-declaration code { 53 | display: inline-block; 54 | font-size: .85em; 55 | padding: 4px 0 4px 10px; 56 | border-left: 5px solid rgba(0, 155, 51, .2); 57 | 58 | &:before { 59 | content: "Objective-C"; 60 | display: block; 61 | 62 | font: 9px/1 $body-font; 63 | color: #009b33; 64 | text-transform: uppercase; 65 | letter-spacing: 2px; 66 | padding-bottom: 6px; 67 | } 68 | } 69 | 70 | pre > code { 71 | font-size: inherit; 72 | } 73 | 74 | table, th, td { 75 | border: 1px solid #e9e9e9; 76 | } 77 | 78 | table { 79 | width: 100%; 80 | } 81 | 82 | th, td { 83 | padding: 7px; 84 | 85 | > :first-child { 86 | margin-top: 0; 87 | } 88 | 89 | > :last-child { 90 | margin-bottom: 0; 91 | } 92 | } 93 | 94 | .container { 95 | @extend .clearfix; 96 | 97 | max-width: 980px; 98 | padding: 0 10px; 99 | margin: 0 auto; 100 | 101 | @media (max-width: $mobile-max-width) { 102 | padding: 0; 103 | } 104 | } 105 | 106 | header { 107 | position: fixed; 108 | top: 0; 109 | left: 0; 110 | width: 100%; 111 | z-index: 2; 112 | 113 | background: #414141; 114 | color: #fff; 115 | font-size: 1.1em; 116 | line-height: 25px; 117 | letter-spacing: .05em; 118 | 119 | #library-title { 120 | float: left; 121 | } 122 | 123 | #developer-home { 124 | float: right; 125 | } 126 | 127 | h1 { 128 | font-size: inherit; 129 | font-weight: inherit; 130 | margin: 0; 131 | } 132 | 133 | p { 134 | margin: 0; 135 | } 136 | 137 | h1, a { 138 | color: inherit; 139 | } 140 | 141 | @media (max-width: $mobile-max-width) { 142 | position: absolute; 143 | 144 | .container { 145 | padding: 0 10px; 146 | } 147 | } 148 | } 149 | 150 | aside { 151 | position: fixed; 152 | top: 25px; 153 | left: 0; 154 | width: 100%; 155 | height: 25px; 156 | z-index: 2; 157 | 158 | font-size: 1.1em; 159 | 160 | @media (max-width: $mobile-max-width) { 161 | position: absolute; 162 | } 163 | 164 | #header-buttons { 165 | background: rgba(255, 255, 255, .8); 166 | margin: 0 1px; 167 | padding: 0; 168 | list-style: none; 169 | text-align: right; 170 | line-height: 32px; 171 | 172 | li { 173 | display: inline-block; 174 | cursor: pointer; 175 | padding: 0 10px; 176 | } 177 | 178 | label, select { 179 | cursor: inherit; 180 | } 181 | 182 | #on-this-page { 183 | position: relative; 184 | 185 | .chevron { 186 | display: inline-block; 187 | width: 14px; 188 | height: 4px; 189 | position: relative; 190 | 191 | .chevy { 192 | background: #878787; 193 | height: 2px; 194 | position: absolute; 195 | width: 10px; 196 | 197 | &.chevron-left { 198 | left: 0; 199 | transform: rotateZ(45deg) scale(0.6); 200 | } 201 | 202 | &.chevron-right { 203 | right: 0; 204 | transform: rotateZ(-45deg) scale(0.6); 205 | } 206 | } 207 | } 208 | 209 | #jump-to { 210 | opacity: 0; 211 | font-size: 16px; 212 | 213 | position: absolute; 214 | top: 5px; 215 | left: 0; 216 | width: 100%; 217 | height: 100%; 218 | } 219 | } 220 | } 221 | } 222 | 223 | article { 224 | margin-top: 25px; 225 | 226 | #content { 227 | @extend .clearfix; 228 | 229 | background: $content-background; 230 | border: 1px solid $content-border; 231 | padding: 15px 25px 30px 25px; 232 | 233 | font-size: 1.4em; 234 | line-height: 1.45; 235 | 236 | position: relative; 237 | 238 | @media (max-width: $mobile-max-width) { 239 | padding: 15px 10px 20px 10px; 240 | } 241 | 242 | .navigation-top { 243 | position: absolute; 244 | top: 15px; 245 | right: 25px; 246 | } 247 | 248 | .title { 249 | margin: 21px 0 0 0; 250 | padding: 15px 0; 251 | } 252 | 253 | p { 254 | color: #414141; 255 | margin: 0 0 15px 0; 256 | } 257 | 258 | th, td { 259 | p:last-child { 260 | margin-bottom: 0; 261 | } 262 | } 263 | 264 | main { 265 | ul { 266 | list-style: none; 267 | margin-left: 24px; 268 | margin-bottom: 12px; 269 | padding: 0; 270 | 271 | li { 272 | position: relative; 273 | padding-left: 1.3em; 274 | 275 | &:before { 276 | content: "\02022"; 277 | 278 | color: #414141; 279 | font-size: 1.08em; 280 | line-height: 1; 281 | 282 | position: absolute; 283 | left: 0; 284 | padding-top: 2px; 285 | } 286 | } 287 | } 288 | } 289 | 290 | footer { 291 | @extend .clearfix; 292 | 293 | .footer-copyright { 294 | margin: 70px 25px 10px 0; 295 | } 296 | 297 | p { 298 | font-size: .71em; 299 | color: #a0a0a0; 300 | } 301 | } 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLConfiguration.m: -------------------------------------------------------------------------------- 1 | // 2 | // BCLConfiguration.m 3 | // 4 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 5 | // All rights reserved. 6 | // 7 | // This source code is licensed under the BSD 3-Clause License found in the 8 | // LICENSE.txt file in the root directory of this source tree. 9 | // 10 | 11 | #import "BCLConfiguration.h" 12 | #import "BCLBeacon.h" 13 | #import "BCLZone.h" 14 | #import "BCLTrigger.h" 15 | 16 | #import 17 | 18 | @interface BCLConfiguration () 19 | @property (strong, nonatomic, readwrite) NSSet *extensions; 20 | @property (strong, nonatomic, readwrite) NSSet *beacons; 21 | @property (strong, nonatomic, readwrite) NSSet *zones; 22 | @property (copy, nonatomic, readwrite) NSString *kontaktIOAPIKey; 23 | @end 24 | 25 | @implementation BCLConfiguration 26 | 27 | - (instancetype) init 28 | { 29 | if (self = [super init]) { 30 | self.beacons = [NSSet set]; 31 | } 32 | return self; 33 | } 34 | 35 | - (instancetype) initWithJSON:(NSData *)jsonData 36 | { 37 | if (self = [self init]) { 38 | [self loadFromJSON:jsonData]; 39 | } 40 | return self; 41 | } 42 | 43 | - (NSSet *)extensions 44 | { 45 | if (!_extensions) { 46 | _extensions = (NSSet *)[NSSet set]; 47 | } 48 | return _extensions; 49 | } 50 | 51 | - (BOOL) loadFromJSON:(NSData *)jsonData 52 | { 53 | // load json and translato to BeaconCtrl format 54 | NSError *error = nil; 55 | NSDictionary *configurationDictionary = nil; 56 | if (jsonData) { 57 | configurationDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error]; 58 | } 59 | if (error || !configurationDictionary) 60 | return NO; 61 | 62 | // Load and initialize extension classess 63 | NSDictionary *extensionsDictionary = configurationDictionary[@"extensions"]; 64 | if (extensionsDictionary) { 65 | for (NSString *extensionKey in extensionsDictionary.allKeys) { 66 | Class extensionClass = [BCLConfiguration classForName:extensionKey protocol:@protocol(BCLExtension) selector:@selector(bcl_extensionName)]; 67 | if (extensionClass) { 68 | id extensionImpl = [[extensionClass alloc] initWithParameters:extensionsDictionary[extensionKey]]; 69 | self.extensions = (NSSet *)[self.extensions setByAddingObject:extensionImpl]; 70 | } 71 | } 72 | } 73 | 74 | // Load beacons 75 | NSMutableSet *beaconsSet = [NSMutableSet set]; 76 | 77 | for (NSDictionary *beaconDictionary in configurationDictionary[@"ranges"]) { 78 | BCLBeacon *beacon = [[BCLBeacon alloc] init]; 79 | [beacon updatePropertiesFromDictionary:beaconDictionary]; 80 | [beaconsSet addObject:beacon]; 81 | } 82 | 83 | // load zones 84 | NSMutableSet *zonesSet = [NSMutableSet set]; 85 | 86 | for (NSDictionary *zoneDictionary in configurationDictionary[@"zones"]) { 87 | BCLZone *zone = [[BCLZone alloc] init]; 88 | [zone updatePropertiesFromDictionary:zoneDictionary beacons:beaconsSet]; 89 | [zonesSet addObject:zone]; 90 | } 91 | 92 | // load triggers 93 | for (NSDictionary *triggerDictionary in configurationDictionary[@"triggers"]) { 94 | [triggerDictionary[@"range_ids"] enumerateObjectsUsingBlock:^(NSNumber *beaconId, NSUInteger idx, BOOL *stop) { 95 | BCLTrigger *trigger = [[BCLTrigger alloc] init]; 96 | 97 | if ([beaconId isEqual:@236]) { 98 | NSLog(@""); 99 | } 100 | 101 | NSSet *beaconSet = [beaconsSet filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"beaconIdentifier == %@", beaconId.description]]; 102 | for (BCLBeacon *beacon in beaconSet) { 103 | trigger.beacon = beacon; //FIXME: fix strong cross reference 104 | [trigger updatePropertiesFromDictionary:triggerDictionary]; 105 | beacon.triggers = [beacon.triggers arrayByAddingObject:trigger]; 106 | } 107 | }]; 108 | 109 | [triggerDictionary[@"zone_ids"] enumerateObjectsUsingBlock:^(NSNumber *zoneId, NSUInteger idx, BOOL *stop) { 110 | BCLTrigger *trigger = [[BCLTrigger alloc] init]; 111 | 112 | NSSet *zoneSet = [zonesSet filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"zoneIdentifier == %@", zoneId.description]]; 113 | for (BCLZone *zone in zoneSet) { 114 | trigger.zone = zone; //FIXME: fix strong cross reference 115 | [trigger updatePropertiesFromDictionary:triggerDictionary]; 116 | zone.triggers = [zone.triggers arrayByAddingObject:trigger]; 117 | } 118 | }]; 119 | } 120 | 121 | 122 | 123 | self.beacons = [beaconsSet copy]; 124 | self.zones = [zonesSet copy]; 125 | 126 | if (configurationDictionary[@"kontakt_api_key"] != [NSNull null] && ![configurationDictionary[@"kontakt_api_key"] isEqualToString:@""]) { 127 | self.kontaktIOAPIKey = configurationDictionary[@"kontakt_api_key"]; 128 | } 129 | 130 | return YES; 131 | } 132 | 133 | + (Class) classForName:(NSString *)name protocol:(Protocol *)protocol selector:(SEL)nameSelector 134 | { 135 | int numberOfClasses = objc_getClassList(NULL, 0); 136 | Class classList[numberOfClasses]; 137 | numberOfClasses = objc_getClassList(classList, numberOfClasses); 138 | 139 | for (int idx = 0; idx < numberOfClasses; idx++) 140 | { 141 | Class class = classList[idx]; 142 | if (class_getClassMethod(class, @selector(conformsToProtocol:)) && [class conformsToProtocol:protocol]) 143 | { 144 | #ifdef DEBUG 145 | NSLog(@"Found class %@ (%@)", NSStringFromClass(class), NSStringFromProtocol(protocol)); 146 | #endif 147 | Class extensionClass = class; 148 | if ([class respondsToSelector:nameSelector]) { 149 | NSString *identifier = [class performSelector:nameSelector]; 150 | if ([identifier isEqualToString:name]) { 151 | return extensionClass; 152 | } 153 | } 154 | } 155 | } 156 | return nil; 157 | } 158 | 159 | @end 160 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLBeacon.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD 3-Clause License found in the 6 | // LICENSE.txt file in the root directory of this source tree. 7 | // 8 | 9 | // An app can register up to 20 regions at a time. 10 | // In order to report region changes in a timely manner, the region monitoring service requires network connectivity. 11 | 12 | #import 13 | #import 14 | 15 | #import 16 | 17 | #import 18 | 19 | @class BCLLocation; 20 | @class BCLZone; 21 | 22 | extern NSString * const BCLInvalidBeaconIdentifierException; 23 | extern NSString * const BCLBeaconTimerFireNotification; 24 | 25 | #define BLEBeaconStaysCacheName(beacon) \ 26 | [NSString stringWithFormat:@"com.up-next.BeaconCtrl.stays.%@",beacon.identifier] 27 | 28 | /*! 29 | * A class representing beacons in BeaconCtrl 30 | */ 31 | @interface BCLBeacon : CLBeacon 32 | 33 | /** @name Properties */ 34 | 35 | /// Protocol of a beacon (iBeacon or Eddystone) 36 | @property (readwrite, nonatomic, strong) NSString *protocol; 37 | 38 | /// UUID value of a beacon 39 | @property (readwrite, nonatomic, strong) NSUUID *proximityUUID; 40 | 41 | /// Major value of an iBeacon 42 | @property (readwrite, nonatomic, strong) NSNumber *major; 43 | 44 | /// Minor value of an iBeacon 45 | @property (readwrite, nonatomic, strong) NSNumber *minor; 46 | 47 | /// Namespace value of an Eddystone beacon 48 | @property (readwrite, nonatomic, strong) NSString *namespaceId; 49 | 50 | /// Intance id of an Eddystone beacon 51 | @property (readwrite, nonatomic, strong) NSString *instanceId; 52 | 53 | /// Proximity of a beacon to a device running the SDK described as a CLProximity constant 54 | @property (readwrite, nonatomic, assign) CLProximity proximity; 55 | 56 | /// Rough distance in meters from a beacon to a device running the SDK, 0 if the beacon is out of range 57 | @property (readwrite, nonatomic, assign) CLLocationAccuracy accuracy; 58 | 59 | /// Estimated distance in meters from a beacon to a device running the SDK 60 | @property (readwrite, nonatomic, assign) double estimatedDistance; 61 | 62 | /// Bluetooth signal strength of a beacon 63 | @property (readwrite, nonatomic, assign) NSInteger rssi; 64 | 65 | /// The date when a beacon's range was last entered 66 | @property (readwrite, nonatomic, strong) NSDate *lastEnteredDate; 67 | 68 | /// Name of a beacon. 69 | @property (strong) NSString *name; 70 | 71 | /// A zone to which a beacon is assigned, nil if there's none 72 | @property (nonatomic, weak) BCLZone *zone; 73 | 74 | /// How long a beacon has been in range of a device running the SDK (time since last entry, if there was no leave afterwards) 75 | @property (assign, readonly) NSTimeInterval staysTimeInterval; 76 | 77 | /// Triggers defined for beacon 78 | @property (strong, nonatomic) NSArray *triggers; 79 | 80 | /// A unique identifier - string of proximityUUID+major+minor 81 | @property (readonly) NSString *identifier; 82 | 83 | /// Beacon identifier assigned by the backend 84 | @property (strong) NSString *beaconIdentifier; 85 | 86 | /// Beacon's vendor (i.e. Kontakt.io, Estimote or other) 87 | @property (strong) NSString *vendor; 88 | 89 | /// Beacon's vendor-specific identifier 90 | @property (strong) NSString *vendorIdentifier; 91 | 92 | /// Beacon's vendor-specific firmware version 93 | @property (strong) NSString *vendorFirmwareVersion; 94 | 95 | /// Transmission power for a beacon. May be NSNotFound, if vendor is unknown 96 | @property (nonatomic) NSUInteger transmissionPower; 97 | 98 | /// Transmission interval for a beacon. May be NSNotFound, if vendor is unknown 99 | @property (nonatomic) NSUInteger transmissionInterval; 100 | 101 | /// Battery level for a beacon. May be NSNotFound, if vendor is unknown 102 | @property (nonatomic) NSUInteger batteryLevel; 103 | 104 | /// A flag stating whether a given beacon has outdated properties 105 | @property (nonatomic) BOOL needsCharacteristicsUpdate; 106 | 107 | /// A dictionary of fields to update with property names as keys and new values as values. May be nil for beacons with an unknown vendor 108 | @property (nonatomic, strong) NSDictionary *fieldsToUpdate; 109 | 110 | /// A flag stating whether a given beacon is currently being updated 111 | @property (nonatomic) BOOL characteristicsAreBeingUpdated; 112 | 113 | /// A flag stating whether a given beacon has outdated firmware 114 | @property (nonatomic) BOOL needsFirmwareUpdate; 115 | 116 | /// Firmware update progress 117 | @property (nonatomic) NSUInteger firmwareUpdateProgress; 118 | 119 | /// Callback called when a beacon's range is entered 120 | @property (copy) void(^onEnterCallback)(BCLBeacon *beacon); 121 | 122 | /// Callback called when a beacon's range is left 123 | @property (copy) void(^onExitCallback)(BCLBeacon *beacon); 124 | 125 | /// Callback called when beacon's proximity changes 126 | @property (copy) void(^onChangeProximityCallback)(BCLBeacon *beacon); 127 | 128 | /** @name MKAnnotation-related properties */ 129 | 130 | @property (nonatomic, copy, readonly) NSString *title; 131 | @property (nonatomic, strong) BCLLocation *location; 132 | @property (nonatomic, readonly) CLLocationCoordinate2D coordinate; 133 | 134 | /** @name Methods */ 135 | 136 | /*! 137 | * @brief Initialize beacon with parameters 138 | * 139 | * @param beaconIdentifier immutable value representing single beacon. 140 | * @param proximityUUID proximity UUID 141 | * @param major major 142 | * @param minor minor 143 | * 144 | * @return Initialized object 145 | */ 146 | - (instancetype) initWithIdentifier:(NSString *)beaconIdentifier proximityUUID:(NSUUID *)proximityUUID major:(NSNumber *)major minor:(NSNumber *)minor; 147 | 148 | /*! 149 | * @brief Update a beacon's properties with values taken from dictionary 150 | * @param dictionary A dictionary with beacon's properties 151 | */ 152 | - (void)updatePropertiesFromDictionary:(NSDictionary *)dictionary; 153 | 154 | /*! 155 | * @brief Check if a new proximity can be set for a beacon 156 | * @param newProximity a proximity that will be checked 157 | * @return YES, if a new proximity can be set for a beacon 158 | */ 159 | - (BOOL)canSetProximity:(CLProximity)newProximity; 160 | 161 | @end 162 | -------------------------------------------------------------------------------- /help/html/Constants/BCLEventType.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | BCLEventType Constants Reference 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 | 16 |

17 | BeaconCtrl 18 |

19 | 20 |

21 | UP-NEXT 22 |

23 | 24 |
25 |
26 | 27 | 57 | 58 |
59 |
60 |
61 |
62 |

BCLEventType Constants Reference

63 | 64 | 65 |
66 | 67 | 68 | 69 | 70 |
Declared inBCLTypes.h
71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |

BCLEventType

79 | 80 |
81 | 82 | 83 |

Definition

84 | typedef NS_ENUM(NSInteger, BCLEventType ) {
85 | 86 |    BCLEventTypeUnknown = 0,
87 | 88 |    BCLEventTypeEnter = 1,
89 | 90 |    BCLEventTypeLeave = 2,
91 | 92 |    BCLEventTypeRangeImmediate = 3,
93 | 94 |    BCLEventTypeRangeNear = 4,
95 | 96 |    BCLEventTypeRangeFar = 5,
97 | 98 |    BCLEventTypeDwellTime = 6,
99 | 100 |    BCLEventTypeTimer = 7,
101 | 102 | };
103 | 104 |
105 | 106 |
107 |

Constants

108 |
109 | 110 |
BCLEventTypeUnknown
111 |
112 | 113 | 114 |

115 | Declared In BCLTypes.h. 116 |

117 | 118 |
119 | 120 |
BCLEventTypeEnter
121 |
122 | 123 | 124 |

125 | Declared In BCLTypes.h. 126 |

127 | 128 |
129 | 130 |
BCLEventTypeLeave
131 |
132 | 133 | 134 |

135 | Declared In BCLTypes.h. 136 |

137 | 138 |
139 | 140 |
BCLEventTypeRangeImmediate
141 |
142 | 143 | 144 |

145 | Declared In BCLTypes.h. 146 |

147 | 148 |
149 | 150 |
BCLEventTypeRangeNear
151 |
152 | 153 | 154 |

155 | Declared In BCLTypes.h. 156 |

157 | 158 |
159 | 160 |
BCLEventTypeRangeFar
161 |
162 | 163 | 164 |

165 | Declared In BCLTypes.h. 166 |

167 | 168 |
169 | 170 |
BCLEventTypeDwellTime
171 |
172 | 173 | 174 |

175 | Declared In BCLTypes.h. 176 |

177 | 178 |
179 | 180 |
BCLEventTypeTimer
181 |
182 | 183 | 184 |

185 | Declared In BCLTypes.h. 186 |

187 | 188 |
189 | 190 |
191 |
192 | 193 | 194 | 195 | 196 | 197 | 198 |
199 | 200 |
201 | 209 |
210 |
211 |
212 |
213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /help/html/Constants/BCLBeaconCtrlPushEnvironment.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | BCLBeaconCtrlPushEnvironment Constants Reference 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 | 16 |

17 | BeaconCtrl 18 |

19 | 20 |

21 | UP-NEXT 22 |

23 | 24 |
25 |
26 | 27 | 57 | 58 |
59 |
60 |
61 |
62 |

BCLBeaconCtrlPushEnvironment Constants Reference

63 | 64 | 65 |
66 | 67 | 68 | 69 | 70 |
Declared inBCLBeaconCtrl.h
71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |

BCLBeaconCtrlPushEnvironment

79 | 80 | 81 |
82 |

@typedef BCLBeaconCtrlPushEnvironment

83 |
84 | 85 | 86 |
87 | 88 | 89 |

Definition

90 | typedef NS_ENUM(NSUInteger, BCLBeaconCtrlPushEnvironment ) {
91 | 92 |    BCLBeaconCtrlPushEnvironmentNone,
93 | 94 |    BCLBeaconCtrlPushEnvironmentSandbox,
95 | 96 |    BCLBeaconCtrlPushEnvironmentProduction,
97 | 98 | };
99 | 100 |
101 | 102 |
103 |

Constants

104 |
105 | 106 |
BCLBeaconCtrlPushEnvironmentNone
107 |
108 | 109 | 110 |

A list of possible push environments 111 | @constant BCLBeaconCtrlPushEnvironmentNone is for application builds that don’t have any push environment set up 112 | @constant BCLBeaconCtrlPushEnvironmentSandbox is for debug builds of applications with set up sandbox push environments 113 | @constant BCLBeaconCtrlPushEnvironmentProduction is for production builds of applications with set up production push environments

114 | 115 | 116 | 117 | 118 | 119 | 120 |

121 | Declared In BCLBeaconCtrl.h. 122 |

123 | 124 |
125 | 126 |
BCLBeaconCtrlPushEnvironmentSandbox
127 |
128 | 129 | 130 |

A list of possible push environments 131 | @constant BCLBeaconCtrlPushEnvironmentNone is for application builds that don’t have any push environment set up 132 | @constant BCLBeaconCtrlPushEnvironmentSandbox is for debug builds of applications with set up sandbox push environments 133 | @constant BCLBeaconCtrlPushEnvironmentProduction is for production builds of applications with set up production push environments

134 | 135 | 136 | 137 | 138 | 139 | 140 |

141 | Declared In BCLBeaconCtrl.h. 142 |

143 | 144 |
145 | 146 |
BCLBeaconCtrlPushEnvironmentProduction
147 |
148 | 149 | 150 |

A list of possible push environments 151 | @constant BCLBeaconCtrlPushEnvironmentNone is for application builds that don’t have any push environment set up 152 | @constant BCLBeaconCtrlPushEnvironmentSandbox is for debug builds of applications with set up sandbox push environments 153 | @constant BCLBeaconCtrlPushEnvironmentProduction is for production builds of applications with set up production push environments

154 | 155 | 156 | 157 | 158 | 159 | 160 |

161 | Declared In BCLBeaconCtrl.h. 162 |

163 | 164 |
165 | 166 |
167 |
168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 |
177 |

Declared In

178 |

BCLBeaconCtrl.h

179 |
180 | 181 | 182 | 183 | 184 | 185 |
186 | 187 |
188 | 196 |
197 |
198 |
199 |
200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLBeaconCtrlAdmin.h: -------------------------------------------------------------------------------- 1 | // 2 | // BCLBeaconCtrlAdmin.h 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import "BCLTypes.h" 14 | 15 | @class BCLBeacon; 16 | @class BCLZone; 17 | 18 | /*! 19 | * A BCLBeaconCtrlAdmin singleton is the main point of interaction with BeaconCtrl S2S API 20 | */ 21 | @interface BCLBeaconCtrlAdmin : NSObject 22 | 23 | /** @name Properties */ 24 | 25 | /// Beacons fetched from the backend 26 | @property(nonatomic, strong) NSSet *beacons; 27 | 28 | // Zones fetched from the backend 29 | @property(nonatomic, strong) NSSet *zones; 30 | 31 | // Available zone colors fetched from the backend 32 | @property(nonatomic, strong) NSArray *zoneColors; 33 | 34 | 35 | /** @name Methods */ 36 | 37 | /*! 38 | * @brief The main setup method for BCLBeaconCtrlAdmin 39 | * @param clientId A client id obtained from the s2s API provider, used for authentication 40 | * @param clientSecret A client secret obtained from the s2s API provider, used for authentication 41 | * @return An initialized instance of BCLBeaconCtrlAdmin 42 | */ 43 | + (instancetype)beaconCtrlAdminWithCliendId:(NSString *)clientId clientSecret:(NSString *)clientSecret; 44 | 45 | /*! 46 | * @brief Fethes beacons and zones from the backend 47 | * @param completion A completion handler that is called after the fetch is finished 48 | */ 49 | - (void)fetchZonesAndBeacons:(void (^)(NSError *error))completion; 50 | 51 | /*! 52 | * @brief Syncs a given beacon with its state on the backend 53 | * @param beacon A beacon to sync 54 | * @param completion The completion handler that is fires after the sync is finished 55 | */ 56 | - (void)syncBeacon:(BCLBeacon *)beacon completion:(void (^)(NSError *error))completion; 57 | 58 | /*! 59 | * @brief Fetch available zone colors from the backend 60 | * @discussion Each zone can have a color that is one the colors stored in the zoneColors property that is populated once this method is successfully called 61 | * @param completion A completion handler that is called after the fetch is finished 62 | */ 63 | - (void)fetchZoneColors:(void (^)(NSError *error))completion; 64 | 65 | /*! 66 | * @brief Registers a new admin user on the backend 67 | * @param email The new user's email 68 | * @param password The new user's password 69 | * @param passwordConfirmation The new user's password confirmation for verification 70 | * @param completion A completion block that is called after the registration is finished 71 | */ 72 | - (void)registerAdminUserWithEmail:(NSString *)email password:(NSString *)password passwordConfirmation:(NSString *)passwordConfirmation completion:(void (^)(BOOL success, NSError *error))completion; 73 | 74 | /*! 75 | * @brief Authenticates an existing admin user against the backend 76 | * @param email Admin user's email 77 | * @param password Admin user's password 78 | * @param completion A completion block that is called after the authentication is finished 79 | */ 80 | - (void)loginAdminUserWithEmail:(NSString *)email password:(NSString *)password completion:(void (^)(BOOL success, NSError *error))completion; 81 | 82 | /*! 83 | * @brief Fethes a cliend id and client secret for the currently logged in admin user's test application 84 | * @discussion Every admin user has exactly one test application that monitors all the beacons and zones added to the admin user's account 85 | * @param completion A completion block that is called after the fetch is finished 86 | */ 87 | - (void)fetchTestApplicationCredentials:(void (^)(NSString *applicationClientId, NSString *applicationClientSecret, NSError *error))completion; 88 | 89 | /*! 90 | * @brief Creates a beacon on the backend 91 | * @discussion When creating a beacon, an admin SDK user can create the first test action. It will be added as a custom action with given attributes on the backend. 92 | * @param beacon A beacon that will be created 93 | * @param testActionName Name of the test action 94 | * @param testActionTrigger Trigger of the test action 95 | * @param testActionAttributes Attributes of the test action 96 | * @param completion A completion handler that will be called after the creation is finished 97 | */ 98 | - (void)createBeacon:(BCLBeacon *)beacon testActionName:(NSString *)testActionName testActionTrigger:(BCLEventType)trigger testActionAttributes:(NSArray *)testActionAttributes completion:(void (^)(BCLBeacon *, NSError *))completion; 99 | 100 | /*! 101 | * @brief Updates a beacon on the backend 102 | * @discussion When updating a beacon, an admin SDK user can create or update its test action. Any test action is added as a custom action with given attributes on the backend. 103 | * @param beacon A beacon that will be updated 104 | * @param testActionName Name of the test action 105 | * @param testActionTrigger Trigger of the test action 106 | * @param testActionAttributes Attributes of the test action 107 | * @param completion A completion handler that will be called after the update is finished 108 | */ 109 | - (void)updateBeacon:(BCLBeacon *)beacon testActionName:(NSString *)testActionName testActionTrigger:(BCLEventType)trigger testActionAttributes:(NSArray *)testActionAttributes completion:(void (^)(BOOL success, NSError *error))completion; 110 | 111 | /*! 112 | * @brief Deletes a beacon on the backend 113 | * @param beacon A beacon that will be deleted 114 | * @param completion A completion handler that will be called after the deletion is finished 115 | */ 116 | - (void)deleteBeacon:(BCLBeacon *)beacon completion:(void (^)(BOOL success, NSError *error))completion; 117 | 118 | /*! 119 | * @brief Creates a zone on the backend 120 | * @param zone A zone that will be created 121 | * @param completion A completion handler that will be called after the creation is finished 122 | */ 123 | - (void)createZone:(BCLZone *)zone completion:(void (^)(BCLZone *newZone, NSError *error))completion; 124 | 125 | /*! 126 | * @brief Updates a zone on the backend 127 | * @param zone A zone that will be updated 128 | * @param completion A completion handler that will be called after the update is finished 129 | */ 130 | - (void)updateZone:(BCLZone *)zone completion:(void (^)(BOOL success, NSError *error))completion; 131 | 132 | /*! 133 | * @brief Deletes a zone on the backend 134 | * @param zone A zone that will be deleted 135 | * @param completion A completion handler that will be called after the deletion is finished 136 | */ 137 | - (void)deleteZone:(BCLZone *)zone completion:(void (^)(BOOL success, NSError *error))completion; 138 | 139 | /*! 140 | * @brief Fetches an array of available vendors 141 | * @param completion A completion handler that will be called after the fetch is complete 142 | */ 143 | - (void)fetchVendors:(void (^)(NSArray *vendors, NSError *error))completion; 144 | 145 | - (void)logout; 146 | 147 | @end 148 | -------------------------------------------------------------------------------- /BeaconCtrl/Private/BCLActionEventScheduler.m: -------------------------------------------------------------------------------- 1 | // 2 | // BCLActionEventScheduler.m 3 | // BeaconCtrl 4 | // 5 | // Copyright (c) 2015, Upnext Technologies Sp. z o.o. 6 | // All rights reserved. 7 | // 8 | // This source code is licensed under the BSD 3-Clause License found in the 9 | // LICENSE.txt file in the root directory of this source tree. 10 | // 11 | 12 | #import "BCLActionEventScheduler.h" 13 | #import "BCLActionEvent.h" 14 | #import "BCLBackend.h" 15 | #import "SAMCache+BeaconCtrl.h" 16 | #import 17 | 18 | static NSTimeInterval BCLActionEventSchedulerMinSendIdleInterval = 15; 19 | static NSString * const BCLActionEventSchedulerCachedEventsCacheKey = @"cachedEventsMutableArray"; 20 | NSString * const BCLActionEventSchedulerBackgroundTaskIdentifier = @"backgroundTaskIdentifier"; 21 | 22 | NSString * _cacheKeyForEventType(BCLEventType type) { 23 | return [NSString stringWithFormat:@"%li", type]; 24 | }; 25 | 26 | @interface BCLActionEventScheduler () 27 | 28 | @property (weak) BCLBackend *backend; 29 | 30 | @property (nonatomic, strong) NSTimer *sendEventsTimer; 31 | @property (nonatomic, strong) NSDate *lastSendDate; 32 | @property (nonatomic, strong) NSNumber *currentBackgroundTaskIdentifierNumber; 33 | 34 | @end 35 | 36 | 37 | /** 38 | * Action send events scheduler, connected to BCLBackend and initialized from there. 39 | */ 40 | @implementation BCLActionEventScheduler 41 | 42 | #pragma mark - Events recorder 43 | 44 | /** 45 | * Initialize with backend instance, called from BCLBackend 46 | * 47 | * @param backend weak reference to backend instance 48 | * 49 | * @return Initialized instance 50 | */ 51 | - (instancetype) initWithBackend:(BCLBackend *)backend 52 | { 53 | if (self = [self init]) { 54 | self.backend = backend; 55 | } 56 | return self; 57 | } 58 | 59 | /** 60 | * Schedule for sending actions periodicaly 61 | */ 62 | - (void) scheduleSendingActionEventsWithDelay:(NSTimeInterval)delay userInfo:(NSDictionary *)userInfo 63 | { 64 | if (self.sendEventsTimer) { 65 | return; 66 | } 67 | 68 | self.sendEventsTimer = [NSTimer timerWithTimeInterval:delay target:self selector:@selector(sendActionEventsTimerHandler:) userInfo:userInfo repeats:NO]; 69 | [[NSRunLoop mainRunLoop] addTimer:self.sendEventsTimer forMode:NSDefaultRunLoopMode]; 70 | } 71 | 72 | /** 73 | * Send action events 74 | */ 75 | - (void) sendActionEventsTimerHandler:(NSTimer *)timer 76 | { 77 | NSDictionary *userInfo = timer.userInfo; 78 | 79 | self.sendEventsTimer = nil; 80 | 81 | [self sendActionEvents:^(NSError *error) { 82 | if (userInfo[BCLActionEventSchedulerBackgroundTaskIdentifier]) { 83 | UIBackgroundTaskIdentifier backgroundTaskIdentifier = [userInfo[BCLActionEventSchedulerBackgroundTaskIdentifier] unsignedIntegerValue]; 84 | 85 | if (backgroundTaskIdentifier != UIBackgroundTaskInvalid) { 86 | [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskIdentifier]; 87 | self.currentBackgroundTaskIdentifierNumber = nil; 88 | #ifdef DEBUG 89 | NSLog(@"sendActionEventsTimerHandler endBackgroundTask"); 90 | #endif 91 | } 92 | } 93 | }]; 94 | } 95 | 96 | - (void)sendActionEvents:(void (^)(NSError *error))completion 97 | { 98 | NSMutableArray *cachedEvents = [[SAMCache bcl_actionEventsCache] objectForKey:BCLActionEventSchedulerCachedEventsCacheKey]; 99 | 100 | if (cachedEvents.count) { 101 | self.lastSendDate = [NSDate date]; 102 | } 103 | 104 | [self.backend sendEvents:cachedEvents completion:^(NSError *error) { 105 | if (error) { 106 | NSLog(@"Unable to send events %@",error); 107 | if (completion) { 108 | completion(error); 109 | } 110 | return; 111 | } 112 | 113 | // clear storage 114 | [self.class clearCache]; 115 | 116 | if (completion) { 117 | completion(nil); 118 | } 119 | }]; 120 | 121 | self.sendEventsTimer = nil; 122 | } 123 | 124 | - (dispatch_queue_t)eventsDispatchQueue 125 | { 126 | static dispatch_queue_t events_queue; 127 | 128 | if (!events_queue) { 129 | events_queue = dispatch_queue_create("events queue", DISPATCH_QUEUE_SERIAL); 130 | } 131 | return events_queue; 132 | } 133 | 134 | - (void) storeEvent:(BCLActionEvent *)event 135 | { 136 | if (!self.currentBackgroundTaskIdentifierNumber) { 137 | __weak typeof(self) weakSelf = self; 138 | self.currentBackgroundTaskIdentifierNumber = @([[UIApplication sharedApplication] beginBackgroundTaskWithName:@"beacon-os-action-event-scheduler" expirationHandler:^{ 139 | weakSelf.currentBackgroundTaskIdentifierNumber = nil; 140 | NSLog(@"Application about to terminate with unsent action events: %@", [[SAMCache bcl_actionEventsCache] objectForKey:BCLActionEventSchedulerCachedEventsCacheKey]); 141 | }]); 142 | } 143 | 144 | dispatch_queue_t queue = [self eventsDispatchQueue]; 145 | dispatch_async(queue, ^{ 146 | // store in cache 147 | NSMutableArray *cachedEvents = [[[SAMCache bcl_actionEventsCache] objectForKey:BCLActionEventSchedulerCachedEventsCacheKey] mutableCopy]; 148 | if (!cachedEvents) { 149 | cachedEvents = [NSMutableArray array]; 150 | } 151 | 152 | [cachedEvents addObject:event]; 153 | 154 | [[SAMCache bcl_actionEventsCache] setObject:cachedEvents.copy forKey:BCLActionEventSchedulerCachedEventsCacheKey]; 155 | 156 | [[SAMCache bcl_lastActionEventsCache] setObject:event forKey:_cacheKeyForEventType(event.eventType)]; 157 | 158 | NSDictionary *userInfo = @{BCLActionEventSchedulerBackgroundTaskIdentifier: self.currentBackgroundTaskIdentifierNumber}; 159 | 160 | NSTimeInterval intervalSinceLastSendDate = [[NSDate date] timeIntervalSinceDate:self.lastSendDate]; 161 | 162 | if (!self.lastSendDate || (intervalSinceLastSendDate > BCLActionEventSchedulerMinSendIdleInterval)) { 163 | NSLog(@"BEACON OS WILL SEND AN ACTION EVENT RIGHT AWAY"); 164 | [self scheduleSendingActionEventsWithDelay:1 userInfo:userInfo]; 165 | } else { 166 | NSLog(@"BEACON OS WILL SEND AN ACTION EVENT IN %f SECONDS", BCLActionEventSchedulerMinSendIdleInterval - intervalSinceLastSendDate); 167 | [self scheduleSendingActionEventsWithDelay:(BCLActionEventSchedulerMinSendIdleInterval - intervalSinceLastSendDate) userInfo:userInfo]; 168 | } 169 | }); 170 | } 171 | 172 | - (BCLActionEvent *)lastStoredEventWithType:(BCLEventType)type 173 | { 174 | return [[SAMCache bcl_lastActionEventsCache] objectForKey:_cacheKeyForEventType(type)]; 175 | } 176 | 177 | + (void)clearCache 178 | { 179 | [[SAMCache bcl_actionEventsCache] setObject:nil forKey:BCLActionEventSchedulerCachedEventsCacheKey]; 180 | } 181 | 182 | @end 183 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | #BeaconControl 3 | ##Integration Guide ver. 1.0 4 | ###Revision History 5 | 6 | 7 | Date |Revision |Description 8 | -----------|-------------|----------- 9 | 10.07.2015 | 1.0 |Added BeaconCtrl usage guide. Added BeaconControl iOS SDK integration guide. 10 | 15.10.2015 | 1.1 |Switched to publicly available podspec version of UNNetworking. Bug fixes. 11 | 14.04.2016 | 1.2 |Added support to override hosting default base URL. Fixed issues with beacons ranging and events cache. 12 | 13 | ###Overview 14 | 15 | BeaconControl is your free entry to the beacon world. It's an open source platform that lets your applications sense the world around them. Beacons provide context-rich information to a user’s device upon entering the range of a specific beacon. BeaconControl allows you to set-up predefined triggers and actions for each beacon. For example, when a “listening” mobile device walks by a beacon, you can configure your app to send notifications, trigger URL openings, or deliver content. 16 | 17 | In order to use BeaconCtrl you will need to: 18 | 19 | 1. Setup your beacon infrastructure (with the help of BeaconControl iOS App - link needed!) and configure actions triggered in your mobile applications. 20 | 2. Integrate the BeaconControl SDK with an application. 21 | 22 | 23 | ### BeaconControl Architechture Description 24 | 25 | BeaconControl SDK provides intuitive interfaces for interaction with two APIs provided by BeaconControl: Client API and Server-to-Server API (S2S API). 26 | 27 | Main public interfaces (refer to the efficial documentation for more detailed information): 28 | 29 | BCLBeaconCtrl - the main interface for interaction with the Client API. You'll use it to authenticate your mobile application against the backend, fetch beacon and action configurations, respond to beacon events etc. 30 | 31 | BCLBeaconCtrlAdmin - the main interface for interaction with the S2S API. You'll use it to authorize as an admin user, create beacons, zones and actions, update them, etc. 32 | 33 | BCLRange - the BeaconCtrl SDK class that corresponds to your phisical beacons. You'll use it to get information about your beacons and update it using BCLBeaconCtrlAdmin 34 | 35 | BCLZone - zone corresponds to a group of beacons in BeaconCtrl. You can use them to describe larger phisical areas, covered with many beacons. Other than that, zones behave similarly to beacons, e.g. you can also define actions for them. BCLZone is the interface that describes zones in BeaconCtrl. You'll use it to retrieve information about zones and change it using BCLBeaconCtrlAdmin 36 | 37 | BCLAction - this is the BeaconCtrl class that corresponds to actions that you can assign to your beacons or zones. There are several types of actions, some of them are handled automatically by the SDK (but you can always override the default behavior), some are left for the developer to handle. You can use this class to get information about your actions, e.g. to show them to your mobile users 38 | 39 | BCLConfiguration - each mobile application has a configurations of beacons, zones and actions that it uses. This is the class that describes such an app configuration. You'll use it to get detailed information about your configuration, e.g. the number of beacons (and their details information) it interacts with, etc. 40 | 41 | BCLBeaconCtrlDelegate - this is a protocol that you'll implement in your interfaces to respond to BeaconControl SDK events. You'll get called each time an action is just about to be triggered, when the closest beacon or the current zone have changed, etc. You can also use this protocol to let the SDK know, which exact actions you want it to handle automatically and which you want to deal with on your own. 42 | 43 | 44 | ###Beacons Infrastructure Setup 45 | 46 | 1. Create your BeaconControl account at www.beaconctrl.com 47 | 2. Download the BeaconControl mobile application from the App Store 48 | 3. Log in to the application using your e-mail and password 49 | 4. Add your beacons using the application or BeaconControl Admin Panel (UUID, Minor i Major numbers are essential to identify your beacons and are provided by their producer) 50 | 5. Use BeaconControl test notifications to check your setup on the BeaconControl mobile application 51 | 6. Create a folder of your new application using BeaconControl Admin Panel (Applications) 52 | 7. Copy the automatically generatedClient ID and Client Secret from the application settings in the Admin Panel 53 | 8. Follow the below SDK integration instructions to start interacting with your beacons in your new mobile application 54 | 55 | 56 | ###Beacon OS iOS SDK Integration 57 | 58 | 1. It's easiest to integrate BeaconControl iOS SDK using CocoaPods. The name of the pod is just "BeaconControl" 59 | 2. Add ``NSLocationWhenInUseUsageDescription`` and ``NSLocationAlwaysUsageDescription`` keys to project’s Info.plist file. 60 | 3. In case of a self-hosted BeaconControl environment, you'll need to add the ``BCLBaseURLAPI`` key to project's Info.plist file in order to override the default base url. 61 | 4. Import BeaconControl iOS SDK headers into project’s source code and create a variable or property which will keep strong reference to ``BCLBeaconCtrl`` or ``BCLBeaconCtrlAdmin`` object. 62 | 5. Initialise BeaconControl object: 63 | ````objc 64 | [BCLBeaconCtrl setupBeaconCtrlWithClientId: 65 | clientSecret: 66 | userId:email 67 | pushEnvironment: 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 |
95 |
96 |
97 |
98 |

BCLConfiguration Class Reference

99 | 100 | 101 |
102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 |
Inherits fromBCLEncodableObject : NSObject
Declared inBCLConfiguration.h
BCLConfiguration.m
110 | 111 | 112 | 113 | 114 |
115 | 116 |

Overview

117 |

A BCLConfiguration object represents a beacon, zone, actions and extensions configuration relevant for a given BeaconCtrl Application, fetched from the BeaconCtrl Client API and is kept as a reference in 118 | the BCLBeaconCtrl singleton

119 |
120 | 121 | 122 | 123 | 124 | 125 |
126 | 127 | 128 | 129 | 130 |

Properties

131 | 132 |
133 |
134 | 135 |

  extensions 136 |

137 | 138 |
139 |
140 | 141 |
142 | 143 | 144 |
145 |

Fetched extensions. Set of initialized instances of objects.

146 |
147 | 148 | 149 | 150 |
@property (strong, nonatomic, readonly) NSSet<BCLExtension> *extensions
151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 |
167 |

Declared In

168 |

BCLConfiguration.h

169 |
170 | 171 | 172 |
173 |
174 |
175 | 176 |

  beacons 177 |

178 | 179 |
180 |
181 | 182 |
183 | 184 | 185 |
186 |

Fetched beacons. A set of CTLBeacon objects

187 |
188 | 189 | 190 | 191 |
@property (strong, nonatomic, readonly) NSSet *beacons
192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 |
208 |

Declared In

209 |

BCLConfiguration.h

210 |
211 | 212 | 213 |
214 |
215 |
216 | 217 |

  zones 218 |

219 | 220 |
221 |
222 | 223 |
224 | 225 | 226 |
227 |

Fetched zones. A set of CTLZone objects

228 |
229 | 230 | 231 | 232 |
@property (strong, nonatomic, readonly) NSSet *zones
233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 |
249 |

Declared In

250 |

BCLConfiguration.h

251 |
252 | 253 | 254 |
255 |
256 |
257 | 258 |

  kontaktIOAPIKey 259 |

260 | 261 |
262 |
263 | 264 |
265 | 266 | 267 |
268 |

Kontakt.io API key or nil if the kontakt.io add-on is not switched on

269 |
270 | 271 | 272 | 273 |
@property (nonatomic, copy, readonly) NSString *kontaktIOAPIKey
274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 |
290 |

Declared In

291 |

BCLConfiguration.h

292 |
293 | 294 | 295 |
296 |
297 |
298 |
299 | 300 | 301 | 302 |

Methods

303 | 304 |
305 |
306 | 307 |

– initWithJSON: 308 |

309 | 310 |
311 |
312 | 313 |
314 | 315 | 316 |
317 |

inits a BCLConfiguration object with jsonData fetched from the backend

318 |
319 | 320 | 321 | 322 |
- (instancetype)initWithJSON:(NSData *)jsonData
323 | 324 | 325 | 326 |
327 |

Parameters

328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 |
jsonData

An NSData object that contains json with a configuration representation fetched from the backend

336 |
337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 |
351 |

Declared In

352 |

BCLConfiguration.h

353 |
354 | 355 | 356 |
357 |
358 |
359 | 360 |

+ classForName:protocol:selector: 361 |

362 | 363 |
364 |
365 | 366 |
367 | 368 | 369 |
370 |

Finds a class with a given name (found by calling a given selector on a class) and protocol

371 |
372 | 373 | 374 | 375 |
+ (Class)classForName:(NSString *)name protocol:(Protocol *)protocol selector:(SEL)nameSelector
376 | 377 | 378 | 379 |
380 |

Parameters

381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 |
name

A name of the class to find

protocol

A protocol that the class needs to conform to

nameSelector

A selector that will be called on a class to get its name

399 |
400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 |
414 |

Declared In

415 |

BCLConfiguration.h

416 |
417 | 418 | 419 |
420 |
421 |
422 |
423 | 424 |
425 | 426 | 427 | 428 | 429 | 430 | 431 |
432 | 433 |
434 | 442 |
443 |
444 |
445 |
446 | 447 | 448 | 449 | -------------------------------------------------------------------------------- /BeaconCtrl/BCLKontaktIOBeaconConfigManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // BCLKontaktIOBeaconConfigManager.m 3 | // Pods 4 | // 5 | // Created by Artur Wdowiarski on 18.09.2015. 6 | // 7 | // 8 | 9 | #import "BCLKontaktIOBeaconConfigManager.h" 10 | #import 11 | #import 12 | #import 13 | #import 14 | #import 15 | #import 16 | #import 17 | #import 18 | 19 | @interface BCLKontaktIOBeaconConfigManager () 20 | 21 | @property (nonatomic, strong) KTKClient *kontaktClient; 22 | @property (nonatomic, strong) KTKBluetoothManager *kontaktBluetoothManager; 23 | @property (nonatomic) BOOL isUpdatingBeacons; 24 | 25 | @end 26 | 27 | @implementation BCLKontaktIOBeaconConfigManager 28 | 29 | - (instancetype)initWithApiKey:(NSString *)apiKey 30 | { 31 | if (self = [super init]) { 32 | _kontaktClient = [KTKClient new]; 33 | _kontaktClient.apiKey = apiKey; 34 | 35 | _kontaktBluetoothManager = [KTKBluetoothManager new]; 36 | _kontaktBluetoothManager.delegate = self; 37 | 38 | _configsToUpdate = @{}.mutableCopy; 39 | } 40 | 41 | return self; 42 | } 43 | 44 | - (void)fetchConfiguration:(void (^)(NSError *))completion 45 | { 46 | NSError *error; 47 | 48 | NSArray *configsToChangeArray = [self.kontaktClient configsPaged:[[KTKPagingConfigs alloc] initWithIndexStart:0 andMaxResults:1000] forDevices:KTKDeviceTypeBeacon withError:&error]; 49 | 50 | if (error) { 51 | if (completion) { 52 | completion(error); 53 | } 54 | return; 55 | } 56 | 57 | [configsToChangeArray enumerateObjectsUsingBlock:^(KTKBeacon *beacon, NSUInteger idx, BOOL *stop) { 58 | self.configsToUpdate[beacon.uniqueID] = beacon; 59 | }]; 60 | 61 | NSArray *kontaktBeacons = [self.kontaktClient beaconsPaged:[[KTKPagingBeacons alloc] initWithIndexStart:0 andMaxResults:1000] withError:&error]; 62 | 63 | if (error) { 64 | if (completion) { 65 | completion(error); 66 | } 67 | return; 68 | } 69 | 70 | NSMutableArray *kontaktBeaconsUniqueIds = @[].mutableCopy; 71 | 72 | NSMutableDictionary *kontaktBeaconsDictionary = @{}.mutableCopy; 73 | [kontaktBeacons enumerateObjectsUsingBlock:^(KTKBeacon *beacon, NSUInteger idx, BOOL *stop) { 74 | [kontaktBeaconsUniqueIds addObject:beacon.uniqueID]; 75 | kontaktBeaconsDictionary[beacon.uniqueID] = beacon; 76 | }]; 77 | 78 | self.kontaktBeaconsDictionary = kontaktBeaconsDictionary; 79 | 80 | NSError *firmareUpdatesError; 81 | self.firmwaresToUpdate = [self.kontaktClient firmwaresLatestForBeaconsUniqueIds:kontaktBeaconsUniqueIds.copy withError:&firmareUpdatesError].mutableCopy; 82 | 83 | if (firmareUpdatesError) { 84 | if (completion) { 85 | completion(firmareUpdatesError); 86 | } 87 | return; 88 | } 89 | 90 | [self.delegate kontaktIOBeaconManagerDidFetchKontaktIOBeacons:self]; 91 | 92 | if (completion) { 93 | completion(nil); 94 | } 95 | } 96 | 97 | - (void)startManagement 98 | { 99 | [self.kontaktBluetoothManager startFindingDevices]; 100 | } 101 | 102 | - (NSDictionary *)fieldsToUpdateForKontaktBeacon:(KTKBeacon *)beacon 103 | { 104 | NSMutableDictionary *fieldsToUpdate = @{}.mutableCopy; 105 | 106 | KTKBeacon *config = self.configsToUpdate[beacon.uniqueID]; 107 | 108 | if (config) { 109 | if (config.interval) { 110 | fieldsToUpdate[@"interval"] = config.interval; 111 | } 112 | 113 | if (config.power) { 114 | fieldsToUpdate[@"power"] = config.power; 115 | } 116 | 117 | if (config.proximity) { 118 | fieldsToUpdate[@"proximity"] = config.proximity; 119 | } 120 | 121 | if (config.major) { 122 | fieldsToUpdate[@"major"] = config.major; 123 | } 124 | 125 | if (config.minor) { 126 | fieldsToUpdate[@"minor"] = config.minor; 127 | } 128 | } 129 | 130 | return fieldsToUpdate.copy; 131 | } 132 | 133 | #pragma mark - KTKBluetoothManagerDelegate 134 | 135 | - (void)bluetoothManager:(KTKBluetoothManager *)bluetoothManager didChangeDevices:(NSSet *)devices 136 | { 137 | NSLog(@"Kontakt.io bluetooth manager did change devices: %@", devices); 138 | if (self.isUpdatingBeacons) { 139 | return; 140 | } 141 | 142 | [self.delegate kontaktIOBeaconManager:self didMonitorBeaconDevices:[devices allObjects]]; 143 | [self updateKontaktBeaconDevices:devices]; 144 | } 145 | 146 | #pragma mark - Private 147 | 148 | - (void)updateKontaktBeaconDevices:(NSSet *)devices 149 | { 150 | self.isUpdatingBeacons = YES; 151 | dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^() { 152 | [devices enumerateObjectsUsingBlock:^(KTKBeaconDevice *beacon, BOOL *stop) { 153 | if ([self.configsToUpdate.allKeys containsObject:beacon.uniqueID] || [self.firmwaresToUpdate.allKeys containsObject:beacon.uniqueID]) { 154 | NSLog(@"Trying update kontakt.io beacon with uniqueId %@", beacon.uniqueID); 155 | NSString *password; 156 | NSString *masterPassword; 157 | KTKError *error; 158 | [self.kontaktClient beaconPassword:&password andMasterPassword:&masterPassword byUniqueId:beacon.uniqueID withError:&error]; 159 | if (error) { 160 | return; 161 | } 162 | 163 | if ([self.configsToUpdate.allKeys containsObject:beacon.uniqueID]) { 164 | if ([beacon connectWithPassword:password andError:&error]) { 165 | KTKBeacon *newConfig = self.configsToUpdate[beacon.uniqueID]; 166 | NSError *updateError; 167 | [self updateKontaktBeaconDevice:beacon withNewConfig:newConfig error:&updateError]; 168 | [beacon disconnect]; 169 | } 170 | } 171 | 172 | if ([self.firmwaresToUpdate.allKeys containsObject:beacon.uniqueID]) { 173 | KTKFirmware *newFirmware = self.firmwaresToUpdate[beacon.uniqueID]; 174 | if ([beacon connectWithPassword:password andError:&error]) { 175 | NSError *firmwareUpdateError; 176 | [self updateFirmwareForKontaktBeaconDevice:beacon masterPassword:masterPassword newFirmware:newFirmware error:&firmwareUpdateError]; 177 | [beacon disconnect]; 178 | } 179 | } 180 | } 181 | }]; 182 | 183 | self.isUpdatingBeacons = NO; 184 | }); 185 | } 186 | 187 | - (BOOL)updateFirmwareForKontaktBeaconDevice:(KTKBeaconDevice *)beaconDevice masterPassword:(NSString *)masterPassword newFirmware:(KTKFirmware *)newFirmware error:(NSError **)error 188 | { 189 | NSError *firmwareUpdateError = [beaconDevice updateFirmware:newFirmware usingMasterPassword:masterPassword progressHandler:^(KTKBeaconDeviceFirmwareUpdateState state, int progress) { 190 | switch (state) { 191 | case KTKBeaconDeviceFirmwareUpdateStatePreparing: 192 | { 193 | dispatch_async(dispatch_get_main_queue(), ^() { 194 | [self.delegate kontaktIOBeaconManager:self didStartUpdatingFirmwareForBeaconWithUniqueId:beaconDevice.uniqueID]; 195 | }); 196 | break; 197 | } 198 | case KTKBeaconDeviceFirmwareUpdateStateUploading: 199 | { 200 | dispatch_async(dispatch_get_main_queue(), ^() { 201 | [self.delegate kontaktIOBeaconManager:self isUpdatingFirmwareForBeaconWithUniqueId:beaconDevice.uniqueID progress:progress]; 202 | }); 203 | break; 204 | } 205 | } 206 | }]; 207 | 208 | if (firmwareUpdateError) { 209 | dispatch_async(dispatch_get_main_queue(), ^() { 210 | [self.delegate kontaktIOBeaconManager:self didFinishUpdatingFirmwareForBeaconWithUniqueId:beaconDevice.uniqueID newFirwmareVersion:nil success:NO]; 211 | }); 212 | return NO; 213 | } KTKBeacon *beaconToUpdate = self.kontaktBeaconsDictionary[beaconDevice.uniqueID]; 214 | beaconToUpdate.firmware = newFirmware.version; 215 | NSError *updateError; 216 | 217 | [self.kontaktClient beaconUpdate:beaconToUpdate withError:&updateError]; 218 | 219 | if (updateError){ 220 | dispatch_async(dispatch_get_main_queue(), ^() { 221 | [self.delegate kontaktIOBeaconManager:self didFinishUpdatingFirmwareForBeaconWithUniqueId:beaconDevice.uniqueID newFirwmareVersion:nil success:NO]; 222 | }); 223 | return NO; 224 | } 225 | 226 | if (self.firmwaresToUpdate[beaconDevice.uniqueID]) { 227 | [self.firmwaresToUpdate removeObjectForKey:beaconDevice.uniqueID]; 228 | } 229 | 230 | dispatch_async(dispatch_get_main_queue(), ^() { 231 | [self.delegate kontaktIOBeaconManager:self didFinishUpdatingFirmwareForBeaconWithUniqueId:beaconDevice.uniqueID newFirwmareVersion:newFirmware.version success:YES]; 232 | }); 233 | return YES; 234 | } 235 | 236 | - (BOOL)updateKontaktBeaconDevice:(KTKBeaconDevice *)beaconDevice withNewConfig:(KTKBeacon *)config error:(NSError **)error 237 | { 238 | dispatch_async(dispatch_get_main_queue(), ^() { 239 | [self.delegate kontaktIOBeaconManager:self didStartUpdatingBeaconWithUniqueId:config.uniqueID]; 240 | }); 241 | 242 | NSError *writeError; 243 | KTKCharacteristicDescriptor *descriptor; 244 | BOOL success = YES; 245 | 246 | KTKBeacon *kontaktBeacon = self.kontaktBeaconsDictionary[config.uniqueID]; 247 | 248 | if (success && config.power) { 249 | descriptor = [beaconDevice characteristicDescriptorWithType:kKTKCharacteristicDescriptorTypeTxPowerLevel]; 250 | writeError = [beaconDevice writeString:config.power.stringValue forCharacteristicWithDescriptor:descriptor]; 251 | if (writeError) { 252 | *error = writeError; 253 | success = NO; 254 | } else { 255 | kontaktBeacon.power = config.power; 256 | } 257 | } 258 | 259 | if (success && config.proximity) { 260 | descriptor = [beaconDevice characteristicDescriptorWithType:kKTKCharacteristicDescriptorTypeProximityUUID]; 261 | writeError = [beaconDevice writeString:config.proximity forCharacteristicWithDescriptor:descriptor]; 262 | if (writeError) { 263 | *error = writeError; 264 | success = NO; 265 | } else { 266 | kontaktBeacon.proximity = config.proximity; 267 | } 268 | } 269 | 270 | if (success && config.major) { 271 | descriptor = [beaconDevice characteristicDescriptorWithType:kKTKCharacteristicDescriptorTypeMajor]; 272 | writeError = [beaconDevice writeString:config.major.stringValue forCharacteristicWithDescriptor:descriptor]; 273 | if (writeError) { 274 | *error = writeError; 275 | return NO; 276 | } else { 277 | kontaktBeacon.major = config.major; 278 | } 279 | } 280 | 281 | if (success && config.minor) { 282 | descriptor = [beaconDevice characteristicDescriptorWithType:kKTKCharacteristicDescriptorTypeMinor]; 283 | writeError = [beaconDevice writeString:config.minor.stringValue forCharacteristicWithDescriptor:descriptor]; 284 | if (writeError) { 285 | *error = writeError; 286 | success = NO; 287 | } else { 288 | kontaktBeacon.minor = config.minor; 289 | } 290 | } 291 | 292 | if (success && config.interval) { 293 | descriptor = [beaconDevice characteristicDescriptorWithType:kKTKCharacteristicDescriptorTypeAdvertisingInterval]; 294 | writeError = [beaconDevice writeString:config.interval.stringValue forCharacteristicWithDescriptor:descriptor]; 295 | if (writeError) { 296 | *error = writeError; 297 | success = NO; 298 | } else { 299 | kontaktBeacon.interval = config.interval; 300 | } 301 | } 302 | 303 | if (success) { 304 | NSError *updateError; 305 | success = [self.kontaktClient beaconUpdate:config withError:&updateError]; 306 | if (!success) { 307 | *error = updateError; 308 | NSLog(@"There was an error while trying to update a kontakt.io beacon in kontakt.io panel: %@", updateError); 309 | } else if (self.configsToUpdate[beaconDevice.uniqueID]) { 310 | [self.configsToUpdate removeObjectForKey:beaconDevice.uniqueID]; 311 | } 312 | } 313 | 314 | dispatch_async(dispatch_get_main_queue(), ^() { 315 | [self.delegate kontaktIOBeaconManager:self didFinishUpdatingBeaconWithUniqueId:config.uniqueID newConfig:config success:success]; 316 | }); 317 | 318 | return success; 319 | } 320 | 321 | @end 322 | --------------------------------------------------------------------------------