How do I open phone settings when a button is clic

2019-01-01 14:42发布

问题:

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.

回答1:

Using UIApplication.openSettingsURLString

Update for 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: 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 2.x

Using UIApplicationOpenSettingsURLString

override func viewDidAppear(animated: Bool) {
    var alertController = UIAlertController (title: \"Title\", message: \"Go to Settings?\", preferredStyle: .Alert)

    var settingsAction = UIAlertAction(title: \"Settings\", style: .Default) { (_) -> Void in
        let settingsUrl = NSURL(string: UIApplicationOpenSettingsURLString)
        if let url = settingsUrl {
            UIApplication.sharedApplication().openURL(url)
        }
    }

    var cancelAction = UIAlertAction(title: \"Cancel\", style: .Default, handler: nil)
    alertController.addAction(settingsAction)
    alertController.addAction(cancelAction)

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


回答2:

Swift 4

UIApplication.shared.open(URL.init(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

\"enter

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

  • 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

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



回答3:

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)


回答4:

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!



回答5:

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)
    }
  }


回答6:

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



回答7:

in ios10/ Xcode 8 in simulator:

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

works

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

does not.



回答8:

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.



回答9:

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.



回答10:

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)
    }
}


回答11:

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.



回答12:

SWIFT 4

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

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


回答13:

In iOS 10 and Swift 3, use the code below:

UIApplication.shared.open(URL.init(string: \"App-Prefs:root=General\")!, options: [:]) { (success) in
}


回答14:

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.