iOS Core Bluetooth : Getting API MISUSE Warning - ios

I am writing a test app in iOS 7 with the Core Bluetooth API. When I am testing the application I found that I am getting the following warning message:
TestBluetooth[626:60b] CoreBluetooth[API MISUSE] can only accept commands while in the powered on state
Later I debugged app and found that, warning is coming from the following line of code:
[manager scanForPeripheralsWithServices:array options:scanOptions];
So can anyone please tell me why I am getting this message in the console?
There are bluetooth 4.0 android devices around me, but this app is not discovering them as peripheral device. So why it is not discovering bluetooth 4.0 LE Android devices as peripherals?

You have to wait until the [-CBCentralManagerDelegate centralManagerDidUpdateState:] callback has been called. And then, verify that the state is PoweredOn before you start scanning for peripherals.

Please use the following code to solve the warning:
(You can reference to the code in https://github.com/luoxubin/BlueTooth4.0)
if (bluetoothPowerOn) {
[self.centralManager scanForPeripheralsWithServices:[serviceIDs copy] options:#{CBCentralManagerScanOptionAllowDuplicatesKey:#(NO)}];
}
-(void)centralManagerDidUpdateState:(CBCentralManager *)central{
switch (central.state) {
case CBManagerStatePoweredOn:
{
bluetoothPowerOn = YES; //new code
[self start];
break;
}
default:
{
bluetoothPowerOn = NO; //new code
[self stopScan:[NSError hardwareStatusErrorWithMessage:#"Cannot open Bluetooth, please check the setting." hardwareStatus:central.state]];
break;
}
}
}

Do scan when bluetooth is poweredOn:
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .unknown:
print("unknown")
case .resetting:
print("resetting")
case .unsupported:
print("unsupported")
case .unauthorized:
print("unauthorized")
case .poweredOff:
print("poweredOff")
centralManager?.stopScan()
case .poweredOn:
print("poweredOn")
centralManager?.scanForPeripherals(withServices: nil, options: nil)
}
}

Just turn on my iphone Bluetooth resolve my problem. after turn on bluetooth not getting below warning.
CoreBluetooth[API MISUSE] can only accept commands while in the powered on state

Related

App Tracking Transparency on mac Silicon crash

I have iOS application (that works properly on iOS) and it has enabled destination: Mac(Designed for iPad). When run it on mac M1, the dialog doesnt appear and the code that it used to ask permissions for tracking always returns ATTrackingManager.AuthorizationStatus.notDetermined
The code it here:
if #available(iOS 14, *) {
ATTrackingManager.requestTrackingAuthorization { [weak self] status in
switch status {
case .authorized:
DispatchQueue.main.async {
self?.didTrackingAuthorized?()
}
// Tracking authorization dialog was shown
// and we are authorized
case .denied:
// Tracking authorization dialog was
// shown and permission is denied
print("FB - Denied")
case .notDetermined:
self?.setup()
print("FB - Not Determined")
case .restricted:
print("FB - Restricted")
#unknown default:
print("FB - Unknown")
}
}
}
In documentation I read the Note about such behaviour:
If you call ATTrackingManager.trackingAuthorizationStatus in macOS, ATTrackingManager.AuthorizationStatus.notDetermined returns.
So the question is how in this case properly ask user permission for tracking activity on macos?

ATTrackingManager.requestTrackingAuthorization always returns "Not Determined" and prompt is never shown

I have read all exisiting posts about this topic, but until now I can not get it to work.
Somehow calling ATTrackingManager.requestTrackingAuthorization never shows the popup.
I added Privacy - Tracking Usage Description to the info list. I also turned on the system permissions.
I am developing the app with SwiftUI. Target device runs ios 15.4.
Any ideas what else to try? Maybe this is related to swiftUI?
Code:
DeckListView(decks: $store.decks){
Task {
....
}
}
}.onAppear{
requestPermission()
}
func requestPermission() {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
if #available(iOS 14, *) {
ATTrackingManager.requestTrackingAuthorization { status in
switch status {
case .authorized:
print("Authorized")
print(ASIdentifierManager.shared().advertisingIdentifier)
case .denied:
print("Denied")
case .notDetermined:
// Tracking authorization dialog has not been shown
// always the case for me
print("Not Determined")
case .restricted:
print("Restricted")
#unknown default:
print("Unknown")
}
}
}
}
}
Finally I found the source of my problem.
I accidentally called ATTrackingManager.requestTrackingAuthorization twice.
The first time I called while the app was not in an active state. It seems if the first call is made outside active state, any other calls will no longer show the popup.

Swift - App Tracking Transparency - No Show Pop-Up due to ‘Allow Apps to Request to Track’ Greyed Out

As you now, Apple changed rules in mobile development in terms of Ads and tracking.
Apple prepared new Beta 14.5 iOS version. With this version tracking will be restricted. So, I wanted to simulate this option in my apps.
When I updated my phone to 14.5 iOS version(Beta) and Xcode(Version 12.5 beta 3 (12E5244e)), ‘Allow Apps to Request to Track’ option is greyed out, and can not changed.
So, in below code snipped, always return .restricted due to the above issue.
func requestPermission() {
if #available(iOS 14, *) {
ATTrackingManager.requestTrackingAuthorization { status in
switch status {
case .authorized:
// Tracking authorization dialog was shown
// and we are authorized
print("Authorized")
// Now that we are authorized we can get the IDFA
print(ASIdentifierManager.shared().advertisingIdentifier)
case .denied:
// Tracking authorization dialog was
// shown and permission is denied
print("Denied")
case .notDetermined:
// Tracking authorization dialog has not been shown
print("Not Determined")
case .restricted:
print("Restricted")
#unknown default:
print("Unknown")
}
}
} else {
// Fallback on earlier versions
}
}
So, I am in stuck because of this issue. Do you have any option/suggession?
Not: In iOS 14.2 version everything was good, and ‘Allow Apps to Request to Track’ option could be changed. But now It's greyed out.
This worked for me
func requestIDFA() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
if #available(iOS 14, *) {
ATTrackingManager.requestTrackingAuthorization(completionHandler: { status in
// Tracking authorization completed. Start loading ads here.
})
} else {
// Fallback on earlier versions
}
}
}
IF you are using Appdelegate call it from ApplicationDidBecomeActive and if you are using Scenedelegate call it from SceneDidBecomeActive

How to convert value of Type 'CBManagerState' to expected type 'CBCentralManagerState' after conversion to Swift 3.0 syntax?

I am working on an iOS App which uses the CoreBluetooth Central Manager. The app was working as expected, until I updated to xCode 8. This update somehow forced me to convert the code from Swift 2.3 to Swift 3.0 with the conversion manager.
After this, I got the error message 'cannot convert value of Type 'CBManagerState' to expected argument type 'CBCentralManagerState' and I was searching for an answer, but due to the reason the update is new, there aren't any helpful issues or documentation regarding the CB Bluetooth used with Swift 3.0 or iOS 10.0.
The lines marked with a star are the lines which produced the error.
final class BluetoothSerial: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
....//some code here from HM10 Bluetooth Serial
var centralManager: CBCentralManager!
var state: CBCentralManagerState { get { return centralManager.state } *
func centralManagerDidUpdateState(_ central: CBCentralManager) {
//note that "didDisconnectPeripheral" won't be called if BLE is turned off while connected
connectedPeripheral = nil
pendingPeripheral = nil
//send it to the delegate
delegate.serialDidChangeState(central.state) *
}
}
Any help is appreciated.
Thanks in advance.
This compiles for me:
var state: CBCentralManagerState { get { return CBCentralManagerState(rawValue: centralManager.state.rawValue)! }
According to the dev forums:
The enums are binary compatible so your code will run fine on any iOS version
I'm only using the state in the
centralManagerDidUpdateState func - but doing so as follows:
switch central.state{
case .poweredOn:
NSLog("CoreBluetooth BLE hardware is powered on");
break
case .poweredOff:
NSLog("CoreBluetooth BLE hardware is powered off");
break;
case .unauthorized:
NSLog("CoreBluetooth BLE state is unauthorized");
break
case .unknown:
NSLog("CoreBluetooth BLE state is unknown");
break;
case .unsupported:
NSLog("CoreBluetooth BLE hardware is unsupported on this platform");
break;
default:
break
}
Which the compiler seems to be happy with (ie - removing the preceding CBCentralManager from CBCentralManager.poweredOn

Mac Low Energy...Developers license necessary to test?

So, I am writing an app for my mac to operate as a central and connect to my iPhone as a peripheral. My iPhone is ready to receive connections and I'm working on the Mac app. When I wrote the iPhone app I found that the simulator in Xcode would not simulate the low-energy functionality and so I purchased an iOS developers license to deploy the app to my phone and test it, which solved my problem.
Now, with the mac app, I think I may be having the same problem...with one difference.
- (BOOL) isLECapableHardware
{
NSString * state = nil;
switch ([manager state])
{
case CBCentralManagerStateUnsupported:
state = #"The platform/hardware doesn't support Bluetooth Low Energy.";
NSLog(#"Central manager state: %#", state);
break;
case CBCentralManagerStateUnauthorized:
state = #"The app is not authorized to use Bluetooth Low Energy.";
NSLog(#"Central manager state: %#", state);
break;
case CBCentralManagerStatePoweredOff:
state = #"Bluetooth is currently powered off.";
NSLog(#"Central manager state: %#", state);
break;
case CBCentralManagerStatePoweredOn:
return TRUE;
case CBCentralManagerStateUnknown:
default:
state = #"Bluetooth is currently powered off.";
NSLog(#"Central manager state: %#", state);
return FALSE;
}
NSLog(#"Central manager state: %#", state);
[_textField setStringValue:state];
return false;
}
When this is called, it always falls all the way through to the default case. With the iPhone app I was falling into state unsupported while trying to test it with the simulator. Does this just mean that I need to buy a mac developers license in addition to the iOS one? Or could there be some other issue?

Resources