简体   繁体   中英

How do I open phone settings when a button is clicked?

I am trying to implement a feature in an App that shows an alert when the internet connection is not available. The alert has two actions (OK and Settings), whenever a user clicks on settings, I want to take them to the phone settings programmatically.

I am using Swift and Xcode.

Using UIApplication.openSettingsURLString

Update for Swift 5.1

 override func viewDidAppear(_ animated: Bool) {
    let alertController = UIAlertController (title: "Title", message: "Go to Settings?", preferredStyle: .alert)

    let settingsAction = UIAlertAction(title: "Settings", style: .default) { (_) -> Void in

        guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
            return
        }

        if UIApplication.shared.canOpenURL(settingsUrl) {
            UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
                print("Settings opened: \(success)") // Prints true
            })
        }
    }
    alertController.addAction(settingsAction)
    let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
    alertController.addAction(cancelAction)

    present(alertController, animated: true, completion: nil)
}

Swift 4.2

override func viewDidAppear(_ animated: Bool) {
    let alertController = UIAlertController (title: "Title", message: "Go to Settings?", preferredStyle: .alert)

    let settingsAction = UIAlertAction(title: "Settings", style: .default) { (_) -> Void in

        guard let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) else {
            return
        }

        if UIApplication.shared.canOpenURL(settingsUrl) {
            UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
                print("Settings opened: \(success)") // Prints true
            })
        }
    }
    alertController.addAction(settingsAction)
    let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
    alertController.addAction(cancelAction)

    present(alertController, animated: true, completion: nil)
}

⚠️ Be careful!

This answer is based on undocumented APIs and recently (since iOS12) Apple is rejecting apps with this approach.

Original answer below

Swift 5

UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)

Swift 4

UIApplication.shared.open(URL(string: UIApplicationOpenSettingsURLString)!, options: [:], completionHandler: nil)

NOTE: The following method works for all the versions below iOS 11, for higher versions the app might get rejected since it's a private API

Sometimes we want to take a user to settings other than our app settings. The following method will help you achieve that:

First, configure the URL Schemes in your project. You will find it in Target -> Info -> URL Scheme. click on + button and type prefs in URL Schemes

在此处输入图片说明

Swift 5

UIApplication.shared.open(URL(string: "App-prefs:Bluetooth")!)

Swift 3

UIApplication.shared.open(URL(string:"App-Prefs:root=General")!, options: [:], completionHandler: nil)

Swift

UIApplication.sharedApplication().openURL(NSURL(string:"prefs:root=General")!)

Objective-C

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=General"]];

and following are all the available URLs

**On IOS < 12 **

  • prefs:root=General&path=About
  • prefs:root=General&path=ACCESSIBILITY
  • prefs:root=AIRPLANE_MODE
  • prefs:root=General&path=AUTOLOCK
  • prefs:root=General&path=USAGE/CELLULAR_USAGE
  • prefs:root=Brightness
  • prefs:root=Bluetooth
  • prefs:root=General&path=DATE_AND_TIME
  • prefs:root=FACETIME
  • prefs:root=General
  • prefs:root=General&path=Keyboard
  • prefs:root=CASTLE
  • prefs:root=CASTLE&path=STORAGE_AND_BACKUP
  • prefs:root=General&path=INTERNATIONAL
  • prefs:root=LOCATION_SERVICES
  • prefs:root=ACCOUNT_SETTINGS
  • prefs:root=MUSIC
  • prefs:root=MUSIC&path=EQ
  • prefs:root=MUSIC&path=VolumeLimit
  • prefs:root=General&path=Network
  • prefs:root=NIKE_PLUS_IPOD
  • prefs:root=NOTES
  • prefs:root=NOTIFICATIONS_ID
  • prefs:root=Phone
  • prefs:root=Photos
  • prefs:root=General&path=ManagedConfigurationList
  • prefs:root=General&path=Reset
  • prefs:root=Sounds&path=Ringtone
  • prefs:root=Safari
  • prefs:root=General&path=Assistant
  • prefs:root=Sounds
  • prefs:root=General&path=SOFTWARE_UPDATE_LINK
  • prefs:root=STORE
  • prefs:root=TWITTER
  • prefs:root=FACEBOOK
  • prefs:root=General&path=USAGE prefs:root=VIDEO
  • prefs:root=General&path=Network/VPN
  • prefs:root=Wallpaper
  • prefs:root=WIFI
  • prefs:root=INTERNET_TETHERING
  • prefs:root=Phone&path=Blocked
  • prefs:root=DO_NOT_DISTURB

On IOS 13

  • App-prefs:General&path=About
  • App-prefs:AIRPLANE_MODE
  • App-prefs:General&path=AUTOLOCK
  • App-prefs:Bluetooth
  • App-prefs:General&path=DATE_AND_TIME
  • App-prefs:FACETIME
  • App-prefs:General
  • App-prefs:General&path=Keyboard
  • App-prefs:CASTLE
  • App-prefs:CASTLE&path=STORAGE_AND_BACKUP
  • App-prefs:General&path=INTERNATIONAL
  • App-prefs:MUSIC
  • App-prefs:NOTES
  • App-prefs:NOTIFICATIONS_ID
  • App-prefs:Phone
  • App-prefs:Photos
  • App-prefs:General&path=ManagedConfigurationList
  • App-prefs:General&path=Reset
  • App-prefs:Sounds&path=Ringtone
  • App-prefs:Sounds
  • App-prefs:General&path=SOFTWARE_UPDATE_LINK
  • App-prefs:STORE
  • App-prefs:Wallpaper
  • App-prefs:WIFI
  • App-prefs:INTERNET_TETHERING
  • App-prefs:DO_NOT_DISTURB

    Not tested

  • App-prefs:TWITTER (??)

  • App-prefs:FACEBOOK (??)
  • App-prefs:NIKE_PLUS_IPOD (??)

Note: Network setting will not be opened in a simulator, but the link will work on a real device.

SWIFT 5

if let settingsUrl = URL(string: UIApplication.openSettingsURLString) {

   UIApplication.shared.open(settingsUrl)

 }

In iOS 8+ you can do the following:

 func buttonClicked(sender:UIButton)
    {
        UIApplication.sharedApplication().openURL(NSURL(string: UIApplicationOpenSettingsURLString))
    }

Swift 4

    let settingsUrl = URL(string: UIApplicationOpenSettingsURLString)!
    UIApplication.shared.open(settingsUrl)

Using @vivek's hint I develop an utils class based on Swift 3 , hope you appreciate!

import Foundation
import UIKit

public enum PreferenceType: String {

    case about = "General&path=About"
    case accessibility = "General&path=ACCESSIBILITY"
    case airplaneMode = "AIRPLANE_MODE"
    case autolock = "General&path=AUTOLOCK"
    case cellularUsage = "General&path=USAGE/CELLULAR_USAGE"
    case brightness = "Brightness"
    case bluetooth = "Bluetooth"
    case dateAndTime = "General&path=DATE_AND_TIME"
    case facetime = "FACETIME"
    case general = "General"
    case keyboard = "General&path=Keyboard"
    case castle = "CASTLE"
    case storageAndBackup = "CASTLE&path=STORAGE_AND_BACKUP"
    case international = "General&path=INTERNATIONAL"
    case locationServices = "LOCATION_SERVICES"
    case accountSettings = "ACCOUNT_SETTINGS"
    case music = "MUSIC"
    case equalizer = "MUSIC&path=EQ"
    case volumeLimit = "MUSIC&path=VolumeLimit"
    case network = "General&path=Network"
    case nikePlusIPod = "NIKE_PLUS_IPOD"
    case notes = "NOTES"
    case notificationsId = "NOTIFICATIONS_ID"
    case phone = "Phone"
    case photos = "Photos"
    case managedConfigurationList = "General&path=ManagedConfigurationList"
    case reset = "General&path=Reset"
    case ringtone = "Sounds&path=Ringtone"
    case safari = "Safari"
    case assistant = "General&path=Assistant"
    case sounds = "Sounds"
    case softwareUpdateLink = "General&path=SOFTWARE_UPDATE_LINK"
    case store = "STORE"
    case twitter = "TWITTER"
    case facebook = "FACEBOOK"
    case usage = "General&path=USAGE"
    case video = "VIDEO"
    case vpn = "General&path=Network/VPN"
    case wallpaper = "Wallpaper"
    case wifi = "WIFI"
    case tethering = "INTERNET_TETHERING"
    case blocked = "Phone&path=Blocked"
    case doNotDisturb = "DO_NOT_DISTURB"

}

enum PreferenceExplorerError: Error {
    case notFound(String)
}

open class PreferencesExplorer {

    // MARK: - Class properties -

    static private let preferencePath = "App-Prefs:root"

    // MARK: - Class methods -

    static func open(_ preferenceType: PreferenceType) throws {
        let appPath = "\(PreferencesExplorer.preferencePath)=\(preferenceType.rawValue)"
        if let url = URL(string: appPath) {
            if #available(iOS 10.0, *) {
                UIApplication.shared.open(url, options: [:], completionHandler: nil)
            } else {
               UIApplication.shared.openURL(url)
            }
        } else {
            throw PreferenceExplorerError.notFound(appPath)
        }
    }

}

This is very helpful since that API's will change for sure and you can refactor once and very fast!

The first response from App-Specific URL Schemes worked for me on iOS 10.3.

if let appSettings = URL(string: UIApplicationOpenSettingsURLString + Bundle.main.bundleIdentifier!) {
    if UIApplication.shared.canOpenURL(appSettings) {
      UIApplication.shared.open(appSettings)
    }
  }

App-Prefs:root=Privacy&path=LOCATION worked for me for getting to general location settings. Note: only works on a device.

word of warning: the prefs:root or App-Prefs:root URL schemes are considered private API. Apple may reject you app if you use those, here is what you may get when submitting your app:

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. Continuing to use or conceal non-public APIs in future submissions of this app may result in the termination of your Apple Developer account, as well as removal of all associated apps from the App Store.

Next Steps

To resolve this issue, please revise your app to provide the associated functionality using public APIs or remove the functionality using the "prefs:root" or "App-Prefs:root" URL scheme.

If there are no alternatives for providing the functionality your app requires, you can file an enhancement request.

in ios10/ Xcode 8 in simulator:

UIApplication.shared.openURL(URL(string:UIApplicationOpenSettingsURLString)!)

works

UIApplication.shared.openURL(URL(string:"prefs:root=General")!)

does not.

I have seen this line of code

UIApplication.sharedApplication() .openURL(NSURL(string:"prefs:root=General")!)

is not working, it didn't work for me in ios10/ Xcode 8, just a small code difference, please replace this with

UIApplication.sharedApplication().openURL(NSURL(string:"App-Prefs:root=General")!)

Swift3

UIApplication.shared.openURL(URL(string:"prefs:root=General")!)

Replace with

UIApplication.shared.openURL(URL(string:"App-Prefs:root=General")!)

Hope it helps. Cheers.

Swift 4.2, iOS 12

The open(url:options:completionHandler:) method has been updated to include a non-nil options dictionary, which as of this post only contains one possible option of type UIApplication.OpenExternalURLOptionsKey (in the example).

@objc func openAppSpecificSettings() {
    guard let url = URL(string: UIApplication.openSettingsURLString),
        UIApplication.shared.canOpenURL(url) else {
            return
    }
    let optionsKeyDictionary = [UIApplication.OpenExternalURLOptionsKey(rawValue: "universalLinksOnly"): NSNumber(value: true)]
    
    UIApplication.shared.open(url, options: optionsKeyDictionary, completionHandler: nil)
}

Explicitly constructing a URL, such as with "App-Prefs", has, AFAIK, gotten some apps rejected from the store.

Adding to @Luca Davanzo

iOS 11, some permissions settings have moved to the app path:

iOS 11 Support

 static func open(_ preferenceType: PreferenceType) throws {
    var preferencePath: String
    if #available(iOS 11.0, *), preferenceType == .video || preferenceType == .locationServices || preferenceType == .photos {
        preferencePath = UIApplicationOpenSettingsURLString
    } else {
        preferencePath = "\(PreferencesExplorer.preferencePath)=\(preferenceType.rawValue)"
    }

    if let url = URL(string: preferencePath) {
        if #available(iOS 10.0, *) {
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
        } else {
            UIApplication.shared.openURL(url)
        }
    } else {
        throw PreferenceExplorerError.notFound(preferencePath)
    }
}

SWIFT 4

This could take your app's specific settings, if that's what you're looking for.

UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!)

As above @niravdesai said App-prefs. I found that App-Prefs: works for both iOS 9, 10 and 11. devices tested. where as prefs: only works on iOS 9.

UIApplication.open(_:options:completionHandler:) must be used from main thread only -----> Bug fix

if let appSettings = URL(string: UIApplication.openSettingsURLString + Bundle.main.bundleIdentifier!) {
  if UIApplication.shared.canOpenURL(appSettings) {
    DispatchQueue.main.async {
        UIApplication.shared.open(appSettings)
    }
  }
}

可以打开iphone存储设置页面吗?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM