Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open Bluetooth settings programmatically from UIAlertController

As titled, the question is how can I open bluetooth settings programmatically from my App? I checked all answers on stackoverflow and not even one is working fine with iOS 11. All of them are old answers for is below 11 or are left without answer. All I can make is take me to general settings or app settings, but I want user to be taken directly to Bluetooth settings, so he can turn it on.

let alert = UIAlertController(title: "Bluetooth is off", message: "Please turn on your bluetooth", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "Go to settings", style: UIAlertActionStyle.default, handler: { (action) in
                switch action.style {
                case .default:
                    let url = URL(string: "App-Prefs:root=Bluetooth") //for bluetooth setting
                    let app = UIApplication.shared
                    app.openURL(url!)
                    print("default")
                case .cancel:
                    print("cancel")
                case .destructive:
                    print("destrucive")
                }

What I tried more, also without result:

UIApplication.shared.openURL(NSURL(string: "prefs:root=General&path=Bluetoth")! as URL)

Or:

let url = URL(string: "App-Prefs:root=Bluetooth")

All above is not working

like image 247
M. Wojcik Avatar asked Dec 19 '17 17:12

M. Wojcik


3 Answers

So after some deep research (I couldn't believe that it is not possible) and tries with fails I can write a short answer (summary) for my question. As @maddy wrote, iOS doesn't support URL scheme to launching any direct settings, only to General Settings (the list of all settings), or to Application Settings (your application settings (which you can implement)/permissions list). Unfortunately, for you application settings you can't add there also any of iOS System settings to be easy accessed there. Poor..

To go to General Settings you can use:

let url = URL(string: "App-Prefs:root=General")

To go to YouApp Settings your can use:

let url = URL(string: UIApplicationOpenSettingsURLString)

And of course remember to open that URL: (Yes, I know you can do it all in one line)

let app = UIApplication.shared
app.openURL(url!)

Also, as @Paulw11 mentioned, you can open bluetooth settings directly by CBCentralManagerShowPowerAlertKey option. So when you open your app and instantiate CBCentralManager the built-in alert dialog will popup, telling you that you need to "turn on bluetooth to use accessories (peripherals) with your app", with 2 buttons: Settings (that direct's you to bluetooth settings) and OK (dismiss dialog). Unfortunately this shows up when instantiating central manager, so if you want to hold central manager for your whole app (like singleton etc) than it's not so good as you want, cause it will popup only once. In other case that might be it..

NOW! There is something really wrong with ios bluetooth. In iOS you can turn on/off your bluetooth by 2 ways: one from Settings -> Bluetooth, and the second one by swiping from down to top and selecting bluetooth icon. BUT. Now, when you do it by second way, the bluetooth in Settings is still turned on! So even if you open your application and the bluetooth Alert Dialog will popup, and you select go to settings, you will see that bluetooth is ON.

That is really strange here on iOS..

So, in short summary, the answer for my question is:

YOU CANNOT OPEN BLUETOOTH SETTINGS PROGRAMATICALLY by your own AlertDialog. You can use built-in iOS CBCentralManager AlertDialog.

Hope I saved some of your time.


opening URL For iOS 10+ (when I changed version in my project I had to change it):

app.open(url!, options: [:], completionHandler: nil)

Bluetooth strange behavior - update

As I mentioned above, you can switch bluetooth on/off by two ways, which causes strange behavior. Now I should make myself better at this point: that was strange behavior for me (I was used to Android before). Now I know why this behavior is like this. It is because, the way of turning bluetooth by the second way I described (swiping top from down and pressing bluetooth icon) TURNS OFF NOT BLUETOOTH CONNECTION, BUT IT TURNS OFF ALLOWING CONNECTIONS (bluetooth is still turned on, but can not connect with devices (which in apps is treated as bluetooth would be turned off!!). But still you can not manage it programatically anyway.. And I still think that it should be improved by apple.

Warning

As @user3620372 wrote, using prefs urls can cause app rejection with:

Your app uses the "prefs:root=" non-public URL scheme, which is a private entity. The use of non-public APIs is not permitted on the App Store because it can lead to a poor user experience should these APIs change.

like image 156
M. Wojcik Avatar answered Nov 10 '22 18:11

M. Wojcik


You cannot open the preferences directly, but if you include CBCentralManagerShowPowerAlertKey with a value of true when you create your CBCentralManager then iOS will prompt the user to turn Bluetooth on if it is turned off. The alert shown by iOS includes a button to open the Bluetooth settings.

like image 23
Paulw11 Avatar answered Nov 10 '22 17:11

Paulw11


_ = CBCentralManager(delegate: nil, queue: nil, options: [CBCentralManagerOptionShowPowerAlertKey:true])

The CBCentralManager is the class of CoreBluetooth, which is support by Apple, you can place this code in a method that called by a click action,

then it will pop up an alert view that ask you to choose an option, if u choose setting it will go to bluetooth settings page of iPhone. because u don't use this, so it may release after execute. but must u must turn off the bluetooth setting, or it will not pop up the alert view

let button = UIButton(type: .custom)
    button.setTitle("check bluetooth state", for: .normal)
    button.addTarget(self, action: #selector(didClick), for: .touchUpInside)


@objc func didClick(){
     _ = CBCentralManager(delegate: nil, queue: nil, options: [CBCentralManagerOptionShowPowerAlertKey:true])
}
like image 1
Fat Panda Avatar answered Nov 10 '22 18:11

Fat Panda