In iOS 11, we can easily configure Wi-Fi networks by reading QR code for Wi-Fi. But some reasonable situations that is keeping iOS version lower than iOS 11 can exist.
WiFiQRCodeKit provides the Wi-Fi configuration feature via QR code for the situations. It can work with iOS 8.0+.
github "Kuniwak/WiFiQRCodeKit" >= 1.0
pod 'WiFiQRCodeKit', '~> 1.0'
- iOS 8.0+
And WiFiQRCodeKit requires 2 other libraries:
- A QR code reader library
- A local HTTP server library
It means that you can use any libraries you want.
This is an simple example for using with yannickl/QRCodeReader.swift and httpswift/swifter:
// AppDelegate.swift
import QRCodeReader
import WiFiQRCodeKit
class AppDelegate: UIResponder, UIApplicationDelegate {
// ...
private let installer = WiFIQRCodeKit.MobileConfig.Installer(
distributingBy: SwifterMobileConfigDistributionServer(listeningOn: 8989)
)
private var qrCodeReaderWindow: UIWindow?
private var originalWindow: UIWindow?
// ...
func applicationDidEnterBackground(_ application: UIApplication) {
// This method MUST be called in the method.
self.installer.keepDistributionServerForBackground(for: application)
}
// Open a QR code reader.
func readQRCode() {
let qrCodeReaderBuilder = QRCodeReaderViewControllerBuilder()
qrCodeReaderBuilder.reader = QRCodeReader(
metadataObjectTypes: [.qr],
captureDevicePosition: .back
)
let qrCodeReaderViewController = QRCodeReaderViewController(builder: qrCodeReaderBuilder)
qrCodeReaderViewController.completionBlock = { [weak self] result in
guard let `self` = self else { return }
if let result = result {
self.install(qrCodeContent: result.value)
}
self.qrCodeReaderWindow = nil
self.originalWindow.makeKeyAndVisible()
}
self.originalWindow = UIApplication.shared.keyWindow
let qrCodeReaderWindow = UIWindow()
qrCodeReaderWindow.rootViewController = qrCodeReaderViewController
qrCodeReaderWindow.makeKeyAndVisible()
self.qrCodeReaderWindow = window
}
// Install the Wi-Fi settings.
private func install(qrCodeContent: String) {
switch WiFiQRCodeKit.parse(text: qrCodeContent) {
case .success(let wiFiQRCode):
var mobileConfig = WiFiQRCodeKit.MobileConfig.from(
wiFiQRCode: wiFiQRCode,
organization: .init(organizationName: "Example, Inc.")
// Also you can specify the following optional items:
//
// identifier: .init(identifier: "com.example.WiFiSettings"),
// description: "Joining the Wi-Fi network that managed by Example, Inc.",
// displayName: .init(displayName: "Wi-Fi settings for Example, Inc."),
// consentText: .init(consentTextsForEachLanguages: [
// .default: "Would you join the Wi-Fi network that manged by Example, Inc.?",
// .en: "Would you join the Wi-Fi network that manged by Example, Inc.?",
// .jp: "Example, Inc. の Wi-Fi ネットワークへ接続しますか?",
// ])
)
// You can modify other items such as the expiration option of the configuration profile.
// Configurable items are listed on "Configuration Profile Reference".
// See https://developer.apple.com/library/content/featuredarticles/iPhoneConfigurationProfileRef/
// It open the configuration profile on Safari.
self.installer.install(mobileConfig: mobileConfig)
case .failed(because: let reason):
dump(reason)
}
}
}
// SwifterMobileConfigDistributionServer.swift
import Swifter
import WiFiQRCodeKit
class SwifterMobileConfigDistributionServer: WiFiQRCodeKit.MobileConfig.DistributionServer {
let distributionURL: URL
private let server: Swifter.HttpServer
private let port: UInt16
private var mobileConfig: (data: Data, mimeType: String)?
init(listeningOn port: UInt16) {
let mobileConfigPath = "/WiFi.mobileConfig"
self.distributionURL = URL(string: "http://127.0.0.1:\(port)\(mobileConfigPath)")!
self.port = port
self.server = Swifter.HttpServer()
self.server[mobileConfigPath] = { [weak self] (_: Swifter.HttpRequest) -> Swifter.HttpResponse in
guard let `self` = self, let mobileConfig = self.mobileConfig else {
return .notFound
}
let statusCode = 20
let statusText = "OK"
let headers = ["Content-Type": mobileConfig.mimeType]
return .raw(
statusCode,
statusText,
headers,
{ (writer: Swifter.HttpResponseBodyWriter) throws in
try writer.write(mobileConfig.data)
}
)
}
}
func start() -> WiFiQRCodeKit.MobileConfig.DistributionServerState {
do {
try self.server.start(self.port)
return .successfullyStarted
}
catch {
return .failed(because: "\(error)")
}
}
func update(mobileConfigData: Data, mimeType: String) {
self.mobileConfig = (data: mobileConfigData, mimeType: mimeType)
}
}
See Kuniwak/WiFiQRCodeKitExampleApp.
The procedure of WiFiQRCodeKit is the following:
- Get a Wi-Fi QR code content by a QR code reader library
- WiFiQRCodeKit create the provisioing profile for Wi-Fi settings
- WiFiQRCodeKit start a local HTTP server that will deliver the provisoning profile
- WiFiQRCodeKit open Safari with an URL of the local HTTP server
- Safari confirm the provisioning profile to the user
- Connect to the Wi-Fi
- Barcode Contents - zxing/zxing
- Phonebook Registration - NTT docomo
- Configuration Profile Reference - Apple
- Installing a configuration profile on iPhone - programmatically
- Monadic Parse Combinators
The MIT License (MIT)