iOS 13 - Estimote SDK - Beacon ranging - ios

I've encountered problem with beacon ranging in iOS 13
Ranging Nearable stickers stop working
self.nearableManager.startRanging(forIdentifier: nearableIdentifier)
Nothing happens in delegate method:
func nearableManager(_ manager: ESTNearableManager, didRangeNearable nearable: ESTNearable) { }
UPDATE
Error found:
Ranging nearables failed with error: Error
Domain=com.estimote.nearables Code=301 "Blueooth is not powerd on."
UserInfo={NSLocalizedDescription=Blueooth is not powerd on.}
When I use CBCentralManager() then in its delegate I am getting poweredOn status
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .unknown:
print("central.state is .unknown")
case .resetting:
print("central.state is .resetting")
case .unsupported:
print("central.state is .unsupported")
case .unauthorized:
print("central.state is .unauthorized")
case .poweredOff:
print("central.state is .poweredOff")
case .poweredOn:
print("central.state is .poweredOn")
}
}
private init(rangingTimeout: TimeInterval? = nil) {
super.init()
self.centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main)
self.nearableManager.delegate = self
self.rangingTimeout = rangingTimeout
self.beaconManager.delegate = self
self.beaconManager.requestAlwaysAuthorization()
}
All this code is used in singleton object used on multiple screens of application.
class NearableTablesManager : NSObject {
// MARK: - Singleton
private static var shared : NearableTablesManager?
static func shared(rangingTimeout: TimeInterval? = nil) -> NearableTablesManager {
if shared == nil {
shared = NearableTablesManager(rangingTimeout: rangingTimeout)
}
return shared!
}

Related

Setup Family Sharing for in-app purchases in iOS

Apple has just released Family Sharing for in-app purchases, I'm trying to add this to my apps with auto-renewable subscriptions without luck.
From WWDC2020 video they say everything should be working like a magic without code changes but not for me I guess. Even after restoring purchase on family member device nothing happens.
Do I need any additional setup just to make it work?
I have restore / purchase logic Implemented in the app like this:
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .purchased:
complete(transaction: transaction)
break
case .failed:
fail(transaction: transaction)
break
case .restored:
restore(transaction: transaction)
break
case .deferred:
break
case .purchasing:
break
}
}
}
private func complete(transaction: SKPaymentTransaction) {
print("complete...")
deliverPurchaseNotificationFor(identifier: transaction.payment.productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
promotedPayment = nil
}
private func restore(transaction: SKPaymentTransaction) {
guard let productIdentifier = transaction.original?.payment.productIdentifier else { return }
print("restore... \(productIdentifier)")
deliverPurchaseNotificationFor(identifier: productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
}
private func fail(transaction: SKPaymentTransaction) {
print("fail...")
if let transactionError = transaction.error as NSError? {
if transactionError.code != SKError.paymentCancelled.rawValue {
let failedString = "Transaction Error: \(String(describing: transaction.error?.localizedDescription ?? ""))"
print(failedString)
NotificationCenter.default.post(name: NSNotification.Name(rawValue: IAPHelper.failedNotification), object: failedString)
}
}
NotificationCenter.default.post(name: NSNotification.Name(rawValue: IAPHelper.failedNotification), object: nil)
SKPaymentQueue.default().finishTransaction(transaction)
promotedPayment = nil
}
private func deliverPurchaseNotificationFor(identifier: String?) {
guard let identifier = identifier else { return }
purchasedProductIdentifiers.insert(identifier)
UserDefaults.standard.set(true, forKey: identifier)
UserDefaults.standard.synchronize()
NotificationCenter.default.post(name: NSNotification.Name(rawValue: IAPHelper.purchaseNotification), object: identifier)
}

Multipeer Connectivity wifi & bluetooth off

Is there any way in iOS to detect if Wifi & Bluetooth is off so that I can show alert to the user to enable it from settings.
Note: I am interested in the hardware setting is on/off not the internet is reachable or not.
You can try the following for network connection availability
func isInternetAvailable() -> Bool {
var isNetworkReachable = false
if let reachability: Reachability = try? Reachability() {
isNetworkReachable = reachability.connection != .unavailable
}
return isNetworkReachable
}
for BLE
class BLEManager: NSObject, CBCentralManagerDelegate {
var bleManagerDelegate: BLEManagerDelegate?
var bluetoothManager: CBCentralManager?
private override init() {
super.init()
bleManager = CBCentralManager(delegate: self, queue:nil,
options:[CBCentralManagerOptionShowPowerAlertKey: true])
}
//CBCentralManagerDelegate method invoked
func centralManagerDidUpdateState(_ central: CBCentralManager) {
var bleStateError: BLEError = .kBLEStateUnknown
switch central.state {
case .poweredOff:
// powered Off
case .poweredOn:
// powered On
case .unknown:
//
case .resetting:
//
case .unsupported:
//
case .unauthorized:
//
}
}
}
//For Wifi
Use SwiftReachability https://github.com/ashleymills/Reachability.swift
//declare this property where it won't go out of scope relative to your listener
let reachability = try! Reachability()
//declare this inside of viewWillAppear
NotificationCenter.default.addObserver(self, selector: #selector(reachabilityChanged(note:)), name: .reachabilityChanged, object: reachability)
do{
try reachability.startNotifier()
}catch{
print("could not start reachability notifier")
}
#objc func reachabilityChanged(note: Notification) {
let reachability = note.object as! Reachability
switch reachability.connection {
case .wifi:
print("Reachable via WiFi")
case .cellular:
print("Reachable via Cellular")
case .unavailable:
print("Network not reachable")
}
}
stopping notifications
reachability.stopNotifier()
NotificationCenter.default.removeObserver(self, name: .reachabilityChanged, object: reachability)
// For bluetooth
import CoreBluetooth
var myBTManager = CBPeripheralManager(delegate: self, queue: nil, options: nil)
//BT Manager
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager)
{
if peripheral.state == .poweredOn {
// myBTManager!.startAdvertising(_broadcastBeaconDict)
} else if peripheral.state == .poweredOff {
// myBTManager!.stopAdvertising()
} else if peripheral.state == .unsupported
{
} else if peripheral.state == .unauthorized
{
}
}

iOS issue checking if Bluetooth is ON

I need to check if Bluetooth is On.
I use this code:
func startDetectingBluetoothState() {
if self.centralManager == nil {
self.centralManager = CBCentralManager(delegate: self, queue: self.workingQueue, options: [CBCentralManagerOptionShowPowerAlertKey: false])
}
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
let state = central.state
DispatchQueue.main.async { [weak self] in
// notify observers about state change
self?.stateObservers.invokeDelegates { stateObserver in
stateObserver.bluetoothStateChanged()
}
}
}
I start the app on iPhone X 11.3 (Bluetooth is On in the Settings), then almost immidiatly it enters in centralManagerDidUpdateState(_ central: CBCentralManager) with state == .poweredOff. So the value is wrong. Then I turn off Bluetooth in Settings, centralManagerDidUpdateState(_ central: CBCentralManager) function is not called (because the previous state it detected was .poweredOff), then I turn on Bluetooth and centralManagerDidUpdateState(_ central: CBCentralManager) is called with .poweredOn value. Then it detects every state change properly. But if I restart the app and Bluetooth is On, it can't detect it again. If during start the Bluetooth is Off, everything is OK.
I have another device iPhone 6+ 11.2.5, where everything works as a charm :)
You need to implement CBCentralManagerDelegate. Below is the sample code which might help you to check the condition -
var centralManager:CBCentralManager!
in init() or viewDidLoad()
{
centralManager = CBCentralManager()
centralManager.delegate = self
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
print("Bluetooth is connected")
}
else if central.state == .poweredOff{
print("Bluetooth is not Connected.")
}
}
Use this Code Working for you
var centralManager:CBCentralManager!
override func viewDidLoad()
{
super.viewDidLoad()
// This will trigger centralManagerDidUpdateState
centralManager = CBCentralManager(delegate: self, queue: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager)
{
print("Central Manager did update state")
if (central.state == .poweredOn)
{
self.centralManager?.scanForPeripherals(withServices: nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey: false])
}
else
{
// Bluetooth is unavailable for some reason
// Give feedback
var message = String()
switch central.state
{
case .unsupported:
message = "Bluetooth is unsupported"
case .unknown:
message = "Bluetooth state is unkown"
case .unauthorized:
message = "Bluetooth is unauthorized"
case .poweredOff:
message = "Bluetooth is powered off"
default:
break
}
print(message)
UIAlertView(
title: "Bluetooth unavailable",
message: message,
delegate: nil,
cancelButtonTitle: "OK")
.show()
}
}

Bluetooth broken in IOS 9.1/Xcode 7.1.1

Running IOS 9.1 with Xcode 7.1.1 under 10.11.1. Cut'n'pasted this code from this tutorial; and double check it with several other sources/sites.
http://hatemfaheem.blogspot.ch/2014/12/how-would-you-scan-for-nearby-ble.html
This is the code I have ...
import Foundation
import CoreBluetooth
class BLEManager {
var centralManager : CBCentralManager!
var bleHandler : BLEHandler // delegate
init() {
self.bleHandler = BLEHandler()
self.centralManager = CBCentralManager(delegate: self.bleHandler, queue: nil)
}
}
class BLEHandler : NSObject, CBCentralManagerDelegate {
override init() {
super.init()
}
func centralManagerDidUpdateState(central: CBCentralManager) {
switch (central.state)
{
case .Unsupported:
print("BLE is unsupported")
case .Unauthorized:
print("BLE is unauthorized")
case .Unknown:
print("BLE is unknown")
case .Resetting:
print("BLE is reseting")
case .PoweredOff:
print("BLE is powered off")
case .PoweredOn:
print("BLE is powered on")
central.scanForPeripheralsWithServices(nil, options: nil)
default:
print("BLE default")
}
}
func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
print("didConnectPeripheral")
}
func centralManager(central: CBCentralManager!,
didDiscoverPeripheral peripheral: CBPeripheral!,
adverismentData: [NSObject : AnyObject]!,
RSSI: NSNumber!)
{
print("\(peripheral.name) : \(RSSI) dBm")
}
}
Which I invoke in the View Controller with this code
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var bleManager: BLEManager!
bleManager = BLEManager()
}
Now I run it on an iPad Air with 9.1 and plug in and unplug and replug an ibeacon but nothing appears on the console, suggesting it simply isn't working. Now I know the ibeacon is working; cause I find it with the ScanBeacon tool by Radius Networks.
OK I understand that ibeacons and Core Bluetooth don't go together so well, but surely didDiscoverPeripheral should be called ? Or have I missed a critical line in my code?
Your BLEManager is going out of scope and being deallocated at the end of viewDidLoad. Make it a member variable to give it a longer, more useful lifetime:
var bleManager = BLEManager()
override func viewDidLoad() {
// etc
}

Output status message about Bluetooth in ViewController.swift

I'm create app only for me. Nad create it with MVC.
And i have this peace of code in my model "BTData.swift":
func centralManagerDidUpdateState(central: CBCentralManager!) {
switch (central.state)
{
case .Unsupported:
println("BLE не поддерживается")
break
case .Unauthorized:
println("Приложение не авторизовано для использования BLE")
break
case .Unknown:
println("Состояние Central Manager не известно")
break
case .Resetting:
println("Соединение с системным сервисом потеряно")
break
case .PoweredOff:
println("BLE выключено")
break
case .PoweredOn:
startScanning()
default:
break
}
}
func startScanning() {
println("Scanning...")
if let central = centralManager {
central.scanForPeripheralsWithServices(nil, options: nil)
}
}
All works good in debug. I saw this messages there.
But i can't understand how to output State status message in the label.
I got to do with NSNotification.
Here code for model:
func sendBTServiceNotification(BTStatus: String) {
var connectionDetails = ["Статус": BTStatus]
NSNotificationCenter.defaultCenter().postNotificationName(BLEServiceStatusNotification, object: self, userInfo: connectionDetails)
}
// Получаем состояние при обновлении Central Manager (обязательная)
func centralManagerDidUpdateState(central: CBCentralManager!) {
switch (central.state)
{
case .Unsupported:
sendBTServiceNotification("BLE не поддерживается")
break
case .Unauthorized:
sendBTServiceNotification("Приложение не авторизовано для использования BLE")
break
case .Unknown:
sendBTServiceNotification("Состояние Central Manager не известно")
break
case .Resetting:
sendBTServiceNotification("Соединение с системным сервисом потеряно")
break
case .PoweredOff:
sendBTServiceNotification("BLE выключено")
break
case .PoweredOn:
startScanning()
default:
break
}
}
func startScanning() {
sendBTServiceNotification("Сканирование...")
if let central = centralManager {
central.scanForPeripheralsWithServices(nil, options: nil)
}
}
And this code for ViewController:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
btData = BTData()
// Читаем статус BLE
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("statusChanged:"), name: btData.BLEServiceStatusNotification, object: nil)
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self, name: btData.BLEServiceStatusNotification, object: nil)
}
// Обновляем статус BLE
func statusChanged(notification: NSNotification) {
let userInfo = notification.userInfo as! [String: String]
let statusMsg: String! = userInfo["Статус"]
Status.text = "Статус: \(statusMsg)"
}

Resources